From b20478248590eb3868e5f82d571267153d5c36ff Mon Sep 17 00:00:00 2001 From: Ziyi Lin Date: Fri, 18 Oct 2024 17:44:16 +0800 Subject: [PATCH] [Misc] Return suggested value when violate option constraints Summary: Return suggested option value when it violates the constraints. Exit the VM after all input options are checked. Testing: JTreg Reviewers: Kuaiwei, wenjie Issue: https://github.com/dragonwell-project/dragonwell11/issues/894 --- src/hotspot/os/posix/os_posix.cpp | 31 ++- .../share/compiler/compilerDefinitions.cpp | 65 +++-- .../share/gc/cms/jvmFlagConstraintsCMS.cpp | 10 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 44 +++- .../share/gc/g1/jvmFlagConstraintsG1.cpp | 90 +++++-- .../parallel/jvmFlagConstraintsParallel.cpp | 16 +- .../share/gc/shared/collectorPolicy.cpp | 57 ++++- .../share/gc/shared/jvmFlagConstraintsGC.cpp | 230 +++++++++++++++--- .../share/gc/shared/jvmFlagConstraintsGC.hpp | 2 +- src/hotspot/share/memory/metaspace.cpp | 12 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 60 +++-- .../flags/jvmFlagConstraintsCompiler.cpp | 222 +++++++++++++---- .../flags/jvmFlagConstraintsRuntime.cpp | 74 +++++- src/hotspot/share/runtime/globals.hpp | 4 + src/hotspot/share/runtime/init.cpp | 4 + .../sanity/VerifyFlagConstraintsTests.java | 183 ++++++++++++++ 16 files changed, 933 insertions(+), 171 deletions(-) create mode 100644 test/hotspot/jtreg/sanity/VerifyFlagConstraintsTests.java diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index bc5d1fe24a2..fe10de1d4c0 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1516,10 +1516,17 @@ jint os::Posix::set_minimum_stack_sizes() { // The '-Xss' and '-XX:ThreadStackSize=N' options both set // ThreadStackSize so we go with "Java thread stack size" instead // of "ThreadStackSize" to be more friendly. - tty->print_cr("\nThe Java thread stack size specified is too small. " + if (VerifyFlagConstraints) { + ThreadStackSize = _java_thread_min_stack_allowed / K; + stack_size_in_bytes = ThreadStackSize * K; + tty->print_cr("ThreadStackSize:"SIZE_FORMAT"\n", ThreadStackSize); + } else { + tty->print_cr("\nThe Java thread stack size specified is too small. " "Specify at least " SIZE_FORMAT "k", _java_thread_min_stack_allowed / K); - return JNI_ERR; + return JNI_ERR; + } + } // Make the stack size a multiple of the page size so that @@ -1537,10 +1544,16 @@ jint os::Posix::set_minimum_stack_sizes() { stack_size_in_bytes = CompilerThreadStackSize * K; if (stack_size_in_bytes != 0 && stack_size_in_bytes < _compiler_thread_min_stack_allowed) { - tty->print_cr("\nThe CompilerThreadStackSize specified is too small. " + if (VerifyFlagConstraints) { + CompilerThreadStackSize = _compiler_thread_min_stack_allowed / K; + stack_size_in_bytes = CompilerThreadStackSize * K; + tty->print_cr("CompilerThreadStackSize:"SIZE_FORMAT"\n", CompilerThreadStackSize); + } else { + tty->print_cr("\nThe CompilerThreadStackSize specified is too small. " "Specify at least " SIZE_FORMAT "k", _compiler_thread_min_stack_allowed / K); - return JNI_ERR; + return JNI_ERR; + } } _vm_internal_thread_min_stack_allowed = align_up(_vm_internal_thread_min_stack_allowed, vm_page_size()); @@ -1549,10 +1562,16 @@ jint os::Posix::set_minimum_stack_sizes() { stack_size_in_bytes = VMThreadStackSize * K; if (stack_size_in_bytes != 0 && stack_size_in_bytes < _vm_internal_thread_min_stack_allowed) { - tty->print_cr("\nThe VMThreadStackSize specified is too small. " + if (VerifyFlagConstraints) { + VMThreadStackSize = _vm_internal_thread_min_stack_allowed / K; + stack_size_in_bytes = VMThreadStackSize * K; + tty->print_cr("VMThreadStackSize:"SIZE_FORMAT"\n", VMThreadStackSize); + } else { + tty->print_cr("\nThe VMThreadStackSize specified is too small. " "Specify at least " SIZE_FORMAT "k", _vm_internal_thread_min_stack_allowed / K); - return JNI_ERR; + return JNI_ERR; + } } return JNI_OK; } diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index cd5f0827ef9..800d85ee44a 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -293,31 +293,62 @@ bool CompilerConfig::check_args_consistency(bool status) { // Template Interpreter code is approximately 3X larger in debug builds. uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); if (ReservedCodeCacheSize < InitialCodeCacheSize) { - jio_fprintf(defaultStream::error_stream(), + if (VerifyFlagConstraints) { + ReservedCodeCacheSize = InitialCodeCacheSize; + jio_fprintf(defaultStream::error_stream(), "ReservedCodeCacheSize:%d\n", ReservedCodeCacheSize); + status = true; + } else { + jio_fprintf(defaultStream::error_stream(), "Invalid ReservedCodeCacheSize: %dK. Must be at least InitialCodeCacheSize=%dK.\n", ReservedCodeCacheSize/K, InitialCodeCacheSize/K); - status = false; + status = false; + } } else if (ReservedCodeCacheSize < min_code_cache_size) { - jio_fprintf(defaultStream::error_stream(), + if (VerifyFlagConstraints) { + ReservedCodeCacheSize = min_code_cache_size; + jio_fprintf(defaultStream::error_stream(), "ReservedCodeCacheSize:%d\n", ReservedCodeCacheSize); + status = true; + } else { + jio_fprintf(defaultStream::error_stream(), "Invalid ReservedCodeCacheSize=%dK. Must be at least %uK.\n", ReservedCodeCacheSize/K, min_code_cache_size/K); - status = false; + status = false; + } + } else if (ReservedCodeCacheSize > CODE_CACHE_SIZE_LIMIT) { - // Code cache size larger than CODE_CACHE_SIZE_LIMIT is not supported. - jio_fprintf(defaultStream::error_stream(), - "Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M, - CODE_CACHE_SIZE_LIMIT/M); - status = false; + if (VerifyFlagConstraints) { + ReservedCodeCacheSize = CODE_CACHE_SIZE_LIMIT; + jio_fprintf(defaultStream::error_stream(), "ReservedCodeCacheSize=%d\n", ReservedCodeCacheSize); + status = true; + } else { + // Code cache size larger than CODE_CACHE_SIZE_LIMIT is not supported. + jio_fprintf(defaultStream::error_stream(), + "Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M, + CODE_CACHE_SIZE_LIMIT/M); + status = false; + } } else if (NonNMethodCodeHeapSize < min_code_cache_size) { - jio_fprintf(defaultStream::error_stream(), - "Invalid NonNMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonNMethodCodeHeapSize/K, - min_code_cache_size/K); - status = false; + if (VerifyFlagConstraints) { + NonNMethodCodeHeapSize = min_code_cache_size; + jio_fprintf(defaultStream::error_stream(), "NonNMethodCodeHeapSize=%d\n", NonNMethodCodeHeapSize); + status = true; + } else { + jio_fprintf(defaultStream::error_stream(), + "Invalid NonNMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonNMethodCodeHeapSize/K, + min_code_cache_size/K); + status = false; + } } else if (InlineCacheBufferSize > NonNMethodCodeHeapSize / 2) { - jio_fprintf(defaultStream::error_stream(), - "Invalid InlineCacheBufferSize=" SIZE_FORMAT "K. Must be less than or equal to " SIZE_FORMAT "K.\n", - InlineCacheBufferSize/K, NonNMethodCodeHeapSize/2/K); - status = false; + if (VerifyFlagConstraints) { + InlineCacheBufferSize = NonNMethodCodeHeapSize / 2; + jio_fprintf(defaultStream::error_stream(), "InlineCacheBufferSize=%d\n", InlineCacheBufferSize); + status = true; + } else { + jio_fprintf(defaultStream::error_stream(), + "Invalid InlineCacheBufferSize=" SIZE_FORMAT "K. Must be less than or equal to " SIZE_FORMAT "K.\n", + InlineCacheBufferSize/K, NonNMethodCodeHeapSize/2/K); + status = false; + } } #ifdef _LP64 diff --git a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp index 9c22c29a107..1d93d4d37ee 100644 --- a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp +++ b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp @@ -36,6 +36,10 @@ static JVMFlag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { // CMSWorkQueueDrainThreshold is verified to be less than max_juint if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { + if (VerifyFlagConstraints) { + //JVMFlag::printError(true, "ParallelGCThreads:"UINT32_FORMAT"\n", ) + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" UINTX_FORMAT ") is too large\n", @@ -109,7 +113,7 @@ JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { value, CMSOldPLABMax); return JVMFlag::VIOLATES_CONSTRAINT; } - status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); + status = MaxPLABSizeBounds("CMSOldPLABMin", &CMSOldPLABMin, value, verbose); } return status; } @@ -118,7 +122,7 @@ JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { JVMFlag::Error status = JVMFlag::SUCCESS; if (UseConcMarkSweepGC) { - status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); + status = MaxPLABSizeBounds("CMSOldPLABMax", &CMSOldPLABMax, value, verbose); } return status; } @@ -236,5 +240,5 @@ JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { // For CMS, OldPLABSize is the number of free blocks of a given size that are used when // replenishing the local per-worker free list caches. // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags(). - return MaxPLABSizeBounds("OldPLABSize", value, verbose); + return MaxPLABSizeBounds("OldPLABSize", &OldPLABSize, value, verbose); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index eb5eae05543..d53b7ea1607 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -433,9 +433,14 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, assert(ConcGCThreads > 0, "ConcGCThreads have been set."); if (ConcGCThreads > ParallelGCThreads) { - log_warning(gc)("More ConcGCThreads (%u) than ParallelGCThreads (%u).", + if (VerifyFlagConstraints) { + ConcGCThreads = ParallelGCThreads; + tty->print_cr("ConcGCThreads:%u\n", ConcGCThreads); + } else { + log_warning(gc)("More ConcGCThreads (%u) than ParallelGCThreads (%u).", ConcGCThreads, ParallelGCThreads); - return; + return; + } } log_debug(gc)("ConcGCThreads: %u offset %u", ConcGCThreads, _worker_id_offset); @@ -454,10 +459,15 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, // Verify that the calculated value for MarkStackSize is in range. // It would be nice to use the private utility routine from Arguments. if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) { - log_warning(gc)("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): " + if (VerifyFlagConstraints) { + MarkStackSize = mark_stack_size < 1 ? 1 : MarkStackSizeMax; + tty->print_cr("MarkStackSize:"SIZE_FORMAT"\n", MarkStackSize); + } else { + log_warning(gc)("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): " "must be between 1 and " SIZE_FORMAT, mark_stack_size, MarkStackSizeMax); - return; + return; + } } FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size); } else { @@ -465,17 +475,27 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, if (FLAG_IS_CMDLINE(MarkStackSize)) { if (FLAG_IS_DEFAULT(MarkStackSizeMax)) { if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) { - log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): " - "must be between 1 and " SIZE_FORMAT, - MarkStackSize, MarkStackSizeMax); - return; + if (VerifyFlagConstraints) { + MarkStackSize = MarkStackSize < 1 ? 1 : MarkStackSizeMax; + tty->print_cr("MarkStackSize:"SIZE_FORMAT"\n", MarkStackSize); + } else { + log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): " + "must be between 1 and " SIZE_FORMAT, + MarkStackSize, MarkStackSizeMax); + return; + } } } else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) { if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) { - log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")" - " or for MarkStackSizeMax (" SIZE_FORMAT ")", - MarkStackSize, MarkStackSizeMax); - return; + if (VerifyFlagConstraints) { + MarkStackSize = MarkStackSize < 1 ? 1 : MarkStackSizeMax; + tty->print_cr("MarkStackSize:"SIZE_FORMAT"\n", MarkStackSize); + } else { + log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")" + " or for MarkStackSizeMax (" SIZE_FORMAT ")", + MarkStackSize, MarkStackSizeMax); + return; + } } } } diff --git a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index a5e10c4b674..d31910f5ba4 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -29,16 +29,22 @@ #include "utilities/globalDefinitions.hpp" JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; - // Default value of G1RSetRegionEntries=0 means will be set ergonomically. // Minimum value is 1. if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) { - JVMFlag::printError(verbose, - "G1RSetRegionEntries (" INTX_FORMAT ") must be " - "greater than or equal to 1\n", - value); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + G1RSetRegionEntries = 1; + JVMFlag::printError(true, "G1RSetRegionEntries:1\n"); + return JVMFlag::SUCCESS; + } else { + JVMFlag::printError(verbose, + "G1RSetRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return JVMFlag::VIOLATES_CONSTRAINT; + } } else { return JVMFlag::SUCCESS; } @@ -46,15 +52,20 @@ JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { if (!UseG1GC) return JVMFlag::SUCCESS; - // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. // Minimum value is 1. if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) { - JVMFlag::printError(verbose, - "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " - "greater than or equal to 1\n", - value); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + G1RSetSparseRegionEntries = 1; + JVMFlag::printError(true, "G1RSetSparseRegionEntries:1\n"); + return JVMFlag::SUCCESS; + } else { + JVMFlag::printError(verbose, + "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return JVMFlag::VIOLATES_CONSTRAINT; + } } else { return JVMFlag::SUCCESS; } @@ -62,9 +73,13 @@ JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { if (!UseG1GC) return JVMFlag::SUCCESS; - // Default value of G1HeapRegionSize=0 means will be set ergonomically. if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { + if (VerifyFlagConstraints) { + G1HeapRegionSize = HeapRegionBounds::min_size(); + JVMFlag::printError(true, "G1HeapRegionSize:"SIZE_FORMAT"\n", HeapRegionBounds::min_size()); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "G1HeapRegionSize (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic heap region minimum size\n", @@ -77,8 +92,12 @@ JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { if (!UseG1GC) return JVMFlag::SUCCESS; - if (value > G1MaxNewSizePercent) { + if (VerifyFlagConstraints) { + G1NewSizePercent = G1MaxNewSizePercent; + JVMFlag::printError(true, "G1NewSizePercent:"UINTX_FORMAT"\n", G1MaxNewSizePercent); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n", @@ -91,8 +110,12 @@ JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { if (!UseG1GC) return JVMFlag::SUCCESS; - if (value < G1NewSizePercent) { + if (VerifyFlagConstraints) { + G1MaxNewSizePercent = G1NewSizePercent; + JVMFlag::printError(true, "G1MaxNewSizePercent:"UINTX_FORMAT"\n", G1NewSizePercent); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n", @@ -105,6 +128,15 @@ JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { + if (VerifyFlagConstraints) { + if (GCPauseIntervalMillis <= 1) { + GCPauseIntervalMillis = 2; + JVMFlag::printError(true, "GCPauseIntervalMillis:"UINTX_FORMAT"\n", GCPauseIntervalMillis); + } + JVMFlag::printError(true, "MaxGCPauseMillis:"UINTX_FORMAT"\n", (GCPauseIntervalMillis - 1)); + MaxGCPauseMillis = GCPauseIntervalMillis - 1; + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxGCPauseMillis (" UINTX_FORMAT ") must be " "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", @@ -118,15 +150,25 @@ JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC) { if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { - if (value < 1) { + if (value <= 1) { + if (VerifyFlagConstraints) { + GCPauseIntervalMillis = 2; + JVMFlag::printError(true, "GCPauseIntervalMillis:"UINTX_FORMAT"\n", 2); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " - "greater than or equal to 1\n", + "greater than 1\n", value); return JVMFlag::VIOLATES_CONSTRAINT; } if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { + if (VerifyFlagConstraints) + { + JVMFlag::printError(true, "GCPauseIntervalMillis:MaxGCPauseMillis\n"); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "GCPauseIntervalMillis cannot be set " "without setting MaxGCPauseMillis\n"); @@ -134,6 +176,14 @@ JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) } if (value <= MaxGCPauseMillis) { + if (VerifyFlagConstraints) { + if (MaxGCPauseMillis == max_uintx - 1) { + MaxGCPauseMillis = MaxGCPauseMillis - 1; + } + GCPauseIntervalMillis = MaxGCPauseMillis + 1; + JVMFlag::printError(true, "GCPauseIntervalMillis:"UINTX_FORMAT"\n", (MaxGCPauseMillis + 1)); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", @@ -153,6 +203,12 @@ JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { // i.e. result of '(uint)(NewSize / region size(1~32MB))' // So maximum of NewSize should be 'max_juint * 1M' if (UseG1GC && (value > (max_juint * 1 * M))) { + if (VerifyFlagConstraints) + { + NewSize = max_juint * 1 * M; + JVMFlag::printError(true, "NewSize:"SIZE_FORMAT"\n", (max_juint * 1 * M)); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", value); diff --git a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp index e951014fd96..78d269b6909 100644 --- a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp +++ b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp @@ -30,8 +30,12 @@ JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. // So can't exceed with "max_jint" - if (UseParallelGC && (value > (uint)max_jint)) { + if (VerifyFlagConstraints) { + ParallelGCThreads = max_jint; + JVMFlag::printError(true, "ParallelGCThreads:"UINT32_FORMAT"\n", ParallelGCThreads); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for Parallel GC\n", @@ -44,6 +48,11 @@ JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // InitialTenuringThreshold is only used for ParallelGC. if (UseParallelGC && (value > MaxTenuringThreshold)) { + if (VerifyFlagConstraints) { + InitialTenuringThreshold = MaxTenuringThreshold; + JVMFlag::printError(true, "InitialTenuringThreshold"UINTX_FORMAT"\n", InitialTenuringThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "InitialTenuringThreshold (" UINTX_FORMAT ") must be " "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", @@ -57,6 +66,11 @@ JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verb // As only ParallelGC uses InitialTenuringThreshold, // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. if (UseParallelGC && (value < InitialTenuringThreshold)) { + if (VerifyFlagConstraints) { + MaxTenuringThreshold = InitialTenuringThreshold; + JVMFlag::printError(true, "MaxTenuringThreshold"UINTX_FORMAT"\n", InitialTenuringThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxTenuringThreshold (" UINTX_FORMAT ") must be " "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", diff --git a/src/hotspot/share/gc/shared/collectorPolicy.cpp b/src/hotspot/share/gc/shared/collectorPolicy.cpp index 564fd3c59ff..9a326615899 100644 --- a/src/hotspot/share/gc/shared/collectorPolicy.cpp +++ b/src/hotspot/share/gc/shared/collectorPolicy.cpp @@ -80,25 +80,54 @@ void CollectorPolicy::initialize_flags() { assert(_heap_alignment % _space_alignment == 0, "heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, _heap_alignment, _space_alignment); - + bool reset_init = false; + bool reset_max = false; if (FLAG_IS_CMDLINE(MaxHeapSize)) { if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { - vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size"); + if (VerifyFlagConstraints) { + InitialHeapSize = MaxHeapSize; + reset_init = true; + } else { + vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size"); + } } if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + if (VerifyFlagConstraints) { + MaxHeapSize = _min_heap_byte_size; + reset_max = true; + if (InitialHeapSize > MaxHeapSize) { + InitialHeapSize = MaxHeapSize; + reset_init = true; + } + } else { + vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + } } } // Check heap parameter properties if (MaxHeapSize < 2 * M) { - vm_exit_during_initialization("Too small maximum heap"); + if (VerifyFlagConstraints) { + MaxHeapSize = 2 * M; + reset_max = true; + } else { + vm_exit_during_initialization("Too small maximum heap"); + } } if (InitialHeapSize < M) { - vm_exit_during_initialization("Too small initial heap"); + if (VerifyFlagConstraints) { + InitialHeapSize = M; + reset_init = true; + } else { + vm_exit_during_initialization("Too small initial heap"); + } } if (_min_heap_byte_size < M) { - vm_exit_during_initialization("Too small minimum heap"); + if (VerifyFlagConstraints) { + _min_heap_byte_size = M; + } else { + vm_exit_during_initialization("Too small minimum heap"); + } } // User inputs from -Xmx and -Xms must be aligned @@ -116,7 +145,21 @@ void CollectorPolicy::initialize_flags() { if (FLAG_IS_CMDLINE(InitialHeapSize) && _min_heap_byte_size != 0 && InitialHeapSize < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); + if (VerifyFlagConstraints) { + InitialHeapSize = _min_heap_byte_size; + reset_init = true; + } else { + vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); + } + } + + if (VerifyFlagConstraints) { + if (reset_init) { + tty->print("InitialHeapSize:"SIZE_FORMAT"\n", InitialHeapSize); + } + if (reset_max) { + tty->print("MaxHeapSize:"SIZE_FORMAT"\n", MaxHeapSize); + } } if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { FLAG_SET_ERGO(size_t, MaxHeapSize, InitialHeapSize); diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 7eb09bd66ee..f2fa6d50c91 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -50,6 +50,7 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif // COMPILER2 +#include // Some flags that have default values that indicate that the // JVM should automatically determine an appropriate value @@ -62,7 +63,6 @@ // As ParallelGCThreads differs among GC modes, we need constraint function. JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { JVMFlag::Error status = JVMFlag::SUCCESS; - #if INCLUDE_PARALLELGC status = ParallelGCThreadsConstraintFuncParallel(value, verbose); if (status != JVMFlag::SUCCESS) { @@ -86,6 +86,11 @@ JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { // CMS and G1 GCs use ConcGCThreads. if ((GCConfig::is_gc_selected(CollectedHeap::CMS) || GCConfig::is_gc_selected(CollectedHeap::G1)) && (value > ParallelGCThreads)) { + if (VerifyFlagConstraints) { + ConcGCThreads = ParallelGCThreads; + JVMFlag::printError(true, "ConcGCThreads"UINT32_FORMAT"\n", ConcGCThreads); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "ConcGCThreads (" UINT32_FORMAT ") must be " "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", @@ -96,10 +101,15 @@ JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { return JVMFlag::SUCCESS; } -static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t* value_addr, size_t value, bool verbose) { if ((GCConfig::is_gc_selected(CollectedHeap::CMS) || GCConfig::is_gc_selected(CollectedHeap::G1) || GCConfig::is_gc_selected(CollectedHeap::Parallel)) && (value < PLAB::min_size())) { + if (VerifyFlagConstraints) { + *value_addr = PLAB::min_size(); + JVMFlag::printError(true, "%s:"SIZE_FORMAT"\n", name, PLAB::min_size()); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "%s (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", @@ -110,10 +120,15 @@ static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool ver return JVMFlag::SUCCESS; } -JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t* value_addr, size_t value, bool verbose) { if ((GCConfig::is_gc_selected(CollectedHeap::CMS) || GCConfig::is_gc_selected(CollectedHeap::G1) || GCConfig::is_gc_selected(CollectedHeap::Parallel)) && (value > PLAB::max_size())) { + if (VerifyFlagConstraints) { + *value_addr = PLAB::max_size(); + JVMFlag::printError(true, "%s:"SIZE_FORMAT"\n", name, PLAB::max_size()); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", @@ -124,17 +139,17 @@ JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { return JVMFlag::SUCCESS; } -static JVMFlag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - JVMFlag::Error status = MinPLABSizeBounds(name, value, verbose); +static JVMFlag::Error MinMaxPLABSizeBounds(const char* name, size_t *value_addr, size_t value, bool verbose) { + JVMFlag::Error status = MinPLABSizeBounds(name, value_addr, value, verbose); if (status == JVMFlag::SUCCESS) { - return MaxPLABSizeBounds(name, value, verbose); + return MaxPLABSizeBounds(name, value_addr, value, verbose); } return status; } JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { - return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); + return MinMaxPLABSizeBounds("YoungPLABSize", &YoungPLABSize, value, verbose); } JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { @@ -146,7 +161,7 @@ JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { } else #endif { - status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose); + status = MinMaxPLABSizeBounds("OldPLABSize", &OldPLABSize, value, verbose); } return status; @@ -154,6 +169,11 @@ JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { + if (VerifyFlagConstraints) { + MinHeapFreeRatio = MaxHeapFreeRatio; + JVMFlag::printError(true, "MinHeapFreeRatio:"UINTX_FORMAT"\n", MinHeapFreeRatio); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MinHeapFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", @@ -166,6 +186,11 @@ JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinHeapFreeRatio) { + if (VerifyFlagConstraints) { + MaxHeapFreeRatio = MinHeapFreeRatio; + JVMFlag::printError(true, "MaxHeapFreeRatio:"UINTX_FORMAT"\n", MaxHeapFreeRatio); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxHeapFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n", @@ -190,11 +215,30 @@ static JVMFlag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, } JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { - return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); + if ((value > 0) && ((MaxHeapSize / M) > (max_uintx / value))) { + if (VerifyFlagConstraints) { + SoftRefLRUPolicyMSPerMB = max_uintx/(MaxHeapSize / M); + JVMFlag::printError(true, "SoftRefLRUPolicyMSPerMB:"INTX_FORMAT"\n", SoftRefLRUPolicyMSPerMB); + return JVMFlag::SUCCESS; + } + JVMFlag::printError(verbose, + "Desired lifetime of SoftReferences cannot be expressed correctly. " + "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " + "(" INTX_FORMAT ") is too large\n", + MaxHeapSize, value); + return JVMFlag::VIOLATES_CONSTRAINT; + } else { + return JVMFlag::SUCCESS; + } } JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { if (value > MarkStackSizeMax) { + if (VerifyFlagConstraints) { + MarkStackSize = MarkStackSizeMax; + JVMFlag::printError(true, "MarkStackSize:"SIZE_FORMAT"\n", MarkStackSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MarkStackSize (" SIZE_FORMAT ") must be " "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", @@ -207,6 +251,11 @@ JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { + if (VerifyFlagConstraints) { + MinMetaspaceFreeRatio = MaxMetaspaceFreeRatio; + JVMFlag::printError(true, "MinMetaspaceFreeRatio:"UINTX_FORMAT"\n", MinMetaspaceFreeRatio); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n", @@ -219,6 +268,11 @@ JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinMetaspaceFreeRatio) { + if (VerifyFlagConstraints) { + MaxMetaspaceFreeRatio = MinMetaspaceFreeRatio; + JVMFlag::printError(true, "MaxMetaspaceFreeRatio:"UINTX_FORMAT"\n", MaxMetaspaceFreeRatio); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n", @@ -250,6 +304,11 @@ JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true if ((value == 0) && (NeverTenure || !AlwaysTenure)) { + if (VerifyFlagConstraints) { + MaxTenuringThreshold = 1; + JVMFlag::printError(true, "MaxTenuringThreshold:1\n"); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxTenuringThreshold (0) should match to NeverTenure=false " "&& AlwaysTenure=true. But we have NeverTenure=%s " @@ -286,6 +345,11 @@ JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words()); if (value > aligned_max) { + if (VerifyFlagConstraints) { + InitialBootClassLoaderMetaspaceSize = aligned_max; + JVMFlag::printError(true, "InitialBootClassLoaderMetaspaceSize:"SIZE_FORMAT"\n", InitialBootClassLoaderMetaspaceSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", @@ -296,9 +360,14 @@ JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, b } // To avoid an overflow by 'align_up(value, alignment)'. -static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { +static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t* value_addr, size_t value, size_t alignment, bool verbose) { size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1)); if (value > aligned_max) { + if (VerifyFlagConstraints) { + *value_addr = aligned_max; + JVMFlag::printError(true, "%s:"SIZE_FORMAT"\n", name, aligned_max); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", @@ -308,7 +377,7 @@ static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t value, size_t return JVMFlag::SUCCESS; } -static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t* value_addr, size_t value, bool verbose) { size_t heap_alignment; #if INCLUDE_G1GC @@ -321,18 +390,33 @@ static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bo heap_alignment = CollectorPolicy::compute_heap_alignment(); } - return MaxSizeForAlignment(name, value, heap_alignment, verbose); + return MaxSizeForAlignment(name, value_addr, value, heap_alignment, verbose); } JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { - return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); + return MaxSizeForHeapAlignment("InitialHeapSize", &InitialHeapSize, value, verbose); } JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); + JVMFlag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", &MaxHeapSize, value, verbose); if (status == JVMFlag::SUCCESS) { - status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); + if ((SoftRefLRUPolicyMSPerMB > 0) && ((value / M) > (max_uintx / SoftRefLRUPolicyMSPerMB))) { + if (VerifyFlagConstraints) { + MaxHeapSize = max_uintx / SoftRefLRUPolicyMSPerMB *M; + JVMFlag::printError(true, "MaxHeapSize:"SIZE_FORMAT"\n", MaxHeapSize); + return JVMFlag::SUCCESS; + } + JVMFlag::printError(verbose, + "Desired lifetime of SoftReferences cannot be expressed correctly. " + "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " + "(" INTX_FORMAT ") is too large\n", + value, SoftRefLRUPolicyMSPerMB); + return JVMFlag::VIOLATES_CONSTRAINT; + } else { + return JVMFlag::SUCCESS; + } + //status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); } return status; } @@ -340,6 +424,11 @@ JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { #if INCLUDE_ZGC JVMFlag::Error SoftMaxHeapSizeConstraintFunc(size_t value, bool verbose) { if (value > MaxHeapSize) { + if (VerifyFlagConstraints) { + SoftMaxHeapSize = MaxHeapSize; + JVMFlag::printError(true, "SoftMaxHeapSize:"SIZE_FORMAT"\n", SoftMaxHeapSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "SoftMaxHeapSize must be less than or equal to the maximum heap size\n"); return JVMFlag::VIOLATES_CONSTRAINT; } @@ -352,14 +441,19 @@ JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + HeapBaseMinAddress = max_uintx - MaxHeapSize; + JVMFlag::printError(true, "HeapBaseMinAddress:"SIZE_FORMAT"\n", HeapBaseMinAddress); + } else { + JVMFlag::printError(verbose, "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. " "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n", value, MaxHeapSize, max_uintx); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } } - return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose); + return MaxSizeForHeapAlignment("HeapBaseMinAddress", &HeapBaseMinAddress, value, verbose); } JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) { @@ -375,19 +469,34 @@ JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { // At least, alignment reserve area is needed. + bool verifyFailed = false; if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + verifyFailed = true; + value = ThreadLocalAllocBuffer::alignment_reserve_in_bytes(); + } else { + JVMFlag::printError(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + value = (ThreadLocalAllocBuffer::max_size() * HeapWordSize); + verifyFailed = true; + } else { + JVMFlag::printError(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } + } + if (verifyFailed) { + MinTLABSize = value; + JVMFlag::printError(true, "MinTLABSize:"SIZE_FORMAT"\n", value); } return JVMFlag::SUCCESS; } @@ -395,19 +504,34 @@ JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { // Skip for default value of zero which means set ergonomically. if (FLAG_IS_CMDLINE(TLABSize)) { + bool verifyFailed = false; if (value < MinTLABSize) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + value = MinTLABSize; + verifyFailed = true; + } else { + JVMFlag::printError(verbose, "TLABSize (" SIZE_FORMAT ") must be " "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", value, MinTLABSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + value = ThreadLocalAllocBuffer::max_size() * HeapWordSize; + verifyFailed = true; + } else { + JVMFlag::printError(verbose, "TLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } + } + if (verifyFailed) { + TLABSize = value; + JVMFlag::printError(true, "TLABSize:"SIZE_FORMAT"\n", value); } } return JVMFlag::SUCCESS; @@ -421,6 +545,11 @@ JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { // Compare with 'max_uintx' as ThreadLocalAllocBuffer::_refill_waste_limit is 'size_t'. if (refill_waste_limit > (max_uintx - value)) { + if (VerifyFlagConstraints) { + TLABWasteIncrement = max_uintx - refill_waste_limit; + JVMFlag::printError(true, "TLABWasteIncrement:"UINTX_FORMAT"\n", TLABWasteIncrement); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "TLABWasteIncrement (" UINTX_FORMAT ") must be " "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n", @@ -434,7 +563,12 @@ JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { if (FLAG_IS_CMDLINE(SurvivorRatio) && (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + SurvivorRatio = MaxHeapSize / Universe::heap()->collector_policy()->space_alignment(); + JVMFlag::printError(true, "SurvivorRatio:"UINTX_FORMAT"\n", SurvivorRatio); + return JVMFlag::SUCCESS; + } + JVMFlag::printError(verbose, "SurvivorRatio (" UINTX_FORMAT ") must be " "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", value, @@ -447,6 +581,11 @@ JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value > MaxMetaspaceSize) { + if (VerifyFlagConstraints) { + MetaspaceSize = MaxMetaspaceSize; + JVMFlag::printError(true, "MetaspaceSize:"SIZE_FORMAT"\n", MetaspaceSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", @@ -459,6 +598,11 @@ JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value < MetaspaceSize) { + if (VerifyFlagConstraints) { + MaxMetaspaceSize = MetaspaceSize; + JVMFlag::printError(true, "MaxMetaspaceSize:"SIZE_FORMAT"\n", MaxMetaspaceSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "MaxMetaspaceSize (" SIZE_FORMAT ") must be " "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", @@ -471,19 +615,35 @@ JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (value != 0) { + bool verifyFailed = false; + if (value < ObjectAlignmentInBytes) { + if (VerifyFlagConstraints) { + verifyFailed = true; + value = ObjectAlignmentInBytes; + } else { + JVMFlag::printError(verbose, + "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " + "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", + value, ObjectAlignmentInBytes); + return JVMFlag::VIOLATES_CONSTRAINT; + } + } if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + verifyFailed = true; + int logValue = log2_intptr(value); + value = (intx)pow(2, logValue); + } else { + JVMFlag::printError(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } } - if (value < ObjectAlignmentInBytes) { - JVMFlag::printError(verbose, - "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " - "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", - value, ObjectAlignmentInBytes); - return JVMFlag::VIOLATES_CONSTRAINT; + if (verifyFailed) { + SurvivorAlignmentInBytes = value; + JVMFlag::printError(true, "SurvivorAlignmentInBytes:"INTX_FORMAT"\n", value); } } return JVMFlag::SUCCESS; diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp index 11060b23897..5217228d78e 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -73,6 +73,6 @@ JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); // Internal -JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t* value_addr, size_t value, bool verbose); #endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index c4d59765686..547587687c8 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1276,7 +1276,17 @@ void Metaspace::ergo_initialize() { if (UseCompressedClassPointers) { if ((min_metaspace_sz + CompressedClassSpaceSize) > MaxMetaspaceSize) { if (min_metaspace_sz >= MaxMetaspaceSize) { - vm_exit_during_initialization("MaxMetaspaceSize is too small."); + if (VerifyFlagConstraints) { + MaxMetaspaceSize = min_metaspace_sz * 2; + MetaspaceSize = MaxMetaspaceSize; + tty->print_cr("MaxMetaspaceSize:" SIZE_FORMAT, + MaxMetaspaceSize); + tty->print_cr("MetaspaceSize:" SIZE_FORMAT, + MetaspaceSize); + } else { + vm_exit_during_initialization("MaxMetaspaceSize is too small."); + } + } else { FLAG_SET_ERGO(size_t, CompressedClassSpaceSize, MaxMetaspaceSize - min_metaspace_sz); diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 630c8becd97..a449f49d7ce 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -1086,11 +1086,16 @@ JVMFlag::Error JVMFlag::intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origi if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_int()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + int old_value = flag->get_int(); JVMFlag::Error check = apply_constraint_and_check_range_int(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - int old_value = flag->get_int(); + trace_flag_changed(name, old_value, *value, origin); - check = flag->set_int(*value); + if (VerifyFlagConstraints && old_value != flag->get_int()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_int(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1135,11 +1140,16 @@ JVMFlag::Error JVMFlag::uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags ori if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_uint()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + uint old_value = flag->get_uint(); JVMFlag::Error check = apply_constraint_and_check_range_uint(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - uint old_value = flag->get_uint(); + trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint(*value); + if (VerifyFlagConstraints && old_value != flag->get_uint()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_uint(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1184,11 +1194,16 @@ JVMFlag::Error JVMFlag::intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags ori if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_intx()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + intx old_value = flag->get_intx(); JVMFlag::Error check = apply_constraint_and_check_range_intx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - intx old_value = flag->get_intx(); + trace_flag_changed(name, old_value, *value, origin); - check = flag->set_intx(*value); + if (VerifyFlagConstraints && old_value != flag->get_intx()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_intx(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1233,11 +1248,15 @@ JVMFlag::Error JVMFlag::uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags o if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_uintx()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + uintx old_value = flag->get_uintx(); JVMFlag::Error check = apply_constraint_and_check_range_uintx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - uintx old_value = flag->get_uintx(); trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uintx(*value); + if (VerifyFlagConstraints && old_value != flag->get_uintx()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_uintx(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1282,11 +1301,15 @@ JVMFlag::Error JVMFlag::uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::F if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_uint64_t()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + uint64_t old_value = flag->get_uint64_t(); JVMFlag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - uint64_t old_value = flag->get_uint64_t(); trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint64_t(*value); + if (VerifyFlagConstraints && old_value != flag->get_uint64_t()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_uint64_t(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1332,11 +1355,15 @@ JVMFlag::Error JVMFlag::size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_size_t()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + size_t old_value = flag->get_size_t(); JVMFlag::Error check = apply_constraint_and_check_range_size_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - size_t old_value = flag->get_size_t(); trace_flag_changed(name, old_value, *value, origin); - check = flag->set_size_t(*value); + if (VerifyFlagConstraints && old_value != flag->get_size_t()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_size_t(*value); + } *value = old_value; flag->set_origin(origin); return check; @@ -1381,11 +1408,16 @@ JVMFlag::Error JVMFlag::doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_double()) return JVMFlag::WRONG_FORMAT; name = flag->_name; + double old_value = flag->get_double(); JVMFlag::Error check = apply_constraint_and_check_range_double(name, *value, !JVMFlagConstraintList::validated_after_ergo()); if (check != JVMFlag::SUCCESS) return check; - double old_value = flag->get_double(); + trace_flag_changed(name, old_value, *value, origin); - check = flag->set_double(*value); + if (VerifyFlagConstraints && old_value != flag->get_double()) { + check = JVMFlag::SUCCESS; + } else { + check = flag->set_double(*value); + } *value = old_value; flag->set_origin(origin); return check; diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index d19b43d19ac..2d8199f5f91 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -33,9 +33,15 @@ #include "runtime/flags/jvmFlagConstraintsCompiler.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose) { if ((value <= 1) && (Arguments::mode() == Arguments::_comp || Arguments::mode() == Arguments::_mixed)) { + if (VerifyFlagConstraints) { + AliasLevel = 2; + JVMFlag::printError(true, "AliasLevel:2\n"); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "AliasLevel (" INTX_FORMAT ") is not " "compatible with -Xcomp or -Xmixed\n", @@ -80,6 +86,11 @@ JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { min_number_of_compiler_threads = MIN2(min_number_of_compiler_threads, CI_COMPILER_COUNT); if (value < (intx)min_number_of_compiler_threads) { + if (VerifyFlagConstraints) { + CICompilerCount = min_number_of_compiler_threads; + JVMFlag::printError(true, "CICompilerCount:"INTX_FORMAT"\n", min_number_of_compiler_threads); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "CICompilerCount (" INTX_FORMAT ") must be " "at least %d \n", @@ -92,6 +103,11 @@ JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { if (value < 0 || value > 512) { + if (VerifyFlagConstraints) { + AllocatePrefetchDistance = value < 0 ? 1 : 512; + JVMFlag::printError(true, "AllocatePrefetchDistance:" INTX_FORMAT "\n", AllocatePrefetchDistance); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "AllocatePrefetchDistance (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", @@ -105,6 +121,15 @@ JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { if (AllocatePrefetchStyle == 3) { if (value % wordSize != 0) { + if (VerifyFlagConstraints) { + int remainder = value % wordSize; + AllocatePrefetchStepSize = value - remainder; + if (AllocatePrefetchStepSize == 0) { + AllocatePrefetchStepSize = wordSize; + } + JVMFlag::printError(true, "AllocatePrefetchStepSize:" INTX_FORMAT "\n", AllocatePrefetchStepSize); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "AllocatePrefetchStepSize (" INTX_FORMAT ") must be multiple of %d\n", value, wordSize); @@ -122,6 +147,11 @@ JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { max_value = 3; #endif if (value < 0 || value > max_value) { + if (VerifyFlagConstraints) { + AllocatePrefetchInstr = value < 0 ? 0 : max_value; + JVMFlag::printError(true, "AllocatePrefetchInstr:" INTX_FORMAT "\n", AllocatePrefetchInstr); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "AllocatePrefetchInstr (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", value, max_value); @@ -133,6 +163,11 @@ JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { + if (VerifyFlagConstraints) { + CompileThreshold = value < 0 ? 0 : INT_MAX >> InvocationCounter::count_shift; + JVMFlag::printError(true, "CompileThreshold:" INTX_FORMAT "\n", CompileThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "CompileThreshold (" INTX_FORMAT ") " "must be between 0 and %d\n", @@ -148,17 +183,27 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) int backward_branch_limit; if (ProfileInterpreter) { if (OnStackReplacePercentage < InterpreterProfilePercentage) { + if (VerifyFlagConstraints) { + OnStackReplacePercentage = InterpreterProfilePercentage; + JVMFlag::printError(true, "OnStackReplacePercentage:"INTX_FORMAT"\n", OnStackReplacePercentage); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, - "OnStackReplacePercentage (" INTX_FORMAT ") must be " - "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", - OnStackReplacePercentage, InterpreterProfilePercentage); + "OnStackReplacePercentage (" INTX_FORMAT ") must be " + "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", + OnStackReplacePercentage, InterpreterProfilePercentage); return JVMFlag::VIOLATES_CONSTRAINT; } - + //InvocationCounter::count_shift = 3 backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) << InvocationCounter::count_shift; if (backward_branch_limit < 0) { + if (VerifyFlagConstraints) { + OnStackReplacePercentage = (INT_MAX >> InvocationCounter::count_shift) / CompileThreshold + InterpreterProfilePercentage; + JVMFlag::printError(true, "OnStackReplacePercentage:"INTX_FORMAT"\n", OnStackReplacePercentage); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "CompileThreshold * (InterpreterProfilePercentage - OnStackReplacePercentage) / 100 = " INTX_FORMAT " " @@ -170,6 +215,12 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) } } else { if (OnStackReplacePercentage < 0 ) { + if (VerifyFlagConstraints) { + OnStackReplacePercentage = 0; + JVMFlag::printError(true, + "OnStackReplacePercentage:"INTX_FORMAT"\n", OnStackReplacePercentage); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "OnStackReplacePercentage (" INTX_FORMAT ") must be " "non-negative\n", OnStackReplacePercentage); @@ -180,6 +231,11 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) << InvocationCounter::count_shift; if (backward_branch_limit < 0) { + if (VerifyFlagConstraints) { + OnStackReplacePercentage = (INT_MAX >> InvocationCounter::count_shift) / CompileThreshold; + JVMFlag::printError(true, "OnStackReplacePercentage:"INTX_FORMAT"\n", OnStackReplacePercentage); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "CompileThreshold * OnStackReplacePercentage / 100 = " INTX_FORMAT " " "must be between 0 and " INTX_FORMAT ", try changing " @@ -193,34 +249,36 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) } JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { + // Don't apply VerifyFlagConstraints here because CodeCacheSegmentSize is not production parameter. if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { JVMFlag::printError(verbose, - "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " - "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") " - "to align entry points\n", - CodeCacheSegmentSize, CodeEntryAlignment); + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") " + "to align entry points\n", + CodeCacheSegmentSize, CodeEntryAlignment); return JVMFlag::VIOLATES_CONSTRAINT; } if (CodeCacheSegmentSize < sizeof(jdouble)) { JVMFlag::printError(verbose, - "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " - "at least " SIZE_FORMAT " to align constants\n", - CodeCacheSegmentSize, sizeof(jdouble)); + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "at least " SIZE_FORMAT " to align constants\n", + CodeCacheSegmentSize, sizeof(jdouble)); return JVMFlag::VIOLATES_CONSTRAINT; } #ifdef COMPILER2 if (CodeCacheSegmentSize < (uintx)OptoLoopAlignment) { + JVMFlag::printError(verbose, - "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " - "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") " - "to align inner loops\n", - CodeCacheSegmentSize, OptoLoopAlignment); + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") " + "to align inner loops\n", + CodeCacheSegmentSize, OptoLoopAlignment); return JVMFlag::VIOLATES_CONSTRAINT; + } #endif - return JVMFlag::SUCCESS; } @@ -241,6 +299,7 @@ JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { } JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { + // Don't apply VerifyFlagConstraints here because CodeEntryAlignment is not production parameter. #ifdef SPARC if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { JVMFlag::printError(verbose, @@ -249,15 +308,15 @@ JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { return JVMFlag::VIOLATES_CONSTRAINT; } #endif - if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, - "CodeEntryAlignment (" INTX_FORMAT ") must be " - "a power of two\n", CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; - } + JVMFlag::printError(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "a power of two\n", + CodeEntryAlignment); + return JVMFlag::VIOLATES_CONSTRAINT; + } - if (CodeEntryAlignment < 16) { + if (value < 16) { JVMFlag::printError(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", @@ -269,28 +328,47 @@ JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { } JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { + bool verifyFailed = false; if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, - "OptoLoopAlignment (" INTX_FORMAT ") " - "must be a power of two\n", - value); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + verifyFailed = true; + int logValue = log2_intptr(value); + value = (intx)pow(2, logValue); + } else { + JVMFlag::printError(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") " + "must be a power of two\n", + value); + return JVMFlag::VIOLATES_CONSTRAINT; + } } // Relevant on ppc, s390, sparc. Will be optimized where // addr_unit() == 1. - if (OptoLoopAlignment % relocInfo::addr_unit() != 0) { - JVMFlag::printError(verbose, - "OptoLoopAlignment (" INTX_FORMAT ") must be " - "multiple of NOP size (%d)\n", - value, relocInfo::addr_unit()); - return JVMFlag::VIOLATES_CONSTRAINT; + if (value % relocInfo::addr_unit() != 0) { + if (VerifyFlagConstraints) { + verifyFailed = true; + int remainder = value % relocInfo::addr_unit(); + value = value - remainder; + } else { + JVMFlag::printError(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size (%d)\n", + value, relocInfo::addr_unit()); + return JVMFlag::VIOLATES_CONSTRAINT; + } + } + + if (verifyFailed) { + OptoLoopAlignment = value; + JVMFlag::printError(verbose, "OptoLoopAlignment:" INTX_FORMAT "\n", value); } return JVMFlag::SUCCESS; } JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + // Don't apply VerifyFlagConstraints here because ArraycopyDstPrefetchDistance is Sparc platform only if (value >= 4032) { JVMFlag::printError(verbose, "ArraycopyDstPrefetchDistance (" UINTX_FORMAT ") must be" @@ -302,6 +380,7 @@ JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verb } JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + // Don't apply VerifyFlagConstraints here because ArraycopySrcPrefetchDistance is Sparc platform only if (value >= 4032) { JVMFlag::printError(verbose, "ArraycopySrcPrefetchDistance (" UINTX_FORMAT ") must be" @@ -313,16 +392,30 @@ JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verb } JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { + bool verifyFailed = false; + int suggested[3]; for (int i = 0; i < 3; i++) { if (value % 10 > 2) { - JVMFlag::printError(verbose, - "Invalid value (" UINTX_FORMAT ") " - "in TypeProfileLevel at position %d\n", value, i); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + verifyFailed = true; + suggested[i] = 2; + } else { + JVMFlag::printError(verbose, + "Invalid value (" UINTX_FORMAT ") " + "in TypeProfileLevel at position %d\n", + value, i); + return JVMFlag::VIOLATES_CONSTRAINT; + } + } else { + suggested[i] = value % 10; } value = value / 10; } - + if (verifyFailed) { + uintx suggestedValue = suggested[0] + suggested[1]*10 + suggested[2]*100; + TypeProfileLevel = suggestedValue; + JVMFlag::printError(true, "TypeProfileLevel:" UINTX_FORMAT "\n", suggestedValue); + } return JVMFlag::SUCCESS; } @@ -336,12 +429,19 @@ JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { #ifdef COMPILER2 JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { + bool verifyFailed = false; + intx suggested; if (InteriorEntryAlignment > CodeEntryAlignment) { - JVMFlag::printError(verbose, - "InteriorEntryAlignment (" INTX_FORMAT ") must be " - "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", - InteriorEntryAlignment, CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + value = CodeEntryAlignment; + verifyFailed = true; + } else { + JVMFlag::printError(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", + InteriorEntryAlignment, CodeEntryAlignment); + return JVMFlag::VIOLATES_CONSTRAINT; + } } #ifdef SPARC @@ -354,11 +454,17 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { #endif if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + int logValue = log2_intptr(value); + value = (intx)pow(2, logValue); + verifyFailed = true; + } else { + JVMFlag::printError(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", InteriorEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; - } + return JVMFlag::VIOLATES_CONSTRAINT; + } + } int minimum_alignment = 16; #if defined(SPARC) || (defined(X86) && !defined(AMD64)) @@ -367,12 +473,22 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { minimum_alignment = 2; #endif - if (InteriorEntryAlignment < minimum_alignment) { - JVMFlag::printError(verbose, + if (value < minimum_alignment) { + if (VerifyFlagConstraints) { + value = minimum_alignment; + verifyFailed = true; + } else { + JVMFlag::printError(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", InteriorEntryAlignment, minimum_alignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } + } + + if(verifyFailed) { + InteriorEntryAlignment = value; + JVMFlag::printError(true, "InteriorEntryAlignment:"INTX_FORMAT"\n", value); } return JVMFlag::SUCCESS; @@ -380,6 +496,12 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { + if (VerifyFlagConstraints) { + intx limit = (value < MaxNodeLimit * 2 / 100)? (MaxNodeLimit * 2 / 100): (MaxNodeLimit * 40 / 100); + NodeLimitFudgeFactor = limit; + JVMFlag::printError(true, "NodeLimitFudgeFactor:"INTX_FORMAT"\n", limit); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "NodeLimitFudgeFactor must be between 2%% and 40%% " "of MaxNodeLimit (" INTX_FORMAT ")\n", diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 6559d4252f0..655a816b2e1 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -29,22 +29,39 @@ #include "runtime/globals.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/task.hpp" +#include JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { + bool verifyFailed = false; if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, - "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " - "power of 2\n", - value); - return JVMFlag::VIOLATES_CONSTRAINT; + if (VerifyFlagConstraints) { + verifyFailed = true; + int logValue = log2_intptr(value); + value = (intx)pow(2, logValue); + } else { + JVMFlag::printError(verbose, + "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " + "power of 2\n", + value); + return JVMFlag::VIOLATES_CONSTRAINT; + } } // In case page size is very small. if (value >= (intx)os::vm_page_size()) { - JVMFlag::printError(verbose, + if (VerifyFlagConstraints) { + verifyFailed = true; + value = (intx)(os::vm_page_size()/2); + } else { + JVMFlag::printError(verbose, "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "less than page size (" INTX_FORMAT ")\n", value, (intx)os::vm_page_size()); - return JVMFlag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; + } + } + if (verifyFailed) { + ObjectAlignmentInBytes = value; + JVMFlag::printError(true, "ObjectAlignmentInBytes:" INTX_FORMAT "\n", value); } return JVMFlag::SUCCESS; } @@ -53,6 +70,12 @@ JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { // It is sufficient to check against the largest type size. JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { if ((value % BytesPerLong) != 0) { + if (VerifyFlagConstraints) { + int remainder = value % BytesPerLong; + ContendedPaddingWidth = value - remainder; + JVMFlag::printError(true, "ContendedPaddingWidth:" INTX_FORMAT "\n", ContendedPaddingWidth); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "ContendedPaddingWidth (" INTX_FORMAT ") must be " "a multiple of %d\n", @@ -65,6 +88,11 @@ JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { if (value > BiasedLockingBulkRevokeThreshold) { + if (VerifyFlagConstraints) { + BiasedLockingBulkRebiasThreshold = BiasedLockingBulkRevokeThreshold; + JVMFlag::printError(true, "BiasedLockingBulkRebiasThreshold:" INTX_FORMAT "\n", BiasedLockingBulkRevokeThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ") must be " "less than or equal to BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")\n", @@ -77,6 +105,12 @@ JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran) != 0) { + if (VerifyFlagConstraints) { + int remainder = value % PeriodicTask::interval_gran; + BiasedLockingStartupDelay = value - remainder; + JVMFlag::printError(true, "BiasedLockingStartupDelay:" INTX_FORMAT "\n", BiasedLockingStartupDelay); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "BiasedLockingStartupDelay (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", @@ -89,12 +123,22 @@ JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { if (value < BiasedLockingBulkRebiasThreshold) { + if (VerifyFlagConstraints) { + BiasedLockingBulkRevokeThreshold = BiasedLockingBulkRebiasThreshold; + JVMFlag::printError(true, "BiasedLockingBulkRevokeThreshold:" INTX_FORMAT "\n", BiasedLockingBulkRevokeThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ") must be " "greater than or equal to BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRebiasThreshold); return JVMFlag::VIOLATES_CONSTRAINT; } else if ((double)value/(double)BiasedLockingDecayTime > 0.1) { + if (VerifyFlagConstraints) { + BiasedLockingBulkRevokeThreshold = (intx)(BiasedLockingDecayTime * 0.1); + JVMFlag::printError(true, "BiasedLockingBulkRevokeThreshold:" INTX_FORMAT "\n", BiasedLockingBulkRevokeThreshold); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "The ratio of BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " @@ -108,6 +152,11 @@ JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { if (BiasedLockingBulkRebiasThreshold/(double)value > 0.1) { + if (VerifyFlagConstraints) { + BiasedLockingDecayTime = BiasedLockingBulkRebiasThreshold * 10; + JVMFlag::printError(true, "BiasedLockingDecayTime:"INTX_FORMAT"\n", BiasedLockingDecayTime); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "The ratio of BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " @@ -121,6 +170,12 @@ JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran != 0)) { + if (VerifyFlagConstraints) { + int remainder = value % PeriodicTask::interval_gran; + PerfDataSamplingInterval = value - remainder; + JVMFlag::printError(true, "PerfDataSamplingInterval:"INTX_FORMAT"\n", PerfDataSamplingInterval); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "PerfDataSamplingInterval (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", @@ -134,6 +189,11 @@ JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { if (value) { if (!SafepointMechanism::supports_thread_local_poll()) { + if (VerifyFlagConstraints) { + VerifyFlagConstraints = false; + JVMFlag::printError(true, "ThreadLocalHandshakes:false\n"); + return JVMFlag::SUCCESS; + } JVMFlag::printError(verbose, "ThreadLocalHandshakes not yet supported on this platform\n"); return JVMFlag::VIOLATES_CONSTRAINT; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index db06b9a263a..b3745a4451c 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1290,6 +1290,10 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); product(bool, PrintFlagsInitial, false, \ "Print all VM flags before argument processing and exit VM") \ \ + diagnostic(bool, VerifyFlagConstraints, false, \ + "Verify flags, calculate suggested legal values for that " \ + "violate the constraints, and then exit VM") \ + \ product(bool, PrintFlagsFinal, false, \ "Print all VM flags after argument and ergonomic processing") \ \ diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 90b203bf8b6..726a9be3699 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -160,6 +160,10 @@ jint init_globals() { JVMFlag::printFlags(tty, false, PrintFlagsRanges); } + if (VerifyFlagConstraints){ + vm_exit(0); + } + return JNI_OK; } diff --git a/test/hotspot/jtreg/sanity/VerifyFlagConstraintsTests.java b/test/hotspot/jtreg/sanity/VerifyFlagConstraintsTests.java new file mode 100644 index 00000000000..087e66d8119 --- /dev/null +++ b/test/hotspot/jtreg/sanity/VerifyFlagConstraintsTests.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Alibaba designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package sanity; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.util.HashMap; +import java.util.Map; + +/* + * @test + * @summary make sure various basic java options work + * @library /test/lib + * @run driver sanity.VerifyFlagConstraintsTests + */ +public class VerifyFlagConstraintsTests { + public static void main(String[] args) throws Exception { + FlagConstraintTester.create().run("-XX:+UseG1GC", + "-XX:MaxGCPauseMillis=18446744073709551614", + "-XX:GCPauseIntervalMillis=0", + "-XX:AllocatePrefetchDistance=-1", + "-XX:AllocatePrefetchStepSize=29", + "-XX:AllocatePrefetchStyle=3") + /* .testEq("MaxGCPauseMillis", "1") + .testEq("GCPauseIntervalMillis", "2") + .testEq("AllocatePrefetchDistance", "8") + .testEq("AllocatePrefetchStepSize", "24")*/ + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:InteriorEntryAlignment=99", + "-XX:OptoLoopAlignment=9") + /*.testEq("InteriorEntryAlignment", "32") + .testEq("OptoLoopAlignment", "8")*/ + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:CompileThreshold=268435456") + // .testEq("CompileThreshold", "268435455") + // .testEq("OnStackReplacePercentage", "34") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:ObjectAlignmentInBytes=99") + //.testEq("ObjectAlignmentInBytes", "64") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:TypeProfileLevel=123") + // .testEq("TypeProfileLevel", "122") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:TypeProfileLevel=333") + //.testEq("TypeProfileLevel", "222") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:BiasedLockingBulkRebiasThreshold=250", + "-XX:BiasedLockingBulkRevokeThreshold=249", + "-XX:BiasedLockingDecayTime=2500") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:BiasedLockingStartupDelay=99") + // .testEq("BiasedLockingStartupDelay", "90") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:YoungPLABSize=128") + // .testEq("YoungPLABSize", "256") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:YoungPLABSize=9999999") + //.testEq("YoungPLABSize", "65536") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:ThreadStackSize=128") + //.testEq("ThreadStackSize", "136") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:ReservedCodeCacheSize=4096") + //.testEq("ReservedCodeCacheSize", "2555904") + .testWithSuggested(); + + FlagConstraintTester.create().run("-XX:MarkStackSize=0") + //.testEq("ReservedCodeCacheSize", "2555904") + .testWithSuggested(); + } + + static class FlagConstraintTester { + private static String[] enableArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+VerifyFlagConstraints"}; + private Map suggestedArgs = new HashMap<>(); + private Map inputArgs = new HashMap<>(); + + public static FlagConstraintTester create() { + return new FlagConstraintTester(); + } + + public FlagConstraintTester run(String... flags) throws Exception { + OutputAnalyzer outputAnalyzer = doRun(flags, true); + extractSuggestions(outputAnalyzer); + return this; + } + + private OutputAnalyzer doRun(String[] flags, boolean updateInputs) throws Exception { + String[] cmds = new String[flags.length + 2]; + cmds[0] = enableArgs[0]; + cmds[1] = enableArgs[1]; + for (int i = 0; i < flags.length; i++) { + cmds[i + 2] = flags[i]; + if (updateInputs) { + String[] values = flags[i].split("="); + String key; + String value; + if (values.length == 1) { + // case of -XX:+SomeOpt + key = values[0].substring(5); + value = String.valueOf(values[0].charAt(4)); + } else { + key = values[0].substring(4); + value = values[1]; + } + inputArgs.put(key, value); + } + } + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm(cmds); + System.out.println(outputAnalyzer.getOutput()); + outputAnalyzer.shouldHaveExitValue(0); + return outputAnalyzer; + } + + private void extractSuggestions(OutputAnalyzer outputAnalyzer) { + for (String line : outputAnalyzer.asLines()) { + String[] rets = line.split(":"); + if (rets.length != 2) { + throw new RuntimeException("Expect 2 entries in the result of flag verifying, but is " + line); + } + suggestedArgs.put(rets[0], rets[1]); + } + } + + /** + * Start JVM with suggested flags again. This time there should be no suggestion anymore. + * + * @throws Exception + */ + public void testWithSuggested() throws Exception { + suggestedArgs.entrySet().forEach(suggested -> + inputArgs.put(suggested.getKey(), suggested.getValue()) + ); + String[] args = inputArgs.entrySet().stream().map(entry -> { + if (entry.getValue().equals("-") || entry.getValue().equalsIgnoreCase("false")) { + return "-XX:-" + entry.getKey(); + } + if (entry.getValue().equals("+") || entry.getValue().equalsIgnoreCase("true")) { + return "-XX:+" + entry.getKey(); + } + return "-XX:" + entry.getKey() + "=" + entry.getValue(); + }).toArray(String[]::new); + OutputAnalyzer outputAnalyzer = doRun(args, false); + outputAnalyzer.shouldBeEmpty(); + } + + public FlagConstraintTester testEq(String param, String expected) { + Asserts.assertEquals(expected, suggestedArgs.get(param)); + return this; + } + } +}