#include #include #include #include "globals.hpp" #define assert(a,b) // Implementation macros #define MATERIALIZE_PRODUCT_FLAG(type, name, value, doc, ...) type name = value; #define MATERIALIZE_PD_PRODUCT_FLAG(type, name, doc, ...) type name = pd_##name; #ifdef PRODUCT #define MATERIALIZE_DEVELOP_FLAG(type, name, value, doc, ...) #define MATERIALIZE_PD_DEVELOP_FLAG(type, name, doc, ...) #define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc, ...) #else #define MATERIALIZE_DEVELOP_FLAG(type, name, value, doc, ...) type name = value; #define MATERIALIZE_PD_DEVELOP_FLAG(type, name, doc, ...) type name = pd_##name; #define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc, ...) type name = value; #endif // PRODUCT ALL_FLAGS(MATERIALIZE_DEVELOP_FLAG, MATERIALIZE_PD_DEVELOP_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) struct JVMFlag { enum Attr { DEFAULT = 0, COMMAND_LINE = 1, ENVIRON_VAR = 2, CONFIG_FILE = 3, MANAGEMENT = 4, ERGONOMIC = 5, ATTACH_ON_DEMAND = 6, INTERNAL = 7, JIMAGE_RESOURCE = 8, LAST_VALUE_ORIGIN = JIMAGE_RESOURCE, VALUE_ORIGIN_BITS = 4, VALUE_ORIGIN_MASK = 0x0f, // right_n_bits(VALUE_ORIGIN_BITS), IS_PRODUCT = 1 << 4, MANAGEABLE = 1 << 5, DIAGNOSTIC = 1 << 6, EXPERIMENTAL = 1 << 7, NOTPRODUCT = 1 << 8, DEVELOP = 1 << 9, PLATFORM_DEPENDENT = 1 << 10, READ_WRITE = 1 << 11, C1 = 1 << 12, C2 = 1 << 13, ARCH = 1 << 14, LP64 = 1 << 15, JVMCI = 1 << 16, STRINGLIST = 1 << 17, // replaces the old ccstrlist -- TODO document RANGE = 1 << 18, // -- TODO document CONSTRAINT = 1 << 19, // -- TODO document // set this bit if the flag was set on the command line ORIG_COMMAND_LINE = 1 << 21, // huh COMMAND_LINE and ORIG_COMMAND_LINE KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE | STRINGLIST | RANGE | CONSTRAINT), ALL_NOT_PRODUCT_FLAGS = DEVELOP | NOTPRODUCT | MANAGEABLE | EXPERIMENTAL | DIAGNOSTIC | LP64 | JVMCI }; typedef Attr Flags; // compatibility for usage of JVMFlag::Flags -- TODO fix in separate RFE enum Error { // no error SUCCESS = 0, // flag name is missing MISSING_NAME, // flag value is missing MISSING_VALUE, // error parsing the textual form of the value WRONG_FORMAT, // flag is not writable NON_WRITABLE, // flag value is outside of its bounds OUT_OF_BOUNDS, // flag value violates its constraint VIOLATES_CONSTRAINT, // there is no flag with the given name INVALID_FLAG, // the flag can only be set only on command line during invocation of the VM COMMAND_LINE_ONLY, // the flag may only be set once SET_ONLY_ONCE, // the flag is not writable in this combination of product/debug build CONSTANT, // other, unspecified error related to setting the flag ERR_OTHER }; enum MsgType { NONE = 0, DIAGNOSTIC_FLAG_BUT_LOCKED, EXPERIMENTAL_FLAG_BUT_LOCKED, DEVELOP_FLAG_BUT_PRODUCT_BUILD, NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD }; // During VM initialization, constraint validation will be done order of ConstraintPhase. enum ConstraintPhase { // Will be validated during argument processing (Arguments::parse_argument). AtParse = 0, // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). AfterErgo = 1, // Will be validated inside universe_init(), right after Metaspace::global_initialize(). AfterMemoryInit = 2 }; #define JVM_FLAG_ALL_TYPES_DO(f) \ f(bool) \ f(int) \ f(uint) \ f(intx) \ f(uintx) \ f(uint64_t) \ f(size_t) \ f(double) \ f(ccstr) #define JVM_FLAG_TYPE_DECLARE(t) \ TYPE_ ## t, // Define TYPE_bool, TYPE_int, .... etc enum FlagType { JVM_FLAG_ALL_TYPES_DO(JVM_FLAG_TYPE_DECLARE) NUM_TYPES }; #define FLAG_ACCESSOR(t) \ t get_##t() const { return *((t*)value_addr()); } \ bool is_##t() const { return _type == JVMFlag::TYPE_ ## t; } JVM_FLAG_ALL_TYPES_DO(FLAG_ACCESSOR) void* _value_addr; NOT_PRODUCT(const char* _docs;) const char* _name; short _name_len; short _type; int _attr; public: // constexpr JVMFlag() : _value_addr(0), NOT_PRODUCT_ARG(_docs(0)) _name(0), _name_len(0), _type(0), _attr(0) {} const char* name() const { return _name; } const char* docs() const { return NOT_PRODUCT(_docs) PRODUCT_ONLY(""); } int attr() const { return _attr; } void* value_addr() const { return _value_addr; } FlagType type() const { assert(0 <= _type && _type < JVMFlag::NUM_TYPES, "must be"); return (FlagType)_type; } int get_origin() const { return _attr & VALUE_ORIGIN_MASK; } bool is_default() const { return (get_origin() == DEFAULT); } static JVMFlag::Error boolAt(const JVMFlag* flag, bool* value); static JVMFlag::Error boolAtPut(JVMFlag* flag, bool value, Attr origin); static JVMFlag::Error intAt(const JVMFlag* flag, int* value); static JVMFlag::Error intAtPut(JVMFlag* flag, int value, Attr origin); static JVMFlag::Error uintAt(const JVMFlag* flag, uint* value); static JVMFlag::Error uintAtPut(JVMFlag* flag, uint value, Attr origin); static JVMFlag::Error intxAt(const JVMFlag* flag, intx* value); static JVMFlag::Error intxAtPut(JVMFlag* flag, intx value, Attr origin); static JVMFlag::Error uintxAt(const JVMFlag* flag, uintx* value); static JVMFlag::Error uintxAtPut(JVMFlag* flag, uintx value, Attr origin); static JVMFlag::Error size_tAt(const JVMFlag* flag, size_t* value); static JVMFlag::Error size_tAtPut(JVMFlag* flag, size_t value, Attr origin); static JVMFlag::Error uint64_tAt(const JVMFlag* flag, uint64_t* value); static JVMFlag::Error uint64_tAtPut(JVMFlag* flag, uint64_t value, Attr origin); static JVMFlag::Error doubleAt(const JVMFlag* flag, double* value); static JVMFlag::Error doubleAtPut(JVMFlag* flag, double value, Attr origin); static JVMFlag::Error ccstrAt(const JVMFlag* flag, ccstr* value); // Contract: JVMFlag will make private copy of the incoming value. // Outgoing value is always malloc-ed, and caller MUST call free. static JVMFlag::Error ccstrAtPut(JVMFlag* flag, ccstr* value, Attr origin); static JVMFlag::Error ccstrAtPut(JVMFlag* flag, ccstr value, Attr origin) { return ccstrAtPut(flag, &value, origin); } bool is_product() const { return (_attr & IS_PRODUCT) != 0; } bool is_manageable() const { return (_attr & MANAGEABLE) != 0; } bool is_diagnostic() const { return (_attr & DIAGNOSTIC) != 0; } bool is_experimental() const { return (_attr & EXPERIMENTAL) != 0; } bool is_notproduct() const { return (_attr & NOTPRODUCT) != 0; } bool is_develop() const { return (_attr & DEVELOP) != 0; } bool is_read_write() const { return (_attr & READ_WRITE) != 0; } bool ccstr_accumulates() const { return is_ccstr() && (_attr & STRINGLIST) != 0; } // is this flag a constant in the JVM binary. bool is_constant_in_binary() const { return PRODUCT_ONLY(is_notproduct() || is_develop()) NOT_PRODUCT(false); } bool is_modifiable() const { return !is_constant_in_binary(); } bool is_writeable() const { return is_manageable() || (is_product() && is_read_write()); } public: const char* docs() { PRODUCT_ONLY(return "";) NOT_PRODUCT(return _docs;) } void print(int i, const char* limit_info) const { printf("[%2d] %-30s %s", i, _name, limit_info); if (_attr & JVMFlag::IS_PRODUCT) printf(" product"); if (_attr & JVMFlag::DEVELOP) printf(" develop"); if (_attr & JVMFlag::PLATFORM_DEPENDENT) printf(" pd"); if (_attr & JVMFlag::DIAGNOSTIC) printf(" diagnostic"); if (_attr & JVMFlag::EXPERIMENTAL) printf(" experimental"); if (_attr & JVMFlag::C2) printf(" c2"); } }; #define ALL_CONSTRAINT_FUNCS_DO(f) \ f(TypeProfileLevelConstraintFunc) \ f(ContendedPaddingWidthConstraintFunc) #define FUNC_ENUM(func) enum_##func, enum { enum_zero_is_invalid = 0, ALL_CONSTRAINT_FUNCS_DO(FUNC_ENUM) num_funcs, // must be 16-bit }; #define ATTR 0 #define LEN(s) ((short)(sizeof(s) - 1)) #define IGNORE_FLAG(...) #define STRUCT_FOR_DEVELOP_FLAG( type, name, value, doc, attr, ...) { (void*) &name, NOT_PRODUCT_ARG(doc) STR(name), LEN(XSTR(name)), JVMFlag::TYPE_##type, (attr | JVMFlag::DEVELOP) }, #define STRUCT_FOR_PD_DEVELOP_FLAG(type, name, doc, attr, ...) { (void*) &name, NOT_PRODUCT_ARG(doc) STR(name), LEN(XSTR(name)), JVMFlag::TYPE_##type, (attr | JVMFlag::DEVELOP | JVMFlag::PLATFORM_DEPENDENT) }, #define STRUCT_FOR_PRODUCT_FLAG( type, name, value, doc, attr, ...) { (void*) &name, NOT_PRODUCT_ARG(doc) STR(name), LEN(XSTR(name)), JVMFlag::TYPE_##type, (attr | JVMFlag::IS_PRODUCT) }, #define STRUCT_FOR_PD_PRODUCT_FLAG(type, name, doc, attr, ...) { (void*) &name, NOT_PRODUCT_ARG(doc) STR(name), LEN(XSTR(name)), JVMFlag::TYPE_##type, (attr | JVMFlag::IS_PRODUCT | JVMFlag::PLATFORM_DEPENDENT) }, #define STRUCT_FOR_NOTPRODUCT_FLAG(type, name, value, doc, attr, ...) { (void*) &name, NOT_PRODUCT_ARG(doc) STR(name), LEN(XSTR(name)), JVMFlag::TYPE_##type, (attr | JVMFlag::NOTPRODUCT) }, const static JVMFlag flagTable[] = { // Only product flags ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, STRUCT_FOR_PRODUCT_FLAG, STRUCT_FOR_PD_PRODUCT_FLAG, IGNORE_FLAG) ALL_FLAGS(STRUCT_FOR_DEVELOP_FLAG, STRUCT_FOR_PD_DEVELOP_FLAG, IGNORE_FLAG, IGNORE_FLAG, STRUCT_FOR_NOTPRODUCT_FLAG) }; #define ENUM_FOR_FLAG(type, name, ...) enum_##name, enum FLAG_ENUM { // Only product flags ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, ENUM_FOR_FLAG, ENUM_FOR_FLAG, IGNORE_FLAG) // Only non-product flags ALL_FLAGS(ENUM_FOR_FLAG, ENUM_FOR_FLAG, IGNORE_FLAG, IGNORE_FLAG, ENUM_FOR_FLAG) num_of_flags }; #ifdef PRODUCT #define COUNT_PRODUCT_ENUM_FOR_FLAG(type, name, ...) count_enum_##name, enum FLAG_COUNT_PRODUCT { // Only product flags ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, COUNT_PRODUCT_ENUM_FOR_FLAG, COUNT_PRODUCT_ENUM_FOR_FLAG, IGNORE_FLAG) num_of_product_flags }; #else enum FLAG_COUNT_PRODUCT { num_of_product_flags = num_of_flags }; #endif #define HAS_RANGE 1 #define HAS_CONSTRAINT 2 #if 1 #define CONSTEXPR constexpr /* TODO: turn this on when hotspot supports constexpr. It generate more compact code. All limit_XXX structures and flagLimitTable[] are initialized at compile time. gcc8.3.0-OL6.4+1.0/bin/g++ -DPRODUCT -O3 -c -save-temps -fPIC: _ZL14flagLimitTable: .quad _ZL24limits_SuspendRetryCount .quad 0 .quad 0 .quad _ZL23limits_TypeProfileLevel .quad _ZL28limits_ContendedPaddingWidth .quad _ZL31limits_ObjectCountCutOffPercent .section .rodata _ZL24limits_SuspendRetryCount: .value 0 .byte 0 .byte 1 .zero 4 .quad 0 .quad 9223372036854775807 .section .rodata.str1.1 $ size globals.o (6 JVMFlagLimits) text data bss dec hex filename 1315 280 1 1596 63c globals.o */ #else #define CONSTEXPR /* This generates worse code than with constexpr (~6 instructions per JVMFlagLimit) gcc8.3.0-OL6.4+1.0/bin/g++ -DPRODUCT -O3 -c -save-temps -fPIC: ;; global constructor _GLOBAL__sub_I_globals.cpp: ;; initialize limits_SuspendRetryCount movdqa .LC15(%rip), %xmm0 leaq _ZL24limits_SuspendRetryCount(%rip), %rax movl $16777216, _ZL24limits_SuspendRetryCount(%rip) movq %rax, _ZL14flagLimitTable(%rip) ;; init flagLimitTable[enum_SuspendRetryCount] leaq _ZL23limits_TypeProfileLevel(%rip), %rax movups %xmm0, 8+_ZL24limits_SuspendRetryCount(%rip) ;; initialize null-limit movq $0, 8+_ZL14flagLimitTable(%rip) ;; ... ret ;; JVMFlagLimit structure is uninitialized at compile-time .local _ZL24limits_SuspendRetryCount .comm _ZL24limits_SuspendRetryCount,24,16 .section .rodata.str1.1 $ size globals.o (6 JVMFlagLimits) text data bss dec hex filename 1442 240 200 1882 75a globals.o */ #endif struct JVMFlagLimitBase { short _constraint_func; char _phase; char _kind; CONSTEXPR JVMFlagLimitBase(short func, short phase, short kind) : _constraint_func(func), _phase(phase), _kind(kind) {} }; template struct JVMFlagLimit : public JVMFlagLimitBase { const T _min; const T _max; // dummy - no range or constraint. This object will not be emitted into the .o file // because we declare it as "const" but has no reference to it. CONSTEXPR JVMFlagLimit(int attr) : JVMFlagLimitBase(0, 0, 0), _min(0), _max(0) {} // range only CONSTEXPR JVMFlagLimit(int attr, T min, T max) : JVMFlagLimitBase(0, 0, HAS_RANGE), _min(min), _max(max) {} // constraint only CONSTEXPR JVMFlagLimit(int attr, int dummy, int func, int phase) : JVMFlagLimitBase(func, phase, HAS_CONSTRAINT), _min(0), _max(0) {} // range and constraint CONSTEXPR JVMFlagLimit(int attr, T min, T max, int dummy, int func, int phase) : JVMFlagLimitBase(func, phase, HAS_RANGE | HAS_CONSTRAINT), _min(min), _max(max) {} }; #define INIT_LIMIT_FOR_FLAG( type, name, value, doc, /* attr */ ...) const JVMFlagLimit limits_##name(__VA_ARGS__); #define INIT_LIMIT_FOR_FLAG_PD(type, name, doc, /* attr */ ...) const JVMFlagLimit limits_##name(__VA_ARGS__); #ifdef PRODUCT ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, INIT_LIMIT_FOR_FLAG, INIT_LIMIT_FOR_FLAG_PD, IGNORE_FLAG) #else ALL_FLAGS(INIT_LIMIT_FOR_FLAG, INIT_LIMIT_FOR_FLAG_PD, INIT_LIMIT_FOR_FLAG, INIT_LIMIT_FOR_FLAG_PD, INIT_LIMIT_FOR_FLAG) #endif template static inline CONSTEXPR const JVMFlagLimitBase* get_limit(const JVMFlagLimit* p, int attr) { // This effectively drops the empty JVMFlagLimit return NULL; } template static inline CONSTEXPR const JVMFlagLimitBase* get_limit(const JVMFlagLimit*p, int attr, T min, T max) { return p; } template static inline CONSTEXPR const JVMFlagLimitBase* get_limit(const JVMFlagLimit*p, int attr, int dummy, int func, int phase) { return p; } template static inline CONSTEXPR const JVMFlagLimitBase* get_limit(const JVMFlagLimit*p, int attr, T min, T max, int dummy, int func, int phase) { return p; } #define GET_LIMIT_FOR_FLAG( type, name, value, doc, /* attr */ ...) get_limit(&limits_##name, __VA_ARGS__), #define GET_LIMIT_FOR_FLAG_PD(type, name, doc, /* attr */ ...) get_limit(&limits_##name, __VA_ARGS__), static const JVMFlagLimitBase* const flagLimitTable[] = { ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, GET_LIMIT_FOR_FLAG, GET_LIMIT_FOR_FLAG_PD, ) #ifndef PRODUCT ALL_FLAGS(GET_LIMIT_FOR_FLAG, GET_LIMIT_FOR_FLAG_PD, IGNORE_FLAG, IGNORE_FLAG, GET_LIMIT_FOR_FLAG) #endif }; const char* get_limit_string(int flag_enum) { if (flag_enum < num_of_product_flags) { const JVMFlagLimitBase* p = flagLimitTable[flag_enum]; if (p != NULL) { switch (p->_kind) { case HAS_RANGE : return "r-"; case HAS_CONSTRAINT : return "-c"; case HAS_RANGE | HAS_CONSTRAINT : return "rc"; } } return "--"; } else { return "xx"; } } void print_all_constraints() { int num = int(sizeof(flagLimitTable)/sizeof(flagLimitTable[0])); printf("sizeof(flagLimitTable) = %d\n", int(sizeof(flagLimitTable))); for (int i=0; iprint(i, get_limit_string(i)); printf("\n"); } } //====================================================================== // Compile-time hashing of the names //====================================================================== /* With constexpr, table is completely initialized at compile time .type _ZL13flagHashTable, @object .size _ZL13flagHashTable, 86 _ZL13flagHashTable: .value 0 .value 0 .value 8 .value 5 .value 3 .value 0 .value 1 .value 0 [....] .section .data.rel.ro.local,"aw" .align 32 Without constexpr, hash_code() can be done with a fancy macro .... please google ..... The quality of GCC code generation various. With 8 flags and 3 buckets, the code isn't too bad: movdqa .LC21(%rip), %xmm0 xorl %eax, %eax movw %ax, 28+_ZL13flagHashTable(%rip) movl $0, 24+_ZL13flagHashTable(%rip) movaps %xmm0, _ZL13flagHashTable(%rip) movq %rax, 16+_ZL13flagHashTable(%rip) but it's a lot worse for With 8 flags and 17 buckets (some how it cannot elide the reads from buckets[mybucket]). */ constexpr unsigned int hash_code(const char* s) { unsigned int h = 0; while (*s) { h = 31*h + (unsigned int) *s; s++; } return h; } #define SET_HASH_TABLE(type, name, ...) \ { \ const int mybucket = hash_code(#name) % NUM_BUCKETS; \ table[enum_##name] = buckets[mybucket]; \ buckets[mybucket] = (short)enum_##name; \ } //#define NUM_BUCKETS 17 #define NUM_BUCKETS 3 struct JVMFlagHashtable { short buckets[NUM_BUCKETS]; short table[NUM_BUCKETS + num_of_flags]; CONSTEXPR JVMFlagHashtable() : buckets(), table() { { for (int i = 0; i < NUM_BUCKETS; i++) { buckets[i] = 0; } } ALL_FLAGS(SET_HASH_TABLE, SET_HASH_TABLE, SET_HASH_TABLE, SET_HASH_TABLE, SET_HASH_TABLE) } void print() const { { for (int i = 0; i < NUM_BUCKETS; i++) { printf("buckets[%2d] = %4d\n", i, buckets[i]); } } { for (int i = 0; i < num_of_flags; i++) { printf("table[%2d].next = %4d\n", i, table[i]); } } } }; const static JVMFlagHashtable flagHashTable; void print_hashtable() { flagHashTable.print(); } //====================================================================== // Compiled-time sorting of of the names (constexpr required) //====================================================================== constexpr int comp(int a_isdev, int b_isdev, const char* a, const char* b) { if (a_isdev > b_isdev) { return -1; } if (a_isdev < b_isdev) { return 1; } while (1) { if (*a == 0) { return (*b == 0) ? 0 : 1;} if (*b == 0) { return (*a == 0) ? -1 : 0;} if (*a > *b) { return -1; } if (*a < *b) { return 1; } a++; b++; } } #define PRO_COMP_NAME(type, name, ...) if (comp(isdev, 0, s, #name) < 0) ++rank; #define DEV_COMP_NAME(type, name, ...) if (comp(isdev, 1, s, #name) < 0) ++rank; constexpr int get_rank(int isdev, const char* s) { int rank = 0; ALL_FLAGS(DEV_COMP_NAME, DEV_COMP_NAME, PRO_COMP_NAME, PRO_COMP_NAME, DEV_COMP_NAME) return rank; } #define PRO_SET_NAME_TABLE(type, name, ...) { int rank = get_rank(0, #name); names[rank] = #name; } #define DEV_SET_NAME_TABLE(type, name, ...) { int rank = get_rank(1, #name); names[rank] = #name; } // Split-sorted: // All product flags first (sorted alphabetically) // then all non-product flags (sorted flphabetically) struct SplitSortedNames { const char* names[num_of_flags]; constexpr SplitSortedNames() : names() { ALL_FLAGS(DEV_SET_NAME_TABLE, DEV_SET_NAME_TABLE, PRO_SET_NAME_TABLE, PRO_SET_NAME_TABLE, DEV_SET_NAME_TABLE) } const char* at(int i) const { return names[i]; } }; const static SplitSortedNames sorted_names; void print_sorted_names() { printf("enum SplitSortedFlagNames { // put in generated source file\n"); for (int i=0; i= num_of_product_flags ? " // develop" : ""); } printf("};\n"); } //====================================================================== // Sorting the entire flagTable (must use constexpr) //====================================================================== #define PRO_SET_FLAG_TABLE( type, name, value, docs, attr, ...) { int rank = get_rank(0, #name); init_flag(rank, #name, (void*)&name, LEN(XSTR(name)), JVMFlag::TYPE_##type, NOT_PRODUCT_ARG(docs) (attr | JVMFlag::IS_PRODUCT)); } #define PRO_SET_FLAG_TABLE_PD(type, name, docs, attr, ...) { int rank = get_rank(0, #name); init_flag(rank, #name, (void*)&name, LEN(XSTR(name)), JVMFlag::TYPE_##type, NOT_PRODUCT_ARG(docs) (attr | JVMFlag::IS_PRODUCT)); } #define DEV_SET_FLAG_TABLE( type, name, value, docs, attr, ...) { int rank = get_rank(1, #name); init_flag(rank, #name, (void*)&name, LEN(XSTR(name)), JVMFlag::TYPE_##type, NOT_PRODUCT_ARG(docs) (attr | JVMFlag::DEVELOP)); } #define DEV_SET_FLAG_TABLE_PD(type, name, docs, attr, ...) { int rank = get_rank(1, #name); init_flag(rank, #name, (void*)&name, LEN(XSTR(name)), JVMFlag::TYPE_##type, NOT_PRODUCT_ARG(docs) (attr | JVMFlag::DEVELOP)); } #define SET_SORTED_LIMIT( type, name, value, doc, /* attr */ ...) { int rank = get_rank(0, #name); limits[rank] = get_limit(&limits_##name, __VA_ARGS__);} #define SET_SORTED_LIMIT_PD(type, name, doc, /* attr */ ...) { int rank = get_rank(0, #name); limits[rank] = get_limit(&limits_##name, __VA_ARGS__);} // Split-sorted: // All product flags first (sorted alphabetically) // then all non-product flags (sorted flphabetically) struct SplitSortedFlags { JVMFlag flags[num_of_flags]; const JVMFlagLimitBase* limits[num_of_product_flags]; constexpr void init_flag(int i, const char*name, void* value_addr, short name_len, short type, NOT_PRODUCT_ARG(const char* docs) short attr) { flags[i]._name = name; flags[i]._value_addr = value_addr; flags[i]._name_len = name_len; flags[i]._attr = attr; flags[i]._type = type; #ifndef PRODUCT flags[i]._docs = docs; #endif } constexpr SplitSortedFlags() : flags(), limits() { ALL_FLAGS(DEV_SET_FLAG_TABLE, DEV_SET_FLAG_TABLE_PD, PRO_SET_FLAG_TABLE, PRO_SET_FLAG_TABLE_PD, DEV_SET_FLAG_TABLE) ALL_FLAGS(IGNORE_FLAG, IGNORE_FLAG, SET_SORTED_LIMIT, SET_SORTED_LIMIT_PD, IGNORE_FLAG) } const JVMFlag* at(int i) const { return &flags[i]; } const char* get_limit_string(int i) const { if (i < num_of_product_flags) { const JVMFlagLimitBase* p = limits[i]; if (p != NULL) { switch (p->_kind) { case HAS_RANGE : return "r-"; case HAS_CONSTRAINT : return "-c"; case HAS_RANGE | HAS_CONSTRAINT : return "rc"; } } return "--"; } else { return "xx"; } } }; static const SplitSortedFlags sorted_flags; void print_sorted_flags() { for (int i=0; iprint(i, sorted_flags.get_limit_string(i)); printf("\n"); } }