Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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.

...