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