1 /*
  2  * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "jfr/jfrEvents.hpp"
 27 #include "jvm_io.h"
 28 #include "memory/allocation.inline.hpp"
 29 #include "memory/universe.hpp"
 30 #include "runtime/arguments.hpp"
 31 #include "runtime/flags/jvmFlag.hpp"
 32 #include "runtime/flags/jvmFlagAccess.hpp"
 33 #include "runtime/flags/jvmFlagLookup.hpp"
 34 #include "runtime/globals_extension.hpp"
 35 #include "utilities/bitMap.hpp"
 36 #include "utilities/defaultStream.hpp"
 37 #include "utilities/stringUtils.hpp"
 38 
 39 static bool is_product_build() {
 40 #ifdef PRODUCT
 41   return true;
 42 #else
 43   return false;
 44 #endif
 45 }
 46 
 47 void JVMFlag::set_origin(JVMFlagOrigin new_origin) {
 48   int old_flags = _flags;
 49   int origin = static_cast<int>(new_origin);
 50   assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity");
 51   int was_in_cmdline = (new_origin == JVMFlagOrigin::COMMAND_LINE) ? WAS_SET_ON_COMMAND_LINE : 0;
 52   _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | origin | was_in_cmdline);
 53   if ((old_flags & WAS_SET_ON_COMMAND_LINE) != 0) {
 54     assert((_flags & WAS_SET_ON_COMMAND_LINE) != 0, "once initialized, should never change");
 55   }
 56 }
 57 
 58 /**
 59  * Returns if this flag is a constant in the binary.  Right now this is
 60  * true for develop flags in product builds.
 61  */
 62 bool JVMFlag::is_constant_in_binary() const {
 63 #ifdef PRODUCT
 64   return is_develop();
 65 #else
 66   return false;
 67 #endif
 68 }
 69 
 70 bool JVMFlag::is_unlocker() const {
 71   return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 ||
 72          strcmp(_name, "UnlockExperimentalVMOptions") == 0;
 73 }
 74 
 75 bool JVMFlag::is_unlocked() const {
 76   if (is_diagnostic()) {
 77     return UnlockDiagnosticVMOptions;
 78   }
 79   if (is_experimental()) {
 80     return UnlockExperimentalVMOptions;
 81   }
 82   return true;
 83 }
 84 
 85 void JVMFlag::clear_diagnostic() {
 86   assert(is_diagnostic(), "sanity");
 87   _flags = Flags(_flags & ~KIND_DIAGNOSTIC);
 88   assert(!is_diagnostic(), "sanity");
 89 }
 90 
 91 void JVMFlag::clear_experimental() {
 92   assert(is_experimental(), "sanity");
 93   _flags = Flags(_flags & ~KIND_EXPERIMENTAL);
 94   assert(!is_experimental(), "sanity");
 95 }
 96 
 97 void JVMFlag::set_product() {
 98   assert(!is_product(), "sanity");
 99   _flags = Flags(_flags | KIND_PRODUCT);
100   assert(is_product(), "sanity");
101 }
102 
103 // Get custom message for this locked flag, or null if
104 // none is available. Returns message type produced.
105 JVMFlag::MsgType JVMFlag::get_locked_message(char* buf, int buflen) const {
106   buf[0] = '\0';
107   if (is_diagnostic() && !is_unlocked()) {
108     jio_snprintf(buf, buflen,
109                  "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n"
110                  "Error: The unlock option must precede '%s'.\n",
111                  _name, _name);
112     return JVMFlag::DIAGNOSTIC_FLAG_BUT_LOCKED;
113   }
114   if (is_experimental() && !is_unlocked()) {
115     jio_snprintf(buf, buflen,
116                  "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n"
117                  "Error: The unlock option must precede '%s'.\n",
118                  _name, _name);
119     return JVMFlag::EXPERIMENTAL_FLAG_BUT_LOCKED;
120   }
121   if (is_develop() && is_product_build()) {
122     jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n",
123                  _name);
124     return JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD;
125   }
126   return JVMFlag::NONE;
127 }
128 
129 // Helper function for JVMFlag::print_on().
130 // Fills current line up to requested position.
131 // Should the current position already be past the requested position,
132 // one separator blank is enforced.
133 static void fill_to_pos(outputStream* st, unsigned int req_pos) {
134   if ((unsigned int)st->position() < req_pos) {
135     st->fill_to(req_pos);  // need to fill with blanks to reach req_pos
136   } else {
137     st->print(" ");        // enforce blank separation. Previous field too long.
138   }
139 }
140 
141 void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) const {
142   // Don't print develop flags in a product build.
143   if (is_constant_in_binary()) {
144     return;
145   }
146 
147   if (!printRanges) {
148     // The command line options -XX:+PrintFlags* cause this function to be called
149     // for each existing flag to print information pertinent to this flag. The data
150     // is displayed in columnar form, with the following layout:
151     //  col1 - data type, right-justified
152     //  col2 - name,      left-justified
153     //  col3 - ' ='       double-char, leading space to align with possible '+='
154     //  col4 - value      left-justified
155     //  col5 - kind       right-justified
156     //  col6 - origin     left-justified
157     //  col7 - comments   left-justified
158     //
159     //  The column widths are fixed. They are defined such that, for most cases,
160     //  an eye-pleasing tabular output is created.
161     //
162     //  Sample output:
163     //       bool ThreadPriorityVerbose                    = false                                     {product} {default}
164     //      uintx ThresholdTolerance                       = 10                                        {product} {default}
165     //     size_t TLABSize                                 = 0                                         {product} {default}
166     //      uintx SurvivorRatio                            = 8                                         {product} {default}
167     //     double InitialRAMPercentage                     = 1.562500                                  {product} {default}
168     //      ccstr CompileCommandFile                       = MyFile.cmd                                {product} {command line}
169     //  ccstrlist CompileOnly                              = Method1
170     //            CompileOnly                             += Method2                                   {product} {command line}
171     //  |         |                                       |  |                              |                    |               |
172     //  |         |                                       |  |                              |                    |               +-- col7
173     //  |         |                                       |  |                              |                    +-- col6
174     //  |         |                                       |  |                              +-- col5
175     //  |         |                                       |  +-- col4
176     //  |         |                                       +-- col3
177     //  |         +-- col2
178     //  +-- col1
179 
180     const unsigned int col_spacing = 1;
181     const unsigned int col1_pos    = 0;
182     const unsigned int col1_width  = 9;
183     const unsigned int col2_pos    = col1_pos + col1_width + col_spacing;
184     const unsigned int col2_width  = 39;
185     const unsigned int col3_pos    = col2_pos + col2_width + col_spacing;
186     const unsigned int col3_width  = 2;
187     const unsigned int col4_pos    = col3_pos + col3_width + col_spacing;
188     const unsigned int col4_width  = 30;
189     const unsigned int col5_pos    = col4_pos + col4_width + col_spacing;
190     const unsigned int col5_width  = 20;
191     const unsigned int col6_pos    = col5_pos + col5_width + col_spacing;
192     const unsigned int col6_width  = 15;
193     const unsigned int col7_pos    = col6_pos + col6_width + col_spacing;
194     const unsigned int col7_width  = 1;
195 
196     st->fill_to(col1_pos);
197     st->print("%*s", col1_width, type_string());  // right-justified, therefore width is required.
198 
199     fill_to_pos(st, col2_pos);
200     st->print("%s", _name);
201 
202     fill_to_pos(st, col3_pos);
203     st->print(" =");  // use " =" for proper alignment with multiline ccstr output.
204 
205     fill_to_pos(st, col4_pos);
206     if (is_bool()) {
207       st->print("%s", get_bool() ? "true" : "false");
208     } else if (is_int()) {
209       st->print("%d", get_int());
210     } else if (is_uint()) {
211       st->print("%u", get_uint());
212     } else if (is_intx()) {
213       st->print(INTX_FORMAT, get_intx());
214     } else if (is_uintx()) {
215       st->print(UINTX_FORMAT, get_uintx());
216     } else if (is_uint64_t()) {
217       st->print(UINT64_FORMAT, get_uint64_t());
218     } else if (is_size_t()) {
219       st->print(SIZE_FORMAT, get_size_t());
220     } else if (is_double()) {
221       st->print("%f", get_double());
222     } else if (is_ccstr()) {
223       // Honor <newline> characters in ccstr: print multiple lines.
224       const char* cp = get_ccstr();
225       if (cp != nullptr) {
226         const char* eol;
227         while ((eol = strchr(cp, '\n')) != nullptr) {
228           size_t llen = pointer_delta(eol, cp, sizeof(char));
229           st->print("%.*s", (int)llen, cp);
230           st->cr();
231           cp = eol+1;
232           fill_to_pos(st, col2_pos);
233           st->print("%s", _name);
234           fill_to_pos(st, col3_pos);
235           st->print("+=");
236           fill_to_pos(st, col4_pos);
237         }
238         st->print("%s", cp);
239       }
240     } else {
241       st->print("unhandled  type %s", type_string());
242       st->cr();
243       return;
244     }
245 
246     fill_to_pos(st, col5_pos);
247     print_kind(st, col5_width);
248 
249     fill_to_pos(st, col6_pos);
250     print_origin(st, col6_width);
251 
252 #ifndef PRODUCT
253     if (withComments) {
254       fill_to_pos(st, col7_pos);
255       st->print("%s", _doc);
256     }
257 #endif
258     st->cr();
259   } else if (!is_bool() && !is_ccstr()) {
260     // The command line options -XX:+PrintFlags* cause this function to be called
261     // for each existing flag to print information pertinent to this flag. The data
262     // is displayed in columnar form, with the following layout:
263     //  col1 - data type, right-justified
264     //  col2 - name,      left-justified
265     //  col4 - range      [ min ... max]
266     //  col5 - kind       right-justified
267     //  col6 - origin     left-justified
268     //  col7 - comments   left-justified
269     //
270     //  The column widths are fixed. They are defined such that, for most cases,
271     //  an eye-pleasing tabular output is created.
272     //
273     //  Sample output:
274     //       intx MinPassesBeforeFlush                               [ 0                         ...       9223372036854775807 ]                         {diagnostic} {default}
275     //     double MinRAMPercentage                                   [ 0.000                     ...                   100.000 ]                            {product} {default}
276     //      uintx MinSurvivorRatio                                   [ 3                         ...      18446744073709551615 ]                            {product} {default}
277     //     size_t MinTLABSize                                        [ 1                         ...       9223372036854775807 ]                            {product} {default}
278     //       intx MaxInlineSize                                      [ 0                         ...                2147483647 ]                            {product} {default}
279     //  |         |                                                  |                                                           |                                    |               |
280     //  |         |                                                  |                                                           |                                    |               +-- col7
281     //  |         |                                                  |                                                           |                                    +-- col6
282     //  |         |                                                  |                                                           +-- col5
283     //  |         |                                                  +-- col4
284     //  |         +-- col2
285     //  +-- col1
286 
287     const unsigned int col_spacing = 1;
288     const unsigned int col1_pos    = 0;
289     const unsigned int col1_width  = 9;
290     const unsigned int col2_pos    = col1_pos + col1_width + col_spacing;
291     const unsigned int col2_width  = 49;
292     const unsigned int col3_pos    = col2_pos + col2_width + col_spacing;
293     const unsigned int col3_width  = 0;
294     const unsigned int col4_pos    = col3_pos + col3_width + col_spacing;
295     const unsigned int col4_width  = 60;
296     const unsigned int col5_pos    = col4_pos + col4_width + col_spacing;
297     const unsigned int col5_width  = 35;
298     const unsigned int col6_pos    = col5_pos + col5_width + col_spacing;
299     const unsigned int col6_width  = 15;
300     const unsigned int col7_pos    = col6_pos + col6_width + col_spacing;
301     const unsigned int col7_width  = 1;
302 
303     st->fill_to(col1_pos);
304     st->print("%*s", col1_width, type_string());  // right-justified, therefore width is required.
305 
306     fill_to_pos(st, col2_pos);
307     st->print("%s", _name);
308 
309     fill_to_pos(st, col4_pos);
310     JVMFlagAccess::print_range(st, this);
311 
312     fill_to_pos(st, col5_pos);
313     print_kind(st, col5_width);
314 
315     fill_to_pos(st, col6_pos);
316     print_origin(st, col6_width);
317 
318 #ifndef PRODUCT
319     if (withComments) {
320       fill_to_pos(st, col7_pos);
321       st->print("%s", _doc);
322     }
323 #endif
324     st->cr();
325   }
326 }
327 
328 void JVMFlag::print_kind(outputStream* st, unsigned int width) const {
329   struct Data {
330     int flag;
331     const char* name;
332   };
333 
334   Data data[] = {
335     { KIND_JVMCI, "JVMCI" },
336     { KIND_C1, "C1" },
337     { KIND_C2, "C2" },
338     { KIND_ARCH, "ARCH" },
339     { KIND_PLATFORM_DEPENDENT, "pd" },
340     { KIND_PRODUCT, "product" },
341     { KIND_MANAGEABLE, "manageable" },
342     { KIND_DIAGNOSTIC, "diagnostic" },
343     { KIND_EXPERIMENTAL, "experimental" },
344     { KIND_DEVELOP, "develop" },
345     { KIND_LP64_PRODUCT, "lp64_product" },
346     { -1, "" }
347   };
348 
349   if ((_flags & KIND_MASK) != 0) {
350     bool is_first = true;
351     const size_t buffer_size = 64;
352     size_t buffer_used = 0;
353     char kind[buffer_size];
354 
355     jio_snprintf(kind, buffer_size, "{");
356     buffer_used++;
357     for (int i = 0; data[i].flag != -1; i++) {
358       Data d = data[i];
359       if ((_flags & d.flag) != 0) {
360         if (is_first) {
361           is_first = false;
362         } else {
363           assert(buffer_used + 1 < buffer_size, "Too small buffer");
364           jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " ");
365           buffer_used++;
366         }
367         size_t length = strlen(d.name);
368         assert(buffer_used + length < buffer_size, "Too small buffer");
369         jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name);
370         buffer_used += length;
371       }
372     }
373     assert(buffer_used + 2 <= buffer_size, "Too small buffer");
374     jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}");
375     st->print("%*s", width, kind);
376   }
377 }
378 
379 void JVMFlag::print_origin(outputStream* st, unsigned int width) const {
380   st->print("{");
381   switch(get_origin()) {
382     case JVMFlagOrigin::DEFAULT:
383       st->print("default"); break;
384     case JVMFlagOrigin::COMMAND_LINE:
385       st->print("command line"); break;
386     case JVMFlagOrigin::ENVIRON_VAR:
387       st->print("environment"); break;
388     case JVMFlagOrigin::CONFIG_FILE:
389       st->print("config file"); break;
390     case JVMFlagOrigin::MANAGEMENT:
391       st->print("management"); break;
392     case JVMFlagOrigin::ERGONOMIC:
393       if (_flags & WAS_SET_ON_COMMAND_LINE) {
394         st->print("command line, ");
395       }
396       st->print("ergonomic"); break;
397     case JVMFlagOrigin::ATTACH_ON_DEMAND:
398       st->print("attach"); break;
399     case JVMFlagOrigin::INTERNAL:
400       st->print("internal"); break;
401     case JVMFlagOrigin::JIMAGE_RESOURCE:
402       st->print("jimage"); break;
403   }
404   st->print("}");
405 }
406 
407 void JVMFlag::print_as_flag(outputStream* st) const {
408   if (is_bool()) {
409     st->print("-XX:%s%s", get_bool() ? "+" : "-", _name);
410   } else if (is_int()) {
411     st->print("-XX:%s=%d", _name, get_int());
412   } else if (is_uint()) {
413     st->print("-XX:%s=%u", _name, get_uint());
414   } else if (is_intx()) {
415     st->print("-XX:%s=" INTX_FORMAT, _name, get_intx());
416   } else if (is_uintx()) {
417     st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx());
418   } else if (is_uint64_t()) {
419     st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t());
420   } else if (is_size_t()) {
421     st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t());
422   } else if (is_double()) {
423     st->print("-XX:%s=%f", _name, get_double());
424   } else if (is_ccstr()) {
425     st->print("-XX:%s=", _name);
426     const char* cp = get_ccstr();
427     if (cp != nullptr) {
428       // Need to turn embedded '\n's back into separate arguments
429       // Not so efficient to print one character at a time,
430       // but the choice is to do the transformation to a buffer
431       // and print that.  And this need not be efficient.
432       for (; *cp != '\0'; cp += 1) {
433         switch (*cp) {
434           default:
435             st->print("%c", *cp);
436             break;
437           case '\n':
438             st->print(" -XX:%s=", _name);
439             break;
440         }
441       }
442     }
443   } else {
444     ShouldNotReachHere();
445   }
446 }
447 
448 //----------------------------------------------------------------------
449 // Build flagTable[]
450 
451 // Find out the number of LP64/ARCH/JVMCI/COMPILER1/COMPILER2 flags,
452 // for JVMFlag::flag_group()
453 
454 #define ENUM_F(type, name, ...)  enum_##name,
455 #define IGNORE_F(...)
456 
457 //                                                  dev     dev-pd  pro     pro-pd  range     constraint
458 enum FlagCounter_LP64  { LP64_RUNTIME_FLAGS(        ENUM_F, ENUM_F, ENUM_F, ENUM_F, IGNORE_F, IGNORE_F)  num_flags_LP64   };
459 enum FlagCounter_ARCH  { ARCH_FLAGS(                ENUM_F,         ENUM_F,         IGNORE_F, IGNORE_F)  num_flags_ARCH   };
460 enum FlagCounter_JVMCI { JVMCI_ONLY(JVMCI_FLAGS(    ENUM_F, ENUM_F, ENUM_F, ENUM_F, IGNORE_F, IGNORE_F)) num_flags_JVMCI  };
461 enum FlagCounter_C1    { COMPILER1_PRESENT(C1_FLAGS(ENUM_F, ENUM_F, ENUM_F, ENUM_F, IGNORE_F, IGNORE_F)) num_flags_C1     };
462 enum FlagCounter_C2    { COMPILER2_PRESENT(C2_FLAGS(ENUM_F, ENUM_F, ENUM_F, ENUM_F, IGNORE_F, IGNORE_F)) num_flags_C2     };
463 
464 const int first_flag_enum_LP64   = 0;
465 const int first_flag_enum_ARCH   = first_flag_enum_LP64  + num_flags_LP64;
466 const int first_flag_enum_JVMCI  = first_flag_enum_ARCH  + num_flags_ARCH;
467 const int first_flag_enum_C1     = first_flag_enum_JVMCI + num_flags_JVMCI;
468 const int first_flag_enum_C2     = first_flag_enum_C1    + num_flags_C1;
469 const int first_flag_enum_other  = first_flag_enum_C2    + num_flags_C2;
470 
471 static constexpr int flag_group(int flag_enum) {
472   if (flag_enum < first_flag_enum_ARCH)  return JVMFlag::KIND_LP64_PRODUCT;
473   if (flag_enum < first_flag_enum_JVMCI) return JVMFlag::KIND_ARCH;
474   if (flag_enum < first_flag_enum_C1)    return JVMFlag::KIND_JVMCI;
475   if (flag_enum < first_flag_enum_C2)    return JVMFlag::KIND_C1;
476   if (flag_enum < first_flag_enum_other) return JVMFlag::KIND_C2;
477 
478   return 0;
479 }
480 
481 constexpr JVMFlag::JVMFlag(int flag_enum, FlagType type, const char* name,
482                            void* addr, int flags, int extra_flags, const char* doc) :
483   _addr(addr), _name(name), _flags(), _type(type) NOT_PRODUCT(COMMA _doc(doc)) {
484   flags = flags | extra_flags | static_cast<int>(JVMFlagOrigin::DEFAULT) | flag_group(flag_enum);
485   if ((flags & JVMFlag::KIND_PRODUCT) != 0) {
486     if (flags & (JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_MANAGEABLE | JVMFlag::KIND_EXPERIMENTAL)) {
487       // Backwards compatibility. This will be relaxed in JDK-7123237.
488       flags &= ~(JVMFlag::KIND_PRODUCT);
489     }
490   }
491   _flags = static_cast<Flags>(flags);
492 }
493 
494 constexpr JVMFlag::JVMFlag(int flag_enum,  FlagType type, const char* name,
495                            void* addr, int flags, const char* doc) :
496   JVMFlag(flag_enum, type, name, addr, flags, /*extra_flags*/0, doc) {}
497 
498 const int PRODUCT_KIND     = JVMFlag::KIND_PRODUCT;
499 const int PRODUCT_KIND_PD  = JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT;
500 const int DEVELOP_KIND     = JVMFlag::KIND_DEVELOP;
501 const int DEVELOP_KIND_PD  = JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT;
502 
503 #define FLAG_TYPE(type) (JVMFlag::TYPE_ ## type)
504 #define INITIALIZE_DEVELOP_FLAG(   type, name, value, ...) JVMFlag(FLAG_MEMBER_ENUM(name), FLAG_TYPE(type), XSTR(name), (void*)&name, DEVELOP_KIND,    __VA_ARGS__),
505 #define INITIALIZE_DEVELOP_FLAG_PD(type, name,        ...) JVMFlag(FLAG_MEMBER_ENUM(name), FLAG_TYPE(type), XSTR(name), (void*)&name, DEVELOP_KIND_PD, __VA_ARGS__),
506 #define INITIALIZE_PRODUCT_FLAG(   type, name, value, ...) JVMFlag(FLAG_MEMBER_ENUM(name), FLAG_TYPE(type), XSTR(name), (void*)&name, PRODUCT_KIND,    __VA_ARGS__),
507 #define INITIALIZE_PRODUCT_FLAG_PD(type, name,        ...) JVMFlag(FLAG_MEMBER_ENUM(name), FLAG_TYPE(type), XSTR(name), (void*)&name, PRODUCT_KIND_PD, __VA_ARGS__),
508 
509 // Handy aliases to match the symbols used in the flag specification macros.
510 const int DIAGNOSTIC   = JVMFlag::KIND_DIAGNOSTIC;
511 const int MANAGEABLE   = JVMFlag::KIND_MANAGEABLE;
512 const int EXPERIMENTAL = JVMFlag::KIND_EXPERIMENTAL;
513 
514 #define MATERIALIZE_ALL_FLAGS      \
515   ALL_FLAGS(INITIALIZE_DEVELOP_FLAG,     \
516             INITIALIZE_DEVELOP_FLAG_PD,  \
517             INITIALIZE_PRODUCT_FLAG,     \
518             INITIALIZE_PRODUCT_FLAG_PD,  \
519             IGNORE_RANGE,          \
520             IGNORE_CONSTRAINT)
521 
522 static JVMFlag flagTable[NUM_JVMFlagsEnum + 1] = {
523   MATERIALIZE_ALL_FLAGS
524   JVMFlag() // The iteration code wants a flag with a null name at the end of the table.
525 };
526 
527 // We want flagTable[] to be completely initialized at C++ compilation time, which requires
528 // that all arguments passed to JVMFlag() constructors be constexpr. The following line
529 // checks for this -- if any non-constexpr arguments are passed, the C++ compiler will
530 // generate an error.
531 //
532 // constexpr implies internal linkage. This means the flagTable_verify_constexpr[] variable
533 // will not be included in jvmFlag.o, so there's no footprint cost for having this variable.
534 //
535 // Note that we cannot declare flagTable[] as constexpr because JVMFlag::_flags is modified
536 // at runtime.
537 constexpr JVMFlag flagTable_verify_constexpr[] = { MATERIALIZE_ALL_FLAGS };
538 
539 JVMFlag* JVMFlag::flags = flagTable;
540 size_t JVMFlag::numFlags = (sizeof(flagTable) / sizeof(JVMFlag));
541 
542 #define JVM_FLAG_TYPE_SIGNATURE(t) JVMFlag::type_signature<t>(),
543 
544 const int JVMFlag::type_signatures[] = {
545   JVM_FLAG_NON_STRING_TYPES_DO(JVM_FLAG_TYPE_SIGNATURE)
546   JVMFlag::type_signature<ccstr>(),
547   JVMFlag::type_signature<ccstr>()
548 };
549 
550 // Search the flag table for a named flag
551 JVMFlag* JVMFlag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) {
552   JVMFlag* flag = JVMFlagLookup::find(name, length);
553   if (flag != nullptr) {
554     // Found a matching entry.
555     // Don't report develop flags in product builds.
556     if (flag->is_constant_in_binary()) {
557       return (return_flag ? flag : nullptr);
558     }
559     // Report locked flags only if allowed.
560     if (!(flag->is_unlocked() || flag->is_unlocker())) {
561       if (!allow_locked) {
562         // disable use of locked flags, e.g. diagnostic, experimental,
563         // etc. until they are explicitly unlocked
564         return nullptr;
565       }
566     }
567     return flag;
568   }
569   // JVMFlag name is not in the flag table
570   return nullptr;
571 }
572 
573 JVMFlag* JVMFlag::fuzzy_match(const char* name, size_t length, bool allow_locked) {
574   double VMOptionsFuzzyMatchSimilarity = 0.7;
575   JVMFlag* match = nullptr;
576   double score;
577   double max_score = -1;
578 
579   for (JVMFlag* current = &flagTable[0]; current->_name != nullptr; current++) {
580     score = StringUtils::similarity(current->_name, strlen(current->_name), name, length);
581     if (score > max_score) {
582       max_score = score;
583       match = current;
584     }
585   }
586 
587   if (match == nullptr) {
588     return nullptr;
589   }
590 
591   if (!(match->is_unlocked() || match->is_unlocker())) {
592     if (!allow_locked) {
593       return nullptr;
594     }
595   }
596 
597   if (max_score < VMOptionsFuzzyMatchSimilarity) {
598     return nullptr;
599   }
600 
601   return match;
602 }
603 
604 bool JVMFlag::is_default(JVMFlagsEnum flag) {
605   return flag_from_enum(flag)->is_default();
606 }
607 
608 bool JVMFlag::is_ergo(JVMFlagsEnum flag) {
609   return flag_from_enum(flag)->is_ergonomic();
610 }
611 
612 bool JVMFlag::is_cmdline(JVMFlagsEnum flag) {
613   return flag_from_enum(flag)->is_command_line();
614 }
615 
616 bool JVMFlag::is_jimage_resource(JVMFlagsEnum flag) {
617   return flag_from_enum(flag)->is_jimage_resource();
618 }
619 
620 void JVMFlag::setOnCmdLine(JVMFlagsEnum flag) {
621   flag_from_enum(flag)->set_command_line();
622 }
623 
624 extern "C" {
625   static int compare_flags(const void* void_a, const void* void_b) {
626     return strcmp((*((JVMFlag**) void_a))->name(), (*((JVMFlag**) void_b))->name());
627   }
628 }
629 
630 void JVMFlag::printSetFlags(outputStream* out) {
631   // Print which flags were set on the command line
632   // note: this method is called before the thread structure is in place
633   //       which means resource allocation cannot be used.
634 
635   // The last entry is the null entry.
636   const size_t length = JVMFlag::numFlags - 1;
637 
638   // Sort
639   JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments);
640   for (size_t i = 0; i < length; i++) {
641     array[i] = &flagTable[i];
642   }
643   qsort(array, length, sizeof(JVMFlag*), compare_flags);
644 
645   // Print
646   for (size_t i = 0; i < length; i++) {
647     if (array[i]->get_origin() != JVMFlagOrigin::DEFAULT) {
648       array[i]->print_as_flag(out);
649       out->print(" ");
650     }
651   }
652   out->cr();
653   FREE_C_HEAP_ARRAY(JVMFlag*, array);
654 }
655 
656 #ifndef PRODUCT
657 
658 void JVMFlag::verify() {
659   assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict");
660 }
661 
662 #endif // PRODUCT
663 
664 #ifdef ASSERT
665 
666 void JVMFlag::assert_valid_flag_enum(JVMFlagsEnum i) {
667   assert(0 <= int(i) && int(i) < NUM_JVMFlagsEnum, "must be");
668 }
669 
670 void JVMFlag::check_all_flag_declarations() {
671   for (JVMFlag* current = &flagTable[0]; current->_name != nullptr; current++) {
672     int flags = static_cast<int>(current->_flags);
673     // Backwards compatibility. This will be relaxed/removed in JDK-7123237.
674     int mask = JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_MANAGEABLE | JVMFlag::KIND_EXPERIMENTAL;
675     if ((flags & mask) != 0) {
676       assert((flags & mask) == JVMFlag::KIND_DIAGNOSTIC ||
677              (flags & mask) == JVMFlag::KIND_MANAGEABLE ||
678              (flags & mask) == JVMFlag::KIND_EXPERIMENTAL,
679              "%s can be declared with at most one of "
680              "DIAGNOSTIC, MANAGEABLE or EXPERIMENTAL", current->_name);
681       assert((flags & KIND_DEVELOP) == 0,
682              "%s has an optional DIAGNOSTIC, MANAGEABLE or EXPERIMENTAL "
683              "attribute; it must be declared as a product flag", current->_name);
684     }
685   }
686 }
687 
688 #endif // ASSERT
689 
690 void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, bool skipDefaults) {
691   // Print the flags sorted by name
692   // Note: This method may be called before the thread structure is in place
693   //       which means resource allocation cannot be used. Also, it may be
694   //       called as part of error reporting, so handle native OOMs gracefully.
695 
696   // The last entry is the null entry.
697   constexpr size_t length = (sizeof(flagTable) / sizeof(JVMFlag)) - 1;
698 
699   const char* tag = 0;
700   if (xtty_owns(out))
701     xtty->head("%s", tag = !Universe::is_fully_initialized()
702                ? "vm_flags_initial" : "vm_flags_final");
703 
704   // Print
705   if (!printRanges) {
706     out->print_cr("[Global flags]");
707   } else {
708     out->print_cr("[Global flags ranges]");
709   }
710 
711   BitMap::bm_word_t iteratorArray[BitMap::calc_size_in_words(length)];
712   BitMapView iteratorMarkers(iteratorArray, length);
713   iteratorMarkers.clear_range(0, length);
714   // Print the flag with best sort value, then mark it.
715   for (size_t j = 0; j < length; j++) {
716     JVMFlag* bestFlag = nullptr;
717     size_t bestFlagIndex = 0;
718     for (size_t i = 0; i < length; i++) {
719       const bool skip = (skipDefaults && flagTable[i].is_default());
720       const bool visited = iteratorMarkers.at(i);
721       if (!visited && flagTable[i].is_unlocked() && !skip) {
722         if ((bestFlag == nullptr) || (strcmp(bestFlag->name(), flagTable[i].name()) > 0)) {
723           bestFlag = &flagTable[i];
724           bestFlagIndex = i;
725         }
726       }
727     }
728     if (bestFlag != nullptr) {
729       bestFlag->print_on(out, withComments, printRanges);
730       iteratorMarkers.at_put(bestFlagIndex, true);
731     }
732   }
733   if (xtty_owns(out))
734     xtty->tail(tag);
735 }
736 
737 void JVMFlag::printError(bool verbose, const char* msg, ...) {
738   if (verbose) {
739     va_list listPointer;
740     va_start(listPointer, msg);
741     jio_vfprintf(defaultStream::error_stream(), msg, listPointer);
742     va_end(listPointer);
743   }
744 }