- Loading...
Note: this proposal has been withdrawn. It has been superceded by JDK-8243208
This is a design document for JDK-8236988 - Modular Design for JVM Flags
Improve the implementation of JVM command-line flags (such as -XX:+UseCompressedOops)
Break up monolithic globals.hpp
#include "gc/z/z_globals.hpp
"
#include "memory/metaspaceShared_globals.hpp" // just flags related to CDS
E.g., one can have a "manageable" switch and an "experimental" switch, but not a "manageable_experimental" switch.
(Design contribution by Erik Österlund, Stefan Karlsson, Coleen Phillimore)
NOTE:
Before
product()
, develop()
, diagnostic()
, etc.product(intx, MaxLoopPad, (OptoLoopAlignment-1), \ "Align a loop if padding size in bytes is less or equal to this " \ "value") \ range(0, max_jint) \ \ develop(intx, OptoPrologueNops, 0, \ "Insert this many extra nop instructions " \ "in the prologue of every nmethod") \ range(0, 128) \ \ notproduct(bool, VerifyGraphEdges , false, \ "Verify Bi-directional Edges") \ \ product_pd(intx, InteriorEntryAlignment, \ "Code alignment for interior entry points " \ "in generated code (in bytes)") \ constraint(InteriorEntryAlignmentConstraintFunc, AfterErgo) \ \ diagnostic(bool, StressLCM, false, \ "Randomize instruction scheduling in LCM") \
After
HotSpot developers should consult the HPP for information about the flags (same as before).
XXX_FLAG
macros: see the top of globals.hpp.// PRODUCT_FLAG -- always settable // DEVELOP_FLAG -- settable only during development and are constant in the PRODUCT version // NOTPROD_FLAG -- settable only during development and are *not* declared in the PRODUCT version PRODUCT_FLAG(intx, MaxLoopPad, (OptoLoopAlignment-1), JVMFlag::RANGE, "Align a loop if padding size in bytes is less or equal to this " "value"); FLAG_RANGE( MaxLoopPad, 0, max_jint); DEVELOP_FLAG(intx, OptoPrologueNops, 0, JVMFlag::RANGE, "Insert this many extra nop instructions " "in the prologue of every nmethod"); FLAG_RANGE( OptoPrologueNops, 0, 128); NOTPROD_FLAG(bool, VerifyGraphEdges, false, JVMFlag::DEFAULT, "Verify Bi-directional Edges"); PRODUCT_FLAG_PD(intx, InteriorEntryAlignment, JVMFlag::CONSTRAINT, "Code alignment for interior entry points " "in generated code (in bytes)"); FLAG_CONSTRAINT( InteriorEntryAlignment, (void*)InteriorEntryAlignmentConstraintFunc, JVMFlag::AfterErgo); // NOTE: diagnostic macros are specified by setting the JVMFlag::DIAGNOSTIC bit in the // flag's attr (see globals.hpp for details). // // This allows more flexible specification of attributes. E.g., manageable-experimental flags // in JDK-7123237 can be specified using JVMFlag::MANAGEABLE | JVMFlag::EXPERIMENTAL, PRODUCT_FLAG(bool, StressLCM, false, JVMFlag::DIAGNOSTIC, "Randomize instruction scheduling in LCM");
Macros in the HPP files are expanded to
// The is the main API of this flag for HotSpot code. E.g., // if (StressLCM) {.....} extern "C" bool StressLCM; // This structure has the meta-information about this flag. E.g., HotSpot code can use it // to dynamically query the type of this flag. extern ProductFlag<FLAG_TYPE_StressLCM> FLAG_StressLCM; // The following inline functions pass meta-information about this flag to the CPP file inline bool FLAG_DEFVAL_StressLCM() { return false; } typedef bool FLAG_TYPE_StressLCM; inline JVMFlag::FlagType FLAG_TYPE_NAME_StressLCM() { return JVMFlag::TYPE_bool; } inline int FLAG_ATTR_StressLCM() { return JVMFlag::DIAGNOSTIC; } inline const char* FLAG_DOCS_StressLCM() { return "Randomize instruction scheduling in LCM"; }; <... the expansion of some macros are omitted for clarity> // Range information are expanded like this: inline int FLAG_ATTR_MaxLoopPad() { return JVMFlag::RANGE; } inline FLAG_TYPE_MaxLoopPad FLAG_MIN_MaxLoopPad() { return 0; } inline FLAG_TYPE_MaxLoopPad FLAG_MAX_MaxLoopPad() { return max_jint; }
The main goal of the inline functions is to avoid duplicating the information between the HPP and CPP files, so the CPP files contains just boilerplate code.
DEFN_PRODUCT_FLAG(StressLCM); DEFN_PRODUCT_FLAG(StressGCM); DEFN_PRODUCT_FLAG(MaxLoopPad); DEFN_PRODUCT_RANGE(MaxLoopPad); DEFN_PRODUCT_FLAG_PD(InteriorEntryAlignment); DEFN_PRODUCT_CONSTRAINT(InteriorEntryAlignment);
Macros in the CPP files are expanded to
// Definition of the flag itself FLAG_TYPE_StressLCM StressLCM = FLAG_DEFVAL_StressLCM(); // Definition of the flag's meta information ProductFlag<FLAG_TYPE_StressLCM> FLAG_StressLCM( FLAG_TYPE_NAME_StressLCM(), "StressLCM", (FLAG_ATTR_StressLCM() | JVMFlag::C2), &StressLCM, FLAG_DOCS_StressLCM()); <... the expansion of some macros are omitted for clarity> // Range check is implemented like this JVMFlagRange<FLAG_TYPE_MaxLoopPad> FLAG_RANGE_MaxLoopPad( &FLAG_MaxLoopPad, FLAG_MIN_MaxLoopPad(), FLAG_MAX_MaxLoopPad()); // Inside the constructor of FLAG_RANGE_MaxLoopPad, it essentially registers // itself as the range spec for FLAG_MaxLoopPad, FLAG_MaxLoopPad._range = &FLAG_RANGE_MaxLoopPad;
The consistency between the .hpp/.cpp files are mostly statically enforced at compile time. E.g.,
However, it's possible to forget to put DEFN_PRODUCT_RANGE(MaxLoopPad)
in c2_globals.cpp. I can't think of a way to statically check for that, so I added a runtime check (debug builds only). See JVMFlag::validate_flags().
Meta-information of the flags
As seen above, meta-information about each flag XYZ
is stored in the structure FLAG_XYZ
. This structure can be used directly to access the flag. E.g.,
intx new_val = .....; FLAG_MaxLoopPad.check_range(&new_val, verbose);
As a result, we no longer need to do a linear search for range/constraint checking.
Iterating over all flags:
The FLAG_XXXs are constructed using C++ global constructors, and are appended to a global list. This list can be used for iterating over all the flags (e.g., for implementing -XX:+PrintFlagsFinal
).
struct JVMFlag { static JVMFlag* _head; JVMFlag* _next; ... }; template <typename T> class ProductFlag : /* a subclass of JVMFlag */ { ProductFlagNone(...) { /*effectively*/ this->_next = _head; // executed as C++ global constructor _head = this; }}; #define JVMFLAG_FOR_EACH(f) \ for (f = JVMFlag::head(); f != NULL; f = f->next())
Alternatives
flag type = bool, name = UseCompressedOops, default = false, help = "Use 32-bit object references in 64-bit VM.", type = product | lp64;
Or XML, or ....
Auto-generation of header files from templates