src/hotspot/share/gc/shared/gcConfig.cpp
author pliden
Wed, 28 Mar 2018 11:38:47 +0200
changeset 49629 b786280276dc
child 49922 3a64eea72624
child 56422 b09629f4b243
permissions -rw-r--r--
8199925: Break out GC selection logic from GCArguments to GCConfig Reviewed-by: eosterlund, rkennke

/*
 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#include "precompiled.hpp"
#include "gc/serial/serialArguments.hpp"
#include "gc/shared/gcConfig.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/parallel/parallelArguments.hpp"
#include "gc/cms/cmsArguments.hpp"
#include "gc/g1/g1Arguments.hpp"
#endif // INCLUDE_ALL_GCS

struct SupportedGC {
  bool&               _flag;
  CollectedHeap::Name _name;
  GCArguments&        _arguments;

  SupportedGC(bool& flag, CollectedHeap::Name name, GCArguments& arguments) :
      _flag(flag), _name(name), _arguments(arguments) {}
};

static SerialArguments   serialArguments;
#if INCLUDE_ALL_GCS
static ParallelArguments parallelArguments;
static CMSArguments      cmsArguments;
static G1Arguments       g1Arguments;
#endif // INCLUDE_ALL_GCS

// Table of supported GCs, for translating between command
// line flag, CollectedHeap::Name and GCArguments instance.
static const SupportedGC SupportedGCs[] = {
  SupportedGC(UseSerialGC,        CollectedHeap::Serial,   serialArguments),
#if INCLUDE_ALL_GCS
  SupportedGC(UseParallelGC,      CollectedHeap::Parallel, parallelArguments),
  SupportedGC(UseParallelOldGC,   CollectedHeap::Parallel, parallelArguments),
  SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS,      cmsArguments),
  SupportedGC(UseG1GC,            CollectedHeap::G1,       g1Arguments),
#endif // INCLUDE_ALL_GCS
};

GCArguments* GCConfig::_arguments = NULL;
bool GCConfig::_gc_selected_ergonomically = false;

void GCConfig::select_gc_ergonomically() {
#if INCLUDE_ALL_GCS
  if (os::is_server_class_machine()) {
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);
  } else {
    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
  }
#else
  UNSUPPORTED_OPTION(UseG1GC);
  UNSUPPORTED_OPTION(UseParallelGC);
  UNSUPPORTED_OPTION(UseParallelOldGC);
  UNSUPPORTED_OPTION(UseConcMarkSweepGC);
  FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
#endif // INCLUDE_ALL_GCS
}

bool GCConfig::is_no_gc_selected() {
  for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) {
    if (SupportedGCs[i]._flag) {
      return false;
    }
  }

  return true;
}

bool GCConfig::is_exactly_one_gc_selected() {
  CollectedHeap::Name selected = CollectedHeap::None;

  for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) {
    if (SupportedGCs[i]._flag) {
      if (SupportedGCs[i]._name == selected || selected == CollectedHeap::None) {
        // Selected
        selected = SupportedGCs[i]._name;
      } else {
        // More than one selected
        return false;
      }
    }
  }

  return selected != CollectedHeap::None;
}

GCArguments* GCConfig::select_gc() {
  if (is_no_gc_selected()) {
    // Try select GC ergonomically
    select_gc_ergonomically();

    if (is_no_gc_selected()) {
      // Failed to select GC ergonomically
      vm_exit_during_initialization("Garbage collector not selected "
                                    "(default collector explicitly disabled)", NULL);
    }

    // Succeeded to select GC ergonomically
    _gc_selected_ergonomically = true;
  }

  if (is_exactly_one_gc_selected()) {
    // Exacly one GC selected
    for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) {
      if (SupportedGCs[i]._flag) {
        return &SupportedGCs[i]._arguments;
      }
    }
  }

  // More than one GC selected
  vm_exit_during_initialization("Multiple garbage collectors selected", NULL);

  return NULL;
}

void GCConfig::initialize() {
  assert(_arguments == NULL, "Already initialized");
  _arguments = select_gc();
}

bool GCConfig::is_gc_supported(CollectedHeap::Name name) {
  for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) {
    if (SupportedGCs[i]._name == name) {
      // Supported
      return true;
    }
  }

  // Not supported
  return false;
}

bool GCConfig::is_gc_selected(CollectedHeap::Name name) {
  for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) {
    if (SupportedGCs[i]._name == name && SupportedGCs[i]._flag) {
      // Selected
      return true;
    }
  }

  // Not selected
  return false;
}

bool GCConfig::is_gc_selected_ergonomically() {
  return _gc_selected_ergonomically;
}

GCArguments* GCConfig::arguments() {
  assert(_arguments != NULL, "Not initialized");
  return _arguments;
}