1 /* 2 * Copyright (c) 1997, 2020, 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 "memory/allocation.inline.hpp" 28 #include "runtime/arguments.hpp" 29 #include "runtime/flags/jvmFlag.inline.hpp" 30 #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" 31 #include "runtime/os.hpp" 32 #include "utilities/defaultStream.hpp" 33 #include "utilities/stringUtils.hpp" 34 35 36 JVMFlag* JVMFlag::_head = NULL; 37 int JVMFlag::_num_flags = 0; 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(Attr origin) { 48 assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); 49 int new_origin = (origin == COMMAND_LINE) ? (origin | ORIG_COMMAND_LINE) : origin; 50 _attr = (_attr & ~VALUE_ORIGIN_MASK) | new_origin; 51 } 52 53 bool JVMFlag::is_jimage_resource() { 54 return (get_origin() == JIMAGE_RESOURCE); 55 } 56 57 bool JVMFlag::is_unlocker() const { 58 return strcmp(name(), "UnlockDiagnosticVMOptions") == 0 || 59 strcmp(name(), "UnlockExperimentalVMOptions") == 0; 60 } 61 62 bool JVMFlag::is_unlocked() const { 63 if (is_diagnostic()) { 64 return UnlockDiagnosticVMOptions; 65 } 66 if (is_experimental()) { 67 return UnlockExperimentalVMOptions; 68 } 69 return true; 70 } 71 72 void JVMFlag::clear_diagnostic() { 73 assert(is_diagnostic(), "sanity"); 74 _attr &= ~DIAGNOSTIC; 75 assert(!is_diagnostic(), "sanity"); 76 } 77 78 void JVMFlag::clear_experimental() { 79 assert(is_experimental(), "sanity"); 80 _attr &= ~EXPERIMENTAL; 81 assert(!is_experimental(), "sanity"); 82 } 83 84 void JVMFlag::set_product() { 85 assert(!is_product(), "sanity"); 86 _attr |= IS_PRODUCT; 87 assert(is_product(), "sanity"); 88 } 89 90 // Get custom message for this locked flag, or NULL if 91 // none is available. Returns message type produced. 92 JVMFlag::MsgType JVMFlag::get_locked_message(char* buf, int buflen) const { 93 buf[0] = '\0'; 94 if (is_diagnostic() && !is_unlocked()) { 95 jio_snprintf(buf, buflen, 96 "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" 97 "Error: The unlock option must precede '%s'.\n", 98 _name, _name); 99 return JVMFlag::DIAGNOSTIC_FLAG_BUT_LOCKED; 100 } 101 if (is_experimental() && !is_unlocked()) { 102 jio_snprintf(buf, buflen, 103 "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" 104 "Error: The unlock option must precede '%s'.\n", 105 _name, _name); 106 return JVMFlag::EXPERIMENTAL_FLAG_BUT_LOCKED; 107 } 108 if (is_develop() && is_product_build()) { 109 jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", 110 _name); 111 return JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; 112 } 113 if (is_notproduct() && is_product_build()) { 114 jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", 115 _name); 116 return JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; 117 } 118 return JVMFlag::NONE; 119 } 120 121 // Helper function for JVMFlag::print_on(). 122 // Fills current line up to requested position. 123 // Should the current position already be past the requested position, 124 // one separator blank is enforced. 125 void fill_to_pos(outputStream* st, unsigned int req_pos) { 126 if ((unsigned int)st->position() < req_pos) { 127 st->fill_to(req_pos); // need to fill with blanks to reach req_pos 128 } else { 129 st->print(" "); // enforce blank separation. Previous field too long. 130 } 131 } 132 133 void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) const { 134 // Don't print notproduct and develop flags in a product build. 135 if (is_constant_in_binary()) { 136 return; 137 } 138 139 if (!printRanges) { 140 // The command line options -XX:+PrintFlags* cause this function to be called 141 // for each existing flag to print information pertinent to this flag. The data 142 // is displayed in columnar form, with the following layout: 143 // col1 - data type, right-justified 144 // col2 - name, left-justified 145 // col3 - ' =' double-char, leading space to align with possible '+=' 146 // col4 - value left-justified 147 // col5 - kind right-justified 148 // col6 - origin left-justified 149 // col7 - comments left-justified 150 // 151 // The column widths are fixed. They are defined such that, for most cases, 152 // an eye-pleasing tabular output is created. 153 // 154 // Sample output: 155 // bool ThreadPriorityVerbose = false {product} {default} 156 // uintx ThresholdTolerance = 10 {product} {default} 157 // size_t TLABSize = 0 {product} {default} 158 // uintx SurvivorRatio = 8 {product} {default} 159 // double InitialRAMPercentage = 1.562500 {product} {default} 160 // ccstr CompileCommandFile = MyFile.cmd {product} {command line} 161 // ccstrlist CompileOnly = Method1 162 // CompileOnly += Method2 {product} {command line} 163 // | | | | | | | 164 // | | | | | | +-- col7 165 // | | | | | +-- col6 166 // | | | | +-- col5 167 // | | | +-- col4 168 // | | +-- col3 169 // | +-- col2 170 // +-- col1 171 172 const unsigned int col_spacing = 1; 173 const unsigned int col1_pos = 0; 174 const unsigned int col1_width = 9; 175 const unsigned int col2_pos = col1_pos + col1_width + col_spacing; 176 const unsigned int col2_width = 39; 177 const unsigned int col3_pos = col2_pos + col2_width + col_spacing; 178 const unsigned int col3_width = 2; 179 const unsigned int col4_pos = col3_pos + col3_width + col_spacing; 180 const unsigned int col4_width = 30; 181 const unsigned int col5_pos = col4_pos + col4_width + col_spacing; 182 const unsigned int col5_width = 20; 183 const unsigned int col6_pos = col5_pos + col5_width + col_spacing; 184 const unsigned int col6_width = 15; 185 const unsigned int col7_pos = col6_pos + col6_width + col_spacing; 186 const unsigned int col7_width = 1; 187 188 st->fill_to(col1_pos); 189 st->print("%*s", col1_width, type_string()); // right-justified, therefore width is required. 190 191 fill_to_pos(st, col2_pos); 192 st->print("%s", _name); 193 194 fill_to_pos(st, col3_pos); 195 st->print(" ="); // use " =" for proper alignment with multiline ccstr output. 196 197 fill_to_pos(st, col4_pos); 198 if (is_ccstr()) { 199 // Honor <newline> characters in ccstr: print multiple lines. 200 const char* cp = get_ccstr(); 201 if (cp != NULL) { 202 const char* eol; 203 while ((eol = strchr(cp, '\n')) != NULL) { 204 size_t llen = pointer_delta(eol, cp, sizeof(char)); 205 st->print("%.*s", (int)llen, cp); 206 st->cr(); 207 cp = eol+1; 208 fill_to_pos(st, col2_pos); 209 st->print("%s", _name); 210 fill_to_pos(st, col3_pos); 211 st->print("+="); 212 fill_to_pos(st, col4_pos); 213 } 214 st->print("%s", cp); 215 } 216 } else { 217 print_value(st); 218 } 219 220 fill_to_pos(st, col5_pos); 221 print_kind(st, col5_width); 222 223 fill_to_pos(st, col6_pos); 224 print_origin(st, col6_width); 225 226 #ifndef PRODUCT 227 if (withComments) { 228 fill_to_pos(st, col7_pos); 229 st->print("%s", docs()); 230 } 231 #endif 232 st->cr(); 233 } else if (!is_bool() && !is_ccstr()) { 234 // The command line options -XX:+PrintFlags* cause this function to be called 235 // for each existing flag to print information pertinent to this flag. The data 236 // is displayed in columnar form, with the following layout: 237 // col1 - data type, right-justified 238 // col2 - name, left-justified 239 // col4 - range [ min ... max] 240 // col5 - kind right-justified 241 // col6 - origin left-justified 242 // col7 - comments left-justified 243 // 244 // The column widths are fixed. They are defined such that, for most cases, 245 // an eye-pleasing tabular output is created. 246 // 247 // Sample output: 248 // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} 249 // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} 250 // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} 251 // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} 252 // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} 253 // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} 254 // | | | | | | 255 // | | | | | +-- col7 256 // | | | | +-- col6 257 // | | | +-- col5 258 // | | +-- col4 259 // | +-- col2 260 // +-- col1 261 262 const unsigned int col_spacing = 1; 263 const unsigned int col1_pos = 0; 264 const unsigned int col1_width = 9; 265 const unsigned int col2_pos = col1_pos + col1_width + col_spacing; 266 const unsigned int col2_width = 49; 267 const unsigned int col3_pos = col2_pos + col2_width + col_spacing; 268 const unsigned int col3_width = 0; 269 const unsigned int col4_pos = col3_pos + col3_width + col_spacing; 270 const unsigned int col4_width = 60; 271 const unsigned int col5_pos = col4_pos + col4_width + col_spacing; 272 const unsigned int col5_width = 35; 273 const unsigned int col6_pos = col5_pos + col5_width + col_spacing; 274 const unsigned int col6_width = 15; 275 const unsigned int col7_pos = col6_pos + col6_width + col_spacing; 276 const unsigned int col7_width = 1; 277 278 st->fill_to(col1_pos); 279 st->print("%*s", col1_width, type_string()); // right-justified, therefore width is required. 280 281 fill_to_pos(st, col2_pos); 282 st->print("%s", name()); 283 284 fill_to_pos(st, col4_pos); 285 print_range(st); 286 287 fill_to_pos(st, col5_pos); 288 print_kind(st, col5_width); 289 290 fill_to_pos(st, col6_pos); 291 print_origin(st, col6_width); 292 293 #ifndef PRODUCT 294 if (withComments) { 295 fill_to_pos(st, col7_pos); 296 st->print("%s", docs()); 297 } 298 #endif 299 st->cr(); 300 } 301 } 302 303 void JVMFlag::print_kind(outputStream* st, unsigned int width) const { 304 struct Data { 305 int flag; 306 const char* name; 307 }; 308 309 Data data[] = { 310 { JVMCI, "JVMCI" }, 311 { C1, "C1" }, 312 { C2, "C2" }, 313 { ARCH, "ARCH" }, 314 { PLATFORM_DEPENDENT, "pd" }, 315 { IS_PRODUCT, "product" }, 316 { MANAGEABLE, "manageable" }, 317 { DIAGNOSTIC, "diagnostic" }, 318 { EXPERIMENTAL, "experimental" }, 319 { NOT_PRODUCT, "notproduct" }, 320 { DEVELOP, "develop" }, 321 { LP64, "lp64_product" }, 322 { READ_WRITE, "rw" }, 323 { -1, "" } 324 }; 325 326 if ((_attr & KIND_MASK) != 0) { 327 bool is_first = true; 328 const size_t buffer_size = 64; 329 size_t buffer_used = 0; 330 char kind[buffer_size]; 331 332 jio_snprintf(kind, buffer_size, "{"); 333 buffer_used++; 334 for (int i = 0; data[i].flag != -1; i++) { 335 Data d = data[i]; 336 if ((_attr & d.flag) != 0) { 337 if (is_first) { 338 is_first = false; 339 } else { 340 assert(buffer_used + 1 < buffer_size, "Too small buffer"); 341 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); 342 buffer_used++; 343 } 344 size_t length = strlen(d.name); 345 assert(buffer_used + length < buffer_size, "Too small buffer"); 346 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); 347 buffer_used += length; 348 } 349 } 350 assert(buffer_used + 2 <= buffer_size, "Too small buffer"); 351 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); 352 st->print("%*s", width, kind); 353 } 354 } 355 356 void JVMFlag::print_origin(outputStream* st, unsigned int width) const { 357 int origin = _attr & VALUE_ORIGIN_MASK; 358 st->print("{"); 359 switch(origin) { 360 case DEFAULT: 361 st->print("default"); break; 362 case COMMAND_LINE: 363 st->print("command line"); break; 364 case ENVIRON_VAR: 365 st->print("environment"); break; 366 case CONFIG_FILE: 367 st->print("config file"); break; 368 case MANAGEMENT: 369 st->print("management"); break; 370 case ERGONOMIC: 371 if (_attr & ORIG_COMMAND_LINE) { 372 st->print("command line, "); 373 } 374 st->print("ergonomic"); break; 375 case ATTACH_ON_DEMAND: 376 st->print("attach"); break; 377 case INTERNAL: 378 st->print("internal"); break; 379 case JIMAGE_RESOURCE: 380 st->print("jimage"); break; 381 } 382 st->print("}"); 383 } 384 385 void JVMFlag::print_attr(outputStream* st, int width) const { 386 struct Data { 387 int flag; 388 const char* name; 389 }; 390 391 Data data[] = { 392 { JVMCI, "JVMCI" }, 393 { C1, "C1" }, 394 { C2, "C2" }, 395 { ARCH, "ARCH" }, 396 { PLATFORM_DEPENDENT, "pd" }, 397 { IS_PRODUCT, "product" }, 398 { MANAGEABLE, "manageable" }, 399 { DIAGNOSTIC, "diagnostic" }, 400 { EXPERIMENTAL, "experimental" }, 401 { NOT_PRODUCT, "notproduct" }, 402 { DEVELOP, "develop" }, 403 { LP64, "lp64_product" }, 404 { READ_WRITE, "rw" }, 405 { -1, "" } 406 }; 407 408 int attr = _attr; 409 410 if (attr != 0) { 411 bool is_first = true; 412 const size_t buffer_size = 64; 413 size_t buffer_used = 0; 414 char kind[buffer_size]; 415 416 jio_snprintf(kind, buffer_size, "{"); 417 buffer_used++; 418 for (int i = 0; data[i].flag != -1; i++) { 419 Data d = data[i]; 420 if ((_attr & d.flag) != 0) { 421 if (is_first) { 422 is_first = false; 423 } else { 424 assert(buffer_used + 1 < buffer_size, "Too small buffer"); 425 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); 426 buffer_used++; 427 } 428 size_t length = strlen(d.name); 429 assert(buffer_used + length < buffer_size, "Too small buffer"); 430 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); 431 buffer_used += length; 432 } 433 } 434 assert(buffer_used + 2 <= buffer_size, "Too small buffer"); 435 jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); 436 st->print("%*s", width, kind); 437 } 438 } 439 440 #define DECLARE_TYPE_STRING(t) STR(t), 441 static const char* const jvmflag_string_names[] = { 442 JVM_FLAG_ALL_TYPES_DO(DECLARE_TYPE_STRING) 443 }; 444 445 const char* JVMFlag::type_string() const { 446 assert(type() >= 0 && type() < NUM_TYPES, "sanity"); 447 if (type() == TYPE_ccstr && _attr & STRINGLIST) { 448 return "ccstrlist"; 449 } 450 return jvmflag_string_names[type()]; 451 } 452 453 #define RANGE_FORMAT(type, FMT, RANGE_MIN_FMT, RANGE_MAX_FMT) \ 454 NOT_PRODUCT_ARG(JVMFlag::TYPE_ ## type) \ 455 FMT, \ 456 "%s %s=" FMT " is outside the allowed range [ " FMT " ... " FMT " ]\n", \ 457 "[ " RANGE_MIN_FMT " ... " RANGE_MAX_FMT " ]" 458 459 JVMFlag::PrintFormat JVMFlag::print_formats[] = { 460 { NOT_PRODUCT_ARG(JVMFlag::TYPE_bool) "%s", NULL, NULL }, // range not used 461 { RANGE_FORMAT(int, "%d", "%-25d", "%25d")}, 462 { RANGE_FORMAT(uint, "%u", "%-25u", "%25u")}, 463 { RANGE_FORMAT(intx, INTX_FORMAT, INTX_FORMAT_W(-25), INTX_FORMAT_W(25))}, 464 { RANGE_FORMAT(uintx, UINTX_FORMAT, UINTX_FORMAT_W(-25), UINTX_FORMAT_W(25))}, 465 { RANGE_FORMAT(uint64_t, UINT64_FORMAT, UINT64_FORMAT_W(-25), UINT64_FORMAT_W(25))}, 466 { RANGE_FORMAT(size_t, SIZE_FORMAT, SIZE_FORMAT_W(-25), SIZE_FORMAT_W(25))}, 467 { RANGE_FORMAT(double, "%f", "%-25.3f", "%25.3f")}, 468 { NOT_PRODUCT_ARG(JVMFlag::TYPE_ccstr) "%s", NULL, NULL }, // range not used 469 }; 470 471 // We are calling printf with a non-literal format string indexed from print_formats[] 472 PRAGMA_DIAG_PUSH 473 PRAGMA_FORMAT_NONLITERAL_IGNORED 474 475 // This is called when the JVMFlag has constraint function but no range. 476 void JVMFlag::print_range_for_constraint(outputStream* st, void* constraint_func) const { 477 const char* fmt = print_formats[type()].print_range_format; 478 assert(fmt != NULL, "must be"); 479 480 switch (type()) { 481 case TYPE_int: st->print(fmt, INT_MIN, INT_MAX); break; 482 case TYPE_uint: st->print(fmt, 0, UINT_MAX); break; 483 case TYPE_intx: st->print(fmt, min_intx, max_intx); break; 484 case TYPE_uintx: st->print(fmt, 0, max_uintx ); break; 485 case TYPE_uint64_t: st->print(fmt, 0, uint64_t(max_juint)); break; 486 case TYPE_size_t: st->print(fmt, 0, SIZE_MAX); break; 487 case TYPE_double: st->print(fmt, DBL_MIN, DBL_MAX); break; 488 default: ShouldNotReachHere(); 489 } 490 } 491 492 void JVMFlag::print_value(outputStream* st) const { 493 assert(print_formats[type()].type == type(), "must be"); 494 const char* fmt = print_formats[type()].print_value_format; 495 switch (type()) { 496 case TYPE_bool: st->print(fmt, get_bool() ? "true" : "false"); break; 497 case TYPE_int: st->print(fmt, get_int()); break; 498 case TYPE_uint: st->print(fmt, get_uint()); break; 499 case TYPE_intx: st->print(fmt, get_intx()); break; 500 case TYPE_uintx: st->print(fmt, get_uintx()); break; 501 case TYPE_uint64_t: st->print(fmt, get_uint64_t()); break; 502 case TYPE_size_t: st->print(fmt, get_size_t()); break; 503 case TYPE_double: st->print(fmt, get_double()); break; 504 case TYPE_ccstr: st->print(fmt, get_ccstr()); break; 505 default: ShouldNotReachHere(); 506 } 507 } 508 509 PRAGMA_DIAG_POP 510 511 #define FOOFOO(t) \ 512 case TYPE_##t: TypedJVMFlag<t>::cast(this)->print_typed_range(st); break; 513 514 // This is called when the JVMFlag has no range and no constraint function 515 void JVMFlag::print_range(outputStream* st) const { 516 if (_range != NULL || _constraint != NULL) { 517 switch (type()) { 518 JVM_FLAG_ALL_TYPES_DO(FOOFOO); 519 default: ShouldNotReachHere(); 520 } 521 } else { 522 st->print("[ ... ]"); 523 } 524 } 525 526 #define FOOFOO2(t) \ 527 case TYPE_##t: return TypedJVMFlag<t>::cast(this)->check_typed_range(new_value, verbose); break; 528 529 JVMFlag::Error JVMFlag::check_range(void* new_value, bool verbose) const { 530 if (_range != NULL) { 531 switch (type()) { 532 JVM_FLAG_ALL_TYPES_DO(FOOFOO2); 533 default: ShouldNotReachHere(); 534 } 535 } 536 537 return JVMFlag::SUCCESS; 538 } 539 540 #define FOOFOO3(t) \ 541 case TYPE_##t: return TypedJVMFlag<t>::cast(this)->check_typed_constraint(new_value, verbose); break; 542 543 JVMFlag::Error JVMFlag::check_constraint(void* new_value, bool verbose) const { 544 if (_constraint != NULL) { 545 switch (type()) { 546 JVM_FLAG_ALL_TYPES_DO(FOOFOO3); 547 default: ShouldNotReachHere(); 548 } 549 } 550 551 return JVMFlag::SUCCESS; 552 } 553 554 555 void JVMFlag::print_as_flag(outputStream* st) const { 556 if (is_bool()) { 557 st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); 558 } else { 559 st->print("-XX:%s=", _name); 560 if (is_ccstr()) { 561 const char* cp = get_ccstr(); 562 if (cp != NULL) { 563 // Need to turn embedded '\n's back into separate arguments 564 // Not so efficient to print one character at a time, 565 // but the choice is to do the transformation to a buffer 566 // and print that. And this need not be efficient. 567 for (; *cp != '\0'; cp += 1) { 568 switch (*cp) { 569 default: 570 st->print("%c", *cp); 571 break; 572 case '\n': 573 st->print(" -XX:%s=", _name); 574 break; 575 } 576 } 577 } 578 } else { 579 print_value(st); 580 } 581 } 582 } 583 584 const char* JVMFlag::flag_error_str(JVMFlag::Error error) { 585 switch (error) { 586 case JVMFlag::MISSING_NAME: return "MISSING_NAME"; 587 case JVMFlag::MISSING_VALUE: return "MISSING_VALUE"; 588 case JVMFlag::NON_WRITABLE: return "NON_WRITABLE"; 589 case JVMFlag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; 590 case JVMFlag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; 591 case JVMFlag::INVALID_FLAG: return "INVALID_FLAG"; 592 case JVMFlag::ERR_OTHER: return "ERR_OTHER"; 593 case JVMFlag::SUCCESS: return "SUCCESS"; 594 default: ShouldNotReachHere(); return "NULL"; 595 } 596 } 597 598 bool JVMFlag::check_all_ranges() { 599 bool status = true; 600 bool verbose = true; 601 JVMFlag* flag; 602 JVMFLAG_FOR_EACH(flag) { 603 if (flag->check_range(flag->value_addr(), verbose) != JVMFlag::SUCCESS) { 604 status = false; 605 } 606 } 607 return status; 608 } 609 610 JVMFlag::ConstraintPhase JVMFlag::_constraint_validating_phase = JVMFlag::AtParse; 611 const JVMFlag* JVMFlag::_current_checking = NULL; 612 613 bool JVMFlag::check_all_constraints(JVMFlag::ConstraintPhase phase) { 614 guarantee(phase > _constraint_validating_phase, "Constraint check is out of order."); 615 _constraint_validating_phase = phase; 616 617 bool status = true; 618 bool verbose = true; 619 JVMFlag* flag; 620 JVMFLAG_FOR_EACH(flag) { 621 if (flag->check_constraint(flag->value_addr(), verbose) != JVMFlag::SUCCESS) { 622 status = false; 623 } 624 } 625 626 return status; 627 } 628 629 inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { 630 if (s_len != q_len) return false; 631 return memcmp(s, q, q_len) == 0; 632 } 633 634 // Search the flag table for a named flag 635 JVMFlag* JVMFlag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { 636 JVMFlag* flag; 637 char c = name[0]; 638 JVMFLAG_FOR_EACH(flag) { 639 if (c == flag->_name[0] && str_equal(flag->_name, flag->get_name_length(), name, length)) { 640 // Found a matching entry. 641 // Don't report notproduct and develop flags in product builds. 642 if (flag->is_constant_in_binary()) { 643 return (return_flag ? flag : NULL); 644 } 645 // Report locked flags only if allowed. 646 if (!(flag->is_unlocked() || flag->is_unlocker())) { 647 if (!allow_locked) { 648 // disable use of locked flags, e.g. diagnostic, experimental, 649 // etc. until they are explicitly unlocked 650 return NULL; 651 } 652 } 653 return flag; 654 } 655 } 656 // JVMFlag name is not in the flag table 657 return NULL; 658 } 659 660 // Get or compute the flag name length 661 size_t JVMFlag::get_name_length() { 662 if (_name_len == 0) { 663 size_t len = strlen(_name); 664 assert(len < 0x7fff, "flag name is too long!"); 665 _name_len = (short)len; 666 } 667 return (size_t)_name_len; 668 } 669 670 JVMFlag* JVMFlag::fuzzy_match(const char* name, size_t length, bool allow_locked) { 671 float VMOptionsFuzzyMatchSimilarity = 0.7f; 672 JVMFlag* match = NULL; 673 float score; 674 float max_score = -1; 675 676 JVMFlag* flag; 677 JVMFLAG_FOR_EACH(flag) { 678 score = StringUtils::similarity(flag->name(), strlen(flag->name()), name, length); 679 if (score > max_score) { 680 max_score = score; 681 match = flag; 682 } 683 } 684 685 if (match == NULL) { 686 return NULL; 687 } 688 689 if (!(match->is_unlocked() || match->is_unlocker())) { 690 if (!allow_locked) { 691 return NULL; 692 } 693 } 694 695 if (max_score < VMOptionsFuzzyMatchSimilarity) { 696 return NULL; 697 } 698 699 return match; 700 } 701 702 template <typename T> 703 static JVMFlag::Error get_flag(const JVMFlag* flag, JVMFlag::FlagType type, T* value) { 704 if (flag == NULL) { 705 return JVMFlag::INVALID_FLAG; 706 } 707 if (flag->type() != type) { 708 return JVMFlag::WRONG_FORMAT; 709 } 710 *value = TypedJVMFlag<T>::cast(flag)->get_value(); 711 return JVMFlag::SUCCESS; 712 } 713 714 JVMFlag::Error JVMFlag::boolAt (const JVMFlag* f, bool* v) { return get_flag(f, TYPE_bool, v); } 715 JVMFlag::Error JVMFlag::intAt (const JVMFlag* f, int* v) { return get_flag(f, TYPE_int, v); } 716 JVMFlag::Error JVMFlag::uintAt (const JVMFlag* f, uint* v) { return get_flag(f, TYPE_uint, v); } 717 JVMFlag::Error JVMFlag::intxAt (const JVMFlag* f, intx* v) { return get_flag(f, TYPE_intx, v); } 718 JVMFlag::Error JVMFlag::uintxAt (const JVMFlag* f, uintx* v) { return get_flag(f, TYPE_uintx, v); } 719 JVMFlag::Error JVMFlag::size_tAt (const JVMFlag* f, size_t* v) { return get_flag(f, TYPE_size_t, v); } 720 JVMFlag::Error JVMFlag::uint64_tAt(const JVMFlag* f, uint64_t* v) { return get_flag(f, TYPE_uint64_t, v); } 721 JVMFlag::Error JVMFlag::doubleAt (const JVMFlag* f, double* v) { return get_flag(f, TYPE_double, v); } 722 JVMFlag::Error JVMFlag::ccstrAt (const JVMFlag* f, ccstr* v) { return get_flag(f, TYPE_ccstr, v); } 723 724 template<class E, class T> 725 static void trace_flag_changed(const JVMFlag* flag, T old_value, T new_value, JVMFlag::Attr origin) { 726 E e; 727 e.set_name(flag->name()); 728 e.set_oldValue(old_value); 729 e.set_newValue(new_value); 730 e.set_origin(origin); 731 e.commit(); 732 } 733 734 template <typename T> 735 JVMFlag::Error ProductFlag<T>::check_new_value(T new_value, JVMFlag::Attr origin) { 736 bool verbose = JVMFlag::verbose_checking(); 737 JVMFlag::Error status = this->check_range((void*)(&new_value), verbose); 738 if (status == JVMFlag::SUCCESS) { 739 JVMFlag::set_current_checking(this); 740 status = this->check_constraint((void*)(&new_value), verbose); 741 JVMFlag::set_current_checking(NULL); 742 } 743 return status; 744 } 745 746 template <typename T, class TraceEvent, class TraceType> 747 static JVMFlag::Error flagAtPut(JVMFlag* f, T new_value, JVMFlag::Attr origin, JVMFlag::FlagType type) { 748 if (f == NULL) { 749 return JVMFlag::INVALID_FLAG; 750 } 751 if (f->type() != type) { 752 return JVMFlag::WRONG_FORMAT; 753 } 754 755 ProductFlag<T>* flag = ProductFlag<T>::cast(f); 756 JVMFlag::Error status = flag->check_new_value(new_value, origin); 757 if (status == JVMFlag::SUCCESS) { 758 trace_flag_changed<TraceEvent, TraceType>(flag, flag->get_value(), new_value, origin); 759 flag->write_value(new_value); 760 flag->set_origin(origin); 761 } 762 return status; 763 } 764 765 JVMFlag::Error JVMFlag::boolAtPut (JVMFlag* f, bool v, JVMFlag::Flags o) { return flagAtPut<bool, EventBooleanFlagChanged, bool>(f, v, o, TYPE_bool);} 766 JVMFlag::Error JVMFlag::intAtPut (JVMFlag* f, int v, JVMFlag::Flags o) { return flagAtPut<int, EventIntFlagChanged, s4>(f, v, o, TYPE_int);} 767 JVMFlag::Error JVMFlag::uintAtPut (JVMFlag* f, uint v, JVMFlag::Flags o) { return flagAtPut<uint, EventUnsignedIntFlagChanged, u4>(f, v, o, TYPE_uint);} 768 JVMFlag::Error JVMFlag::intxAtPut (JVMFlag* f, intx v, JVMFlag::Flags o) { return flagAtPut<intx, EventLongFlagChanged, intx>(f, v, o, TYPE_intx);} 769 JVMFlag::Error JVMFlag::uintxAtPut (JVMFlag* f, uintx v, JVMFlag::Flags o) { return flagAtPut<uintx, EventUnsignedLongFlagChanged, u8>(f, v, o, TYPE_uintx);} 770 JVMFlag::Error JVMFlag::uint64_tAtPut(JVMFlag* f, uint64_t v, JVMFlag::Flags o) { return flagAtPut<uint64_t, EventUnsignedLongFlagChanged, u8>(f, v, o, TYPE_uint64_t);} 771 JVMFlag::Error JVMFlag::size_tAtPut (JVMFlag* f, size_t v, JVMFlag::Flags o) { return flagAtPut<size_t, EventUnsignedLongFlagChanged, u8>(f, v, o, TYPE_size_t);} 772 JVMFlag::Error JVMFlag::doubleAtPut (JVMFlag* f, double v, JVMFlag::Flags o) { return flagAtPut<double, EventDoubleFlagChanged, double>(f, v, o, TYPE_double);} 773 774 JVMFlag::Error JVMFlag::ccstrAtPut(JVMFlag* f, ccstr* value, JVMFlag::Flags origin) { 775 if (f == NULL) { 776 return JVMFlag::INVALID_FLAG; 777 } 778 if (!f->is_ccstr()) { 779 return JVMFlag::WRONG_FORMAT; 780 } 781 782 ProductFlag<ccstr> *flag = ProductFlag<ccstr>::cast(f); 783 ccstr old_value = flag->get_value(); 784 trace_flag_changed<EventStringFlagChanged, const char*>(flag, old_value, *value, origin); 785 char* new_value = NULL; 786 if (*value != NULL) { 787 new_value = os::strdup_check_oom(*value); 788 } 789 if (flag->is_default() && old_value != NULL) { 790 // Prior value is NOT heap allocated, but was a literal constant. 791 old_value = os::strdup_check_oom(old_value); 792 } 793 flag->write_value(new_value); 794 flag->set_origin(origin); 795 *value = old_value; 796 return SUCCESS; 797 } 798 799 extern "C" { 800 static int compare_flags(const void* void_a, const void* void_b) { 801 return strcmp((*((JVMFlag**) void_a))->name(), (*((JVMFlag**) void_b))->name()); 802 } 803 } 804 805 void JVMFlag::printSetFlags(outputStream* out) { 806 // Print which flags were set on the command line 807 // note: this method is called before the thread structure is in place 808 // which means resource allocation cannot be used. 809 810 int length = JVMFlag::num_flags(); 811 812 // Sort 813 JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); 814 JVMFlag* flag; 815 int i = 0; 816 JVMFLAG_FOR_EACH(flag) { 817 array[i++] = flag; 818 } 819 qsort(array, length, sizeof(JVMFlag*), compare_flags); 820 821 // Print 822 for (i = 0; i < length; i++) { 823 if (array[i]->get_origin() /* naked field! */) { 824 array[i]->print_as_flag(out); 825 out->print(" "); 826 } 827 } 828 out->cr(); 829 FREE_C_HEAP_ARRAY(JVMFlag*, array); 830 } 831 832 #ifndef PRODUCT 833 834 void JVMFlag::verify() { 835 assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); 836 } 837 838 #endif // PRODUCT 839 840 void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, bool skipDefaults) { 841 // Print the flags sorted by name 842 // Note: This method may be called before the thread structure is in place 843 // which means resource allocation cannot be used. Also, it may be 844 // called as part of error reporting, so handle native OOMs gracefully. 845 846 int length = JVMFlag::num_flags(); 847 JVMFlag* flag; 848 849 // Print 850 if (!printRanges) { 851 out->print_cr("[Global flags]"); 852 } else { 853 out->print_cr("[Global flags ranges]"); 854 } 855 856 // Sort 857 JVMFlag** array = NEW_C_HEAP_ARRAY_RETURN_NULL(JVMFlag*, length, mtArguments); 858 int i = 0; 859 if (array != NULL) { 860 JVMFLAG_FOR_EACH(flag) { 861 array[i++] = flag; 862 } 863 qsort(array, length, sizeof(JVMFlag*), compare_flags); 864 865 for (i = 0; i < length; i++) { 866 if (array[i]->is_unlocked() && !(skipDefaults && array[i]->is_default())) { 867 array[i]->print_on(out, withComments, printRanges); 868 } 869 } 870 FREE_C_HEAP_ARRAY(JVMFlag*, array); 871 } else { 872 // OOM? Print unsorted. 873 JVMFLAG_FOR_EACH(flag) { 874 if (flag->is_unlocked() && !(skipDefaults && flag->is_default())) { 875 flag->print_on(out, withComments, printRanges); 876 } 877 } 878 } 879 } 880 881 void JVMFlag::printError(bool verbose, const char* msg, ...) { 882 if (verbose) { 883 va_list listPointer; 884 va_start(listPointer, msg); 885 jio_vfprintf(defaultStream::error_stream(), msg, listPointer); 886 va_end(listPointer); 887 } 888 } 889 890 void JVMFlagRange_VMPageSize::init() { 891 _r.init((uintx)os::vm_page_size(), max_uintx); 892 } 893 894 void JVMFlagRange_VMAllocationGranularity::init() { 895 _r.init((uintx)os::vm_page_size(), (uintx)(NOT_LP64(2*G) LP64_ONLY(8192*G))); 896 } 897 898 JVMFlagCustomRange* JVMFlagCustomRange::_head = NULL; 899 900 #ifndef PRODUCT 901 void JVMFlag::validate_flags() { 902 JVMFlag* flag; 903 JVMFLAG_FOR_EACH(flag) { 904 if ((flag->_attr & RANGE) != 0) { 905 assert(flag->_range != NULL, "Range must have been defined"); 906 } 907 if ((flag->_attr & CONSTRAINT) != 0) { 908 assert(flag->_constraint != NULL, "Constraint must have been defined"); 909 } 910 } 911 } 912 #endif