/*
* 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/shared/gcConfig.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_CMSGC
#include "gc/cms/cmsArguments.hpp"
#endif
#if INCLUDE_G1GC
#include "gc/g1/g1Arguments.hpp"
#endif
#if INCLUDE_PARALLELGC
#include "gc/parallel/parallelArguments.hpp"
#endif
#if INCLUDE_SERIALGC
#include "gc/serial/serialArguments.hpp"
#endif
#if INCLUDE_EPSILONGC
#include "gc/epsilon/epsilonArguments.hpp"
#endif
struct SupportedGC {
bool& _flag;
CollectedHeap::Name _name;
GCArguments& _arguments;
const char* _hs_err_name;
SupportedGC(bool& flag, CollectedHeap::Name name, GCArguments& arguments, const char* hs_err_name) :
_flag(flag), _name(name), _arguments(arguments), _hs_err_name(hs_err_name) {}
};
CMSGC_ONLY(static CMSArguments cmsArguments;)
G1GC_ONLY(static G1Arguments g1Arguments;)
PARALLELGC_ONLY(static ParallelArguments parallelArguments;)
SERIALGC_ONLY(static SerialArguments serialArguments;)
EPSILONGC_ONLY(static EpsilonArguments epsilonArguments;)
// Table of supported GCs, for translating between command
// line flag, CollectedHeap::Name and GCArguments instance.
static const SupportedGC SupportedGCs[] = {
CMSGC_ONLY_ARG(SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS, cmsArguments, "concurrent mark sweep gc"))
G1GC_ONLY_ARG(SupportedGC(UseG1GC, CollectedHeap::G1, g1Arguments, "g1 gc"))
PARALLELGC_ONLY_ARG(SupportedGC(UseParallelGC, CollectedHeap::Parallel, parallelArguments, "parallel gc"))
PARALLELGC_ONLY_ARG(SupportedGC(UseParallelOldGC, CollectedHeap::Parallel, parallelArguments, "parallel gc"))
SERIALGC_ONLY_ARG(SupportedGC(UseSerialGC, CollectedHeap::Serial, serialArguments, "serial gc"))
EPSILONGC_ONLY_ARG(SupportedGC(UseEpsilonGC, CollectedHeap::Epsilon, epsilonArguments, "epsilon gc"))
};
#define FOR_EACH_SUPPORTED_GC(var) \
for (const SupportedGC* var = &SupportedGCs[0]; var < &SupportedGCs[ARRAY_SIZE(SupportedGCs)]; var++)
GCArguments* GCConfig::_arguments = NULL;
bool GCConfig::_gc_selected_ergonomically = false;
void GCConfig::select_gc_ergonomically() {
if (os::is_server_class_machine()) {
#if INCLUDE_G1GC
FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);
#elif INCLUDE_PARALLELGC
FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
#elif INCLUDE_SERIALGC
FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
#endif
} else {
#if INCLUDE_SERIALGC
FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
#endif
}
NOT_CMSGC( UNSUPPORTED_OPTION(UseConcMarkSweepGC));
NOT_G1GC( UNSUPPORTED_OPTION(UseG1GC);)
NOT_PARALLELGC(UNSUPPORTED_OPTION(UseParallelGC);)
NOT_PARALLELGC(UNSUPPORTED_OPTION(UseParallelOldGC));
NOT_SERIALGC( UNSUPPORTED_OPTION(UseSerialGC);)
NOT_EPSILONGC( UNSUPPORTED_OPTION(UseEpsilonGC);)
}
bool GCConfig::is_no_gc_selected() {
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_flag) {
return false;
}
}
return true;
}
bool GCConfig::is_exactly_one_gc_selected() {
CollectedHeap::Name selected = CollectedHeap::None;
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_flag) {
if (gc->_name == selected || selected == CollectedHeap::None) {
// Selected
selected = gc->_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()) {
// More than one GC selected
vm_exit_during_initialization("Multiple garbage collectors selected", NULL);
}
#if INCLUDE_PARALLELGC && !INCLUDE_SERIALGC
if (FLAG_IS_CMDLINE(UseParallelOldGC) && !UseParallelOldGC) {
vm_exit_during_initialization("This JVM build only supports UseParallelOldGC as the full GC");
}
#endif
// Exactly one GC selected
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_flag) {
return &gc->_arguments;
}
}
fatal("Should have found the selected GC");
return NULL;
}
void GCConfig::initialize() {
assert(_arguments == NULL, "Already initialized");
_arguments = select_gc();
}
bool GCConfig::is_gc_supported(CollectedHeap::Name name) {
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_name == name) {
// Supported
return true;
}
}
// Not supported
return false;
}
bool GCConfig::is_gc_selected(CollectedHeap::Name name) {
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_name == name && gc->_flag) {
// Selected
return true;
}
}
// Not selected
return false;
}
bool GCConfig::is_gc_selected_ergonomically() {
return _gc_selected_ergonomically;
}
const char* GCConfig::hs_err_name() {
if (is_exactly_one_gc_selected()) {
// Exacly one GC selected
FOR_EACH_SUPPORTED_GC(gc) {
if (gc->_flag) {
return gc->_hs_err_name;
}
}
}
// Zero or more than one GC selected
return "unknown gc";
}
GCArguments* GCConfig::arguments() {
assert(_arguments != NULL, "Not initialized");
return _arguments;
}