...
- Builds list of range/constraint checking objects at VM start-up (lots of code and slow start)
- Range/constraint checking needs linear search (further slows down start-up)
The new code design (see here for webrev):
The range/constraint information for a flag of type T is described by a JVMTypedFlagLimit<T>:
Code Block |
---|
class JVMFlagLimit {
enum {
HAS_RANGE = 1,
HAS_CONSTRAINT = 2
};
short _constraint_func;
char _phase;
char _kind; ...};
template <typename T>
class JVMTypedFlagLimit : public JVMFlagLimit {
const T _min;
const T _max; ...} |
Each flag is given a unique enum that starts from 0 to NUM_JVMFlagsEnum-1. We use this enum to find the JVMTypedFlagLimit<T> of this flag from an array:
Code Block |
---|
static constexpr const JVMFlagLimit* const flagLimitTable[1 + NUM_JVMFlagsEnum] = { .... }
const JVMFlagLimit* const* JVMFlagLimit::flagLimits = &flagLimitTable[1]; // excludes dummy
/* E.g., to get the limit of this flag:
product(intx, ContendedPaddingWidth, 128, \
"How many bytes to pad the fields/classes marked @Contended with")\
range(0, 8192) \
constraint(ContendedPaddingWidthConstraintFunc,AfterErgo) \
*/
const JVMTypedFlagLimit<intx>* limit = JVMFlagLimit::flagLimits[Flag_ContendedPaddingWidth_Enum];
// We have:
// limit->_constraint_func ==> constraint_enum_ContendedPaddingWidthConstraintFunc (more on this below)
// limit->_phase ==> AfterErgo
// limit->_kind ==> HAS_RANGE | HAS_CONSTRAINT
// limit->_min ==> 0
// limit->_max ==> 8192 |
Most flags have neither range nor constraint. For those flags, we want its flagLimits[Flag_flagname_Enum] to be NULL.
To do this, we first define a JVMTypedFlagLimit<T> variable for each flag (including the ones that don't have range/constraint. It's done by this macro:
Code Block |
---|
// macro body starts here -------------------+
// |
// v
#define FLAG_LIMIT_DEFINE( type, name, ...) ); const JVMTypedFlagLimit<type> limit_##name(0
#define FLAG_LIMIT_DEFINE_DUMMY(type, name, ...) ); const DummyLimit nolimit_##name(0
#define FLAG_LIMIT_PTR( type, name, ...) ), LimitGetter<type>::get_limit(&limit_##name, 0
#define FLAG_LIMIT_PTR_NONE( type, name, ...) ), LimitGetter<type>::no_limit(0
#define APPLY_FLAG_RANGE(...) , __VA_ARGS__
#define APPLY_FLAG_CONSTRAINT(func, phase) , next_two_args_are_constraint, (short)CONSTRAINT_ENUM(func), int(JVMFlagConstraint::phase)
const JVMTypedFlagLimit<int> limit_dummy
(
#ifdef PRODUCT
ALL_FLAGS(FLAG_LIMIT_DEFINE_DUMMY,
FLAG_LIMIT_DEFINE_DUMMY,
FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE_DUMMY,
APPLY_FLAG_RANGE,
APPLY_FLAG_CONSTRAINT)
#else
ALL_FLAGS(FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE,
FLAG_LIMIT_DEFINE,
APPLY_FLAG_RANGE,
APPLY_FLAG_CONSTRAINT)
#endif
); |
To understand how this works, it's best to compile jvmFlagLimit.c with gcc -save-temps. and look at the generated jvmFlagLimit.ii with the macros expanded. Here's an example:
- Builds the checker objects (JVMFlagLimit) at build-time using constexpr.
- JVMFlagLimit objects are indexed by each flag's enum (or NULL if no limit exists), so it's O(1) time.
...