From 487cc3c5be769d15d61cb950137d52ba0eb982b5 Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Thu, 7 Aug 2025 07:52:48 +0000 Subject: [PATCH 001/471] 8359690: New test TestCPUTimeSampleThrottling still fails intermittently Reviewed-by: mbaesken --- .../TestCPUTimeSampleThrottling.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java index b0b9d6d2be7..ef2c73514a3 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java @@ -23,6 +23,7 @@ package jdk.jfr.event.profiling; import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; import java.time.Duration; import java.time.Instant; import java.util.List; @@ -71,7 +72,7 @@ public class TestCPUTimeSampleThrottling { } /** - * Counting the events that are emitted for a given throttle in a given time. + * Counting the events that are emitted for a given throttle in a given (CPU) time. *

* The result is wall-clock independent; it only records the CPU-time and the number of * emitted events. The result, therefore, does not depend on the load of the machine. @@ -83,15 +84,9 @@ public class TestCPUTimeSampleThrottling { recording.enable(EventNames.CPUTimeSample) .with("throttle", throttle); - var bean = ManagementFactory.getThreadMXBean(); - recording.start(); - long startThreadCpuTime = bean.getCurrentThreadCpuTime(); - - wasteCPU(timeMs); - - long spendCPUTime = bean.getCurrentThreadCpuTime() - startThreadCpuTime; + long spendCPUTime = wasteCPU(timeMs); recording.stop(); @@ -99,19 +94,20 @@ public class TestCPUTimeSampleThrottling { .filter(e -> e.getThread().getJavaName() .equals(Thread.currentThread().getName())) .count(); - return new EventCount(eventCount, spendCPUTime / 1_000_000_000f); } } - private static void wasteCPU(int durationMs) { - long start = System.currentTimeMillis(); + private static long wasteCPU(int durationMs) { + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + long start = bean.getCurrentThreadCpuTime(); double i = 0; - while (System.currentTimeMillis() - start < durationMs) { + while (bean.getCurrentThreadCpuTime() - start < durationMs * 1_000_000) { for (int j = 0; j < 100000; j++) { i = Math.sqrt(i * Math.pow(Math.sqrt(Math.random()), Math.random())); } } + return bean.getCurrentThreadCpuTime() - start; } } From c56fb0b6eff7d3f36bc65f300b784e0dd73c563e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 7 Aug 2025 08:40:42 +0000 Subject: [PATCH 002/471] 8364503: gc/g1/TestCodeCacheUnloadDuringConcCycle.java fails because of race printing to stdout Reviewed-by: ayang, dholmes --- .../jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java index 94f65a4328f..a4fadc185d2 100644 --- a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java +++ b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java @@ -147,6 +147,7 @@ class TestCodeCacheUnloadDuringConcCycleRunner { } public static void main(String[] args) throws Exception { + System.out.println("Running to breakpoint: " + args[0]); try { WB.concurrentGCAcquireControl(); WB.concurrentGCRunTo(args[0]); @@ -157,9 +158,12 @@ class TestCodeCacheUnloadDuringConcCycleRunner { WB.concurrentGCRunToIdle(); } finally { + // Make sure that the marker we use to find the expected log message is printed + // before we release whitebox control, i.e. before the expected garbage collection + // can start. + System.out.println(TestCodeCacheUnloadDuringConcCycle.AFTER_FIRST_CYCLE_MARKER); WB.concurrentGCReleaseControl(); } - System.out.println(TestCodeCacheUnloadDuringConcCycle.AFTER_FIRST_CYCLE_MARKER); Thread.sleep(1000); triggerCodeCacheGC(); } From 8d73fe91bccd1da53424b9f8a52d9efafabeb243 Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Thu, 7 Aug 2025 10:21:54 +0000 Subject: [PATCH 003/471] 8358813: JPasswordField identifies spaces in password via delete shortcuts Reviewed-by: aivanov, dnguyen --- .../com/apple/laf/AquaKeyBindings.java | 3 + .../PasswordFieldInputMapWordTest.java | 118 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 test/jdk/javax/swing/JPasswordField/PasswordFieldInputMapWordTest.java diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java index c6224c63543..8d160230844 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java @@ -157,6 +157,9 @@ public final class AquaKeyBindings { "shift alt KP_LEFT", null, "shift alt RIGHT", null, "shift alt KP_RIGHT", null, + "alt BACK_SPACE", null, + "ctrl W", null, + "alt DELETE", null, })); } diff --git a/test/jdk/javax/swing/JPasswordField/PasswordFieldInputMapWordTest.java b/test/jdk/javax/swing/JPasswordField/PasswordFieldInputMapWordTest.java new file mode 100644 index 00000000000..c49e9f7083c --- /dev/null +++ b/test/jdk/javax/swing/JPasswordField/PasswordFieldInputMapWordTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @bug 8358813 + * @summary Password fields' InputMap should not include any word-related action. + * + * @run main PasswordFieldInputMapWordTest + */ + +import java.util.Collection; +import java.util.Set; + +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JPasswordField; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.text.DefaultEditorKit; + +public class PasswordFieldInputMapWordTest { + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo laf : + UIManager.getInstalledLookAndFeels()) { + System.out.println("Testing LAF: " + laf.getClassName()); + SwingUtilities.invokeAndWait(() -> { + if (setLookAndFeel(laf)) { + runTest(); + } + }); + } + } + + private static boolean setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + return true; + } catch (UnsupportedLookAndFeelException e) { + System.err.println("Skipping unsupported look and feel:"); + e.printStackTrace(); + return false; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static int[] inputMapConditions = new int[] { + JComponent.WHEN_IN_FOCUSED_WINDOW, + JComponent.WHEN_FOCUSED, + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + }; + + /** + * These are all the actions with "word" in their field name. + */ + static Collection wordActions = Set.of( + DefaultEditorKit.deleteNextWordAction, + DefaultEditorKit.deletePrevWordAction, + DefaultEditorKit.beginWordAction, + DefaultEditorKit.endWordAction, + DefaultEditorKit.selectionBeginWordAction, + DefaultEditorKit.selectionEndWordAction, + DefaultEditorKit.previousWordAction, + DefaultEditorKit.nextWordAction, + DefaultEditorKit.selectionPreviousWordAction, + DefaultEditorKit.selectionNextWordAction + ); + + private static void runTest() { + JPasswordField field = new JPasswordField(); + + boolean testPassed = true; + for (int condition : inputMapConditions) { + InputMap inputMap = field.getInputMap(condition); + if (inputMap.allKeys() == null) { + continue; + } + for (KeyStroke keyStroke : inputMap.allKeys()) { + Object actionBinding = inputMap.get(keyStroke); + if (wordActions.contains(actionBinding)) { + if (testPassed) { + System.err.println("The following inputs/actions should not be available in a JPasswordField:"); + } + System.err.println(inputMap.get(keyStroke) + " (try typing " + keyStroke + ")"); + testPassed = false; + } + } + } + + if (!testPassed) { + throw new RuntimeException("One or more input/action binding was observed for a JPasswordField."); + } + } +} From bc3d86564042208cee5119abe11905e747a5ef4c Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 7 Aug 2025 13:26:33 +0000 Subject: [PATCH 004/471] 8364128: Improve gathering of cpu feature names using stringStream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johan Sjölen Reviewed-by: kvn, jsjolen --- .../cpu/aarch64/vm_version_aarch64.cpp | 58 ++++++++++++------- .../cpu/aarch64/vm_version_aarch64.hpp | 25 +++++++- src/hotspot/cpu/x86/vm_version_x86.cpp | 42 +++++++------- src/hotspot/cpu/x86/vm_version_x86.hpp | 4 +- .../bsd_aarch64/vm_version_bsd_aarch64.cpp | 18 +++--- .../vm_version_linux_aarch64.cpp | 42 ++++++++------ .../share/runtime/abstract_vm_version.cpp | 13 ----- .../share/runtime/abstract_vm_version.hpp | 3 - src/hotspot/share/utilities/ostream.hpp | 14 +++++ 9 files changed, 130 insertions(+), 89 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 9321dd0542e..24c77174711 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -32,6 +32,7 @@ #include "runtime/vm_version.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" +#include "utilities/ostream.hpp" int VM_Version::_cpu; int VM_Version::_model; @@ -50,6 +51,8 @@ uintptr_t VM_Version::_pac_mask; SpinWait VM_Version::_spin_wait; +const char* VM_Version::_features_names[MAX_CPU_FEATURES] = { nullptr }; + static SpinWait get_spin_wait_desc() { SpinWait spin_wait(OnSpinWaitInst, OnSpinWaitInstCount); if (spin_wait.inst() == SpinWait::SB && !VM_Version::supports_sb()) { @@ -60,6 +63,11 @@ static SpinWait get_spin_wait_desc() { } void VM_Version::initialize() { +#define SET_CPU_FEATURE_NAME(id, name, bit) \ + _features_names[bit] = XSTR(name); + CPU_FEATURE_FLAGS(SET_CPU_FEATURE_NAME) +#undef SET_CPU_FEATURE_NAME + _supports_atomic_getset4 = true; _supports_atomic_getadd4 = true; _supports_atomic_getset8 = true; @@ -194,7 +202,7 @@ void VM_Version::initialize() { // Cortex A53 if (_cpu == CPU_ARM && model_is(0xd03)) { - _features |= CPU_A53MAC; + set_feature(CPU_A53MAC); if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) { FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false); } @@ -234,7 +242,7 @@ void VM_Version::initialize() { } } - if (_features & (CPU_FP | CPU_ASIMD)) { + if (supports_feature(CPU_FP) || supports_feature(CPU_ASIMD)) { if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) { FLAG_SET_DEFAULT(UseSignumIntrinsic, true); } @@ -397,7 +405,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } - if (_features & CPU_ASIMD) { + if (supports_feature(CPU_ASIMD)) { if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { UseChaCha20Intrinsics = true; } @@ -408,7 +416,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } - if (_features & CPU_ASIMD) { + if (supports_feature(CPU_ASIMD)) { if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { UseKyberIntrinsics = true; } @@ -419,7 +427,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseKyberIntrinsics, false); } - if (_features & CPU_ASIMD) { + if (supports_feature(CPU_ASIMD)) { if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { UseDilithiumIntrinsics = true; } @@ -620,32 +628,38 @@ void VM_Version::initialize() { // Sync SVE related CPU features with flags if (UseSVE < 2) { - _features &= ~CPU_SVE2; - _features &= ~CPU_SVEBITPERM; + clear_feature(CPU_SVE2); + clear_feature(CPU_SVEBITPERM); } if (UseSVE < 1) { - _features &= ~CPU_SVE; + clear_feature(CPU_SVE); } // Construct the "features" string - char buf[512]; - int buf_used_len = os::snprintf_checked(buf, sizeof(buf), "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); + stringStream ss(512); + ss.print("0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); if (_model2) { - os::snprintf_checked(buf + buf_used_len, sizeof(buf) - buf_used_len, "(0x%03x)", _model2); + ss.print("(0x%03x)", _model2); } - size_t features_offset = strnlen(buf, sizeof(buf)); -#define ADD_FEATURE_IF_SUPPORTED(id, name, bit) \ - do { \ - if (VM_Version::supports_##name()) strcat(buf, ", " #name); \ - } while(0); - CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED) -#undef ADD_FEATURE_IF_SUPPORTED + ss.print(", "); + int features_offset = (int)ss.size(); + insert_features_names(_features, ss); - _cpu_info_string = os::strdup(buf); + _cpu_info_string = ss.as_string(true); + _features_string = _cpu_info_string + features_offset; +} - _features_string = extract_features_string(_cpu_info_string, - strnlen(_cpu_info_string, sizeof(buf)), - features_offset); +void VM_Version::insert_features_names(uint64_t features, stringStream& ss) { + int i = 0; + ss.join([&]() { + while (i < MAX_CPU_FEATURES) { + if (supports_feature((VM_Version::Feature_Flag)i)) { + return _features_names[i++]; + } + i += 1; + } + return (const char*)nullptr; + }, ", "); } #if defined(LINUX) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 99450d3dde1..5a8642a285a 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -30,6 +30,10 @@ #include "runtime/abstract_vm_version.hpp" #include "utilities/sizes.hpp" +class stringStream; + +#define BIT_MASK(flag) (1ULL<<(flag)) + class VM_Version : public Abstract_VM_Version { friend class VMStructs; friend class JVMCIVMStructs; @@ -66,6 +70,8 @@ public: static void initialize(); static void check_virtualizations(); + static void insert_features_names(uint64_t features, stringStream& ss); + static void print_platform_virtualization_info(outputStream*); // Asserts @@ -139,17 +145,32 @@ enum Ampere_CPU_Model { decl(A53MAC, a53mac, 31) enum Feature_Flag { -#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit), +#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = bit, CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) #undef DECLARE_CPU_FEATURE_FLAG + MAX_CPU_FEATURES }; + STATIC_ASSERT(sizeof(_features) * BitsPerByte >= MAX_CPU_FEATURES); + + static const char* _features_names[MAX_CPU_FEATURES]; + // Feature identification #define CPU_FEATURE_DETECTION(id, name, bit) \ - static bool supports_##name() { return (_features & CPU_##id) != 0; }; + static bool supports_##name() { return supports_feature(CPU_##id); } CPU_FEATURE_FLAGS(CPU_FEATURE_DETECTION) #undef CPU_FEATURE_DETECTION + static void set_feature(Feature_Flag flag) { + _features |= BIT_MASK(flag); + } + static void clear_feature(Feature_Flag flag) { + _features &= (~BIT_MASK(flag)); + } + static bool supports_feature(Feature_Flag flag) { + return (_features & BIT_MASK(flag)) != 0; + } + static int cpu_family() { return _cpu; } static int cpu_model() { return _model; } static int cpu_model2() { return _model2; } diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 001cb6b0255..b81c200c440 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -38,6 +38,7 @@ #include "runtime/stubCodeGenerator.hpp" #include "runtime/vm_version.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/ostream.hpp" #include "utilities/powerOfTwo.hpp" #include "utilities/virtualizationSupport.hpp" @@ -1097,21 +1098,16 @@ void VM_Version::get_processor_features() { } } - char buf[2048]; - size_t cpu_info_size = jio_snprintf( - buf, sizeof(buf), - "(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x", - cores_per_cpu(), threads_per_core(), - cpu_family(), _model, _stepping, os::cpu_microcode_revision()); - assert(cpu_info_size > 0, "not enough temporary space allocated"); + stringStream ss(2048); + ss.print("(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x", + cores_per_cpu(), threads_per_core(), + cpu_family(), _model, _stepping, os::cpu_microcode_revision()); + ss.print(", "); + int features_offset = (int)ss.size(); + insert_features_names(_features, ss); - insert_features_names(_features, buf + cpu_info_size, sizeof(buf) - cpu_info_size); - - _cpu_info_string = os::strdup(buf); - - _features_string = extract_features_string(_cpu_info_string, - strnlen(_cpu_info_string, sizeof(buf)), - cpu_info_size); + _cpu_info_string = ss.as_string(true); + _features_string = _cpu_info_string + features_offset; // Use AES instructions if available. if (supports_aes()) { @@ -3266,13 +3262,15 @@ bool VM_Version::is_intrinsic_supported(vmIntrinsicID id) { return true; } -void VM_Version::insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen) { - for (int i = 0; i < MAX_CPU_FEATURES; i++) { - if (features.supports_feature((VM_Version::Feature_Flag)i)) { - int res = jio_snprintf(buf, buflen, ", %s", _features_names[i]); - assert(res > 0, "not enough temporary space allocated"); - buf += res; - buflen -= res; +void VM_Version::insert_features_names(VM_Version::VM_Features features, stringStream& ss) { + int i = 0; + ss.join([&]() { + while (i < MAX_CPU_FEATURES) { + if (_features.supports_feature((VM_Version::Feature_Flag)i)) { + return _features_names[i++]; + } + i += 1; } - } + return (const char*)nullptr; + }, ", "); } diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 3c8971e474b..6ee9f95fdf5 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -30,6 +30,8 @@ #include "utilities/macros.hpp" #include "utilities/sizes.hpp" +class stringStream; + class VM_Version : public Abstract_VM_Version { friend class VMStructs; friend class JVMCIVMStructs; @@ -922,7 +924,7 @@ public: static bool is_intel_tsc_synched_at_init(); - static void insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen); + static void insert_features_names(VM_Version::VM_Features features, stringStream& ss); // This checks if the JVM is potentially affected by an erratum on Intel CPUs (SKX102) // that causes unpredictable behaviour when jcc crosses 64 byte boundaries. Its microcode diff --git a/src/hotspot/os_cpu/bsd_aarch64/vm_version_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/vm_version_bsd_aarch64.cpp index b55c1cd27c8..ffa7e1d5d2b 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/vm_version_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/vm_version_bsd_aarch64.cpp @@ -67,7 +67,8 @@ void VM_Version::get_os_cpu_info() { // 2) ID_AA64PFR0_EL1 describes AdvSIMD always equals to FP field. // See the Arm ARM, section "ID_AA64PFR0_EL1, AArch64 Processor Feature // Register 0". - _features = CPU_FP | CPU_ASIMD; + set_feature(CPU_FP); + set_feature(CPU_ASIMD); // All Apple-darwin Arm processors have AES, PMULL, SHA1 and SHA2. // See https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/arm/commpage/commpage.c#L412 @@ -75,25 +76,28 @@ void VM_Version::get_os_cpu_info() { // these four CPU features, e.g., "hw.optional.arm.FEAT_AES", but the // corresponding string names are not available before xnu-8019 version. // Hence, assertions are omitted considering backward compatibility. - _features |= CPU_AES | CPU_PMULL | CPU_SHA1 | CPU_SHA2; + set_feature(CPU_AES); + set_feature(CPU_PMULL); + set_feature(CPU_SHA1); + set_feature(CPU_SHA2); if (cpu_has("hw.optional.armv8_crc32")) { - _features |= CPU_CRC32; + set_feature(CPU_CRC32); } if (cpu_has("hw.optional.arm.FEAT_LSE") || cpu_has("hw.optional.armv8_1_atomics")) { - _features |= CPU_LSE; + set_feature(CPU_LSE); } if (cpu_has("hw.optional.arm.FEAT_SHA512") || cpu_has("hw.optional.armv8_2_sha512")) { - _features |= CPU_SHA512; + set_feature(CPU_SHA512); } if (cpu_has("hw.optional.arm.FEAT_SHA3") || cpu_has("hw.optional.armv8_2_sha3")) { - _features |= CPU_SHA3; + set_feature(CPU_SHA3); } if (cpu_has("hw.optional.arm.FEAT_SB")) { - _features |= CPU_SB; + set_feature(CPU_SB); } int cache_line_size; diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index a8edeefc885..1fe06dc640d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -117,22 +117,22 @@ void VM_Version::get_os_cpu_info() { uint64_t auxv = getauxval(AT_HWCAP); uint64_t auxv2 = getauxval(AT_HWCAP2); - static_assert(CPU_FP == HWCAP_FP, "Flag CPU_FP must follow Linux HWCAP"); - static_assert(CPU_ASIMD == HWCAP_ASIMD, "Flag CPU_ASIMD must follow Linux HWCAP"); - static_assert(CPU_EVTSTRM == HWCAP_EVTSTRM, "Flag CPU_EVTSTRM must follow Linux HWCAP"); - static_assert(CPU_AES == HWCAP_AES, "Flag CPU_AES must follow Linux HWCAP"); - static_assert(CPU_PMULL == HWCAP_PMULL, "Flag CPU_PMULL must follow Linux HWCAP"); - static_assert(CPU_SHA1 == HWCAP_SHA1, "Flag CPU_SHA1 must follow Linux HWCAP"); - static_assert(CPU_SHA2 == HWCAP_SHA2, "Flag CPU_SHA2 must follow Linux HWCAP"); - static_assert(CPU_CRC32 == HWCAP_CRC32, "Flag CPU_CRC32 must follow Linux HWCAP"); - static_assert(CPU_LSE == HWCAP_ATOMICS, "Flag CPU_LSE must follow Linux HWCAP"); - static_assert(CPU_DCPOP == HWCAP_DCPOP, "Flag CPU_DCPOP must follow Linux HWCAP"); - static_assert(CPU_SHA3 == HWCAP_SHA3, "Flag CPU_SHA3 must follow Linux HWCAP"); - static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP"); - static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP"); - static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP"); - static_assert(CPU_FPHP == HWCAP_FPHP, "Flag CPU_FPHP must follow Linux HWCAP"); - static_assert(CPU_ASIMDHP == HWCAP_ASIMDHP, "Flag CPU_ASIMDHP must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_FP) == HWCAP_FP, "Flag CPU_FP must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_ASIMD) == HWCAP_ASIMD, "Flag CPU_ASIMD must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_EVTSTRM) == HWCAP_EVTSTRM, "Flag CPU_EVTSTRM must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_AES) == HWCAP_AES, "Flag CPU_AES must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_PMULL) == HWCAP_PMULL, "Flag CPU_PMULL must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_SHA1) == HWCAP_SHA1, "Flag CPU_SHA1 must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_SHA2) == HWCAP_SHA2, "Flag CPU_SHA2 must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_CRC32) == HWCAP_CRC32, "Flag CPU_CRC32 must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_LSE) == HWCAP_ATOMICS, "Flag CPU_LSE must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_DCPOP) == HWCAP_DCPOP, "Flag CPU_DCPOP must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_SHA3) == HWCAP_SHA3, "Flag CPU_SHA3 must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_SHA512) == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_SVE) == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_PACA) == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_FPHP) == HWCAP_FPHP, "Flag CPU_FPHP must follow Linux HWCAP"); + static_assert(BIT_MASK(CPU_ASIMDHP) == HWCAP_ASIMDHP, "Flag CPU_ASIMDHP must follow Linux HWCAP"); _features = auxv & ( HWCAP_FP | HWCAP_ASIMD | @@ -152,8 +152,12 @@ void VM_Version::get_os_cpu_info() { HWCAP_FPHP | HWCAP_ASIMDHP); - if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2; - if (auxv2 & HWCAP2_SVEBITPERM) _features |= CPU_SVEBITPERM; + if (auxv2 & HWCAP2_SVE2) { + set_feature(CPU_SVE2); + } + if (auxv2 & HWCAP2_SVEBITPERM) { + set_feature(CPU_SVEBITPERM); + } uint64_t ctr_el0; uint64_t dczid_el0; @@ -187,7 +191,7 @@ void VM_Version::get_os_cpu_info() { _revision = v; } else if (strncmp(buf, "flags", sizeof("flags") - 1) == 0) { if (strstr(p+1, "dcpop")) { - guarantee(_features & CPU_DCPOP, "dcpop availability should be consistent"); + guarantee(supports_feature(CPU_DCPOP), "dcpop availability should be consistent"); } } } diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 5b9d36115f8..97d4f7f228d 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -325,19 +325,6 @@ unsigned int Abstract_VM_Version::jvm_version() { (Abstract_VM_Version::vm_build_number() & 0xFF); } -const char* Abstract_VM_Version::extract_features_string(const char* cpu_info_string, - size_t cpu_info_string_len, - size_t features_offset) { - assert(features_offset <= cpu_info_string_len, ""); - if (features_offset < cpu_info_string_len) { - assert(cpu_info_string[features_offset + 0] == ',', ""); - assert(cpu_info_string[features_offset + 1] == ' ', ""); - return cpu_info_string + features_offset + 2; // skip initial ", " - } else { - return ""; // empty - } -} - bool Abstract_VM_Version::print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) { char line[500]; FILE* fp = os::fopen(filename, "r"); diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 4972f02e3d8..b9c52b27182 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -132,9 +132,6 @@ class Abstract_VM_Version: AllStatic { static const char* features_string() { return _features_string; } static const char* cpu_info_string() { return _cpu_info_string; } - static const char* extract_features_string(const char* cpu_info_string, - size_t cpu_info_string_len, - size_t features_offset); static VirtualizationType get_detected_virtualization() { return _detected_virtualization; diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index a148557fd32..e971ac4d125 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -165,6 +165,20 @@ class outputStream : public CHeapObjBase { void dec_cr() { dec(); cr(); } void inc_cr() { inc(); cr(); } + + // Append strings returned by gen, separating each with separator. + // Stops when gen returns null. + template + void join(Generator gen, const char* separator) { + bool first = true; + const char* str = gen(); + while (str != nullptr) { + const char* sep = first ? "" : separator; + print("%s%s", sep, str); + first = false; + str = gen(); + } + } }; // standard output From 83953c458eb65b2af184340dd460325f2b56e5b9 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Thu, 7 Aug 2025 14:11:46 +0000 Subject: [PATCH 005/471] 8364822: Comment cleanup, stale references to closeDescriptors and UNIXProcess.c Reviewed-by: kevinw, rriggs --- src/hotspot/os/aix/os_aix.cpp | 3 +-- src/hotspot/os/bsd/os_bsd.cpp | 3 +-- src/hotspot/os/linux/os_linux.cpp | 5 ++--- src/java.base/unix/native/libjava/childproc.c | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 17186fb9f3d..25a930dc1d9 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2343,8 +2343,7 @@ int os::open(const char *path, int oflag, int mode) { // specifically destined for a subprocess should have the // close-on-exec flag set. If we don't set it, then careless 3rd // party native code might fork and exec without closing all - // appropriate file descriptors (e.g. as we do in closeDescriptors in - // UNIXProcess.c), and this in turn might: + // appropriate file descriptors, and this in turn might: // // - cause end-of-file to fail to be detected on some file // descriptors, resulting in mysterious hangs, or diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index eb9b4c3f862..b7b88e8e606 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2251,8 +2251,7 @@ int os::open(const char *path, int oflag, int mode) { // specifically destined for a subprocess should have the // close-on-exec flag set. If we don't set it, then careless 3rd // party native code might fork and exec without closing all - // appropriate file descriptors (e.g. as we do in closeDescriptors in - // UNIXProcess.c), and this in turn might: + // appropriate file descriptors, and this in turn might: // // - cause end-of-file to fail to be detected on some file // descriptors, resulting in mysterious hangs, or diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index b77a1f36954..4d6225cf21e 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4872,9 +4872,8 @@ int os::open(const char *path, int oflag, int mode) { // All file descriptors that are opened in the Java process and not // specifically destined for a subprocess should have the close-on-exec // flag set. If we don't set it, then careless 3rd party native code - // might fork and exec without closing all appropriate file descriptors - // (e.g. as we do in closeDescriptors in UNIXProcess.c), and this in - // turn might: + // might fork and exec without closing all appropriate file descriptors, + // and this in turn might: // // - cause end-of-file to fail to be detected on some file // descriptors, resulting in mysterious hangs, or diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 0dc0788879e..93d2200a465 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -372,7 +372,7 @@ childProcess(void *arg) jtregSimulateCrash(0, 6); #endif /* Close the parent sides of the pipes. - Closing pipe fds here is redundant, since closeDescriptors() + Closing pipe fds here is redundant, since markDescriptorsCloseOnExec() would do it anyways, but a little paranoia is a good thing. */ if ((closeSafely(p->in[1]) == -1) || (closeSafely(p->out[0]) == -1) || From e606278fc8929fe563dd50a1c3f332747e210276 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 7 Aug 2025 15:43:36 +0000 Subject: [PATCH 006/471] 8358598: PhaseIterGVN::PhaseIterGVN(PhaseGVN* gvn) doesn't use its parameter Reviewed-by: galder, mhaessig, shade --- src/hotspot/share/opto/compile.cpp | 7 +++---- src/hotspot/share/opto/phaseX.cpp | 6 +++--- src/hotspot/share/opto/phaseX.hpp | 14 +++++--------- src/hotspot/share/opto/vector.cpp | 2 +- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 2848ab5cc57..5a4a6c2667d 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2149,7 +2149,7 @@ void Compile::inline_incrementally_cleanup(PhaseIterGVN& igvn) { } { TracePhase tp(_t_incrInline_igvn); - igvn.reset_from_gvn(initial_gvn()); + igvn.reset(); igvn.optimize(); if (failing()) return; } @@ -2310,8 +2310,7 @@ void Compile::Optimize() { { // Iterative Global Value Numbering, including ideal transforms - // Initialize IterGVN with types and values from parse-time GVN - PhaseIterGVN igvn(initial_gvn()); + PhaseIterGVN igvn; #ifdef ASSERT _modified_nodes = new (comp_arena()) Unique_Node_List(comp_arena()); #endif @@ -2380,7 +2379,7 @@ void Compile::Optimize() { ResourceMark rm; PhaseRenumberLive prl(initial_gvn(), *igvn_worklist()); } - igvn.reset_from_gvn(initial_gvn()); + igvn.reset(); igvn.optimize(); if (failing()) return; } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 3d67c80f1bb..1df2cdb179e 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -807,9 +807,9 @@ PhaseIterGVN::PhaseIterGVN(PhaseIterGVN* igvn) : _delay_transform(igvn->_delay_t } //------------------------------PhaseIterGVN----------------------------------- -// Initialize with previous PhaseGVN info from Parser -PhaseIterGVN::PhaseIterGVN(PhaseGVN* gvn) : _delay_transform(false), - _worklist(*C->igvn_worklist()) +// Initialize from scratch +PhaseIterGVN::PhaseIterGVN() : _delay_transform(false), + _worklist(*C->igvn_worklist()) { _iterGVN = true; uint max; diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index aeba5e8662d..300c8fc2757 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -459,16 +459,12 @@ protected: public: PhaseIterGVN(PhaseIterGVN* igvn); // Used by CCP constructor - PhaseIterGVN(PhaseGVN* gvn); // Used after Parser + PhaseIterGVN(); - // Reset IGVN from GVN: call deconstructor, and placement new. - // Achieves the same as the following (but without move constructors): - // igvn = PhaseIterGVN(gvn); - void reset_from_gvn(PhaseGVN* gvn) { - if (this != gvn) { - this->~PhaseIterGVN(); - ::new (static_cast(this)) PhaseIterGVN(gvn); - } + // Reset IGVN: call deconstructor, and placement new. + void reset() { + this->~PhaseIterGVN(); + ::new (static_cast(this)) PhaseIterGVN(); } // Reset IGVN with another: call deconstructor, and placement new. diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index 4ffbd2e96b4..cf01b2442e6 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -71,7 +71,7 @@ void PhaseVector::do_cleanup() { } { Compile::TracePhase tp(_t_vector_igvn); - _igvn.reset_from_gvn(C->initial_gvn()); + _igvn.reset(); _igvn.optimize(); if (C->failing()) return; } From e29346dbd6328dcadc347a70d8c06ce141efef02 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 7 Aug 2025 16:03:12 +0000 Subject: [PATCH 007/471] 8348760: RadioButton is not shown if JRadioButtonMenuItem is rendered with ImageIcon in WindowsLookAndFeel Reviewed-by: prr, kizune, abhiscxk --- .../com/sun/java/swing/SwingUtilities3.java | 136 ++++++++++++++- .../swing/plaf/basic/BasicMenuItemUI.java | 144 ++++++---------- .../windows/WindowsCheckBoxMenuItemUI.java | 21 ++- .../plaf/windows/WindowsIconFactory.java | 16 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 142 +++++++++++++++- .../swing/plaf/windows/WindowsMenuUI.java | 21 ++- .../windows/WindowsRadioButtonMenuItemUI.java | 20 ++- .../TestRadioAndCheckMenuItemWithIcon.java | 155 ++++++++++++++++++ 8 files changed, 549 insertions(+), 106 deletions(-) create mode 100644 test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java diff --git a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java index 277b00ba4cf..a17f1f480ed 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. 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 @@ -25,10 +25,13 @@ package com.sun.java.swing; +import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; import java.awt.Stroke; import java.awt.Window; import java.awt.geom.AffineTransform; @@ -36,11 +39,16 @@ import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; +import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; +import javax.swing.JMenu; import javax.swing.RepaintManager; import sun.awt.AppContext; import sun.awt.SunToolkit; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; import static sun.java2d.pipe.Region.clipRound; @@ -61,6 +69,10 @@ public class SwingUtilities3 { private static final Object DELEGATE_REPAINT_MANAGER_KEY = new StringBuilder("DelegateRepaintManagerKey"); + private static Color disabledForeground; + private static Color acceleratorSelectionForeground; + private static Color acceleratorForeground; + /** * Registers delegate RepaintManager for {@code JComponent}. */ @@ -137,6 +149,128 @@ public class SwingUtilities3 { return delegate; } + public static void applyInsets(Rectangle rect, Insets insets) { + if (insets != null) { + rect.x += insets.left; + rect.y += insets.top; + rect.width -= (insets.right + rect.x); + rect.height -= (insets.bottom + rect.y); + } + } + + public static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color holdc, Color foreground) { + if (lh.getCheckIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } else { + g.setColor(holdc); + } + if (lh.useCheckAndArrow()) { + lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, + lr.getCheckRect().x, lr.getCheckRect().y); + } + g.setColor(holdc); + } + } + + public static void paintIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc) { + if (lh.getIcon() != null) { + Icon icon; + ButtonModel model = lh.getMenuItem().getModel(); + if (!model.isEnabled()) { + icon = lh.getMenuItem().getDisabledIcon(); + } else if (model.isPressed() && model.isArmed()) { + icon = lh.getMenuItem().getPressedIcon(); + if (icon == null) { + // Use default icon + icon = lh.getMenuItem().getIcon(); + } + } else { + icon = lh.getMenuItem().getIcon(); + } + + if (icon != null) { + icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, + lr.getIconRect().y); + g.setColor(holdc); + } + } + } + + + public static void paintAccText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + if (!lh.getAccText().isEmpty()) { + ButtonModel model = lh.getMenuItem().getModel(); + g.setFont(lh.getAccFontMetrics().getFont()); + if (!model.isEnabled()) { + + // paint the accText disabled + if (disabledForeground != null) { + g.setColor(disabledForeground); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + } else { + g.setColor(lh.getMenuItem().getBackground().brighter()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x, + lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); + g.setColor(lh.getMenuItem().getBackground().darker()); + SwingUtilities2.drawString(lh.getMenuItem(), g, + lh.getAccText(), lr.getAccRect().x - 1, + lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); + } + } else { + + // paint the accText normally + if (model.isArmed() + || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(acceleratorSelectionForeground); + } else { + g.setColor(acceleratorForeground); + } + SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), + lr.getAccRect().x, lr.getAccRect().y + + lh.getAccFontMetrics().getAscent()); + } + } + } + + public static void setDisabledForeground(Color disabledFg) { + disabledForeground = disabledFg; + } + + public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) { + acceleratorForeground = acceleratorSelectionFg; + } + + public static void setAcceleratorForeground(Color acceleratorFg) { + acceleratorForeground = acceleratorFg; + } + + public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color foreground) { + if (lh.getArrowIcon() != null) { + ButtonModel model = lh.getMenuItem().getModel(); + if (model.isArmed() || (lh.getMenuItem() instanceof JMenu + && model.isSelected())) { + g.setColor(foreground); + } + if (lh.useCheckAndArrow()) { + lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, + lr.getArrowRect().x, lr.getArrowRect().y); + } + } + } + /** * A task which paints an unscaled border after {@code Graphics} * transforms are removed. It's used with the diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java index dcd569910e9..524f0337a8f 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -25,17 +25,52 @@ package javax.swing.plaf.basic; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.InputMap; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.MenuDragMouseEvent; +import javax.swing.event.MenuDragMouseListener; +import javax.swing.event.MenuKeyListener; + +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentInputMapUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.MenuItemUI; +import javax.swing.plaf.UIResource; import javax.swing.text.View; -import sun.swing.*; +import com.sun.java.swing.SwingUtilities3; +import sun.swing.MenuItemCheckIconFactory; +import sun.swing.MenuItemLayoutHelper; +import sun.swing.SwingUtilities2; +import sun.swing.UIAction; + /** * BasicMenuItem implementation @@ -670,84 +705,22 @@ public class BasicMenuItemUI extends MenuItemUI private void paintIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc) { - if (lh.getIcon() != null) { - Icon icon; - ButtonModel model = lh.getMenuItem().getModel(); - if (!model.isEnabled()) { - icon = lh.getMenuItem().getDisabledIcon(); - } else if (model.isPressed() && model.isArmed()) { - icon = lh.getMenuItem().getPressedIcon(); - if (icon == null) { - // Use default icon - icon = lh.getMenuItem().getIcon(); - } - } else { - icon = lh.getMenuItem().getIcon(); - } - - if (icon != null) { - icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x, - lr.getIconRect().y); - g.setColor(holdc); - } - } + SwingUtilities3.paintIcon(g, lh, lr, holdc); } private void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color holdc, Color foreground) { - if (lh.getCheckIcon() != null) { - ButtonModel model = lh.getMenuItem().getModel(); - if (model.isArmed() || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(foreground); - } else { - g.setColor(holdc); - } - if (lh.useCheckAndArrow()) { - lh.getCheckIcon().paintIcon(lh.getMenuItem(), g, - lr.getCheckRect().x, lr.getCheckRect().y); - } - g.setColor(holdc); - } + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); } private void paintAccText(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr) { - if (!lh.getAccText().isEmpty()) { - ButtonModel model = lh.getMenuItem().getModel(); - g.setFont(lh.getAccFontMetrics().getFont()); - if (!model.isEnabled()) { - // *** paint the accText disabled - if (disabledForeground != null) { - g.setColor(disabledForeground); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x, - lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); - } else { - g.setColor(lh.getMenuItem().getBackground().brighter()); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x, - lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); - g.setColor(lh.getMenuItem().getBackground().darker()); - SwingUtilities2.drawString(lh.getMenuItem(), g, - lh.getAccText(), lr.getAccRect().x - 1, - lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); - } - } else { - // *** paint the accText normally - if (model.isArmed() - || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(acceleratorSelectionForeground); - } else { - g.setColor(acceleratorForeground); - } - SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(), - lr.getAccRect().x, lr.getAccRect().y + - lh.getAccFontMetrics().getAscent()); - } - } + SwingUtilities3.setDisabledForeground(disabledForeground); + SwingUtilities3.setAcceleratorSelectionForeground( + acceleratorSelectionForeground); + SwingUtilities3.setAcceleratorForeground(acceleratorForeground); + SwingUtilities3.paintAccText(g, lh, lr); } private void paintText(Graphics g, MenuItemLayoutHelper lh, @@ -766,26 +739,11 @@ public class BasicMenuItemUI extends MenuItemUI private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color foreground) { - if (lh.getArrowIcon() != null) { - ButtonModel model = lh.getMenuItem().getModel(); - if (model.isArmed() || (lh.getMenuItem() instanceof JMenu - && model.isSelected())) { - g.setColor(foreground); - } - if (lh.useCheckAndArrow()) { - lh.getArrowIcon().paintIcon(lh.getMenuItem(), g, - lr.getArrowRect().x, lr.getArrowRect().y); - } - } + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); } private void applyInsets(Rectangle rect, Insets insets) { - if(insets != null) { - rect.x += insets.left; - rect.y += insets.top; - rect.width -= (insets.right + rect.x); - rect.height -= (insets.bottom + rect.y); - } + SwingUtilities3.applyInsets(rect, insets); } /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index 6b85a88e50c..f59a59a5125 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,7 @@ import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.plaf.ComponentUI; @@ -73,6 +74,24 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { } super.paintBackground(g, menuItem, bgColor); } + + /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, defaultTextIconGap, + menuItem, getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + /** * Method which renders the text of the current menu item. * diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java index cf2fd119423..efa710391d5 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -880,6 +880,7 @@ public final class WindowsIconFactory implements Serializable } assert menuItem == null || c == menuItem; Icon icon = getIcon(); + if (type == JCheckBoxMenuItem.class || type == JRadioButtonMenuItem.class) { AbstractButton b = (AbstractButton) c; @@ -903,19 +904,18 @@ public final class WindowsIconFactory implements Serializable } XPStyle xp = XPStyle.getXP(); if (xp != null) { - Skin skin; - skin = xp.getSkin(c, backgroundPart); - skin.paintSkin(g, x, y, - getIconWidth(), getIconHeight(), backgroundState); - if (icon == null) { - skin = xp.getSkin(c, part); + Skin skin = xp.getSkin(c, part); + if (icon == null || icon.getIconHeight() <= 16) { skin.paintSkin(g, x + OFFSET, y + OFFSET, state); + } else { + skin.paintSkin(g, x + OFFSET, y + icon.getIconHeight() / 2, state); } } } } if (icon != null) { - icon.paintIcon(c, g, x + OFFSET, y + OFFSET); + icon.paintIcon(c, g, x + VistaMenuItemCheckIconFactory.getIconWidth(), + y + OFFSET); } } private static WindowsMenuItemUIAccessor getAccessor( diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index 2ee1b2d119f..a8bafc54c33 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -26,13 +26,20 @@ package com.sun.java.swing.plaf.windows; import java.awt.Color; +import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Enumeration; +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; import javax.swing.ButtonModel; +import javax.swing.DefaultButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -41,6 +48,7 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicMenuItemUI; +import com.sun.java.swing.SwingUtilities3; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; import com.sun.java.swing.plaf.windows.XPStyle.Skin; @@ -59,6 +67,9 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { * The instance of {@code PropertyChangeListener}. */ private PropertyChangeListener changeListener; + private static Color disabledForeground; + private static Color acceleratorSelectionForeground; + private static Color acceleratorForeground; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { @@ -123,6 +134,27 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { menuItem.addPropertyChangeListener(changeListener); } + protected void installDefaults() { + super.installDefaults(); + String prefix = getPropertyPrefix(); + + if (acceleratorSelectionForeground == null || + acceleratorSelectionForeground instanceof UIResource) { + acceleratorSelectionForeground = + UIManager.getColor(prefix + ".acceleratorSelectionForeground"); + } + if (acceleratorForeground == null || + acceleratorForeground instanceof UIResource) { + acceleratorForeground = + UIManager.getColor(prefix + ".acceleratorForeground"); + } + if (disabledForeground == null || + disabledForeground instanceof UIResource) { + disabledForeground = + UIManager.getColor(prefix + ".disabledForeground"); + } + } + /** * {@inheritDoc} */ @@ -135,6 +167,114 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { changeListener = null; } + private static void applyInsets(Rectangle rect, Insets insets) { + SwingUtilities3.applyInsets(rect, insets); + } + + private static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color holdc, Color foreground) { + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); + } + + private static void paintIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, Color holdc) { + SwingUtilities3.paintIcon(g, lh, lr, holdc); + } + + private static void paintAccText(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr) { + SwingUtilities3.setDisabledForeground(disabledForeground); + SwingUtilities3.setAcceleratorSelectionForeground( + acceleratorSelectionForeground); + SwingUtilities3.setAcceleratorForeground(acceleratorForeground); + SwingUtilities3.paintAccText(g, lh, lr); + } + + private static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, + MenuItemLayoutHelper.LayoutResult lr, + Color foreground) { + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); + } + + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, + defaultTextIconGap, menuItem, + getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + + static void paintMenuItem(WindowsMenuItemUIAccessor accessor, Graphics g, + JComponent c, Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap, JMenuItem menuItem, String prefix) { + // Save original graphics font and color + Font holdf = g.getFont(); + Color holdc = g.getColor(); + + JMenuItem mi = (JMenuItem) c; + g.setFont(mi.getFont()); + + Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); + applyInsets(viewRect, mi.getInsets()); + + String acceleratorDelimiter = + UIManager.getString("MenuItem.acceleratorDelimiter"); + if (acceleratorDelimiter == null) { acceleratorDelimiter = "+"; } + Font acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont"); + if (acceleratorFont == null) { + acceleratorFont = UIManager.getFont("MenuItem.font"); + } + + MenuItemLayoutHelper lh = new MenuItemLayoutHelper(mi, checkIcon, + arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter, + mi.getComponentOrientation().isLeftToRight(), mi.getFont(), + acceleratorFont, MenuItemLayoutHelper.useCheckAndArrow(menuItem), + prefix); + MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); + + paintBackground(accessor, g, mi, background); + paintCheckIcon(g, lh, lr, holdc, foreground); + paintIcon(g, lh, lr, holdc); + + if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { + Rectangle rect = lr.getTextRect(); + + rect.x += lh.getAfterCheckIconGap(); + + lr.setTextRect(rect); + } + if (!lh.getText().isEmpty()) { + if (lh.getHtmlView() != null) { + // Text is HTML + lh.getHtmlView().paint(g, lr.getTextRect()); + } else { + // Text isn't HTML + paintText(accessor, g, lh.getMenuItem(), + lr.getTextRect(), lh.getText()); + } + } + if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { + Rectangle rect = lr.getAccRect(); + rect.x += lh.getAfterCheckIconGap(); + lr.setAccRect(rect); + } + paintAccText(g, lh, lr); + paintArrowIcon(g, lh, lr, foreground); + + // Restore original graphics font and color + g.setColor(holdc); + g.setFont(holdf); + } + /** * Method which renders the text of the current menu item. * diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 5562ce60388..81c01c11036 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -130,6 +130,25 @@ public final class WindowsMenuUI extends BasicMenuUI { hotTrackingOn = (obj instanceof Boolean) ? (Boolean)obj : true; } + /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, + background, foreground, + defaultTextIconGap, menuItem, + getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + + /** * Draws the background of the menu. * @since 1.4 diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index f6f3d4f06d1..385ab6b3634 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,7 @@ import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.ButtonModel; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.plaf.ComponentUI; @@ -74,6 +75,23 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem super.paintBackground(g, menuItem, bgColor); } + /** + * Paint MenuItem. + */ + protected void paintMenuItem(Graphics g, JComponent c, + Icon checkIcon, Icon arrowIcon, + Color background, Color foreground, + int defaultTextIconGap) { + if (WindowsMenuItemUI.isVistaPainting()) { + WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, + arrowIcon, background, foreground, defaultTextIconGap, + menuItem, getPropertyPrefix()); + return; + } + super.paintMenuItem(g, c, checkIcon, arrowIcon, background, + foreground, defaultTextIconGap); + } + /** * Method which renders the text of the current menu item. * diff --git a/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java b/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java new file mode 100644 index 00000000000..15b1c7fe217 --- /dev/null +++ b/test/jdk/javax/swing/JMenuItem/TestRadioAndCheckMenuItemWithIcon.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8348760 + * @summary Verify if RadioButtonMenuItem bullet and + * JCheckboxMenuItem checkmark is shown if + * JRadioButtonMenuItem and JCheckboxMenuItem + * is rendered with ImageIcon in WindowsLookAndFeel + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestRadioAndCheckMenuItemWithIcon + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.KeyStroke; +import javax.swing.UIManager; + +public class TestRadioAndCheckMenuItemWithIcon { + + private static final String INSTRUCTIONS = """ + A top level Menu will be shown. + + Clicking on the Menu will show a + JRadioButtonMenuItem group with 3 radiobutton menuitems + and a JCheckBoxMenuItem group with 3 checkbox menuitems. + + First radiobutton menuitem is selected with imageicon of a red square. + Second radiobutton menuitem is unselected with imageicon. + Third radiobutton menuItem is unselected without imageicon. + + First checkbox menuitem is selected with imageicon. + Second checkbox menuitem is unselected with imageicon. + Third checkbox menuItem is unselected without imageicon. + + Verify that for first JRadioButtonMenuItem with imageicon, + a bullet is shown alongside the imageicon and + for first JCheckBoxMenuItem with imageicon + a checkmark is shown alongside the imageicon. + + If bullet and checkmark is shown, test passes else fails."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + PassFailJFrame.builder() + .title("JRadioButtonMenuItem Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestRadioAndCheckMenuItemWithIcon::doTest) + .build() + .awaitAndCheck(); + } + + public static JFrame doTest() { + BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + Graphics g = img.getGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, img.getWidth(), img.getHeight()); + g.dispose(); + + BufferedImage img2 = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); + Graphics g2 = img2.getGraphics(); + g2.setColor(Color.red); + g2.fillRect(0, 0, img2.getWidth(), img2.getHeight()); + g2.dispose(); + + JFrame frame = new JFrame("RadioButtonWithImageIcon"); + ImageIcon imageIcon1 = new ImageIcon(img); + ImageIcon imageIcon2 = new ImageIcon(img2); + AbstractButton button1; + JRadioButtonMenuItem m1 = new JRadioButtonMenuItem("JRadioButtonMenuItem 1", + imageIcon1); + m1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, ActionEvent.ALT_MASK|ActionEvent.CTRL_MASK|ActionEvent.SHIFT_MASK)); + button1 = m1; + button1.setSelected(true); + AbstractButton button2 = new JRadioButtonMenuItem("JRadioButtonMenuItem 2", imageIcon2); + AbstractButton button3 = new JRadioButtonMenuItem("JRadioButtonMenuItem 3"); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(button1); + buttonGroup.add(button2); + buttonGroup.add(button3); + + AbstractButton check1 = new JCheckBoxMenuItem("JCheckBoxMenuItem 1", + imageIcon1); + check1.setSelected(true); + AbstractButton check2 = new JCheckBoxMenuItem("JCheckBoxMenuItem 2", imageIcon1); + JCheckBoxMenuItem c3; + AbstractButton check3 = c3 = new JCheckBoxMenuItem("JCheckBoxMenuItem 3"); + c3.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, ActionEvent.ALT_MASK|ActionEvent.CTRL_MASK|ActionEvent.SHIFT_MASK)); + + JMenu topLevel = new JMenu("Menu"); + + topLevel.add(button1); + topLevel.add(button2); + topLevel.add(button3); + + topLevel.addSeparator(); + + topLevel.add(check1); + topLevel.add(check2); + topLevel.add(check3); + + AbstractButton menuitem1 = new JMenuItem("MenuItem1"); + AbstractButton menuitem2 = new JMenuItem("MenuItem2", imageIcon1); + topLevel.addSeparator(); + topLevel.add(menuitem1); + topLevel.add(menuitem2); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(topLevel); + + frame.setJMenuBar(menuBar); + frame.setSize(300, 300); + return frame; + + } +} From 90ea42f716770fd567e4e3b3bf7466fa93964f07 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 7 Aug 2025 16:23:32 +0000 Subject: [PATCH 008/471] 8364558: Failure to generate compiler stubs from compiler thread should not crash VM when compilation disabled due to full CodeCache Reviewed-by: kvn, shade --- src/hotspot/share/opto/c2compiler.cpp | 6 ++++++ src/hotspot/share/runtime/stubRoutines.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index bed0f38d6a6..acc28964627 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -90,6 +90,12 @@ bool C2Compiler::init_c2_runtime() { compiler_stubs_init(true /* in_compiler_thread */); // generate compiler's intrinsics stubs + // If there was an error generating the blob then UseCompiler will + // have been unset and we need to skip the remaining initialization + if (!UseCompiler) { + return false; + } + Compile::pd_compiler2_init(); CompilerThread* thread = CompilerThread::current(); diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index b287b89df84..86975f7d0a6 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -181,6 +181,17 @@ static BufferBlob* initialize_stubs(BlobId blob_id, int size = code_size + CodeEntryAlignment * max_aligned_stubs; BufferBlob* stubs_code = BufferBlob::create(buffer_name, size); if (stubs_code == nullptr) { + // The compiler blob may be created late by a C2 compiler thread + // rather than during normal initialization by the initial thread. + // In that case we can tolerate an allocation failure because the + // compiler will have been shut down and we have no need of the + // blob. + if (Thread::current()->is_Compiler_thread()) { + assert(blob_id == BlobId::stubgen_compiler_id, "sanity"); + assert(DelayCompilerStubsGeneration, "sanity"); + log_warning(stubs)("%s\t not generated:\t no space left in CodeCache", buffer_name); + return nullptr; + } vm_exit_out_of_memory(code_size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", buffer_name); } CodeBuffer buffer(stubs_code); From 02e187119d0ca94d46e631a174c55db4945f3295 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 7 Aug 2025 18:24:22 +0000 Subject: [PATCH 009/471] 8364277: (fs) BasicFileAttributes.isDirectory and isOther return true for NTFS directory junctions when links not followed Reviewed-by: alanb --- .../classes/sun/nio/fs/WindowsConstants.java | 5 +- .../sun/nio/fs/WindowsFileAttributes.java | 12 +- .../sun/nio/fs/WindowsFileSystemProvider.java | 3 +- .../BasicFileAttributeView/Basic.java | 39 ++++- test/lib/jdk/test/lib/util/FileUtils.java | 36 +++- test/lib/jdk/test/lib/util/libFileUtils.c | 158 +++++++++++++++++- 6 files changed, 228 insertions(+), 25 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java index 46315533515..b1de66ac4f2 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -72,8 +72,9 @@ class WindowsConstants { public static final int BACKUP_SPARSE_BLOCK = 0x00000009; // reparse point/symbolic link related constants - public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C; public static final int IO_REPARSE_TAG_AF_UNIX = 0x80000023; + public static final int IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; + public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C; public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024; public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1; public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2; diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 6e544b1c926..3c94e8bc4a2 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -412,6 +412,10 @@ class WindowsFileAttributes return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); } + boolean isDirectoryJunction() { + return reparseTag == IO_REPARSE_TAG_MOUNT_POINT; + } + @Override public boolean isSymbolicLink() { return reparseTag == IO_REPARSE_TAG_SYMLINK; @@ -423,10 +427,8 @@ class WindowsFileAttributes @Override public boolean isDirectory() { - // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link - if (isSymbolicLink()) - return false; - return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0); + return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && + (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0); } @Override diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index 7c280d87f62..3a1bb416fe7 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -243,7 +243,8 @@ class WindowsFileSystemProvider try { // need to know if file is a directory or junction attrs = WindowsFileAttributes.get(file, false); - if (attrs.isDirectory() || attrs.isDirectoryLink()) { + if (attrs.isDirectory() || attrs.isDirectoryLink() || + attrs.isDirectoryJunction()) { RemoveDirectory(file.getPathForWin32Calls()); } else { DeleteFile(file.getPathForWin32Calls()); diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/Basic.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/Basic.java index 1605910a2dd..c988d89a2c7 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/Basic.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -22,9 +22,12 @@ */ /* @test - * @bug 4313887 6838333 + * @bug 4313887 6838333 8364277 * @summary Unit test for java.nio.file.attribute.BasicFileAttributeView - * @library ../.. + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * jdk.test.lib.util.FileUtils + * @run main/othervm --enable-native-access=ALL-UNNAMED Basic */ import java.nio.file.*; @@ -33,6 +36,9 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.io.*; +import jdk.test.lib.Platform; +import jdk.test.lib.util.FileUtils; + public class Basic { static void check(boolean okay, String msg) { @@ -97,6 +103,17 @@ public class Basic { check(!attrs.isOther(), "is not other"); } + static void checkAttributesOfJunction(Path junction) + throws IOException + { + BasicFileAttributes attrs = + Files.readAttributes(junction, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); + check(!attrs.isSymbolicLink(), "is a link"); + check(!attrs.isDirectory(), "is a directory"); + check(!attrs.isRegularFile(), "is not a regular file"); + check(attrs.isOther(), "is other"); + } + static void attributeReadWriteTests(Path dir) throws IOException { @@ -114,12 +131,18 @@ public class Basic { Path link = dir.resolve("link"); try { Files.createSymbolicLink(link, file); - } catch (UnsupportedOperationException x) { - return; - } catch (IOException x) { - return; + checkAttributesOfLink(link); + } catch (IOException | UnsupportedOperationException x) { + if (!Platform.isWindows()) + return; + } + + // NTFS junctions are Windows-only + if (Platform.isWindows()) { + Path junction = dir.resolve("junction"); + FileUtils.createWinDirectoryJunction(junction, dir); + checkAttributesOfJunction(junction); } - checkAttributesOfLink(link); } public static void main(String[] args) throws IOException { diff --git a/test/lib/jdk/test/lib/util/FileUtils.java b/test/lib/jdk/test/lib/util/FileUtils.java index 8b99d1e9d54..3e537835c0b 100644 --- a/test/lib/jdk/test/lib/util/FileUtils.java +++ b/test/lib/jdk/test/lib/util/FileUtils.java @@ -24,6 +24,7 @@ package jdk.test.lib.util; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; @@ -33,6 +34,7 @@ import java.lang.management.ManagementFactory; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; @@ -64,6 +66,14 @@ public final class FileUtils { private static final int MAX_RETRY_DELETE_TIMES = IS_WINDOWS ? 15 : 0; private static volatile boolean nativeLibLoaded; + @SuppressWarnings("restricted") + private static void loadNativeLib() { + if (!nativeLibLoaded) { + System.loadLibrary("FileUtils"); + nativeLibLoaded = true; + } + } + /** * Deletes a file, retrying if necessary. * @@ -392,14 +402,10 @@ public final class FileUtils { } // Return the current process handle count - @SuppressWarnings("restricted") public static long getProcessHandleCount() { if (IS_WINDOWS) { - if (!nativeLibLoaded) { - System.loadLibrary("FileUtils"); - nativeLibLoaded = true; - } - return getWinProcessHandleCount(); + loadNativeLib(); + return getWinProcessHandleCount0(); } else { return ((UnixOperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean()).getOpenFileDescriptorCount(); } @@ -443,7 +449,23 @@ public final class FileUtils { Files.write(path, lines); } - private static native long getWinProcessHandleCount(); + // Create a directory junction with the specified target + public static boolean createWinDirectoryJunction(Path junction, Path target) + throws IOException + { + assert IS_WINDOWS; + + // Convert "target" to its real path + target = target.toRealPath(); + + // Create a directory junction + loadNativeLib(); + return createWinDirectoryJunction0(junction.toString(), target.toString()); + } + + private static native long getWinProcessHandleCount0(); + private static native boolean createWinDirectoryJunction0(String junction, + String target) throws IOException; // Possible command locations and arguments static String[][] lsCommands = new String[][] { diff --git a/test/lib/jdk/test/lib/util/libFileUtils.c b/test/lib/jdk/test/lib/util/libFileUtils.c index 1af90afff49..d0da04f9fb1 100644 --- a/test/lib/jdk/test/lib/util/libFileUtils.c +++ b/test/lib/jdk/test/lib/util/libFileUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -27,9 +27,49 @@ #ifdef _WIN32 #include "jni.h" +#include "jni_util.h" +#include #include +#include +#include +#include +#include +#include -JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount(JNIEnv *env) +// Based on Microsoft documentation +#define MAX_REPARSE_BUFFER_SIZE 16384 + +// Unavailable in standard header files: +// copied from Microsoft documentation +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER; + +JNIEXPORT jlong JNICALL +Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount0 + (JNIEnv* env) { DWORD handleCount; HANDLE handle = GetCurrentProcess(); @@ -40,4 +80,118 @@ JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCoun } } +void throwIOExceptionWithLastError(JNIEnv* env) { +#define BUFSIZE 256 + DWORD errval; + WCHAR buf[BUFSIZE]; + + if ((errval = GetLastError()) != 0) { + jsize n = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errval, 0, buf, BUFSIZE, NULL); + + jclass ioExceptionClass = (*env)->FindClass(env, "java/io/IOException"); + (*env)->ThrowNew(env, ioExceptionClass, (const char*) buf); + } +} + +JNIEXPORT jboolean JNICALL +Java_jdk_test_lib_util_FileUtils_createWinDirectoryJunction0 + (JNIEnv* env, jclass unused, jstring sjunction, jstring starget) +{ + BOOL error = FALSE; + + const jshort bpc = sizeof(wchar_t); // bytes per character + HANDLE hJunction = INVALID_HANDLE_VALUE; + + const jchar* junction = (*env)->GetStringChars(env, sjunction, NULL); + const jchar* target = (*env)->GetStringChars(env, starget, NULL); + if (junction == NULL || target == NULL) { + jclass npeClass = (*env)->FindClass(env, "java/lang/NullPointerException"); + (*env)->ThrowNew(env, npeClass, NULL); + error = TRUE; + } + + USHORT wlen = (USHORT)0; + USHORT blen = (USHORT)0; + void* lpInBuffer = NULL; + if (!error) { + wlen = (USHORT)wcslen(target); + blen = (USHORT)(wlen * sizeof(wchar_t)); + lpInBuffer = calloc(MAX_REPARSE_BUFFER_SIZE, sizeof(char)); + if (lpInBuffer == NULL) { + jclass oomeClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); + (*env)->ThrowNew(env, oomeClass, NULL); + error = TRUE; + } + } + + if (!error) { + if (CreateDirectoryW(junction, NULL) == 0) { + throwIOExceptionWithLastError(env); + error = TRUE; + } + } + + if (!error) { + hJunction = CreateFileW(junction, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT + | FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hJunction == INVALID_HANDLE_VALUE) { + throwIOExceptionWithLastError(env); + error = TRUE; + } + } + + if (!error) { + PREPARSE_DATA_BUFFER reparseBuffer = (PREPARSE_DATA_BUFFER)lpInBuffer; + reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + reparseBuffer->Reserved = 0; + WCHAR* prefix = L"\\??\\"; + USHORT prefixLength = (USHORT)(bpc * wcslen(prefix)); + reparseBuffer->MountPointReparseBuffer.SubstituteNameOffset = 0; + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength = + prefixLength + blen; + reparseBuffer->MountPointReparseBuffer.PrintNameOffset = + prefixLength + blen + sizeof(WCHAR); + reparseBuffer->MountPointReparseBuffer.PrintNameLength = blen; + memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer, + prefix, prefixLength); + memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer[prefixLength/bpc], + target, blen); + memcpy(&reparseBuffer->MountPointReparseBuffer.PathBuffer[prefixLength/bpc + blen/bpc + 1], + target, blen); + reparseBuffer->ReparseDataLength = + (USHORT)(sizeof(reparseBuffer->MountPointReparseBuffer) + + prefixLength + bpc*blen + bpc); + DWORD nInBufferSize = FIELD_OFFSET(REPARSE_DATA_BUFFER, + MountPointReparseBuffer) + reparseBuffer->ReparseDataLength; + BOOL result = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, + lpInBuffer, nInBufferSize, + NULL, 0, NULL, NULL); + if (result == 0) { + throwIOExceptionWithLastError(env); + error = TRUE; + } + } + + if (junction != NULL) { + (*env)->ReleaseStringChars(env, sjunction, junction); + if (target != NULL) { + (*env)->ReleaseStringChars(env, starget, target); + if (lpInBuffer != NULL) { + free(lpInBuffer); + if (hJunction != INVALID_HANDLE_VALUE) { + // Ignore any error in CloseHandle + CloseHandle(hJunction); + } + } + } + } + + return error ? JNI_FALSE : JNI_TRUE; +} + #endif /* _WIN32 */ From 78117eff563e59a738c59efa7ef595b13f62b621 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 7 Aug 2025 18:58:28 +0000 Subject: [PATCH 010/471] 8364230: javax/swing/text/StringContent can be migrated away from using finalize Reviewed-by: psadhukhan, abhiscxk, kizune --- .../javax/swing/text/StringContent.java | 30 +++----- .../StringContentPositionTest.java | 69 +++++++++++++++++++ 2 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 test/jdk/javax/swing/text/AbstractDocument/StringContentPositionTest.java diff --git a/src/java.desktop/share/classes/javax/swing/text/StringContent.java b/src/java.desktop/share/classes/javax/swing/text/StringContent.java index 562b336c770..1ce375fa3ab 100644 --- a/src/java.desktop/share/classes/javax/swing/text/StringContent.java +++ b/src/java.desktop/share/classes/javax/swing/text/StringContent.java @@ -27,6 +27,7 @@ package javax.swing.text; import java.util.Vector; import java.io.Serializable; import javax.swing.undo.*; +import java.lang.ref.WeakReference; /** * An implementation of the AbstractDocument.Content interface that is @@ -227,7 +228,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab int n = marks.size(); for (int i = 0; i < n; i++) { PosRec mark = marks.elementAt(i); - if (mark.unused) { + if (mark.get() == null) { // this record is no longer used, get rid of it marks.removeElementAt(i); i -= 1; @@ -242,7 +243,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab int n = marks.size(); for (int i = 0; i < n; i++) { PosRec mark = marks.elementAt(i); - if (mark.unused) { + if (mark.get() == null) { // this record is no longer used, get rid of it marks.removeElementAt(i); i -= 1; @@ -278,7 +279,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab Vector placeIn = (v == null) ? new Vector() : v; for (int i = 0; i < n; i++) { PosRec mark = marks.elementAt(i); - if (mark.unused) { + if (mark.get() == null) { // this record is no longer used, get rid of it marks.removeElementAt(i); i -= 1; @@ -303,7 +304,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab for(int counter = positions.size() - 1; counter >= 0; counter--) { UndoPosRef ref = (UndoPosRef) positions.elementAt(counter); // Check if the Position is still valid. - if(ref.rec.unused) { + if(ref.rec.get() == null) { positions.removeElementAt(counter); } else @@ -323,26 +324,20 @@ public final class StringContent implements AbstractDocument.Content, Serializab * it.... the update table holds only a reference * to this grungy thing. */ - static final class PosRec { + static final class PosRec extends WeakReference { - PosRec(int offset) { + PosRec(int offset, StickyPosition position) { + super(position); this.offset = offset; } int offset; - boolean unused; } - /** - * This really wants to be a weak reference but - * in 1.1 we don't have a 100% pure solution for - * this... so this class tries to hack a solution - * to causing the marks to be collected. - */ final class StickyPosition implements Position { StickyPosition(int offset) { - rec = new PosRec(offset); + rec = new PosRec(offset, this); marks.addElement(rec); } @@ -350,13 +345,6 @@ public final class StringContent implements AbstractDocument.Content, Serializab return rec.offset; } - @SuppressWarnings("removal") - protected void finalize() throws Throwable { - // schedule the record to be removed later - // on another thread. - rec.unused = true; - } - public String toString() { return Integer.toString(getOffset()); } diff --git a/test/jdk/javax/swing/text/AbstractDocument/StringContentPositionTest.java b/test/jdk/javax/swing/text/AbstractDocument/StringContentPositionTest.java new file mode 100644 index 00000000000..c535c4819e6 --- /dev/null +++ b/test/jdk/javax/swing/text/AbstractDocument/StringContentPositionTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.text.BadLocationException; +import javax.swing.text.Position; +import javax.swing.text.StringContent; + +/* + * @test + * @summary test that StringContent Position APIs behave as expected. + */ + +public class StringContentPositionTest { + + static final int SIZE = 20; + static final String TEXT = "hello"; + static final int LEN = TEXT.length(); + static final StringContent SC = new StringContent(); + + public static void main(String[] args) throws BadLocationException { + + for (int i = 0; i < 1000; i++) { + test(); + System.gc(); + } + } + + static void test() throws BadLocationException { + + Position[] positions = new Position[SIZE]; + + for (int i = 0; i < SIZE; i++) { + SC.insertString(0, TEXT); + positions[i] = SC.createPosition(LEN); + } + for (int i = 0; i < SIZE; i++) { + int expected = ((SIZE - i) * LEN); + if (positions[i].getOffset() != expected) { + throw new RuntimeException("insert: Bad offset i=" + i + " off=" + positions[i].getOffset()); + } + } + SC.remove(0, SIZE * LEN); + for (int i = 0; i < SIZE; i++) { + if (positions[i].getOffset() != 0) { + throw new RuntimeException("remove: Bad offset i=" + i + " off=" + positions[i].getOffset()); + } + } + } +} From 5116d9e5fe6b63f12e9ae0eb5283433256872dc1 Mon Sep 17 00:00:00 2001 From: Brett Okken Date: Thu, 7 Aug 2025 19:27:28 +0000 Subject: [PATCH 011/471] 8364213: (bf) Improve java/nio/Buffer/CharBufferAsCharSequenceTest test comments 8364345: Test java/nio/Buffer/CharBufferAsCharSequenceTest.java failed Reviewed-by: bpb, rriggs --- .../Buffer/CharBufferAsCharSequenceTest.java | 178 +++++++++--------- 1 file changed, 86 insertions(+), 92 deletions(-) diff --git a/test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java b/test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java index f127cb96c84..ae5a6122712 100644 --- a/test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java +++ b/test/jdk/java/nio/Buffer/CharBufferAsCharSequenceTest.java @@ -41,11 +41,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test - * @bug 8343110 8361299 + * @bug 8343110 8361299 8364345 * @key randomness * @library /test/lib * @build jdk.test.lib.RandomFactory - * @summary tests the CharBuffer implementations behaving as CharSequence in various states (position, limit, offset) + * @summary Tests CharBuffer implementations of CharSequence * @run junit CharBufferAsCharSequenceTest */ public class CharBufferAsCharSequenceTest { @@ -61,15 +61,28 @@ public class CharBufferAsCharSequenceTest { return chars; } + /** + * Randomly adjusts the position and limit such that the position will be in the + * first 1/4th and the limit in the last half. + */ private static CharBuffer randomizeRange(CharBuffer cb) { int mid = cb.capacity() >>> 1; - int start = RAND.nextInt(mid - 3); // from 0 to mid - int end = RAND.nextInt(mid + 3, cb.capacity()); // from mid to capacity + int start = RAND.nextInt(mid >> 1); // from 0 to 1/4 + int end = RAND.nextInt(mid + 1, cb.capacity()); // from mid to capacity cb.position(start); cb.limit(end); return cb; } + /** + * Generates random content to use for populating cb then calling through + * to {@code addCases(String, char[], CharBuffer, List)} + * + * @param type String description of the type of CharBuffer under test. + * @param cb CharBuffer instance to populate as base of creating cases. + * @param cases The {@code List} to populate with the cases for use from + * {@link #charBufferArguments()}. + */ private static void populateAndAddCases(String type, CharBuffer cb, List cases) { assert cb.position() == 0 && cb.limit() == cb.capacity(); char[] buf = randomChars(); @@ -78,26 +91,82 @@ public class CharBufferAsCharSequenceTest { addCases(type, buf, cb, cases); } + /** + * Adds 4 cases to cases. + *

+ */ private static void addCases(String type, char[] buf, CharBuffer cb, List cases) { assert cb.position() == 0 && cb.limit() == cb.capacity(); cases.add(Arguments.of(cb, buf, 0, buf.length, type + " full")); CharBuffer rndRange = randomizeRange(cb.duplicate()); - cases.add(Arguments.of(rndRange, buf, rndRange.position(), rndRange.limit(), type + " at " + rndRange.position() + " through " + rndRange.limit())); - cases.add(Arguments.of(rndRange.slice(), buf, rndRange.position(), rndRange.limit(), type + " sliced at " + rndRange.position() + " through " + rndRange.limit())); + cases.add(Arguments.of(rndRange, buf, rndRange.position(), rndRange.limit(), + type + " at " + rndRange.position() + " through " + rndRange.limit())); + cases.add(Arguments.of(rndRange.slice(), buf, rndRange.position(), rndRange.limit(), + type + " sliced at " + rndRange.position() + " through " + rndRange.limit())); CharBuffer rndSlicedRange = randomizeRange(rndRange.slice()); - cases.add(Arguments.of(rndSlicedRange, buf, rndRange.position() + rndSlicedRange.position(), rndRange.position() + rndSlicedRange.limit(), type + " sliced at " + rndRange.position() + " with position " + rndSlicedRange.position() + " and limit " + rndSlicedRange.limit())); + cases.add(Arguments.of(rndSlicedRange, + buf, + rndRange.position() + rndSlicedRange.position(), + rndRange.position() + rndSlicedRange.limit(), + type + " sliced at " + rndRange.position() + " with position " + + rndSlicedRange.position() + " and limit " + rndSlicedRange.limit())); } + /** + * Returns a {@code List} of {@link Arguments}, with each entry representing a + * test case scenario. + * + * + * Generates the following sets of arguments/test cases. + * + */ static List charBufferArguments() { List args = new ArrayList<>(); populateAndAddCases("HeapCharBuffer", CharBuffer.allocate(SIZE), args); - populateAndAddCases("BEHeapByteBuffer", ByteBuffer.allocate(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args); - populateAndAddCases("LEHeapByteBuffer", ByteBuffer.allocate(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args); - populateAndAddCases("BEDirectByteBuffer", ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args); - populateAndAddCases("LEDirectByteBuffer", ByteBuffer.allocateDirect(SIZE*2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args); + populateAndAddCases("HeapByteBuffer BE", + ByteBuffer.allocate(SIZE * 2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args); + populateAndAddCases("HeapByteBuffer LE", + ByteBuffer.allocate(SIZE * 2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args); + populateAndAddCases("DirectByteBuffer BE", + ByteBuffer.allocateDirect(SIZE * 2).order(ByteOrder.BIG_ENDIAN).asCharBuffer(), args); + populateAndAddCases("DirectByteBuffer LE", + ByteBuffer.allocateDirect(SIZE * 2).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(), args); char[] randomChars = randomChars(); CharBuffer cb = CharBuffer.wrap(randomChars); @@ -105,81 +174,6 @@ public class CharBufferAsCharSequenceTest { addCases("StringCharBuffer over String", randomChars, CharBuffer.wrap(new String(randomChars)), args); - // nothing magic about 1273, it is just larger than 1k and an odd number - eliminating any alignment assumptions - char[] buf = new char[1273]; - for (int i = 0; i < buf.length; ++i) { - buf[i] = (char) i; - } - String stringBuf = new String(buf); - - // nothing magic about 7, it is simply an odd number to advance - making sure no expectations of alignment - // comparing to 29 results in 5 loops (0, 7, 14, 21, 28), giving decent coverage of offset and limits - for (int i = 0; i < 29; i += 7) { - CharBuffer buffer = CharBuffer.wrap(buf, i, buf.length - i); - args.add(Arguments.of(buffer, buf, i, buf.length, "HeapCharBuffer index " + i + " to end")); - args.add(Arguments.of(buffer.slice(), buf, i, buf.length, "HeapCharBuffer slice " + i + " to end")); - - args.add(Arguments.of(CharBuffer.wrap(new String(buf, i, buf.length - i)), buf, i, buf.length, - "StringCharBuffer index " + i + " to end")); - buffer = CharBuffer.wrap(stringBuf); - buffer.position(i); - args.add(Arguments.of(buffer.slice(), buf, i, buf.length, "StringCharBuffer slice " + i + " to end")); - - CharBuffer lehbbAsCB = ByteBuffer.allocate(buf.length * 2) - .order(ByteOrder.LITTLE_ENDIAN) - .asCharBuffer() - .put(buf) - .position(i); - args.add(Arguments.of(lehbbAsCB, buf, i, buf.length, "LE HeapByteBuffer as CharBuffer index " + i + " to end")); - - CharBuffer behbdAsCB = ByteBuffer.allocateDirect(buf.length * 2) - .order(ByteOrder.BIG_ENDIAN) - .asCharBuffer() - .put(buf) - .position(i); - args.add(Arguments.of(behbdAsCB, buf, i, buf.length, - "BE DirectByteBuffer as CharBuffer index " + i + " to end")); - - if (i > 0) { - buffer = CharBuffer.wrap(buf, 1, buf.length - 1).slice(); - buffer.position(i - 1); - args.add(Arguments.of(buffer, buf, i, buf.length, - "HeapCharBuffer slice/offset 1 index " + (i - 1) + " to end")); - - int end = buf.length - i; - - buffer = CharBuffer.wrap(buf, i, buf.length - (2 * i)); - args.add(Arguments.of(buffer, buf, i, end, "HeapCharBuffer index " + i + " to " + end)); - args.add(Arguments.of(buffer.slice(), buf, i, end, "HeapCharBuffer slice " + i + " to " + end)); - - args.add(Arguments.of(CharBuffer.wrap(new String(buf, i, buf.length - (2 * i))), buf, i, end, - "StringCharBuffer index " + i + " to " + end)); - buffer = CharBuffer.wrap(stringBuf); - buffer.position(i); - buffer.limit(end); - args.add(Arguments.of(buffer.slice(), buf, i, end, "StringCharBuffer slice " + i + " to " + end)); - - CharBuffer behbbAsCB = ByteBuffer.allocate(buf.length * 2) - .order(ByteOrder.BIG_ENDIAN) - .asCharBuffer() - .put(buf) - .position(1) - .slice() - .position(i - 1) - .limit(end - 1); - args.add(Arguments.of(behbbAsCB, buf, i, buf.length - i, "BE HeapByteBuffer as CharBuffer index " + i + " to " + end)); - - CharBuffer ledbbAsCB = ByteBuffer.allocateDirect(buf.length * 2) - .order(ByteOrder.LITTLE_ENDIAN) - .asCharBuffer() - .put(buf) - .position(1) - .slice() - .position(i - 1) - .limit(end - 1); - args.add(Arguments.of(ledbbAsCB, buf, i, buf.length - i, "LE DirectByteBuffer as CharBuffer index " + i + " to " + end)); - } - } return args; } @@ -224,42 +218,42 @@ public class CharBufferAsCharSequenceTest { @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsNegativeSourceBeg(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsNegativeSrcBegin(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(-1, 4, val, 1)); } @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsNegativeSourceEnd(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsNegativeSrcEnd(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(0, -4, val, 1)); } @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsSourceEndBeforeBeg(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsSrcEndBeforeBegin(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(3, 2, val, 1)); } @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsNegativeDestBeg(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsNegativeDstBegin(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 3, val, -1)); } @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsDestBegOOB(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsDstBeginOOB(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 4, val, val.length + 1)); } @ParameterizedTest(name="{4}") @MethodSource("charBufferArguments") - void testGetCharsDestLengthOOB(CharSequence actual, char[] expected, int start, int stop, String description) { + void testGetCharsDstLengthOOB(CharSequence actual, char[] expected, int start, int stop, String description) { char[] val = new char[16]; assertThrows(IndexOutOfBoundsException.class, () -> actual.getChars(1, 4, val, val.length - 2)); } From c0e6ffabc216279068ab887939028ca27f5143f2 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 7 Aug 2025 19:43:45 +0000 Subject: [PATCH 012/471] 8364954: (bf) CleaningThread should be InnocuousThread Reviewed-by: rriggs, alanb --- .../share/classes/java/nio/BufferCleaner.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/nio/BufferCleaner.java b/src/java.base/share/classes/java/nio/BufferCleaner.java index ddacecbcf63..f8ee76c4689 100644 --- a/src/java.base/share/classes/java/nio/BufferCleaner.java +++ b/src/java.base/share/classes/java/nio/BufferCleaner.java @@ -29,6 +29,7 @@ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.Objects; +import jdk.internal.misc.InnocuousThread; import sun.nio.Cleaner; /** @@ -200,8 +201,9 @@ class BufferCleaner { } } - private static final class CleaningThread extends Thread { - public CleaningThread() {} + + private static final class CleaningRunnable implements Runnable { + public CleaningRunnable() {} @Override public void run() { @@ -234,14 +236,14 @@ class BufferCleaner { private static final CleanerList cleanerList = new CleanerList(); private static final ReferenceQueue queue = new ReferenceQueue(); - private static CleaningThread cleaningThread = null; + private static Thread cleaningThread; private static void startCleaningThreadIfNeeded() { synchronized (cleanerList) { if (cleaningThread != null) { return; } - cleaningThread = new CleaningThread(); + cleaningThread = InnocuousThread.newThread(new CleaningRunnable()); } cleaningThread.setDaemon(true); cleaningThread.start(); From 244e6293c3b332105658900639a9f3db7b21a9fe Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 7 Aug 2025 19:55:41 +0000 Subject: [PATCH 013/471] 8364984: Many jpackage tests are failing on Linux after JDK-8334238 Reviewed-by: almatvee --- .../tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index b99d2bdeceb..e8f6273b18b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -455,7 +455,7 @@ public final class LinuxHelper { var unpackedDir = cmd.appLayout().desktopIntegrationDirectory(); var packageDir = cmd.pathToPackageFile(unpackedDir); return getPackageFiles(cmd).filter(path -> { - return path.getParent().equals(packageDir) && path.getFileName().toString().endsWith(".desktop"); + return packageDir.equals(path.getParent()) && path.getFileName().toString().endsWith(".desktop"); }).map(Path::getFileName).map(unpackedDir::resolve).toList(); } From b8acbc3ed8675ad4cc4b9dea69ee1e87c2a2ca45 Mon Sep 17 00:00:00 2001 From: Ayush Rigal Date: Thu, 7 Aug 2025 21:11:26 +0000 Subject: [PATCH 014/471] 8364315: Remove unused xml files from test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles Reviewed-by: jpai, joehw --- .../javax/xml/transform/xmlfiles/lexical.xml | 24 ------------------- .../xml/transform/xmlfiles/out/doctypeGF.out | 21 ---------------- .../javax/xml/transform/xmlfiles/publish2.xml | 23 ------------------ .../org/xml/sax/xmlfiles/out/DTDHandlerGF.out | 2 -- 4 files changed, 70 deletions(-) delete mode 100644 test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/lexical.xml delete mode 100644 test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/doctypeGF.out delete mode 100644 test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/publish2.xml delete mode 100644 test/jaxp/javax/xml/jaxp/functional/org/xml/sax/xmlfiles/out/DTDHandlerGF.out diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/lexical.xml b/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/lexical.xml deleted file mode 100644 index e7ea712cdd9..00000000000 --- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/lexical.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - Publishers of the Music of New York Women Composers - The Publishers <![CDATA[<?xml>]]> - - - ACA - info@composers.com - http://www.composers.com/ -
- 170 West 74th St. - NY - NY - 10023 -
- 212-362-8900 - 212-874-8605 - - &familytree; -
-
- diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/doctypeGF.out b/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/doctypeGF.out deleted file mode 100644 index d4a9d98475f..00000000000 --- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/out/doctypeGF.out +++ /dev/null @@ -1,21 +0,0 @@ - - - - Publishers of the Music of New York Women Composers - The Publishers - - ACA - info@composers.com - http://www.composers.com/ -
- 170 West 74th St. - NY - NY - 10023 -
- 212-362-8900 - 212-874-8605 - - -
-
diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/publish2.xml b/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/publish2.xml deleted file mode 100644 index 789983f79f3..00000000000 --- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/xmlfiles/publish2.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - Publishers of the Music of New York Women Composers - The Publishers - - ACA - info@composers.com - http://www.composers.com/ -
- 170 West 74th St. - NY - NY - 10023 -
- 212-362-8900 - 212-874-8605 - - &familytree; -
-
- diff --git a/test/jaxp/javax/xml/jaxp/functional/org/xml/sax/xmlfiles/out/DTDHandlerGF.out b/test/jaxp/javax/xml/jaxp/functional/org/xml/sax/xmlfiles/out/DTDHandlerGF.out deleted file mode 100644 index f4b4241dd39..00000000000 --- a/test/jaxp/javax/xml/jaxp/functional/org/xml/sax/xmlfiles/out/DTDHandlerGF.out +++ /dev/null @@ -1,2 +0,0 @@ -In unparsedEntityDecl... name:logo publicId:null systemId:http://sc11152338.us.oracle.com:8080/xmlsqe/jaxp/web/testfiles/JAXPREP/images/tool.gif notationName:gif -In notationDecl... name:gif publicId:null systemId:http://sardinia/ From c71be802b530034169d17325478dba6e2f1c3238 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Thu, 7 Aug 2025 21:19:47 +0000 Subject: [PATCH 015/471] 8361748: Enforce limits on the size of an XBM image Reviewed-by: prr, jdv --- .../sun/awt/image/XbmImageDecoder.java | 205 ++++++++++-------- .../awt/image/XBMDecoder/XBMDecoderTest.java | 77 +++++++ .../jdk/java/awt/image/XBMDecoder/invalid.xbm | 2 + .../java/awt/image/XBMDecoder/invalid_hex.xbm | 3 + .../java/awt/image/XBMDecoder/invalid_ht.xbm | 3 + test/jdk/java/awt/image/XBMDecoder/valid.xbm | 6 + .../java/awt/image/XBMDecoder/valid_hex.xbm | 4 + 7 files changed, 212 insertions(+), 88 deletions(-) create mode 100644 test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java create mode 100644 test/jdk/java/awt/image/XBMDecoder/invalid.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/invalid_ht.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/valid.xbm create mode 100644 test/jdk/java/awt/image/XBMDecoder/valid_hex.xbm diff --git a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java index 03b36b3b819..cac9f8baab2 100644 --- a/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java +++ b/src/java.desktop/share/classes/sun/awt/image/XbmImageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. 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 @@ -23,13 +23,22 @@ * questions. */ -/*- +/* * Reads xbitmap format images into a DIBitmap structure. */ package sun.awt.image; -import java.io.*; -import java.awt.image.*; +import java.awt.image.ImageConsumer; +import java.awt.image.IndexColorModel; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Math.multiplyExact; /** * Parse files of the form: @@ -50,6 +59,8 @@ public class XbmImageDecoder extends ImageDecoder { ImageConsumer.COMPLETESCANLINES | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME); + private static final int MAX_XBM_SIZE = 16384; + private static final int HEADER_SCAN_LIMIT = 100; public XbmImageDecoder(InputStreamImageSource src, InputStream is) { super(src, is); @@ -72,107 +83,125 @@ public class XbmImageDecoder extends ImageDecoder { * produce an image from the stream. */ public void produceImage() throws IOException, ImageFormatException { - char[] nm = new char[80]; - int c; - int i = 0; - int state = 0; int H = 0; int W = 0; int x = 0; int y = 0; - boolean start = true; + int n = 0; + int state = 0; byte[] raster = null; IndexColorModel model = null; - while (!aborted && (c = input.read()) != -1) { - if ('a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z' || - '0' <= c && c <= '9' || c == '#' || c == '_') { - if (i < 78) - nm[i++] = (char) c; - } else if (i > 0) { - int nc = i; - i = 0; - if (start) { - if (nc != 7 || - nm[0] != '#' || - nm[1] != 'd' || - nm[2] != 'e' || - nm[3] != 'f' || - nm[4] != 'i' || - nm[5] != 'n' || - nm[6] != 'e') - { - error("Not an XBM file"); + + String matchRegex = "(0[xX])?[0-9a-fA-F]+[\\s+]?[,|};]"; + String replaceRegex = "(0[xX])|,|[\\s+]|[};]"; + + String line; + int lineNum = 0; + + try (BufferedReader br = new BufferedReader(new InputStreamReader(input))) { + // loop to process XBM header - width, height and create raster + while (!aborted && (line = br.readLine()) != null + && lineNum <= HEADER_SCAN_LIMIT) { + lineNum++; + // process #define stmts + if (line.trim().startsWith("#define")) { + String[] token = line.split("\\s+"); + if (token.length != 3) { + error("Error while parsing define statement"); + } + try { + if (!token[2].isBlank() && state == 0) { + W = Integer.parseInt(token[2]); + state = 1; // after width is set + } else if (!token[2].isBlank() && state == 1) { + H = Integer.parseInt(token[2]); + state = 2; // after height is set + } + } catch (NumberFormatException nfe) { + // parseInt() can throw NFE + error("Error while parsing width or height."); } - start = false; } - if (nm[nc - 1] == 'h') - state = 1; /* expecting width */ - else if (nm[nc - 1] == 't' && nc > 1 && nm[nc - 2] == 'h') - state = 2; /* expecting height */ - else if (nc > 2 && state < 0 && nm[0] == '0' && nm[1] == 'x') { - int n = 0; - for (int p = 2; p < nc; p++) { - c = nm[p]; - if ('0' <= c && c <= '9') - c = c - '0'; - else if ('A' <= c && c <= 'Z') - c = c - 'A' + 10; - else if ('a' <= c && c <= 'z') - c = c - 'a' + 10; - else - c = 0; - n = n * 16 + c; + + if (state == 2) { + if (W <= 0 || H <= 0) { + error("Invalid values for width or height."); } - for (int mask = 1; mask <= 0x80; mask <<= 1) { - if (x < W) { - if ((n & mask) != 0) - raster[x] = 1; - else - raster[x] = 0; - } - x++; + if (multiplyExact(W, H) > MAX_XBM_SIZE) { + error("Large XBM file size." + + " Maximum allowed size: " + MAX_XBM_SIZE); } - if (x >= W) { - if (setPixels(0, y, W, 1, model, raster, 0, W) <= 0) { - return; + model = new IndexColorModel(8, 2, XbmColormap, + 0, false, 0); + setDimensions(W, H); + setColorModel(model); + setHints(XbmHints); + headerComplete(); + raster = new byte[W]; + state = 3; + break; + } + } + + if (state != 3) { + error("Width or Height of XBM file not defined"); + } + + // loop to process image data + while (!aborted && (line = br.readLine()) != null) { + lineNum++; + + if (line.contains("[]")) { + Matcher matcher = Pattern.compile(matchRegex).matcher(line); + while (matcher.find()) { + if (y >= H) { + error("Scan size of XBM file exceeds" + + " the defined width x height"); } - x = 0; - if (y++ >= H) { - break; + + int startIndex = matcher.start(); + int endIndex = matcher.end(); + String hexByte = line.substring(startIndex, endIndex); + + if (!(hexByte.startsWith("0x") + || hexByte.startsWith("0X"))) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); } - } - } else { - int n = 0; - for (int p = 0; p < nc; p++) - if ('0' <= (c = nm[p]) && c <= '9') - n = n * 10 + c - '0'; - else { - n = -1; - break; + hexByte = hexByte.replaceAll(replaceRegex, ""); + if (hexByte.length() != 2) { + error("Invalid hexadecimal number at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); } - if (n > 0 && state > 0) { - if (state == 1) - W = n; - else - H = n; - if (W == 0 || H == 0) - state = 0; - else { - model = new IndexColorModel(8, 2, XbmColormap, - 0, false, 0); - setDimensions(W, H); - setColorModel(model); - setHints(XbmHints); - headerComplete(); - raster = new byte[W]; - state = -1; + + try { + n = Integer.parseInt(hexByte, 16); + } catch (NumberFormatException nfe) { + error("Error parsing hexadecimal at Ln#:" + lineNum + + " Col#:" + (startIndex + 1)); + } + for (int mask = 1; mask <= 0x80; mask <<= 1) { + if (x < W) { + if ((n & mask) != 0) + raster[x] = 1; + else + raster[x] = 0; + } + x++; + } + + if (x >= W) { + int result = setPixels(0, y, W, 1, model, raster, 0, W); + if (result <= 0) { + error("Unexpected error occurred during setPixel()"); + } + x = 0; + y++; } } } } + imageComplete(ImageConsumer.STATICIMAGEDONE, true); } - input.close(); - imageComplete(ImageConsumer.STATICIMAGEDONE, true); } } diff --git a/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java new file mode 100644 index 00000000000..19bc6d95c39 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/XBMDecoderTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8361748 + * @summary Tests XBM image size limits and if XBMImageDecoder.produceImage() + * throws appropriate error when parsing invalid XBM image data. + * @run main XBMDecoderTest + */ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.PrintStream; +import javax.swing.ImageIcon; + +public class XBMDecoderTest { + + public static void main(String[] args) throws Exception { + String dir = System.getProperty("test.src"); + PrintStream originalErr = System.err; + boolean validCase; + + File currentDir = new File(dir); + File[] files = currentDir.listFiles((File d, String s) + -> s.endsWith(".xbm")); + + for (File file : files) { + String fileName = file.getName(); + validCase = fileName.startsWith("valid"); + + System.out.println("--- Testing " + fileName + " ---"); + try (FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream errContent = new ByteArrayOutputStream()) { + System.setErr(new PrintStream(errContent)); + + ImageIcon icon = new ImageIcon(fis.readAllBytes()); + boolean isErrEmpty = errContent.toString().isEmpty(); + if (!isErrEmpty) { + System.out.println("Expected ImageFormatException occurred."); + System.out.print(errContent); + } + + if (validCase && !isErrEmpty) { + throw new RuntimeException("Test failed: Error stream not empty"); + } else if (!validCase && isErrEmpty) { + throw new RuntimeException("Test failed: ImageFormatException" + + " expected but not thrown"); + } + System.out.println("PASSED\n"); + } finally { + System.setErr(originalErr); + } + } + } +} diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid.xbm new file mode 100644 index 00000000000..8a8cfc27632 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid.xbm @@ -0,0 +1,2 @@ +#define k_ht 3 +h` k[] = { 01x0, 42222222222236319330:: diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm new file mode 100644 index 00000000000..c6f819582d0 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_hex.xbm @@ -0,0 +1,3 @@ +#define k_wt 16 +#define k_ht 1 +k[] = { 0x10, 1234567890}; diff --git a/test/jdk/java/awt/image/XBMDecoder/invalid_ht.xbm b/test/jdk/java/awt/image/XBMDecoder/invalid_ht.xbm new file mode 100644 index 00000000000..5244651a4cb --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/invalid_ht.xbm @@ -0,0 +1,3 @@ +#define k_wt 16 +#define k_ht 0 +k[] = { 0x10, 0x12}; diff --git a/test/jdk/java/awt/image/XBMDecoder/valid.xbm b/test/jdk/java/awt/image/XBMDecoder/valid.xbm new file mode 100644 index 00000000000..23b57b2c811 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/valid.xbm @@ -0,0 +1,6 @@ +#define test_width 16 +#define test_height 3 +#define ht_x 1 +#define ht_y 2 +static unsigned char test_bits[] = { +0x13, 0x11, 0x15, 0x00, 0xAB, 0xcd }; diff --git a/test/jdk/java/awt/image/XBMDecoder/valid_hex.xbm b/test/jdk/java/awt/image/XBMDecoder/valid_hex.xbm new file mode 100644 index 00000000000..e365d802447 --- /dev/null +++ b/test/jdk/java/awt/image/XBMDecoder/valid_hex.xbm @@ -0,0 +1,4 @@ +#define test_width 16 +#define test_height 2 +static unsigned char test_bits[] = { 0x13, 0x11, + 0xAB, 0xff }; From 4c9eaddaef83c6ba30e27ae3e0d16caeeec206cb Mon Sep 17 00:00:00 2001 From: John Jiang Date: Fri, 8 Aug 2025 02:27:30 +0000 Subject: [PATCH 016/471] 8364597: Replace THL A29 Limited with Tencent Reviewed-by: jiefu --- src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp | 2 +- src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp | 2 +- src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp | 2 +- src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 2 +- .../gc/shenandoah/shenandoahGenerationalControlThread.cpp | 2 +- .../arraycopy/TestIllegalArrayCopyBeforeInfiniteLoop.java | 2 +- .../jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex1.java | 2 +- .../jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex2.java | 2 +- .../compiler/arraycopy/TestNegativeArrayCopyAfterLoop.java | 2 +- test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java | 2 +- .../jtreg/compiler/c2/TestDuplicateSimpleLoopBackedge.java | 2 +- test/hotspot/jtreg/compiler/c2/cr6865031/Test.java | 2 +- .../compiler/c2/irTests/TestAutoVectorization2DArray.java | 2 +- .../compiler/compilercontrol/TestConflictInlineCommands.java | 2 +- test/hotspot/jtreg/compiler/debug/TraceIterativeGVN.java | 2 +- .../jtreg/compiler/intrinsics/math/TestPow0Dot5Opt.java | 2 +- test/hotspot/jtreg/compiler/intrinsics/math/TestPow2Opt.java | 2 +- .../sha/cli/TestUseSHA3IntrinsicsOptionOnSupportedCPU.java | 2 +- .../sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java | 2 +- .../compiler/jvmci/errors/TestInvalidTieredStopAtLevel.java | 2 +- .../jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java | 2 +- test/hotspot/jtreg/compiler/loopopts/TestLoopPredicateDep.java | 2 +- .../jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java | 2 +- .../jtreg/compiler/oracle/TestInvalidCompileCommand.java | 2 +- test/hotspot/jtreg/compiler/print/TestTraceOptoParse.java | 2 +- .../jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java | 3 +-- .../jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java | 2 +- .../hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java | 2 +- .../hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java | 2 +- .../jtreg/compiler/vectorapi/VectorReinterpretTest.java | 2 +- .../jtreg/containers/docker/TestMemoryWithCgroupV1.java | 2 +- test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java | 2 +- .../hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java | 2 +- test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java | 2 +- test/jdk/javax/net/ssl/DTLS/DTLSNamedGroups.java | 3 +-- test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java | 3 +-- .../javax/net/ssl/SSLException/CheckSSLHandshakeException.java | 2 +- test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java | 2 +- .../net/ssl/SSLException/CheckSSLPeerUnverifiedException.java | 2 +- .../javax/net/ssl/SSLException/CheckSSLProtocolException.java | 2 +- test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java | 2 +- test/jdk/javax/net/ssl/SSLParameters/NamedGroupsSpec.java | 2 +- test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java | 2 +- test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java | 3 +-- test/jdk/javax/net/ssl/templates/SSLExampleCert.java | 2 +- .../auth/callback/PasswordCallback/CheckCleanerBound.java | 3 +-- .../auth/callback/PasswordCallback/PasswordCleanup.java | 3 +-- .../jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java | 2 +- .../jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java | 2 +- test/jdk/sun/security/ec/ECDHKeyAgreementParamValidation.java | 2 +- test/jdk/sun/security/jgss/GssContextCleanup.java | 3 +-- test/jdk/sun/security/jgss/GssNameCleanup.java | 3 +-- .../security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java | 2 +- .../security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java | 2 +- test/micro/org/openjdk/bench/java/security/Signatures.java | 3 +-- .../openjdk/bench/vm/compiler/AutoVectorization2DArray.java | 2 +- test/micro/org/openjdk/bench/vm/compiler/LoopUnroll.java | 2 +- 58 files changed, 58 insertions(+), 67 deletions(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp index 299a37b88fd..5130fd2c9d2 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2025, Intel Corporation. All rights reserved. -* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +* Copyright (C) 2021, Tencent. All rights reserved. * Intel Math Library (LIBM) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp index 8665aec5903..6b5b4d704e3 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2025, Intel Corporation. All rights reserved. -* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +* Copyright (C) 2021, Tencent. All rights reserved. * Intel Math Library (LIBM) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp index 22ac8059458..3c3df7e6ac4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2025, Intel Corporation. All rights reserved. -* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +* Copyright (C) 2021, Tencent. All rights reserved. * Intel Math Library (LIBM) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 807d4197b12..8210718126b 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, 2021, Red Hat, Inc. All rights reserved. - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 0c80b800ac5..6290101bc49 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved. - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index f5de41cb9ca..1cf8b78ef1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved. - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestIllegalArrayCopyBeforeInfiniteLoop.java b/test/hotspot/jtreg/compiler/arraycopy/TestIllegalArrayCopyBeforeInfiniteLoop.java index 0b3572d6afa..af166571909 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestIllegalArrayCopyBeforeInfiniteLoop.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestIllegalArrayCopyBeforeInfiniteLoop.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex1.java b/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex1.java index 2f35a11e948..b7da2119bd3 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex1.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex1.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex2.java b/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex2.java index da8f0936cae..b101254d189 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex2.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestNegArrayLengthAsIndex2.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestNegativeArrayCopyAfterLoop.java b/test/hotspot/jtreg/compiler/arraycopy/TestNegativeArrayCopyAfterLoop.java index e28cfb871f7..901ff78347d 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestNegativeArrayCopyAfterLoop.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestNegativeArrayCopyAfterLoop.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java b/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java index 9da8a5390da..0f5b8860195 100644 --- a/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java +++ b/test/hotspot/jtreg/compiler/c1/TestRangeCheckEliminated.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. All rights reserved. * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/c2/TestDuplicateSimpleLoopBackedge.java b/test/hotspot/jtreg/compiler/c2/TestDuplicateSimpleLoopBackedge.java index 0b102b4c9fd..414a351e53f 100644 --- a/test/hotspot/jtreg/compiler/c2/TestDuplicateSimpleLoopBackedge.java +++ b/test/hotspot/jtreg/compiler/c2/TestDuplicateSimpleLoopBackedge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2022, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java index af23628577b..beb41943183 100644 --- a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java +++ b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java @@ -1,6 +1,6 @@ /* * Copyright 2009 Goldman Sachs International. All Rights Reserved. - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java index ac622e3bcc3..5b1d6f51bb3 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestAutoVectorization2DArray.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/compilercontrol/TestConflictInlineCommands.java b/test/hotspot/jtreg/compiler/compilercontrol/TestConflictInlineCommands.java index 9c12ea6b8a7..c7e20157e7e 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/TestConflictInlineCommands.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/TestConflictInlineCommands.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/debug/TraceIterativeGVN.java b/test/hotspot/jtreg/compiler/debug/TraceIterativeGVN.java index 59d3de0d58e..8e6169f07dc 100644 --- a/test/hotspot/jtreg/compiler/debug/TraceIterativeGVN.java +++ b/test/hotspot/jtreg/compiler/debug/TraceIterativeGVN.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/TestPow0Dot5Opt.java b/test/hotspot/jtreg/compiler/intrinsics/math/TestPow0Dot5Opt.java index a0560870d2a..9854eb8c386 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/math/TestPow0Dot5Opt.java +++ b/test/hotspot/jtreg/compiler/intrinsics/math/TestPow0Dot5Opt.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/TestPow2Opt.java b/test/hotspot/jtreg/compiler/intrinsics/math/TestPow2Opt.java index 2bf48407a36..db05baf9683 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/math/TestPow2Opt.java +++ b/test/hotspot/jtreg/compiler/intrinsics/math/TestPow2Opt.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnSupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnSupportedCPU.java index 3706f3abfd8..d3c0a4a8da7 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnSupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnSupportedCPU.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java index 633ceb1d9ab..c0045ae2922 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA3IntrinsicsOptionOnUnsupportedCPU.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/jvmci/errors/TestInvalidTieredStopAtLevel.java b/test/hotspot/jtreg/compiler/jvmci/errors/TestInvalidTieredStopAtLevel.java index 3527dd891d6..0a00987f3d8 100644 --- a/test/hotspot/jtreg/compiler/jvmci/errors/TestInvalidTieredStopAtLevel.java +++ b/test/hotspot/jtreg/compiler/jvmci/errors/TestInvalidTieredStopAtLevel.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java b/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java index a4683db4f70..e3b5bdff12f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestLoopEndNodeEliminate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/loopopts/TestLoopPredicateDep.java b/test/hotspot/jtreg/compiler/loopopts/TestLoopPredicateDep.java index ca651a20750..bb945342c0d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestLoopPredicateDep.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestLoopPredicateDep.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java b/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java index 38a82139553..eae00ca3522 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestSkeletonPredicateNegation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. All rights reserved. * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java b/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java index 791b1d042e3..a64e5f2b8bb 100644 --- a/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java +++ b/test/hotspot/jtreg/compiler/oracle/TestInvalidCompileCommand.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/print/TestTraceOptoParse.java b/test/hotspot/jtreg/compiler/print/TestTraceOptoParse.java index 65aa6bcb2d0..52a7aba1a7e 100644 --- a/test/hotspot/jtreg/compiler/print/TestTraceOptoParse.java +++ b/test/hotspot/jtreg/compiler/print/TestTraceOptoParse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2022, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java b/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java index fe2fd7e4444..c99bdca2cb1 100644 --- a/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java +++ b/test/hotspot/jtreg/compiler/regalloc/TestGCMRecalcPressureNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 @@ -50,4 +50,3 @@ public class TestGCMRecalcPressureNodes { } } } - diff --git a/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java b/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java index 84752a0ccf0..f4b1e3f0a53 100644 --- a/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java +++ b/test/hotspot/jtreg/compiler/unsafe/TestMisalignedUnsafeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java index 72e1c3aa30f..b6ddadad49b 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, 2022, THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, 2022, Tencent. All rights reserved. * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java index 4f9f8ca3bd2..0fd586f8d6e 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorErgonomics.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorReinterpretTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorReinterpretTest.java index b453311f857..2f9b97b56d7 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorReinterpretTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorReinterpretTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java index f80a83842c9..3340f9de03c 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java b/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java index 5a705ffe8ed..3aec113990c 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (C) 2025 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2025, Tencent. 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 diff --git a/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java b/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java index 79d377ca876..8538155375c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java b/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java index 70b73884d92..2b23d866af4 100644 --- a/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java +++ b/test/jdk/java/lang/Thread/virtual/ParkWithFixedThreadPool.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/DTLS/DTLSNamedGroups.java b/test/jdk/javax/net/ssl/DTLS/DTLSNamedGroups.java index e9165fa391c..1fc4f962675 100644 --- a/test/jdk/javax/net/ssl/DTLS/DTLSNamedGroups.java +++ b/test/jdk/javax/net/ssl/DTLS/DTLSNamedGroups.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -140,4 +140,3 @@ public class DTLSNamedGroups extends DTLSOverDatagram { } } } - diff --git a/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java b/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java index 5dd897b1bd7..9c1c64f7fa0 100644 --- a/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java +++ b/test/jdk/javax/net/ssl/DTLS/DTLSSignatureSchemes.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -134,4 +134,3 @@ public class DTLSSignatureSchemes extends DTLSOverDatagram { } } } - diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java index 4c8aba3de44..4ba3e906597 100644 --- a/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java index dcd62fcf8e7..2d271236de1 100644 --- a/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java index 04184e99306..1d37271ed53 100644 --- a/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java index 3f62fac8f77..c1bd53e21e9 100644 --- a/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java b/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java index fc5001e89b8..25f73606b96 100644 --- a/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java +++ b/test/jdk/javax/net/ssl/SSLParameters/NamedGroups.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLParameters/NamedGroupsSpec.java b/test/jdk/javax/net/ssl/SSLParameters/NamedGroupsSpec.java index 9146e7b5f7b..0d910ccfb67 100644 --- a/test/jdk/javax/net/ssl/SSLParameters/NamedGroupsSpec.java +++ b/test/jdk/javax/net/ssl/SSLParameters/NamedGroupsSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java b/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java index 7dadeff5703..7f41cb1af79 100644 --- a/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java +++ b/test/jdk/javax/net/ssl/SSLParameters/SignatureSchemes.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java b/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java index bac110aa033..5438f429455 100644 --- a/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java +++ b/test/jdk/javax/net/ssl/ServerName/EndingDotHostname.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -248,4 +248,3 @@ public class EndingDotHostname { sslIS.read(); } } - diff --git a/test/jdk/javax/net/ssl/templates/SSLExampleCert.java b/test/jdk/javax/net/ssl/templates/SSLExampleCert.java index 0b82aed3b7b..46f69a62e41 100644 --- a/test/jdk/javax/net/ssl/templates/SSLExampleCert.java +++ b/test/jdk/javax/net/ssl/templates/SSLExampleCert.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/jdk/javax/security/auth/callback/PasswordCallback/CheckCleanerBound.java b/test/jdk/javax/security/auth/callback/PasswordCallback/CheckCleanerBound.java index 8f68773398c..6d500fea656 100644 --- a/test/jdk/javax/security/auth/callback/PasswordCallback/CheckCleanerBound.java +++ b/test/jdk/javax/security/auth/callback/PasswordCallback/CheckCleanerBound.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -55,4 +55,3 @@ public final class CheckCleanerBound { } } } - diff --git a/test/jdk/javax/security/auth/callback/PasswordCallback/PasswordCleanup.java b/test/jdk/javax/security/auth/callback/PasswordCallback/PasswordCleanup.java index ea8b1d1c145..64db7de2b18 100644 --- a/test/jdk/javax/security/auth/callback/PasswordCallback/PasswordCleanup.java +++ b/test/jdk/javax/security/auth/callback/PasswordCallback/PasswordCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -49,4 +49,3 @@ public final class PasswordCleanup { } } } - diff --git a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java index 92b8cf282b7..b7721899ea3 100644 --- a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022, Tencent. 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 diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 8e3d0cacd57..b9d031f0309 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022, Tencent. All rights reserved. * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/jdk/sun/security/ec/ECDHKeyAgreementParamValidation.java b/test/jdk/sun/security/ec/ECDHKeyAgreementParamValidation.java index 0864d650162..3a77030f259 100644 --- a/test/jdk/sun/security/ec/ECDHKeyAgreementParamValidation.java +++ b/test/jdk/sun/security/ec/ECDHKeyAgreementParamValidation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024, THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2024, Tencent. 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 diff --git a/test/jdk/sun/security/jgss/GssContextCleanup.java b/test/jdk/sun/security/jgss/GssContextCleanup.java index 00d84e8a70e..1e992df97d5 100644 --- a/test/jdk/sun/security/jgss/GssContextCleanup.java +++ b/test/jdk/sun/security/jgss/GssContextCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -59,4 +59,3 @@ public final class GssContextCleanup { } } } - diff --git a/test/jdk/sun/security/jgss/GssNameCleanup.java b/test/jdk/sun/security/jgss/GssNameCleanup.java index be68c46087d..ef19479b6a0 100644 --- a/test/jdk/sun/security/jgss/GssNameCleanup.java +++ b/test/jdk/sun/security/jgss/GssNameCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -66,4 +66,3 @@ public final class GssNameCleanup { } } } - diff --git a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java index 598c0fe62af..43bc40fabf2 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (C) 2021, 2024 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, 2024, Tencent. 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 diff --git a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java index 2ad48f59e83..034af3ac7c5 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS13.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 diff --git a/test/micro/org/openjdk/bench/java/security/Signatures.java b/test/micro/org/openjdk/bench/java/security/Signatures.java index 1bd72334343..1216e253663 100644 --- a/test/micro/org/openjdk/bench/java/security/Signatures.java +++ b/test/micro/org/openjdk/bench/java/security/Signatures.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 @@ -194,4 +194,3 @@ public class Signatures { } } } - diff --git a/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java b/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java index a2a4654b40a..e41b1e7a4d0 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java +++ b/test/micro/org/openjdk/bench/vm/compiler/AutoVectorization2DArray.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022, Tencent. 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 diff --git a/test/micro/org/openjdk/bench/vm/compiler/LoopUnroll.java b/test/micro/org/openjdk/bench/vm/compiler/LoopUnroll.java index cbb216bbaa6..2e7e1da4ba9 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/LoopUnroll.java +++ b/test/micro/org/openjdk/bench/vm/compiler/LoopUnroll.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2021, Tencent. 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 From d0624f8b62fe0c70e5b6a47e05235ca65a2e1a13 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 8 Aug 2025 05:03:55 +0000 Subject: [PATCH 017/471] 8364808: Make BasicDesktopPaneUI.Actions.MOVE_RESIZE_INCREMENT static Reviewed-by: tr, azvegint, kizune, aivanov --- .../classes/javax/swing/plaf/basic/BasicDesktopPaneUI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDesktopPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDesktopPaneUI.java index 8d55a12c98f..e9d95a3f970 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDesktopPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ import javax.swing.plaf.*; import java.beans.*; -import java.awt.event.*; +import java.awt.event.ActionEvent; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -374,7 +374,7 @@ public class BasicDesktopPaneUI extends DesktopPaneUI { private static String PREVIOUS_FRAME = "selectPreviousFrame"; private static String NAVIGATE_NEXT = "navigateNext"; private static String NAVIGATE_PREVIOUS = "navigatePrevious"; - private final int MOVE_RESIZE_INCREMENT = 10; + private static final int MOVE_RESIZE_INCREMENT = 10; private static boolean moving = false; private static boolean resizing = false; private static JInternalFrame sourceFrame = null; From 198782c957c728ed959d1fd31e2c2ff6cd1a9bb5 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 8 Aug 2025 07:54:23 +0000 Subject: [PATCH 018/471] 8364877: G1: Inline G1CollectedHeap::set_region_short_lived_locked Reviewed-by: ayang, sangheki --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 14 ++++++-------- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 1 - src/hotspot/share/gc/g1/g1EdenRegions.hpp | 2 +- src/hotspot/share/gc/g1/g1Policy.hpp | 1 - 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 8d65011b560..27a2cbfb000 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2803,12 +2803,6 @@ bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { return _allocator->is_retained_old_region(hr); } -void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) { - _eden.add(hr); - _policy->set_region_eden(hr); - young_regions_cset_group()->add(hr); -} - #ifdef ASSERT class NoYoungRegionsClosure: public G1HeapRegionClosure { @@ -2957,9 +2951,13 @@ G1HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, false /* do_expand */, node_index); if (new_alloc_region != nullptr) { - set_region_short_lived_locked(new_alloc_region); - G1HeapRegionPrinter::alloc(new_alloc_region); + new_alloc_region->set_eden(); + _eden.add(new_alloc_region); + _policy->set_region_eden(new_alloc_region); _policy->remset_tracker()->update_at_allocate(new_alloc_region); + // Install the group cardset. + young_regions_cset_group()->add(new_alloc_region); + G1HeapRegionPrinter::alloc(new_alloc_region); return new_alloc_region; } } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 90e0ea8608a..48d7300bf41 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1214,7 +1214,6 @@ public: return named_heap(CollectedHeap::G1); } - void set_region_short_lived_locked(G1HeapRegion* hr); // add appropriate methods for any other surv rate groups G1SurvivorRegions* survivor() { return &_survivor; } diff --git a/src/hotspot/share/gc/g1/g1EdenRegions.hpp b/src/hotspot/share/gc/g1/g1EdenRegions.hpp index a6e005ff2dc..c7ed9008ee7 100644 --- a/src/hotspot/share/gc/g1/g1EdenRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EdenRegions.hpp @@ -42,7 +42,7 @@ public: G1EdenRegions() : _length(0), _used_bytes(0), _regions_on_node() { } uint add(G1HeapRegion* hr) { - assert(!hr->is_eden(), "should not already be set"); + assert(hr->is_eden(), "must be"); _length++; return _regions_on_node.add(hr); } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 804950f1ef3..3571945d587 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -121,7 +121,6 @@ public: G1OldGenAllocationTracker* old_gen_alloc_tracker() { return &_old_gen_alloc_tracker; } void set_region_eden(G1HeapRegion* hr) { - hr->set_eden(); hr->install_surv_rate_group(_eden_surv_rate_group); } From bcca5cee2d788c745bea55388b2844b395519ed0 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 8 Aug 2025 07:56:29 +0000 Subject: [PATCH 019/471] 8364642: G1: Remove parameter in G1CollectedHeap::abandon_collection_set() Reviewed-by: ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 8 ++++---- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 27a2cbfb000..186abfd81ad 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -772,7 +772,7 @@ void G1CollectedHeap::prepare_heap_for_full_collection() { // set between the last GC or pause and now. We need to clear the // incremental collection set and then start rebuilding it afresh // after this full GC. - abandon_collection_set(collection_set()); + abandon_collection_set(); _hrm.remove_all_free_regions(); } @@ -2791,12 +2791,12 @@ public: } }; -void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) { +void G1CollectedHeap::abandon_collection_set() { G1AbandonCollectionSetClosure cl; collection_set_iterate_all(&cl); - collection_set->clear(); - collection_set->stop_incremental_building(); + collection_set()->clear(); + collection_set()->stop_incremental_building(); } bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 48d7300bf41..49bbcf888be 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -804,7 +804,7 @@ public: // Abandon the current collection set without recording policy // statistics or updating free lists. - void abandon_collection_set(G1CollectionSet* collection_set); + void abandon_collection_set(); // The concurrent marker (and the thread it runs in.) G1ConcurrentMark* _cm; From 47017e38642a58fd6425ec68c1fed96f19f39404 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 8 Aug 2025 07:57:06 +0000 Subject: [PATCH 020/471] 8364760: G1: Remove obsolete code in G1MergeCardSetClosure Reviewed-by: ayang, sangheki --- src/hotspot/share/gc/g1/g1RemSet.cpp | 41 ++-------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 4114f0e7ba5..44b3234d26b 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -986,13 +986,12 @@ class G1MergeHeapRootsTask : public WorkerTask { // Visitor for remembered sets. Several methods of it are called by a region's // card set iterator to drop card set remembered set entries onto the card. - // table. This is in addition to being the HG1eapRegionClosure to iterate over - // all region's remembered sets. + // table. // // We add a small prefetching cache in front of the actual work as dropping // onto the card table is basically random memory access. This improves // performance of this operation significantly. - class G1MergeCardSetClosure : public G1HeapRegionClosure { + class G1MergeCardSetClosure { friend class G1MergeCardSetCache; G1RemSetScanState* _scan_state; @@ -1039,7 +1038,6 @@ class G1MergeHeapRootsTask : public WorkerTask { } public: - G1MergeCardSetClosure(G1RemSetScanState* scan_state) : _scan_state(scan_state), _ct(G1CollectedHeap::heap()->card_table()), @@ -1071,38 +1069,6 @@ class G1MergeHeapRootsTask : public WorkerTask { _scan_state->set_chunk_range_dirty(_region_base_idx + start_card_idx, length); } - // Helper to merge the cards in the card set for the given region onto the card - // table. - // - // Called directly for humongous starts regions because we should not add - // humongous eager reclaim candidates to the "all" list of regions to - // clear the card table by default as we do not know yet whether this region - // will be reclaimed (and reused). - // If the humongous region contains dirty cards, g1 will scan them - // because dumping the remembered set entries onto the card table will add - // the humongous region to the "dirty" region list to scan. Then scanning - // either clears the card during scan (if there is only an initial evacuation - // pass) or the "dirty" list will be merged with the "all" list later otherwise. - // (And there is no problem either way if the region does not contain dirty - // cards). - void merge_card_set_for_region(G1HeapRegion* r) { - assert(r->in_collection_set() || r->is_starts_humongous(), "must be"); - - G1HeapRegionRemSet* rem_set = r->rem_set(); - if (!rem_set->is_empty()) { - rem_set->iterate_for_merge(*this); - } - } - - virtual bool do_heap_region(G1HeapRegion* r) { - assert(r->in_collection_set(), "must be"); - - _scan_state->add_all_dirty_region(r->hrm_index()); - merge_card_set_for_region(r); - - return false; - } - G1MergeCardSetStats stats() { _merge_card_set_cache.flush(); // Compensation for the dummy cards that were initially pushed into the @@ -1189,8 +1155,7 @@ class G1MergeHeapRootsTask : public WorkerTask { "Found a not-small remembered set here. This is inconsistent with previous assumptions."); if (!r->rem_set()->is_empty()) { - _cl.merge_card_set_for_region(r); - + r->rem_set()->iterate_for_merge(_cl); // We should only clear the card based remembered set here as we will not // implicitly rebuild anything else during eager reclaim. Note that at the moment // (and probably never) we do not enter this path if there are other kind of From a26a6f31524aba61ed83bf3ffdc7713e3e5f5911 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 8 Aug 2025 08:06:56 +0000 Subject: [PATCH 021/471] 8364649: G1: Move collection set related full gc reset code into abandon_collection_set() method Reviewed-by: ayang, sangheki --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 4 ++++ src/hotspot/share/gc/g1/g1FullCollector.cpp | 2 -- src/hotspot/share/gc/g1/g1Policy.cpp | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 186abfd81ad..b9b12f628eb 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2797,6 +2797,10 @@ void G1CollectedHeap::abandon_collection_set() { collection_set()->clear(); collection_set()->stop_incremental_building(); + + collection_set()->abandon_all_candidates(); + + young_regions_cset_group()->clear(); } bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 4992df8e214..bae8115bb9c 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -246,8 +246,6 @@ void G1FullCollector::complete_collection(size_t allocation_word_size) { _heap->resize_all_tlabs(); - _heap->young_regions_cset_group()->clear(); - _heap->policy()->record_full_collection_end(); _heap->gc_epilogue(true); diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 49fab954799..3bbc64e0fe7 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -574,7 +574,6 @@ void G1Policy::record_full_collection_start() { // Release the future to-space so that it is available for compaction into. collector_state()->set_in_young_only_phase(false); collector_state()->set_in_full_gc(true); - _collection_set->abandon_all_candidates(); _pending_cards_at_gc_start = 0; } From 1b3e23110b2262e470a8c520b977273fd6a9e8d1 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 8 Aug 2025 09:06:43 +0000 Subject: [PATCH 022/471] 8360048: NMT crash in gtest/NMTGtests.java: fatal error: NMT corruption: Block at 0x0000017748307120: header canary broken Reviewed-by: jsjolen, gziemski --- src/hotspot/share/nmt/memBaseline.cpp | 2 +- src/hotspot/share/nmt/memReporter.cpp | 2 +- .../share/nmt/virtualMemoryTracker.cpp | 25 ++- .../share/nmt/virtualMemoryTracker.hpp | 12 +- .../runtime/test_virtualMemoryTracker.cpp | 166 +++++++++--------- 5 files changed, 104 insertions(+), 103 deletions(-) diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 8661f91174a..35dff0d8646 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -215,7 +215,7 @@ bool MemBaseline::aggregate_virtual_memory_allocation_sites() { site = node->data(); } site->reserve_memory(rgn->size()); - site->commit_memory(rgn->committed_size()); + site->commit_memory(VirtualMemoryTracker::Instance::committed_size(rgn)); } _virtual_memory_sites.move(&allocation_sites); diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index c1c847a4f2e..a7c564eff53 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -422,7 +422,7 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* outputStream* out = output(); const char* scale = current_scale(); const NativeCallStack* stack = reserved_rgn->call_stack(); - bool all_committed = reserved_rgn->size() == reserved_rgn->committed_size(); + bool all_committed = reserved_rgn->size() == VirtualMemoryTracker::Instance::committed_size(reserved_rgn); const char* region_type = (all_committed ? "reserved and committed" : "reserved"); out->cr(); print_virtual_memory_region(region_type, reserved_rgn->base(), reserved_rgn->size()); diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 51d8696a9ce..8a97253860c 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -219,20 +219,29 @@ bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) { return true; } -size_t ReservedMemoryRegion::committed_size() const { - size_t committed = 0; +size_t VirtualMemoryTracker::committed_size(const ReservedMemoryRegion* rmr) { size_t result = 0; - VirtualMemoryTracker::Instance::tree()->visit_committed_regions(*this, [&](CommittedMemoryRegion& crgn) { + tree()->visit_committed_regions(*rmr, [&](CommittedMemoryRegion& crgn) { result += crgn.size(); return true; }); return result; } -address ReservedMemoryRegion::thread_stack_uncommitted_bottom() const { - address bottom = base(); - address top = base() + size(); - VirtualMemoryTracker::Instance::tree()->visit_committed_regions(*this, [&](CommittedMemoryRegion& crgn) { +size_t VirtualMemoryTracker::Instance::committed_size(const ReservedMemoryRegion* rmr) { + assert(_tracker != nullptr, "Sanity check"); + return _tracker->committed_size(rmr); +} + +address VirtualMemoryTracker::Instance::thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr) { + assert(_tracker != nullptr, "Sanity check"); + return _tracker->thread_stack_uncommitted_bottom(rmr); +} + +address VirtualMemoryTracker::thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr) { + address bottom = rmr->base(); + address top = rmr->end(); + tree()->visit_committed_regions(*rmr, [&](CommittedMemoryRegion& crgn) { address committed_top = crgn.base() + crgn.size(); if (committed_top < top) { // committed stack guard pages, skip them @@ -291,7 +300,7 @@ public: assert_lock_strong(NmtVirtualMemory_lock); } if (rgn->mem_tag() == mtThreadStack) { - address stack_bottom = rgn->thread_stack_uncommitted_bottom(); + address stack_bottom = VirtualMemoryTracker::Instance::thread_stack_uncommitted_bottom(rgn); address committed_start; size_t committed_size; size_t stack_size = rgn->base() + rgn->size() - stack_bottom; diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index 1c9628cd828..3c6c1efd6a2 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -330,12 +330,6 @@ class ReservedMemoryRegion : public VirtualMemoryRegion { inline MemTag mem_tag() const { return _mem_tag; } - // uncommitted thread stack bottom, above guard pages if there is any. - address thread_stack_uncommitted_bottom() const; - - size_t committed_size() const; - - ReservedMemoryRegion& operator= (const ReservedMemoryRegion& other) { set_base(other.base()); set_size(other.size()); @@ -382,6 +376,9 @@ class VirtualMemoryTracker { // Snapshot current thread stacks void snapshot_thread_stacks(); void apply_summary_diff(VMATree::SummaryDiff diff); + size_t committed_size(const ReservedMemoryRegion* rmr); + address thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr); + RegionsTree* tree() { return &_tree; } class Instance : public AllStatic { @@ -404,6 +401,9 @@ class VirtualMemoryTracker { static bool print_containing_region(const void* p, outputStream* st); static void snapshot_thread_stacks(); static void apply_summary_diff(VMATree::SummaryDiff diff); + static size_t committed_size(const ReservedMemoryRegion* rmr); + // uncommitted thread stack bottom, above guard pages if there is any. + static address thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr); static RegionsTree* tree() { return _tracker->tree(); } }; diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index 9c0599fb513..b7ef0663c8a 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -50,14 +50,14 @@ namespace { }; } -#define check(rmr, regions) check_inner((rmr), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__) +#define check(vmt, rmr, regions) check_inner((vmt), (rmr), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__) -#define check_empty(rmr) \ +#define check_empty(vmt, rmr) \ do { \ - check_inner((rmr), nullptr, 0, __FILE__, __LINE__); \ + check_inner((vmt), (rmr), nullptr, 0, __FILE__, __LINE__); \ } while (false) -static void diagnostic_print(const ReservedMemoryRegion& rmr) { +static void diagnostic_print(VirtualMemoryTracker& vmt, const ReservedMemoryRegion& rmr) { LOG("In reserved region " PTR_FORMAT ", size %X:", p2i(rmr.base()), rmr.size()); VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr, [&](CommittedMemoryRegion& region) { LOG(" committed region: " PTR_FORMAT ", size %X", p2i(region.base()), region.size()); @@ -65,16 +65,16 @@ static void diagnostic_print(const ReservedMemoryRegion& rmr) { }); } -static void check_inner(const ReservedMemoryRegion& rmr, R* regions, size_t regions_size, const char* file, int line) { +static void check_inner(VirtualMemoryTracker& vmt, const ReservedMemoryRegion& rmr, R* regions, size_t regions_size, const char* file, int line) { size_t i = 0; size_t size = 0; // Helpful log - diagnostic_print(rmr); + diagnostic_print(vmt, rmr); #define WHERE " from " << file << ":" << line - VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr, [&](CommittedMemoryRegion& region) { + vmt.tree()->visit_committed_regions(rmr, [&](CommittedMemoryRegion& region) { EXPECT_LT(i, regions_size) << WHERE; EXPECT_EQ(region.base(), regions[i]._addr) << WHERE; EXPECT_EQ(region.size(), regions[i]._size) << WHERE; @@ -84,16 +84,18 @@ static void check_inner(const ReservedMemoryRegion& rmr, R* regions, size_t regi }); EXPECT_EQ(i, regions_size) << WHERE; - EXPECT_EQ(size, rmr.committed_size()) << WHERE; + EXPECT_EQ(size, vmt.committed_size(&rmr)) << WHERE; } class VirtualMemoryTrackerTest { public: static void test_add_committed_region_adjacent() { + VirtualMemoryTracker vmt(true); + RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; - ReservedSpace rs = MemoryReserver::reserve(size, mtTest); + const address addr = (address)0x0000A000; - address addr = (address)rs.base(); + vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); address frame1 = (address)0x1234; address frame2 = (address)0x1235; @@ -102,9 +104,6 @@ public: NativeCallStack stack2(&frame2, 1); // Fetch the added RMR for the space - RegionsTree* rtree = VirtualMemoryTracker::Instance::tree(); - MemTracker::NmtVirtualMemoryLocker nvml; - ReservedMemoryRegion rmr = rtree->find_reserved_region(addr); ASSERT_EQ(rmr.size(), size); @@ -118,24 +117,24 @@ public: { // Commit one region rtree->commit_region(addr + cs, cs, stack); R r[] = { {addr + cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent - lower address rtree->commit_region(addr, cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent - higher address rtree->commit_region(addr + 2 * cs, cs, stack); R r[] = { {addr, 3 * cs} }; - check(rmr, r); + check(vmt,rmr, r); } // Cleanup rtree->uncommit_region(addr, 3 * cs); - ASSERT_EQ(rmr.committed_size(), 0u); + ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent regions with different stacks @@ -143,14 +142,14 @@ public: { // Commit one region rtree->commit_region(addr + cs, cs, stack); R r[] = { {addr + cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent - lower address rtree->commit_region(addr, cs, stack2); R r[] = { {addr, cs}, {addr + cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent - higher address @@ -158,25 +157,21 @@ public: R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } // Cleanup rtree->uncommit_region(addr, 3 * cs); - ASSERT_EQ(rmr.committed_size(), 0u); - - rtree->tree().remove_all(); + ASSERT_EQ(vmt.committed_size(&rmr), 0u); } static void test_add_committed_region_adjacent_overlapping() { + VirtualMemoryTracker vmt(true); + RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; - ReservedSpace rs = MemoryReserver::reserve(size, mtTest); - - RegionsTree* rtree = VirtualMemoryTracker::Instance::tree(); - MemTracker::NmtVirtualMemoryLocker nvml; - - address addr = (address)rs.base(); + const address addr = (address)0x0000A000; + vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); address frame1 = (address)0x1234; address frame2 = (address)0x1235; @@ -199,28 +194,28 @@ public: rtree->commit_region(addr + 3 * cs, 2 * cs, stack); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent and overlapping rtree->commit_region(addr + 2 * cs, 2 * cs, stack); R r[] = { {addr, 5 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } // revert to two non-adjacent regions rtree->uncommit_region(addr + 2 * cs, cs); - ASSERT_EQ(rmr.committed_size(), 4 * cs); + ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent rtree->commit_region(addr + cs, 2 * cs, stack); R r[] = { {addr, 5 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } // Cleanup rtree->uncommit_region(addr, 5 * cs); - ASSERT_EQ(rmr.committed_size(), 0u); + ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent and overlapping regions with different stacks @@ -230,7 +225,7 @@ public: rtree->commit_region(addr + 3 * cs, 2 * cs, stack); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit adjacent and overlapping @@ -238,33 +233,32 @@ public: R r[] = { {addr, 2 * cs}, {addr + 2 * cs, 2 * cs}, {addr + 4 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } // revert to two non-adjacent regions rtree->commit_region(addr, 5 * cs, stack); rtree->uncommit_region(addr + 2 * cs, cs); - ASSERT_EQ(rmr.committed_size(), 4 * cs); + ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent rtree->commit_region(addr + cs, 2 * cs, stack2); R r[] = { {addr, cs}, {addr + cs, 2 * cs}, {addr + 3 * cs, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } rtree->tree().remove_all(); } static void test_add_committed_region_overlapping() { + VirtualMemoryTracker vmt(true); + RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; - ReservedSpace rs = MemoryReserver::reserve(size, mtTest); + const address addr = (address)0x0000A000; - RegionsTree* rtree = VirtualMemoryTracker::Instance::tree(); - MemTracker::NmtVirtualMemoryLocker nvml; - - address addr = (address)rs.base(); + vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); address frame1 = (address)0x1234; address frame2 = (address)0x1235; @@ -287,54 +281,54 @@ public: { // Commit one region rtree->commit_region(addr, cs, stack); R r[] = { {addr, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit the same region rtree->commit_region(addr, cs, stack); R r[] = { {addr, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit a succeeding region rtree->commit_region(addr + cs, cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit over two regions rtree->commit_region(addr, 2 * cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } {// Commit first part of a region rtree->commit_region(addr, cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit second part of a region rtree->commit_region(addr + cs, cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit a third part rtree->commit_region(addr + 2 * cs, cs, stack); R r[] = { {addr, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit in the middle of a region rtree->commit_region(addr + 1 * cs, cs, stack); R r[] = { {addr, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } // Cleanup rtree->uncommit_region(addr, 3 * cs); - ASSERT_EQ(rmr.committed_size(), 0u); + ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With preceding region @@ -345,71 +339,71 @@ public: { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } rtree->commit_region(addr + 3 * cs, cs, stack); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } rtree->commit_region(addr + 4 * cs, cs, stack); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } // Cleanup rtree->uncommit_region(addr, 5 * cs); - ASSERT_EQ(rmr.committed_size(), 0u); + ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With different stacks { // Commit one region rtree->commit_region(addr, cs, stack); R r[] = { {addr, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit the same region rtree->commit_region(addr, cs, stack2); R r[] = { {addr, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit a succeeding region rtree->commit_region(addr + cs, cs, stack); R r[] = { {addr, cs}, {addr + cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit over two regions rtree->commit_region(addr, 2 * cs, stack); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } {// Commit first part of a region rtree->commit_region(addr, cs, stack2); R r[] = { {addr, cs}, {addr + cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit second part of a region rtree->commit_region(addr + cs, cs, stack2); R r[] = { {addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit a third part rtree->commit_region(addr + 2 * cs, cs, stack2); R r[] = { {addr, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); } { // Commit in the middle of a region @@ -417,7 +411,7 @@ public: R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } rtree->tree().remove_all(); @@ -435,14 +429,12 @@ public: } static void test_remove_uncommitted_region() { + VirtualMemoryTracker vmt(true); + RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; - ReservedSpace rs = MemoryReserver::reserve(size, mtTest); - - RegionsTree* rtree = VirtualMemoryTracker::Instance::tree(); - MemTracker::NmtVirtualMemoryLocker nvml; - - address addr = (address)rs.base(); + const address addr = (address)0x0000A000; + vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); address frame1 = (address)0x1234; address frame2 = (address)0x1235; @@ -461,11 +453,11 @@ public: { // Commit regions rtree->commit_region(addr, 3 * cs, stack); R r[] = { {addr, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); // Remove only existing rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { @@ -477,7 +469,7 @@ public: rtree->uncommit_region(addr, cs); R r[] = { {addr + 2 * cs, cs}, {addr + 4 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } // add back @@ -487,7 +479,7 @@ public: rtree->uncommit_region(addr + 2 * cs, cs); R r[] = { {addr + 0 * cs, cs}, {addr + 4 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } // add back @@ -497,17 +489,17 @@ public: rtree->uncommit_region(addr + 4 * cs, cs); R r[] = { {addr + 0 * cs, cs}, {addr + 2 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); } rtree->uncommit_region(addr, 5 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove larger region rtree->commit_region(addr + 1 * cs, cs, stack); rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove smaller region - in the middle @@ -515,50 +507,50 @@ public: rtree->uncommit_region(addr + 1 * cs, cs); R r[] = { { addr + 0 * cs, cs}, { addr + 2 * cs, cs} }; - check(rmr, r); + check(vmt, rmr, r); rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove smaller region - at the beginning rtree->commit_region(addr, 3 * cs, stack); rtree->uncommit_region(addr + 0 * cs, cs); R r[] = { { addr + 1 * cs, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove smaller region - at the end rtree->commit_region(addr, 3 * cs, stack); rtree->uncommit_region(addr + 2 * cs, cs); R r[] = { { addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the beginning rtree->commit_region(addr + 1 * cs, 4 * cs, stack); rtree->uncommit_region(addr, 2 * cs); R r[] = { { addr + 2 * cs, 3 * cs} }; - check(rmr, r); + check(vmt, rmr, r); rtree->uncommit_region(addr + 1 * cs, 4 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the end rtree->commit_region(addr, 3 * cs, stack); rtree->uncommit_region(addr + 2 * cs, 2 * cs); R r[] = { { addr, 2 * cs} }; - check(rmr, r); + check(vmt, rmr, r); rtree->uncommit_region(addr, 3 * cs); - check_empty(rmr); + check_empty(vmt, rmr); } rtree->tree().remove_all(); From 241808e13fb032b0ec192e0b7ff94891a653ac94 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 8 Aug 2025 09:12:08 +0000 Subject: [PATCH 023/471] 8364269: Simplify code cache API by storing adapter entry offsets in blob Reviewed-by: kvn, shade, asmehra --- src/hotspot/share/code/aotCodeCache.cpp | 43 ++++----------------- src/hotspot/share/code/aotCodeCache.hpp | 18 +++------ src/hotspot/share/code/codeBlob.cpp | 31 +++++++++++---- src/hotspot/share/code/codeBlob.hpp | 16 +++++--- src/hotspot/share/runtime/sharedRuntime.cpp | 24 ++++++------ 5 files changed, 60 insertions(+), 72 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 38974da2eeb..df2e9648b84 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -799,7 +799,7 @@ bool AOTCodeCache::finish_write() { //------------------Store/Load AOT code ---------------------- -bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name, int entry_offset_count, int* entry_offsets) { +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name) { AOTCodeCache* cache = open_for_dump(); if (cache == nullptr) { return false; @@ -883,18 +883,6 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind return false; } - // Write entries offsets - n = cache->write_bytes(&entry_offset_count, sizeof(int)); - if (n != sizeof(int)) { - return false; - } - for (int i = 0; i < entry_offset_count; i++) { - uint32_t off = (uint32_t)entry_offsets[i]; - n = cache->write_bytes(&off, sizeof(uint32_t)); - if (n != sizeof(uint32_t)) { - return false; - } - } uint entry_size = cache->_write_position - entry_position; AOTCodeEntry* entry = new(cache) AOTCodeEntry(entry_kind, encode_id(entry_kind, id), entry_position, entry_size, name_offset, name_size, @@ -903,13 +891,13 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind return true; } -bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id, int entry_offset_count, int* entry_offsets) { +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id) { assert(AOTCodeEntry::is_blob(entry_kind), "wrong entry kind for blob id %s", StubInfo::name(id)); - return store_code_blob(blob, entry_kind, (uint)id, StubInfo::name(id), entry_offset_count, entry_offsets); + return store_code_blob(blob, entry_kind, (uint)id, StubInfo::name(id)); } -CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name, int entry_offset_count, int* entry_offsets) { +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name) { AOTCodeCache* cache = open_for_use(); if (cache == nullptr) { return nullptr; @@ -929,20 +917,20 @@ CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, c return nullptr; } AOTCodeReader reader(cache, entry); - CodeBlob* blob = reader.compile_code_blob(name, entry_offset_count, entry_offsets); + CodeBlob* blob = reader.compile_code_blob(name); log_debug(aot, codecache, stubs)("%sRead blob '%s' (id=%u, kind=%s) from AOT Code Cache", (blob == nullptr? "Failed to " : ""), name, id, aot_code_entry_kind_name[entry_kind]); return blob; } -CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, BlobId id, int entry_offset_count, int* entry_offsets) { +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, BlobId id) { assert(AOTCodeEntry::is_blob(entry_kind), "wrong entry kind for blob id %s", StubInfo::name(id)); - return load_code_blob(entry_kind, (uint)id, StubInfo::name(id), entry_offset_count, entry_offsets); + return load_code_blob(entry_kind, (uint)id, StubInfo::name(id)); } -CodeBlob* AOTCodeReader::compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets) { +CodeBlob* AOTCodeReader::compile_code_blob(const char* name) { uint entry_position = _entry->offset(); // Read name @@ -989,21 +977,6 @@ CodeBlob* AOTCodeReader::compile_code_blob(const char* name, int entry_offset_co fix_relocations(code_blob); - // Read entries offsets - offset = read_position(); - int stored_count = *(int*)addr(offset); - assert(stored_count == entry_offset_count, "entry offset count mismatch, count in AOT code cache=%d, expected=%d", stored_count, entry_offset_count); - offset += sizeof(int); - set_read_position(offset); - for (int i = 0; i < stored_count; i++) { - uint32_t off = *(uint32_t*)addr(offset); - offset += sizeof(uint32_t); - const char* entry_name = (_entry->kind() == AOTCodeEntry::Adapter) ? AdapterHandlerEntry::entry_name(i) : ""; - log_trace(aot, codecache, stubs)("Reading adapter '%s:%s' (0x%x) offset: 0x%x from AOT Code Cache", - stored_name, entry_name, _entry->id(), off); - entry_offsets[i] = off; - } - #ifdef ASSERT LogStreamHandle(Trace, aot, codecache, stubs) log; if (log.is_enabled()) { diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 69fd7549b43..778ad34e448 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -332,26 +332,18 @@ public: // save and restore API for non-enumerable code blobs static bool store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, - uint id, const char* name, - int entry_offset_count = 0, - int* entry_offsets = nullptr) NOT_CDS_RETURN_(false); + uint id, const char* name) NOT_CDS_RETURN_(false); static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, - uint id, const char* name, - int entry_offset_count = 0, - int* entry_offsets = nullptr) NOT_CDS_RETURN_(nullptr); + uint id, const char* name) NOT_CDS_RETURN_(nullptr); // save and restore API for enumerable code blobs static bool store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, - BlobId id, - int entry_offset_count = 0, - int* entry_offsets = nullptr) NOT_CDS_RETURN_(false); + BlobId id) NOT_CDS_RETURN_(false); static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, - BlobId id, - int entry_offset_count = 0, - int* entry_offsets = nullptr) NOT_CDS_RETURN_(nullptr); + BlobId id) NOT_CDS_RETURN_(nullptr); static uint store_entries_cnt() { if (is_on_for_dump()) { @@ -414,7 +406,7 @@ private: public: AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); - CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets); + CodeBlob* compile_code_blob(const char* name); ImmutableOopMapSet* read_oop_map_set(); diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index cf21f1f89a4..5b87e8c5670 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -389,8 +389,8 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha //---------------------------------------------------------------------------------------------------- // Implementation of BufferBlob -BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size) -: RuntimeBlob(name, kind, size, sizeof(BufferBlob)) +BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) +: RuntimeBlob(name, kind, size, header_size) {} BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { @@ -413,8 +413,8 @@ BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { } -BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size) - : RuntimeBlob(name, kind, cb, size, sizeof(BufferBlob), CodeOffsets::frame_never_safe, 0, nullptr) +BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, uint16_t header_size) + : RuntimeBlob(name, kind, cb, size, header_size, CodeOffsets::frame_never_safe, 0, nullptr) {} // Used by gtest @@ -446,12 +446,20 @@ void BufferBlob::free(BufferBlob *blob) { //---------------------------------------------------------------------------------------------------- // Implementation of AdapterBlob -AdapterBlob::AdapterBlob(int size, CodeBuffer* cb) : - BufferBlob("I2C/C2I adapters", CodeBlobKind::Adapter, cb, size) { +AdapterBlob::AdapterBlob(int size, CodeBuffer* cb, int entry_offset[AdapterBlob::ENTRY_COUNT]) : + BufferBlob("I2C/C2I adapters", CodeBlobKind::Adapter, cb, size, sizeof(AdapterBlob)) { + assert(entry_offset[0] == 0, "sanity check"); + for (int i = 1; i < AdapterBlob::ENTRY_COUNT; i++) { + assert(entry_offset[i] > 0 && entry_offset[i] < cb->insts()->size(), + "invalid entry offset 0x%x", entry_offset[i]); + } + _c2i_offset = entry_offset[1]; + _c2i_unverified_offset = entry_offset[2]; + _c2i_no_clinit_check_offset = entry_offset[3]; CodeCache::commit(this); } -AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { +AdapterBlob* AdapterBlob::create(CodeBuffer* cb, int entry_offset[AdapterBlob::ENTRY_COUNT]) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock CodeCache::gc_on_allocation(); @@ -460,7 +468,7 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { unsigned int size = CodeBlob::allocation_size(cb, sizeof(AdapterBlob)); { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) AdapterBlob(size, cb); + blob = new (size) AdapterBlob(size, cb, entry_offset); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -468,6 +476,13 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { return blob; } +void AdapterBlob::get_offsets(int entry_offset[ENTRY_COUNT]) { + entry_offset[0] = 0; + entry_offset[1] = _c2i_offset; + entry_offset[2] = _c2i_unverified_offset; + entry_offset[3] = _c2i_no_clinit_check_offset; +} + //---------------------------------------------------------------------------------------------------- // Implementation of VtableBlob diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index e5e47e2c5bb..407974f0428 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -372,8 +372,8 @@ class BufferBlob: public RuntimeBlob { private: // Creation support - BufferBlob(const char* name, CodeBlobKind kind, int size); - BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size); + BufferBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size = sizeof(BufferBlob)); + BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, uint16_t header_size = sizeof(BufferBlob)); void* operator new(size_t s, unsigned size) throw(); @@ -404,12 +404,18 @@ class BufferBlob: public RuntimeBlob { // AdapterBlob: used to hold C2I/I2C adapters class AdapterBlob: public BufferBlob { +public: + static const int ENTRY_COUNT = 4; private: - AdapterBlob(int size, CodeBuffer* cb); - + AdapterBlob(int size, CodeBuffer* cb, int entry_offset[ENTRY_COUNT]); + // _i2c_offset is always 0 so no need to store it + int _c2i_offset; + int _c2i_unverified_offset; + int _c2i_no_clinit_check_offset; public: // Creation - static AdapterBlob* create(CodeBuffer* cb); + static AdapterBlob* create(CodeBuffer* cb, int entry_offset[ENTRY_COUNT]); + void get_offsets(int entry_offset[ENTRY_COUNT]); }; //--------------------------------------------------------------------------------------------------- diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 554b94b56c6..149ebef4294 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2769,12 +2769,13 @@ AdapterBlob* AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handle ResourceMark rm; const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); - int offsets[AdapterHandlerEntry::ENTRIES_COUNT]; + int offsets[AdapterBlob::ENTRY_COUNT]; AdapterBlob* adapter_blob = nullptr; - CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::Adapter, id, name, AdapterHandlerEntry::ENTRIES_COUNT, offsets); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::Adapter, id, name); if (blob != nullptr) { adapter_blob = blob->as_adapter_blob(); + adapter_blob->get_offsets(offsets); address i2c_entry = adapter_blob->content_begin(); assert(offsets[0] == 0, "sanity check"); handler->set_entry_points(i2c_entry, i2c_entry + offsets[1], i2c_entry + offsets[2], i2c_entry + offsets[3]); @@ -2837,7 +2838,15 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob, } #endif - adapter_blob = AdapterBlob::create(&buffer); + int entry_offset[AdapterBlob::ENTRY_COUNT]; + assert(AdapterBlob::ENTRY_COUNT == 4, "sanity"); + address i2c_entry = handler->get_i2c_entry(); + entry_offset[0] = 0; // i2c_entry offset + entry_offset[1] = handler->get_c2i_entry() - i2c_entry; + entry_offset[2] = handler->get_c2i_unverified_entry() - i2c_entry; + entry_offset[3] = handler->get_c2i_no_clinit_check_entry() - i2c_entry; + + adapter_blob = AdapterBlob::create(&buffer, entry_offset); if (adapter_blob == nullptr) { // CodeCache is full, disable compilation // Ought to log this but compile log is only per compile thread @@ -2848,14 +2857,7 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob, // try to save generated code const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); - int entry_offset[AdapterHandlerEntry::ENTRIES_COUNT]; - assert(AdapterHandlerEntry::ENTRIES_COUNT == 4, "sanity"); - address i2c_entry = handler->get_i2c_entry(); - entry_offset[0] = 0; // i2c_entry offset - entry_offset[1] = handler->get_c2i_entry() - i2c_entry; - entry_offset[2] = handler->get_c2i_unverified_entry() - i2c_entry; - entry_offset[3] = handler->get_c2i_no_clinit_check_entry() - i2c_entry; - bool success = AOTCodeCache::store_code_blob(*adapter_blob, AOTCodeEntry::Adapter, id, name, AdapterHandlerEntry::ENTRIES_COUNT, entry_offset); + bool success = AOTCodeCache::store_code_blob(*adapter_blob, AOTCodeEntry::Adapter, id, name); assert(success || !AOTCodeCache::is_dumping_adapter(), "caching of adapter must be disabled"); } handler->relocate(adapter_blob->content_begin()); From cd50d78d447f9f39065bc844fb3041cba2db32db Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 8 Aug 2025 17:17:21 +0000 Subject: [PATCH 024/471] 8361300: Document exceptions for Unsafe offset methods Reviewed-by: jrose, vyazici --- src/hotspot/share/prims/unsafe.cpp | 20 ++-- .../atomic/AtomicIntegerFieldUpdater.java | 3 + .../atomic/AtomicLongFieldUpdater.java | 3 + .../atomic/AtomicReferenceFieldUpdater.java | 3 + .../classes/jdk/internal/misc/Unsafe.java | 42 +++++-- .../tck/AtomicIntegerFieldUpdaterTest.java | 11 ++ .../tck/AtomicLongFieldUpdaterTest.java | 11 ++ .../tck/AtomicReferenceFieldUpdaterTest.java | 12 ++ .../AddressComputationContractTest.java | 104 ++++++++++++++++++ 9 files changed, 192 insertions(+), 17 deletions(-) create mode 100644 test/jdk/jdk/internal/misc/Unsafe/AddressComputationContractTest.java diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index a6300e81468..80dfaf90a28 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -480,7 +480,9 @@ UNSAFE_LEAF (void, Unsafe_WriteBackPostSync0(JNIEnv *env, jobject unsafe)) { ////// Random queries -static jlong find_field_offset(jclass clazz, jstring name, TRAPS) { +// Finds the object field offset of a field with the matching name, or an error code +// Error code -1 is not found, -2 is static field +static jlong find_known_instance_field_offset(jclass clazz, jstring name, TRAPS) { assert(clazz != nullptr, "clazz must not be null"); assert(name != nullptr, "name must not be null"); @@ -489,16 +491,20 @@ static jlong find_field_offset(jclass clazz, jstring name, TRAPS) { InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); - jint offset = -1; + jint offset = -1; // Not found for (JavaFieldStream fs(k); !fs.done(); fs.next()) { Symbol *name = fs.name(); if (name->equals(utf_name)) { - offset = fs.offset(); + if (!fs.access_flags().is_static()) { + offset = fs.offset(); + } else { + offset = -2; // A static field + } break; } } if (offset < 0) { - THROW_0(vmSymbols::java_lang_InternalError()); + return offset; // Error code } return field_offset_from_byte_offset(offset); } @@ -527,8 +533,8 @@ UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset0(JNIEnv *env, jobject unsafe, jobje return find_field_offset(field, 0, THREAD); } UNSAFE_END -UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset1(JNIEnv *env, jobject unsafe, jclass c, jstring name)) { - return find_field_offset(c, name, THREAD); +UNSAFE_ENTRY(jlong, Unsafe_KnownObjectFieldOffset0(JNIEnv *env, jobject unsafe, jclass c, jstring name)) { + return find_known_instance_field_offset(c, name, THREAD); } UNSAFE_END UNSAFE_ENTRY(jlong, Unsafe_StaticFieldOffset0(JNIEnv *env, jobject unsafe, jobject field)) { @@ -882,7 +888,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "freeMemory0", CC "(" ADR ")V", FN_PTR(Unsafe_FreeMemory0)}, {CC "objectFieldOffset0", CC "(" FLD ")J", FN_PTR(Unsafe_ObjectFieldOffset0)}, - {CC "objectFieldOffset1", CC "(" CLS LANG "String;)J", FN_PTR(Unsafe_ObjectFieldOffset1)}, + {CC "knownObjectFieldOffset0", CC "(" CLS LANG "String;)J", FN_PTR(Unsafe_KnownObjectFieldOffset0)}, {CC "staticFieldOffset0", CC "(" FLD ")J", FN_PTR(Unsafe_StaticFieldOffset0)}, {CC "staticFieldBase0", CC "(" FLD ")" OBJ, FN_PTR(Unsafe_StaticFieldBase0)}, {CC "ensureClassInitialized0", CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized0)}, diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index f947eb4f7db..2250009e8f5 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -403,6 +403,9 @@ public abstract class AtomicIntegerFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); + if (Modifier.isStatic(modifiers)) + throw new IllegalArgumentException("Must not be a static field"); + // Access to protected field members is restricted to receivers only // of the accessing class, or one of its subclasses, and the // accessing class must in turn be a subclass (or package sibling) diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index b31a8edf53a..5f0a666cb04 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -398,6 +398,9 @@ public abstract class AtomicLongFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); + if (Modifier.isStatic(modifiers)) + throw new IllegalArgumentException("Must not be a static field"); + // Access to protected field members is restricted to receivers only // of the accessing class, or one of its subclasses, and the // accessing class must in turn be a subclass (or package sibling) diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index e3ca4830d5a..4a758f77a47 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -363,6 +363,9 @@ public abstract class AtomicReferenceFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); + if (Modifier.isStatic(modifiers)) + throw new IllegalArgumentException("Must not be a static field"); + // Access to protected field members is restricted to receivers only // of the accessing class, or one of its subclasses, and the // accessing class must in turn be a subclass (or package sibling) diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index ff854a8ecb3..016566ae659 100644 --- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -1069,6 +1069,9 @@ public final class Unsafe { * the field locations in a form usable by {@link #getInt(Object,long)}. * Therefore, code which will be ported to such JVMs on 64-bit platforms * must preserve all bits of static field offsets. + * + * @throws NullPointerException if the field is {@code null} + * @throws IllegalArgumentException if the field is static * @see #getInt(Object, long) */ public long objectFieldOffset(Field f) { @@ -1080,13 +1083,17 @@ public final class Unsafe { } /** - * Reports the location of the field with a given name in the storage - * allocation of its class. + * (For compile-time known instance fields in JDK code only) Reports the + * location of the field with a given name in the storage allocation of its + * class. + *

+ * This API is used to avoid creating reflective Objects in Java code at + * startup. This should not be used to find fields in non-trusted code. + * Use the {@link #objectFieldOffset(Field) Field}-accepting version for + * arbitrary fields instead. * * @throws NullPointerException if any parameter is {@code null}. - * @throws InternalError if there is no field named {@code name} declared - * in class {@code c}, i.e., if {@code c.getDeclaredField(name)} - * would throw {@code java.lang.NoSuchFieldException}. + * @throws InternalError if the presumably known field couldn't be found * * @see #objectFieldOffset(Field) */ @@ -1095,7 +1102,16 @@ public final class Unsafe { throw new NullPointerException(); } - return objectFieldOffset1(c, name); + long result = knownObjectFieldOffset0(c, name); + if (result < 0) { + String type = switch ((int) result) { + case -2 -> "a static field"; + case -1 -> "not found"; + default -> "unknown"; + }; + throw new InternalError("Field %s.%s %s".formatted(c.getTypeName(), name, type)); + } + return result; } /** @@ -1113,6 +1129,9 @@ public final class Unsafe { * a few bits to encode an offset within a non-array object, * However, for consistency with other methods in this class, * this method reports its result as a long value. + * + * @throws NullPointerException if the field is {@code null} + * @throws IllegalArgumentException if the field is not static * @see #getInt(Object, long) */ public long staticFieldOffset(Field f) { @@ -1132,6 +1151,9 @@ public final class Unsafe { * which is a "cookie", not guaranteed to be a real Object, and it should * not be used in any way except as argument to the get and put routines in * this class. + * + * @throws NullPointerException if the field is {@code null} + * @throws IllegalArgumentException if the field is not static */ public Object staticFieldBase(Field f) { if (f == null) { @@ -3848,10 +3870,10 @@ public final class Unsafe { @IntrinsicCandidate private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); private native void copySwapMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize); - private native long objectFieldOffset0(Field f); - private native long objectFieldOffset1(Class c, String name); - private native long staticFieldOffset0(Field f); - private native Object staticFieldBase0(Field f); + private native long objectFieldOffset0(Field f); // throws IAE + private native long knownObjectFieldOffset0(Class c, String name); // error code: -1 not found, -2 static + private native long staticFieldOffset0(Field f); // throws IAE + private native Object staticFieldBase0(Field f); // throws IAE private native boolean shouldBeInitialized0(Class c); private native void ensureClassInitialized0(Class c); private native int arrayBaseOffset0(Class arrayClass); // public version returns long to promote correct arithmetic diff --git a/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java b/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java index edbf0f3ae86..91900e37b6a 100644 --- a/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java +++ b/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java @@ -44,6 +44,7 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { private volatile int privateField; int w; float z; + static volatile int q; public static void main(String[] args) { main(suite(), args); } @@ -88,6 +89,16 @@ public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase { } catch (IllegalArgumentException success) {} } + /** + * construction with static field throws IllegalArgumentException + */ + public void testConstructor4() { + try { + updaterFor("q"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + /** * construction using private field from subclass throws RuntimeException */ diff --git a/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java b/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java index 17689061426..5edcf871f42 100644 --- a/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java +++ b/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java @@ -44,6 +44,7 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { private volatile long privateField; long w; float z; + static volatile long q; public static void main(String[] args) { main(suite(), args); } @@ -88,6 +89,16 @@ public class AtomicLongFieldUpdaterTest extends JSR166TestCase { } catch (IllegalArgumentException success) {} } + /** + * construction with static field throws IllegalArgumentException + */ + public void testConstructor4() { + try { + updaterFor("q"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + /** * construction using private field from subclass throws RuntimeException */ diff --git a/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java b/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java index 6df68c4c634..313f40f7918 100644 --- a/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java +++ b/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java @@ -45,6 +45,7 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase { Object z; Item w; volatile int i; + static volatile Item q; public static void main(String[] args) { main(suite(), args); @@ -100,6 +101,17 @@ public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase { } catch (ClassCastException success) {} } + /** + * construction with static field throws IllegalArgumentException + */ + public void testConstructor5() { + try { + updaterFor("q"); + shouldThrow(); + } catch (IllegalArgumentException success) {} + } + + /** * construction using private field from subclass throws RuntimeException */ diff --git a/test/jdk/jdk/internal/misc/Unsafe/AddressComputationContractTest.java b/test/jdk/jdk/internal/misc/Unsafe/AddressComputationContractTest.java new file mode 100644 index 00000000000..ebdfa843272 --- /dev/null +++ b/test/jdk/jdk/internal/misc/Unsafe/AddressComputationContractTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.Test; + +import static jdk.internal.misc.Unsafe.getUnsafe; +import static org.junit.jupiter.api.Assertions.*; + +/* + * @test + * @bug 8361300 + * @summary Verify Unsafe memory address computation method contracts, + * exposed via sun.misc.Unsafe + * @modules java.base/jdk.internal.misc + * @run junit AddressComputationContractTest + */ +public class AddressComputationContractTest { + + int instanceField; + static int staticField; + + private static final Field INSTANCE_FIELD; + private static final Field STATIC_FIELD; + + static { + try { + INSTANCE_FIELD = AddressComputationContractTest.class.getDeclaredField("instanceField"); + STATIC_FIELD = AddressComputationContractTest.class.getDeclaredField("staticField"); + } catch (ReflectiveOperationException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @Test + void objectFieldOffset() { + assertDoesNotThrow(() -> getUnsafe().objectFieldOffset(INSTANCE_FIELD)); + assertThrows(NullPointerException.class, () -> getUnsafe().objectFieldOffset(null)); + assertThrows(IllegalArgumentException.class, () -> getUnsafe().objectFieldOffset(STATIC_FIELD)); + } + + @Test + void knownObjectFieldOffset() { + assertDoesNotThrow(() -> getUnsafe().objectFieldOffset(AddressComputationContractTest.class, "instanceField")); + assertThrows(NullPointerException.class, () -> getUnsafe().objectFieldOffset(null, "instanceField")); + assertThrows(NullPointerException.class, () -> getUnsafe().objectFieldOffset(AddressComputationContractTest.class, null)); + // Two conventional failure cases, not necessarily complete + var dneMsg = assertThrows(InternalError.class, () -> getUnsafe().objectFieldOffset(AddressComputationContractTest.class, "doesNotExist")).getMessage(); + assertTrue(dneMsg.contains("AddressComputationContractTest.doesNotExist") && dneMsg.contains("not found"), dneMsg); + var staticMsg = assertThrows(InternalError.class, () -> getUnsafe().objectFieldOffset(AddressComputationContractTest.class, "staticField")).getMessage(); + assertTrue(staticMsg.contains("AddressComputationContractTest.staticField") && staticMsg.contains("static field"), staticMsg); + } + + @Test + void staticFieldOffset() { + assertDoesNotThrow(() -> getUnsafe().staticFieldOffset(STATIC_FIELD)); + assertThrows(NullPointerException.class, () -> getUnsafe().staticFieldOffset(null)); + assertThrows(IllegalArgumentException.class, () -> getUnsafe().staticFieldOffset(INSTANCE_FIELD)); + } + + @Test + void staticFieldBase() { + assertDoesNotThrow(() -> getUnsafe().staticFieldBase(STATIC_FIELD)); + assertThrows(NullPointerException.class, () -> getUnsafe().staticFieldBase(null)); + assertThrows(IllegalArgumentException.class, () -> getUnsafe().staticFieldBase(INSTANCE_FIELD)); + } + + @Test + void arrayBaseOffset() { + assertDoesNotThrow(() -> getUnsafe().arrayBaseOffset(int[].class)); + assertThrows(NullPointerException.class, () -> getUnsafe().arrayBaseOffset(null)); + // Caused by VM trying to throw java.lang.InvalidClassException (there's one in java.io instead) + assertThrows(NoClassDefFoundError.class, () -> getUnsafe().arrayBaseOffset(AddressComputationContractTest.class)); + } + + @Test + void arrayIndexScale() { + assertDoesNotThrow(() -> getUnsafe().arrayIndexScale(int[].class)); + assertThrows(NullPointerException.class, () -> getUnsafe().arrayIndexScale(null)); + // Caused by VM trying to throw java.lang.InvalidClassException (there's one in java.io instead) + assertThrows(NoClassDefFoundError.class, () -> getUnsafe().arrayIndexScale(AddressComputationContractTest.class)); + } +} From c1c0155604cbb6c42a220d391a88b029776bdb95 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 8 Aug 2025 21:41:44 +0000 Subject: [PATCH 025/471] 8364129: Rename libwixhelper Reviewed-by: erikj, almatvee --- make/modules/jdk.jpackage/Lib.gmk | 12 ++++++------ .../jdk/jpackage/internal/WixUiFragmentBuilder.java | 2 +- .../classes/jdk/jpackage/internal/resources/main.wxs | 2 +- .../native/{libwixhelper => libmsica}/Version.cpp | 0 .../native/{libwixhelper => libmsica}/Version.h | 0 .../libwixhelper.cpp => libmsica/libmsica.cpp} | 0 .../tools/jpackage/windows/WinLongVersionTest.java | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) rename src/jdk.jpackage/windows/native/{libwixhelper => libmsica}/Version.cpp (100%) rename src/jdk.jpackage/windows/native/{libwixhelper => libmsica}/Version.h (100%) rename src/jdk.jpackage/windows/native/{libwixhelper/libwixhelper.cpp => libmsica/libmsica.cpp} (100%) diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk index e9c55548b0d..d2dd9d92a03 100644 --- a/make/modules/jdk.jpackage/Lib.gmk +++ b/make/modules/jdk.jpackage/Lib.gmk @@ -121,15 +121,15 @@ ifeq ($(call isTargetOs, windows), true) TARGETS += $(BUILD_LIBJPACKAGE) ############################################################################## - ## Build libwixhelper + ## Build libmsica ############################################################################## - # Build Wix custom action helper + # Build MSI custom action library # Output library in resources dir, and symbols in the object dir - $(eval $(call SetupJdkLibrary, BUILD_LIBWIXHELPER, \ - NAME := wixhelper, \ + $(eval $(call SetupJdkLibrary, BUILD_LIBMSICA, \ + NAME := msica, \ OUTPUT_DIR := $(JPACKAGE_OUTPUT_DIR), \ - SYMBOLS_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libwixhelper, \ + SYMBOLS_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libmsica, \ ONLY_EXPORTED := true, \ OPTIMIZATION := LOW, \ EXTRA_SRC := common, \ @@ -139,7 +139,7 @@ ifeq ($(call isTargetOs, windows), true) LIBS_windows := msi.lib ole32.lib shell32.lib shlwapi.lib user32.lib, \ )) - TARGETS += $(BUILD_LIBWIXHELPER) + TARGETS += $(BUILD_LIBMSICA) ############################################################################## ## Build msiwrapper diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java index a00eb16a4a9..4a2a0756dbd 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixUiFragmentBuilder.java @@ -120,7 +120,7 @@ final class WixUiFragmentBuilder extends WixFragmentBuilder { super.addFilesToConfigRoot(); if (withCustomActionsDll) { - String fname = "wixhelper.dll"; // CA dll + String fname = "msica.dll"; // CA dll try (InputStream is = ResourceLocator.class.getResourceAsStream(fname)) { Files.copy(is, getConfigRoot().resolve(fname)); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs index 2a3ea3743e2..f1e8f594164 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs @@ -65,7 +65,7 @@ - + diff --git a/src/jdk.jpackage/windows/native/libwixhelper/Version.cpp b/src/jdk.jpackage/windows/native/libmsica/Version.cpp similarity index 100% rename from src/jdk.jpackage/windows/native/libwixhelper/Version.cpp rename to src/jdk.jpackage/windows/native/libmsica/Version.cpp diff --git a/src/jdk.jpackage/windows/native/libwixhelper/Version.h b/src/jdk.jpackage/windows/native/libmsica/Version.h similarity index 100% rename from src/jdk.jpackage/windows/native/libwixhelper/Version.h rename to src/jdk.jpackage/windows/native/libmsica/Version.h diff --git a/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp b/src/jdk.jpackage/windows/native/libmsica/libmsica.cpp similarity index 100% rename from src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp rename to src/jdk.jpackage/windows/native/libmsica/libmsica.cpp diff --git a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java index d70cda7b264..586b69c1913 100644 --- a/test/jdk/tools/jpackage/windows/WinLongVersionTest.java +++ b/test/jdk/tools/jpackage/windows/WinLongVersionTest.java @@ -126,12 +126,12 @@ public class WinLongVersionTest { Action ended 12:08:38: FindRelatedProducts. Return value 1. ... Action start 12:08:38: JpFindRelatedProducts. - Java [12:08:38.180 libwixhelper.cpp:120 (FindRelatedProductsEx)] TRACE: Entering FindRelatedProductsEx - Java [12:08:38.185 libwixhelper.cpp:85 (`anonymous-namespace'::findInstalledPackages)] TRACE: Found {D88EEA02-56CC-34AD-8216-C2CC244FA898} product + Java [12:08:38.180 libmsica.cpp:120 (FindRelatedProductsEx)] TRACE: Entering FindRelatedProductsEx + Java [12:08:38.185 libmsica.cpp:85 (`anonymous-namespace'::findInstalledPackages)] TRACE: Found {D88EEA02-56CC-34AD-8216-C2CC244FA898} product Java [12:08:38.187 MsiCA.cpp:61 (msi::CAImpl::removeProperty)] TRACE: Removing MSI property 'JP_UPGRADABLE_FOUND' Java [12:08:38.187 MsiCA.cpp:61 (msi::CAImpl::removeProperty)] TRACE: Removing MSI property 'MIGRATE' Java [12:08:38.189 MsiCA.cpp:61 (msi::CAImpl::removeProperty)] TRACE: Removing MSI property 'JP_DOWNGRADABLE_FOUND' - Java [12:08:38.190 libwixhelper.cpp:0 (FindRelatedProductsEx)] TRACE: Exiting FindRelatedProductsEx (entered at libwixhelper.cpp:120) + Java [12:08:38.190 libmsica.cpp:0 (FindRelatedProductsEx)] TRACE: Exiting FindRelatedProductsEx (entered at libmsica.cpp:120) Action ended 12:08:38: JpFindRelatedProducts. Return value 1. */ PackageTest test2 = init.get().addInstallVerifier(cmd -> { From 8ad1fcc48a4ba49ffde6dfbb851dbb3f56077dec Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 8 Aug 2025 22:11:52 +0000 Subject: [PATCH 026/471] 8364564: Shortcut configuration is not recorded in .jpackage.xml file Reviewed-by: almatvee --- .../jpackage/internal/DesktopIntegration.java | 25 ++++--- .../jpackage/internal/LinuxFromParams.java | 9 +-- .../internal/model/LinuxLauncher.java | 11 ++- .../internal/model/LinuxLauncherMixin.java | 20 ++--- .../internal/AddLauncherArguments.java | 8 +- .../jdk/jpackage/internal/FromParams.java | 36 ++++++++- .../internal/StandardBundlerParam.java | 18 ----- .../internal/model/LauncherShortcut.java | 74 +++++++++++++++++++ .../LauncherShortcutStartupDirectory.java | 55 ++++++++++++++ .../jdk/jpackage/internal/WinFromParams.java | 20 +---- .../internal/WixAppImageFragmentBuilder.java | 64 ++++++++++------ .../jpackage/internal/model/WinLauncher.java | 15 +++- .../internal/model/WinLauncherMixin.java | 43 ++++++----- .../jdk/jpackage/test/LauncherShortcut.java | 2 +- .../jdk/jpackage/test/LauncherVerifier.java | 46 +++++++++++- 15 files changed, 327 insertions(+), 119 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcut.java create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 8de462abac7..476ca3201ce 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -24,10 +24,10 @@ */ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.LinuxLauncher; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.Launcher; +import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; +import static jdk.jpackage.internal.model.LauncherShortcut.toRequest; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -45,12 +45,13 @@ import java.util.stream.Stream; import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import static jdk.jpackage.internal.ApplicationImageUtils.createLauncherIconResource; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.LinuxLauncher; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.util.CompositeProxy; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.XmlUtils; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; /** * Helper to create files for desktop integration. @@ -77,7 +78,7 @@ final class DesktopIntegration extends ShellCustomAction { // Need desktop and icon files if one of conditions is met: // - there are file associations configured // - user explicitly requested to create a shortcut - boolean withDesktopFile = !associations.isEmpty() || launcher.shortcut().orElse(false); + boolean withDesktopFile = !associations.isEmpty() || toRequest(launcher.shortcut()).orElse(false); var curIconResource = createLauncherIconResource(pkg.app(), launcher, env::createResource); @@ -132,7 +133,7 @@ final class DesktopIntegration extends ShellCustomAction { nestedIntegrations = pkg.app().additionalLaunchers().stream().map(v -> { return (LinuxLauncher)v; }).filter(l -> { - return l.shortcut().orElse(true); + return toRequest(l.shortcut()).orElse(true); }).map(toFunction(l -> { return new DesktopIntegration(env, pkg, l); })).toList(); @@ -225,6 +226,9 @@ final class DesktopIntegration extends ShellCustomAction { } private Map createDataForDesktopFile() { + + var installedLayout = pkg.asInstalledPackageApplicationLayout().orElseThrow(); + Map data = new HashMap<>(); data.put("APPLICATION_NAME", launcher.name()); data.put("APPLICATION_DESCRIPTION", launcher.description()); @@ -232,8 +236,7 @@ final class DesktopIntegration extends ShellCustomAction { f -> f.installPath().toString()).orElse(null)); data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( - pkg.asInstalledPackageApplicationLayout().orElseThrow().launchersDirectory().resolve( - launcher.executableNameWithSuffix()).toString())); + installedLayout.launchersDirectory().resolve(launcher.executableNameWithSuffix()).toString())); return data; } @@ -481,7 +484,7 @@ final class DesktopIntegration extends ShellCustomAction { private final BuildEnv env; private final LinuxPackage pkg; - private final Launcher launcher; + private final LinuxLauncher launcher; private final List associations; diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 7dff3cd73ae..6967dea111e 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -29,16 +29,14 @@ import static jdk.jpackage.internal.FromParams.createApplicationBuilder; import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; +import static jdk.jpackage.internal.FromParams.findLauncherShortcut; import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxLauncher; @@ -51,11 +49,10 @@ final class LinuxFromParams { private static LinuxApplication createLinuxApplication( Map params) throws ConfigException, IOException { final var launcherFromParams = new LauncherFromParams(); + final var app = createApplicationBuilder(params, toFunction(launcherParams -> { final var launcher = launcherFromParams.create(launcherParams); - final var shortcut = Stream.of(SHORTCUT_HINT, LINUX_SHORTCUT_HINT).map(param -> { - return param.findIn(launcherParams); - }).filter(Optional::isPresent).map(Optional::get).findFirst(); + final var shortcut = findLauncherShortcut(LINUX_SHORTCUT_HINT, params, launcherParams); return LinuxLauncher.create(launcher, new LinuxLauncherMixin.Stub(shortcut)); }), APPLICATION_LAYOUT).create(); return LinuxApplication.create(app); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java index 8970f2198c2..c84b5e3bbf5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncher.java @@ -24,6 +24,7 @@ */ package jdk.jpackage.internal.model; +import java.util.HashMap; import java.util.Map; import jdk.jpackage.internal.util.CompositeProxy; @@ -36,9 +37,11 @@ public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { @Override default Map extraAppImageFileData() { - return shortcut().map(v -> { - return Map.of("shortcut", Boolean.toString(v)); - }).orElseGet(Map::of); + Map map = new HashMap<>(); + shortcut().ifPresent(shortcut -> { + shortcut.store(SHORTCUT_ID, map::put); + }); + return map; } /** @@ -52,4 +55,6 @@ public interface LinuxLauncher extends Launcher, LinuxLauncherMixin { public static LinuxLauncher create(Launcher launcher, LinuxLauncherMixin mixin) { return CompositeProxy.create(LinuxLauncher.class, launcher, mixin); } + + public static final String SHORTCUT_ID = "linux-shortcut"; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java index d5e15101c7e..e8ff61ca239 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxLauncherMixin.java @@ -32,24 +32,20 @@ import java.util.Optional; public interface LinuxLauncherMixin { /** - * Gets the start menu shortcut setting of this application launcher. + * Gets the start menu shortcut of this application launcher. *

- * Returns true if this application launcher was requested to have - * the start menu shortcut. - *

- * Returns false if this application launcher was requested not to - * have the start menu shortcut. - *

- * Returns an empty {@link Optional} instance if there was no request about the - * start menu shortcut for this application launcher. + * Returns a non-empty {@link Optional} instance if a request about the start + * menu shortcut for this application launcher was made and an empty + * {@link Optional} instance if there was no request about the start menu + * shortcut for this application launcher. * - * @return the start menu shortcut setting of this application launcher + * @return the start menu shortcut of this application launcher */ - Optional shortcut(); + Optional shortcut(); /** * Default implementation of {@link LinuxLauncherMixin} interface. */ - record Stub(Optional shortcut) implements LinuxLauncherMixin { + record Stub(Optional shortcut) implements LinuxLauncherMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java index d9946075c4f..93d037c6a45 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java @@ -36,8 +36,6 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Arguments.CLIOptions; import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; /* * AddLauncherArguments @@ -135,16 +133,16 @@ class AddLauncherArguments { Arguments.putUnlessNull(bundleParams, CLIOptions.WIN_CONSOLE_HINT.getId(), getOptionValue(CLIOptions.WIN_CONSOLE_HINT)); - Arguments.putUnlessNull(bundleParams, SHORTCUT_HINT.getID(), + Arguments.putUnlessNull(bundleParams, CLIOptions.WIN_SHORTCUT_HINT.getId(), getOptionValue(CLIOptions.WIN_SHORTCUT_HINT)); - Arguments.putUnlessNull(bundleParams, MENU_HINT.getID(), + Arguments.putUnlessNull(bundleParams, CLIOptions.WIN_MENU_HINT.getId(), getOptionValue(CLIOptions.WIN_MENU_HINT)); } if (OperatingSystem.isLinux()) { Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(), getOptionValue(CLIOptions.LINUX_CATEGORY)); - Arguments.putUnlessNull(bundleParams, SHORTCUT_HINT.getID(), + Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_SHORTCUT_HINT.getId(), getOptionValue(CLIOptions.LINUX_SHORTCUT_HINT)); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 5e940aba18b..34818fafc94 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -24,6 +24,9 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.Arguments.CLIOptions.LINUX_SHORTCUT_HINT; +import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_MENU_HINT; +import static jdk.jpackage.internal.Arguments.CLIOptions.WIN_SHORTCUT_HINT; import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; @@ -63,6 +66,8 @@ import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo; import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherShortcut; +import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.function.ThrowingFunction; @@ -165,6 +170,32 @@ final class FromParams { jdk.jpackage.internal.model.Package.class.getName())); } + static Optional findLauncherShortcut( + BundlerParamInfo shortcutParam, + Map mainParams, + Map launcherParams) { + + Optional launcherValue; + if (launcherParams == mainParams) { + // The main launcher + launcherValue = Optional.empty(); + } else { + launcherValue = shortcutParam.findIn(launcherParams); + } + + return launcherValue.map(withShortcut -> { + if (withShortcut) { + return Optional.of(LauncherShortcutStartupDirectory.DEFAULT); + } else { + return Optional.empty(); + } + }).or(() -> { + return shortcutParam.findIn(mainParams).map(_ -> { + return Optional.of(LauncherShortcutStartupDirectory.DEFAULT); + }); + }).map(LauncherShortcut::new); + } + private static ApplicationLaunchers createLaunchers( Map params, Function, Launcher> launcherMapper) { @@ -195,8 +226,9 @@ final class FromParams { // mainParams), APP_NAME.fetchFrom(launcherParams))); launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); } - return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), ADD_LAUNCHERS - .getID(), FILE_ASSOCIATIONS.getID()); + return AddLauncherArguments.merge(mainParams, launcherParams, ICON.getID(), + ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID(), WIN_MENU_HINT.getId(), + WIN_SHORTCUT_HINT.getId(), LINUX_SHORTCUT_HINT.getId()); } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam(null); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index 076d6bfc895..6b89bb3ee65 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -307,24 +307,6 @@ final class StandardBundlerParam { true : Boolean.valueOf(s) ); - static final BundlerParamInfo SHORTCUT_HINT = - new BundlerParamInfo<>( - "shortcut-hint", // not directly related to a CLI option - Boolean.class, - params -> true, // defaults to true - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - true : Boolean.valueOf(s) - ); - - static final BundlerParamInfo MENU_HINT = - new BundlerParamInfo<>( - "menu-hint", // not directly related to a CLI option - Boolean.class, - params -> true, // defaults to true - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? - true : Boolean.valueOf(s) - ); - static final BundlerParamInfo RESOURCE_DIR = new BundlerParamInfo<>( Arguments.CLIOptions.RESOURCE_DIR.getId(), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcut.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcut.java new file mode 100644 index 00000000000..4188bccb073 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcut.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +/** + * A shortcut to launch an application launcher. + */ +public record LauncherShortcut(Optional startupDirectory) { + + public LauncherShortcut { + Objects.requireNonNull(startupDirectory); + } + + public LauncherShortcut(LauncherShortcutStartupDirectory startupDirectory) { + this(Optional.of(startupDirectory)); + } + + public LauncherShortcut() { + this(Optional.empty()); + } + + void store(String propertyName, BiConsumer sink) { + Objects.requireNonNull(propertyName); + Objects.requireNonNull(sink); + if (startupDirectory.isEmpty()) { + sink.accept(propertyName, Boolean.FALSE.toString()); + } else { + startupDirectory.ifPresent(v -> { + sink.accept(propertyName, v.asStringValue()); + }); + } + } + + /** + * Converts the given shortcut into a shortcut request. + *

+ * Returns true if shortcut was explicitly requested. + *

+ * Returns false if no shortcut was explicitly requested. + *

+ * Returns an empty {@link Optional} instance if there was no shortcut request. + * + * @return shortcut request + */ + public static Optional toRequest(Optional shortcut) { + return shortcut.map(v -> v.startupDirectory().isPresent()); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java new file mode 100644 index 00000000000..c604b00c3e2 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Objects; + +/** + * The directory in which to run an application launcher when it is started from + * a shortcut. + */ +public enum LauncherShortcutStartupDirectory { + + /** + * Platform-specific default value. + *

+ * On Windows, it indicates that the startup directory should be the package's + * installation directory. + *

+ * On Linux, it indicates that a shortcut doesn't have the startup directory + * configured explicitly. + */ + DEFAULT("true"); + + LauncherShortcutStartupDirectory(String stringValue) { + this.stringValue = Objects.requireNonNull(stringValue); + } + + public String asStringValue() { + return stringValue; + } + + private final String stringValue; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 95f16d09575..15d8d2f83b0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -24,24 +24,19 @@ */ package jdk.jpackage.internal; -import static java.util.stream.Collectors.toSet; import static jdk.jpackage.internal.BundlerParamInfo.createBooleanBundlerParam; import static jdk.jpackage.internal.BundlerParamInfo.createStringBundlerParam; import static jdk.jpackage.internal.FromParams.createApplicationBuilder; import static jdk.jpackage.internal.FromParams.createApplicationBundlerParam; import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; -import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT; +import static jdk.jpackage.internal.FromParams.findLauncherShortcut; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; -import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT; import static jdk.jpackage.internal.WinPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; -import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_DESKTOP; -import static jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut.WIN_SHORTCUT_START_MENU; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.UUID; import jdk.jpackage.internal.model.ConfigException; @@ -63,18 +58,11 @@ final class WinFromParams { final boolean isConsole = CONSOLE_HINT.findIn(launcherParams).orElse(false); - final var shortcuts = Map.of(WIN_SHORTCUT_DESKTOP, List.of(SHORTCUT_HINT, - WIN_SHORTCUT_HINT), WIN_SHORTCUT_START_MENU, List.of(MENU_HINT, - WIN_MENU_HINT)).entrySet().stream().filter(e -> { + final var startMenuShortcut = findLauncherShortcut(WIN_MENU_HINT, params, launcherParams); - final var shortcutParams = e.getValue(); + final var desktopShortcut = findLauncherShortcut(WIN_SHORTCUT_HINT, params, launcherParams); - return shortcutParams.get(0).findIn(launcherParams).orElseGet(() -> { - return shortcutParams.get(1).findIn(launcherParams).orElse(false); - }); - }).map(Map.Entry::getKey).collect(toSet()); - - return WinLauncher.create(launcher, new WinLauncherMixin.Stub(isConsole, shortcuts)); + return WinLauncher.create(launcher, new WinLauncherMixin.Stub(isConsole, startMenuShortcut, desktopShortcut)); }), APPLICATION_LAYOUT).create(); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 7e400c5be29..ea4d9eee19a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -25,12 +25,9 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.WinLauncher; -import jdk.jpackage.internal.model.WinMsiPackage; -import jdk.jpackage.internal.model.Launcher; -import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.util.PathGroup; +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.util.CollectionUtils.toCollection; + import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -50,7 +47,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; -import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -60,15 +56,19 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import static jdk.jpackage.internal.util.CollectionUtils.toCollection; -import jdk.jpackage.internal.model.WinLauncherMixin.WinShortcut; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherShortcut; +import jdk.jpackage.internal.model.WinLauncher; +import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.util.PathGroup; import jdk.jpackage.internal.util.PathUtils; -import jdk.jpackage.internal.util.XmlUtils; import jdk.jpackage.internal.util.XmlConsumer; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.NodeList; /** @@ -352,7 +352,7 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { private final Config cfg; private final Id id; - }; + } private static void addComponentGroup(XMLStreamWriter xml, String id, List componentIds) throws XMLStreamException, IOException { @@ -469,7 +469,18 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { launcher.executableNameWithSuffix()); if (folder.isRequestedFor(launcher)) { - String componentId = addShortcutComponent(xml, launcherPath, folder); + var workDirectory = folder.shortcut(launcher).startupDirectory().map(v -> { + switch (v) { + case DEFAULT -> { + return INSTALLDIR; + } + default -> { + throw new AssertionError(); + } + } + }).orElseThrow(); + + String componentId = addShortcutComponent(xml, launcherPath, folder, workDirectory); if (componentId != null) { Path folderPath = folder.getPath(this); @@ -499,23 +510,26 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { } private String addShortcutComponent(XMLStreamWriter xml, Path launcherPath, - ShortcutsFolder folder) throws XMLStreamException, IOException { + ShortcutsFolder folder, Path shortcutWorkDir) throws XMLStreamException, IOException { Objects.requireNonNull(folder); if (!INSTALLDIR.equals(launcherPath.getName(0))) { throw throwInvalidPathException(launcherPath); } + if (!INSTALLDIR.equals(shortcutWorkDir.getName(0))) { + throw throwInvalidPathException(shortcutWorkDir); + } + String launcherBasename = PathUtils.replaceSuffix( IOUtils.getFileName(launcherPath), "").toString(); Path shortcutPath = folder.getPath(this).resolve(launcherBasename); return addComponent(xml, shortcutPath, Component.Shortcut, unused -> { xml.writeAttribute("Name", launcherBasename); - xml.writeAttribute("WorkingDirectory", INSTALLDIR.toString()); + xml.writeAttribute("WorkingDirectory", Id.Folder.of(shortcutWorkDir)); xml.writeAttribute("Advertise", "no"); - xml.writeAttribute("Target", String.format("[#%s]", - Component.File.idOf(launcherPath))); + xml.writeAttribute("Target", String.format("[#%s]", Id.File.of(launcherPath))); }); } @@ -906,15 +920,15 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { } enum ShortcutsFolder { - ProgramMenu(PROGRAM_MENU_PATH, WinShortcut.WIN_SHORTCUT_START_MENU, + ProgramMenu(PROGRAM_MENU_PATH, WinLauncher::startMenuShortcut, "JP_INSTALL_STARTMENU_SHORTCUT", "JpStartMenuShortcutPrompt"), - Desktop(DESKTOP_PATH, WinShortcut.WIN_SHORTCUT_DESKTOP, + Desktop(DESKTOP_PATH, WinLauncher::desktopShortcut, "JP_INSTALL_DESKTOP_SHORTCUT", "JpDesktopShortcutPrompt"); - private ShortcutsFolder(Path root, WinShortcut shortcutId, + private ShortcutsFolder(Path root, Function> shortcut, String property, String wixVariableName) { this.root = root; - this.shortcutId = shortcutId; + this.shortcut = shortcut; this.wixVariableName = wixVariableName; this.property = property; } @@ -927,7 +941,11 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { } boolean isRequestedFor(WinLauncher launcher) { - return launcher.shortcuts().contains(shortcutId); + return LauncherShortcut.toRequest(shortcut.apply(launcher)).orElse(false); + } + + LauncherShortcut shortcut(WinLauncher launcher) { + return shortcut.apply(launcher).orElseThrow(); } String getWixVariableName() { @@ -947,7 +965,7 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { private final Path root; private final String property; private final String wixVariableName; - private final WinShortcut shortcutId; + private final Function> shortcut; } private boolean systemWide; diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java index b10ca99d483..3052029a33c 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncher.java @@ -24,9 +24,8 @@ */ package jdk.jpackage.internal.model; -import static java.util.stream.Collectors.toMap; - import java.io.InputStream; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import jdk.jpackage.internal.resources.ResourceLocator; @@ -47,10 +46,20 @@ public interface WinLauncher extends Launcher, WinLauncherMixin { @Override default Map extraAppImageFileData() { - return shortcuts().stream().collect(toMap(WinShortcut::name, v -> Boolean.toString(true))); + Map map = new HashMap<>(); + desktopShortcut().ifPresent(shortcut -> { + shortcut.store(SHORTCUT_DESKTOP_ID, map::put); + }); + startMenuShortcut().ifPresent(shortcut -> { + shortcut.store(SHORTCUT_START_MENU_ID, map::put); + }); + return map; } public static WinLauncher create(Launcher launcher, WinLauncherMixin mixin) { return CompositeProxy.create(WinLauncher.class, launcher, mixin); } + + public static final String SHORTCUT_START_MENU_ID = "win-menu"; + public static final String SHORTCUT_DESKTOP_ID = "win-shortcut"; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java index 65b6a1bab46..1762678434b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinLauncherMixin.java @@ -24,30 +24,37 @@ */ package jdk.jpackage.internal.model; -import java.util.Set; +import java.util.Optional; public interface WinLauncherMixin { boolean isConsole(); - enum WinShortcut { - WIN_SHORTCUT_DESKTOP("shortcut"), - WIN_SHORTCUT_START_MENU("menu"), - ; + /** + * Gets the start menu shortcut of this application launcher. + *

+ * Returns a non-empty {@link Optional} instance if a request about the start + * menu shortcut for this application launcher was made and an empty + * {@link Optional} instance if there was no request about the start menu + * shortcut for this application launcher. + * + * @return the start menu shortcut of this application launcher + */ + Optional startMenuShortcut(); - WinShortcut(String name) { - this.name = name; - } + /** + * Gets the desktop shortcut of this application launcher. + *

+ * Returns a non-empty {@link Optional} instance if a request about the desktop + * shortcut for this application launcher was made and an empty {@link Optional} + * instance if there was no request about the desktop shortcut for this + * application launcher. + * + * @return the start menu shortcut of this application launcher + */ + Optional desktopShortcut(); - public String getName() { - return name; - } - - private final String name; - } - - Set shortcuts(); - - record Stub(boolean isConsole, Set shortcuts) implements WinLauncherMixin { + record Stub(boolean isConsole, Optional startMenuShortcut, + Optional desktopShortcut) implements WinLauncherMixin { } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java index 5e86f975870..15bb3ea0333 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java @@ -92,7 +92,7 @@ public enum LauncherShortcut { } public String appImageFilePropertyName() { - return propertyName.substring(propertyName.indexOf('-') + 1); + return propertyName; } public String optionName() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index ceda32eb8ed..b3ed030c69d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -77,6 +77,11 @@ public final class LauncherVerifier { VERIFY_UNINSTALLED((verifier, cmd) -> { verifier.verifyInstalled(cmd, false); }), + VERIFY_APP_IMAGE_FILE((verifier, cmd) -> { + if (cmd.isImagePackageType()) { + verifier.verifyInAppImageFile(cmd); + } + }), EXECUTE_LAUNCHER(LauncherVerifier::executeLauncher), ; @@ -91,7 +96,7 @@ public final class LauncherVerifier { private final BiConsumer action; static final List VERIFY_APP_IMAGE = List.of( - VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED + VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED, VERIFY_APP_IMAGE_FILE ); static final List VERIFY_DEFAULTS = Stream.concat( @@ -279,6 +284,45 @@ public final class LauncherVerifier { } } + private void verifyInAppImageFile(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.IMAGE); + if (!isMainLauncher()) { + Stream shortcuts; + if (TKit.isWindows()) { + shortcuts = Stream.of(LauncherShortcut.WIN_DESKTOP_SHORTCUT, LauncherShortcut.WIN_START_MENU_SHORTCUT); + } else if (TKit.isLinux()) { + shortcuts = Stream.of(LauncherShortcut.LINUX_SHORTCUT); + } else { + shortcuts = Stream.of(); + } + + var aif = AppImageFile.load(cmd.outputBundle()); + var aifFileName = AppImageFile.getPathInAppImage(Path.of("")).getFileName(); + + var aifProps = Objects.requireNonNull(aif.addLaunchers().get(name)); + + shortcuts.forEach(shortcut -> { + var recordedShortcut = aifProps.get(shortcut.appImageFilePropertyName()); + properties.flatMap(props -> { + return props.findProperty(shortcut.propertyName()); + }).ifPresentOrElse(expectedShortcut -> { + TKit.assertNotNull(recordedShortcut, String.format( + "Check shortcut [%s] of launcher [%s] is recorded in %s file", + shortcut, name, aifFileName)); + TKit.assertEquals( + StartupDirectory.parse(expectedShortcut), + StartupDirectory.parse(recordedShortcut), + String.format("Check the value of shortcut [%s] of launcher [%s] recorded in %s file", + shortcut, name, aifFileName)); + }, () -> { + TKit.assertNull(recordedShortcut, String.format( + "Check shortcut [%s] of launcher [%s] is NOT recorded in %s file", + shortcut, name, aifFileName)); + }); + }); + } + } + private void executeLauncher(JPackageCommand cmd) throws IOException { Path launcherPath = cmd.appLauncherPath(name); From f83454cd61538b653656ccf81759b3cc7286ed67 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sat, 9 Aug 2025 02:00:58 +0000 Subject: [PATCH 027/471] 8364786: Test java/net/vthread/HttpALot.java intermittently fails - 24999 handled, expected 25000 Reviewed-by: dfuchs, alanb, vyazici --- test/jdk/java/net/vthread/HttpALot.java | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/test/jdk/java/net/vthread/HttpALot.java b/test/jdk/java/net/vthread/HttpALot.java index c016824a92a..6418e103a35 100644 --- a/test/jdk/java/net/vthread/HttpALot.java +++ b/test/jdk/java/net/vthread/HttpALot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -21,7 +21,7 @@ * questions. */ -/** +/* * @test * @bug 8284161 * @summary Stress test the HTTP protocol handler and HTTP server @@ -44,6 +44,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @@ -52,6 +53,8 @@ import jdk.test.lib.net.URIBuilder; public class HttpALot { + private static final String HELLO = "Hello"; + public static void main(String[] args) throws Exception { int requests = 25_000; if (args.length > 0) { @@ -65,12 +68,20 @@ public class HttpALot { InetAddress lb = InetAddress.getLoopbackAddress(); HttpServer server = HttpServer.create(new InetSocketAddress(lb, 0), 1024); ThreadFactory factory = Thread.ofVirtual().factory(); - server.setExecutor(Executors.newThreadPerTaskExecutor(factory)); + final ExecutorService serverExecutor = Executors.newThreadPerTaskExecutor(factory); + server.setExecutor(serverExecutor); server.createContext("/hello", e -> { - byte[] response = "Hello".getBytes("UTF-8"); - e.sendResponseHeaders(200, response.length); - try (OutputStream out = e.getResponseBody()) { - out.write(response); + try { + byte[] response = HELLO.getBytes("UTF-8"); + e.sendResponseHeaders(200, response.length); + try (OutputStream out = e.getResponseBody()) { + out.write(response); + } + } catch (Throwable t) { + System.err.println("failed to handle request " + e.getRequestURI() + + " due to: " + t); + t.printStackTrace(); + throw t; // let it propagate } requestsHandled.incrementAndGet(); }); @@ -85,15 +96,21 @@ public class HttpALot { // go server.start(); - try { - factory = Thread.ofVirtual().name("fetcher-", 0).factory(); - try (var executor = Executors.newThreadPerTaskExecutor(factory)) { - for (int i = 1; i <= requests; i++) { - executor.submit(() -> fetch(url)).get(); + try (serverExecutor) { + try { + factory = Thread.ofVirtual().name("fetcher-", 0).factory(); + try (var executor = Executors.newThreadPerTaskExecutor(factory)) { + for (int i = 1; i <= requests; i++) { + final String actual = executor.submit(() -> fetch(url)).get(); + if (!HELLO.equals(actual)) { + throw new RuntimeException("unexpected response: \"" + actual + + "\" for request " + i); + } + } } + } finally { + server.stop(1); } - } finally { - server.stop(1); } if (requestsHandled.get() < requests) { From e13b4c8de944ab14a1d12f6251e83f4fdd9e0198 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Sat, 9 Aug 2025 23:44:21 +0000 Subject: [PATCH 028/471] 8358535: Changes in ClassValue (JDK-8351996) caused a 1-9% regression in Renaissance-PageRank Reviewed-by: jrose, shade --- .../share/classes/java/lang/ClassValue.java | 3 + test/jdk/java/lang/invoke/ClassValueTest.java | 73 +++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/ClassValue.java b/src/java.base/share/classes/java/lang/ClassValue.java index dfbdf3c5bf8..2a133324fb5 100644 --- a/src/java.base/share/classes/java/lang/ClassValue.java +++ b/src/java.base/share/classes/java/lang/ClassValue.java @@ -476,6 +476,9 @@ public abstract class ClassValue { if (updated != entry) { put(classValue.identity, updated); } + // Add to the cache, to enable the fast path, next time. + checkCacheLoad(); + addToCache(classValue, updated); } return item; } diff --git a/test/jdk/java/lang/invoke/ClassValueTest.java b/test/jdk/java/lang/invoke/ClassValueTest.java index 856653b3f92..34f7af1a8a0 100644 --- a/test/jdk/java/lang/invoke/ClassValueTest.java +++ b/test/jdk/java/lang/invoke/ClassValueTest.java @@ -23,23 +23,23 @@ /* * @test - * @bug 8351045 8351996 - * @enablePreview - * @comment Remove preview if ScopedValue is finalized + * @bug 8351045 8351996 8358535 * @summary tests for class-specific values + * @modules java.base/java.lang:+open * @library /test/lib * @run junit ClassValueTest */ import java.lang.classfile.ClassFile; import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.ref.WeakReference; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; @@ -49,9 +49,7 @@ import java.util.concurrent.atomic.AtomicReference; import jdk.test.lib.util.ForceGC; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; import static org.junit.jupiter.api.Assertions.*; @@ -479,4 +477,67 @@ final class ClassValueTest { awaitThreads(t); assertEquals(42, clv.get(int.class), "slow computation reinstalled value"); } + + // ClassValue cache invalidated and not reinstated when another + // unrelated entry is removed + @Test + public void testCacheRefresh() throws Throwable { + // Setup + var lookup = MethodHandles.privateLookupIn(ClassValue.class, MethodHandles.lookup()); + var classValueEntryClass = Class.forName("java.lang.ClassValue$Entry"); + MethodHandle getCacheCarefully = lookup.findStatic(ClassValue.class, "getCacheCarefully", + MethodType.methodType(classValueEntryClass.arrayType(), Class.class)); + var classValueMapClass = Class.forName("java.lang.ClassValue$ClassValueMap"); + MethodHandle probeHomeLocation = lookup.findStatic(classValueMapClass, "probeHomeLocation", + MethodType.methodType(classValueEntryClass, classValueEntryClass.arrayType(), ClassValue.class)); + MethodHandle match = lookup.findVirtual(ClassValue.class, "match", + MethodType.methodType(boolean.class, classValueEntryClass)); + + // Work + ClassValue clv = new ClassValue<>() { + @Override + protected String computeValue(Class type) { + return ""; + } + }; + // A class that shouldn't have arbitrary values stuffing the cache + var cleanClass = clv.getClass(); + clv.get(cleanClass); // create cache on clean class + assertTrue(checkDirectCacheMatch( + getCacheCarefully, + probeHomeLocation, + match, + clv, + cleanClass + )); + clv.get(int.class); + clv.remove(int.class); // invalidate cache on clean class + assertFalse(checkDirectCacheMatch( + getCacheCarefully, + probeHomeLocation, + match, + clv, + cleanClass + )); + clv.get(cleanClass); + assertTrue(checkDirectCacheMatch( + getCacheCarefully, + probeHomeLocation, + match, + clv, + cleanClass + )); + } + + private static boolean checkDirectCacheMatch( + MethodHandle getCacheCarefully, + MethodHandle probeHomeLocation, + MethodHandle match, + ClassValue clv, + Class cl + ) throws Throwable { + Object cache = getCacheCarefully.invoke(cl); + Object entry = probeHomeLocation.invoke(cache, clv); + return (boolean) match.invoke(clv, entry); + } } From 022e29a77533aacabd56820d00ecffa9646a8362 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sun, 10 Aug 2025 04:22:10 +0000 Subject: [PATCH 029/471] 8365086: CookieStore.getURIs() and get(URI) should return an immutable List Reviewed-by: liach, vyazici, dfuchs --- .../classes/java/net/InMemoryCookieStore.java | 18 +-- test/jdk/java/net/CookieStoreTest.java | 113 ++++++++++++++++++ 2 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/net/CookieStoreTest.java diff --git a/src/java.base/share/classes/java/net/InMemoryCookieStore.java b/src/java.base/share/classes/java/net/InMemoryCookieStore.java index 0ce3dc5b68c..1c72549e37d 100644 --- a/src/java.base/share/classes/java/net/InMemoryCookieStore.java +++ b/src/java.base/share/classes/java/net/InMemoryCookieStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -25,10 +25,6 @@ package java.net; -import java.net.URI; -import java.net.CookieStore; -import java.net.HttpCookie; -import java.net.URISyntaxException; import java.util.List; import java.util.Map; import java.util.ArrayList; @@ -72,6 +68,7 @@ class InMemoryCookieStore implements CookieStore { /** * Add one cookie into cookie store. */ + @Override public void add(URI uri, HttpCookie cookie) { // pre-condition : argument can't be null if (cookie == null) { @@ -109,6 +106,7 @@ class InMemoryCookieStore implements CookieStore { * 3) not expired. * See RFC 2965 sec. 3.3.4 for more detail. */ + @Override public List get(URI uri) { // argument can't be null if (uri == null) { @@ -127,12 +125,13 @@ class InMemoryCookieStore implements CookieStore { lock.unlock(); } - return cookies; + return Collections.unmodifiableList(cookies); } /** * Get all cookies in cookie store, except those have expired */ + @Override public List getCookies() { List rt; @@ -156,6 +155,7 @@ class InMemoryCookieStore implements CookieStore { * Get all URIs, which are associated with at least one cookie * of this cookie store. */ + @Override public List getURIs() { List uris = new ArrayList<>(); @@ -165,7 +165,7 @@ class InMemoryCookieStore implements CookieStore { while (it.hasNext()) { URI uri = it.next(); List cookies = uriIndex.get(uri); - if (cookies == null || cookies.size() == 0) { + if (cookies == null || cookies.isEmpty()) { // no cookies list or an empty list associated with // this uri entry, delete it it.remove(); @@ -176,13 +176,14 @@ class InMemoryCookieStore implements CookieStore { lock.unlock(); } - return uris; + return Collections.unmodifiableList(uris); } /** * Remove a cookie from store */ + @Override public boolean remove(URI uri, HttpCookie ck) { // argument can't be null if (ck == null) { @@ -204,6 +205,7 @@ class InMemoryCookieStore implements CookieStore { /** * Remove all cookies in this cookie store. */ + @Override public boolean removeAll() { lock.lock(); try { diff --git a/test/jdk/java/net/CookieStoreTest.java b/test/jdk/java/net/CookieStoreTest.java new file mode 100644 index 00000000000..50a5ab3fac1 --- /dev/null +++ b/test/jdk/java/net/CookieStoreTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.CookieManager; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* + * @test + * @bug 8365086 + * @summary verify that the implementation of java.net.CookieStore works + * as expected + * @run junit CookieStoreTest + */ +class CookieStoreTest { + + // neither the scheme, host nor the port matters in this test + private static final URI COOKIE_TEST_URI = URI.create("https://127.0.0.1:12345"); + + static List cookieStores() { + final List params = new ArrayList<>(); + // empty CookieStore + params.add(Arguments.of(new CookieManager().getCookieStore(), true)); + + final CookieStore cookieStore = new CookieManager().getCookieStore(); + cookieStore.add(COOKIE_TEST_URI, new HttpCookie("foo", "bar")); + // non-empty CookieStore + params.add(Arguments.of(cookieStore, false)); + + return params; + } + + /* + * Verify that the List returned by CookieStore.getURIs() is immutable. + */ + @ParameterizedTest + @MethodSource("cookieStores") + void testImmutableGetURIs(final CookieStore cookieStore, final boolean expectEmpty) { + final List uris = cookieStore.getURIs(); + assertNotNull(uris, "CookieStore.getURIs() returned null"); + assertEquals(expectEmpty, uris.isEmpty(), "CookieStore.getURIs() returned: " + uris); + assertImmutableList(uris, COOKIE_TEST_URI); + } + + /* + * Verify that the List returned by CookieStore.getCookies() is immutable. + */ + @ParameterizedTest + @MethodSource("cookieStores") + void testImmutableGetCookies(final CookieStore cookieStore, final boolean expectEmpty) { + final List cookies = cookieStore.getCookies(); + assertNotNull(cookies, "CookieStore.getCookies() returned null"); + assertEquals(expectEmpty, cookies.isEmpty(), "CookieStore.getCookies() returned: " + cookies); + assertImmutableList(cookies, new HttpCookie("hello", "world")); + } + + /* + * Verify that the List returned by CookieStore.get(URI) is immutable. + */ + @ParameterizedTest + @MethodSource("cookieStores") + void testImmutableGetCookiesForURI(final CookieStore cookieStore, final boolean expectEmpty) { + final List cookies = cookieStore.get(COOKIE_TEST_URI); + assertNotNull(cookies, "CookieStore.get(URI) returned null"); + assertEquals(expectEmpty, cookies.isEmpty(), "CookieStore.get(URI) returned: " + cookies); + assertImmutableList(cookies, new HttpCookie("hello", "world")); + } + + /* + * Verifies that the attempt to modify the contents of the list will fail + * due to the list being immutable. + */ + private static void assertImmutableList(final List list, T elementToAddOrRemove) { + // the list is expected to be immutable, so each of these operations must fail + assertThrows(UnsupportedOperationException.class, () -> list.add(elementToAddOrRemove)); + assertThrows(UnsupportedOperationException.class, () -> list.remove(elementToAddOrRemove)); + assertThrows(UnsupportedOperationException.class, list::clear); + // even try the replace operation when the list isn't empty + if (!list.isEmpty()) { + assertThrows(UnsupportedOperationException.class, () -> list.set(0, elementToAddOrRemove)); + } + } +} From 15e8609a2c3d246e89cfb349cbd21777bc471bae Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 11 Aug 2025 07:08:03 +0000 Subject: [PATCH 030/471] 8364996: java/awt/font/FontNames/LocaleFamilyNames.java times out on Windows Reviewed-by: clanger, prr, asteiner --- .../java/awt/font/FontNames/LocaleFamilyNames.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/awt/font/FontNames/LocaleFamilyNames.java b/test/jdk/java/awt/font/FontNames/LocaleFamilyNames.java index 5356464334e..0fc27ea3de0 100644 --- a/test/jdk/java/awt/font/FontNames/LocaleFamilyNames.java +++ b/test/jdk/java/awt/font/FontNames/LocaleFamilyNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -26,29 +26,32 @@ * @bug 4935798 6521210 6901159 * @summary Tests that all family names that are reported in all locales * correspond to some font returned from getAllFonts(). - * @run main LocaleFamilyNames + * @run main/othervm/timeout=360 LocaleFamilyNames */ import java.awt.*; import java.util.*; public class LocaleFamilyNames { public static void main(String[] args) throws Exception { + System.out.println("Start time: " + java.time.LocalDateTime.now()); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Font[] all_fonts = ge.getAllFonts(); - Locale[] all_locales = Locale.getAvailableLocales(); + System.out.println("Number of fonts: " + all_fonts.length); + System.out.println("Number of locales: " + all_locales.length); + HashSet all_families = new HashSet(); for (int i=0; i Date: Mon, 11 Aug 2025 07:10:38 +0000 Subject: [PATCH 031/471] 8364365: HKSCS encoder does not properly set the replacement character Reviewed-by: sherman --- .../share/classes/sun/nio/cs/HKSCS.java | 13 +- .../sun/nio/cs/TestEncoderReplaceLatin1.java | 229 ++++++++++++++++++ .../sun/nio/cs/TestEncoderReplaceUTF16.java | 205 ++++++++++++++++ 3 files changed, 436 insertions(+), 11 deletions(-) create mode 100644 test/jdk/sun/nio/cs/TestEncoderReplaceLatin1.java create mode 100644 test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java diff --git a/src/java.base/share/classes/sun/nio/cs/HKSCS.java b/src/java.base/share/classes/sun/nio/cs/HKSCS.java index 04bbd386a31..cfe9f879c04 100644 --- a/src/java.base/share/classes/sun/nio/cs/HKSCS.java +++ b/src/java.base/share/classes/sun/nio/cs/HKSCS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -28,12 +28,9 @@ package sun.nio.cs; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.util.Arrays; -import sun.nio.cs.DoubleByte; -import sun.nio.cs.Surrogate; + import static sun.nio.cs.CharsetMapping.*; public class HKSCS { @@ -355,12 +352,6 @@ public class HKSCS { return encodeBufferLoop(src, dst); } - @SuppressWarnings("this-escape") - private byte[] repl = replacement(); - protected void implReplaceWith(byte[] newReplacement) { - repl = newReplacement; - } - public int encode(char[] src, int sp, int len, byte[] dst) { int dp = 0; int sl = sp + len; diff --git a/test/jdk/sun/nio/cs/TestEncoderReplaceLatin1.java b/test/jdk/sun/nio/cs/TestEncoderReplaceLatin1.java new file mode 100644 index 00000000000..401f3650734 --- /dev/null +++ b/test/jdk/sun/nio/cs/TestEncoderReplaceLatin1.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import sun.nio.cs.ArrayEncoder; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8364365 + * @summary Verifies `CodingErrorAction.REPLACE` behaviour of all available + * character set encoders while encoding a Latin-1 character + * @modules java.base/jdk.internal.access + * java.base/sun.nio.cs + * @run junit TestEncoderReplaceLatin1 + */ + +class TestEncoderReplaceLatin1 { + + static Collection charsets() { + return Charset.availableCharsets().values(); + } + + @ParameterizedTest + @MethodSource("charsets") + void testEncoderReplace(Charset charset) { + + // Create an encoder + CharsetEncoder encoder = createEncoder(charset); + if (encoder == null) { + return; + } + + // Find an unmappable character to test the `REPLACE` action. + char[] unmappable = findUnmappable(encoder); + if (unmappable == null) { + return; + } + + // Configure the `REPLACE` action + byte[] replacement = findCustomReplacement(encoder, new byte[]{(byte) unmappable[0]}); + if (replacement == null) { + return; + } + encoder.onUnmappableCharacter(CodingErrorAction.REPLACE).replaceWith(replacement); + + // Verify the replacement + System.err.println("Verifying replacement... " + Map.of( + "unmappable", TestEncoderReplaceLatin1.prettyPrintChars(unmappable), + "replacement", TestEncoderReplaceLatin1.prettyPrintBytes(replacement))); + testCharsetEncoderReplace(encoder, unmappable, replacement); + testArrayEncoderLatin1Replace(encoder, unmappable[0], replacement); + + } + + private static CharsetEncoder createEncoder(Charset charset) { + try { + return charset.newEncoder(); + } catch (UnsupportedOperationException _) { + System.err.println("Could not create the character encoder!"); + } + return null; + } + + private static char[] findUnmappable(CharsetEncoder encoder) { + char[] unmappable1 = {0}; + for (char c = 0; c < 0xFF; c++) { + unmappable1[0] = c; + boolean unmappable = !encoder.canEncode(c); + if (unmappable) { + return unmappable1; + } + } + System.err.println("Could not find an unmappable character!"); + return null; + } + + /** + * Finds a {@linkplain CharsetEncoder#replacement() replacement} which is + * different from the given unmappable and the default one. + */ + static byte[] findCustomReplacement(CharsetEncoder encoder, byte[] unmappable) { + + // Obtain the default replacement + byte[] replacementD = encoder.replacement(); + + // Try to find a single-byte replacement + byte[] replacement1 = {0}; + for (int i = 0; i < 0xFF; i++) { + // Skip if the replacement is equal to the unmappable. + // They need to be distinct to be able to determine whether the replacement has occurred. + if (unmappable[0] == i) { + continue; + } + replacement1[0] = (byte) i; + // Skip the default value, since we're verifying if a custom one works + if (replacement1[0] == replacementD[0]) { + continue; + } + if (encoder.isLegalReplacement(replacement1)) { + return replacement1; + } + } + + // Try to find a double-byte replacement + byte[] replacement2 = {0, 0}; + for (int i = 0; i < 0xFF; i++) { + // Skip if the replacement is equal to the unmappable. + // They need to be distinct to be able to determine whether the replacement has occurred. + if (unmappable[0] == i) { + continue; + } + replacement2[0] = (byte) i; + for (int j = 0; j < 0xFF; j++) { + // Skip if the replacement is equal to the unmappable. + // They need to be distinct to be able to determine whether the replacement has occurred. + if (unmappable.length > 1 && unmappable[1] == j) { + continue; + } + replacement2[1] = (byte) j; + // Skip the default value, since we're verifying if a custom one works + if (replacementD.length > 1 && replacement2[1] == replacementD[1]) { + continue; + } + if (encoder.isLegalReplacement(replacement2)) { + return replacement2; + } + } + } + + System.err.println("Could not find a replacement!"); + return null; + + } + + /** + * Verifies {@linkplain CoderResult#isUnmappable() unmappable} character + * {@linkplain CodingErrorAction#REPLACE replacement} using {@link + * CharsetEncoder#encode(CharBuffer, ByteBuffer, boolean) + * CharsetEncoder::encode}. + */ + static void testCharsetEncoderReplace(CharsetEncoder encoder, char[] unmappable, byte[] replacement) { + CharBuffer charBuffer = CharBuffer.wrap(unmappable); + ByteBuffer byteBuffer = ByteBuffer.allocate(replacement.length); + CoderResult coderResult = encoder.encode(charBuffer, byteBuffer, true); + assertArrayEquals(replacement, byteBuffer.array(), () -> { + Object context = Map.of( + "coderResult", coderResult, + "byteBuffer.position()", byteBuffer.position(), + "byteBuffer.array()", prettyPrintBytes(byteBuffer.array()), + "unmappable", prettyPrintChars(unmappable), + "replacement", prettyPrintBytes(replacement)); + return "Unexpected `CharsetEncoder::encode` output! " + context; + }); + } + + /** + * Verifies {@linkplain CoderResult#isUnmappable() unmappable} character + * {@linkplain CodingErrorAction#REPLACE replacement} using {@link + * ArrayEncoder#encodeFromLatin1(byte[], int, int, byte[]) + * ArrayEncoder::encodeFromLatin1}. + */ + private static void testArrayEncoderLatin1Replace(CharsetEncoder encoder, char unmappable, byte[] replacement) { + if (!(encoder instanceof ArrayEncoder arrayEncoder)) { + System.err.println("Encoder is not of type `ArrayEncoder`, skipping the `ArrayEncoder::encodeFromLatin1` test."); + return; + } + byte[] sa = {(byte) unmappable}; + byte[] da = new byte[replacement.length]; + int dp = arrayEncoder.encodeFromLatin1(sa, 0, 1, da); + assertTrue(dp == replacement.length && Arrays.equals(da, replacement), () -> { + Object context = Map.of( + "dp", dp, + "da", prettyPrintBytes(da), + "sa", prettyPrintBytes(sa), + "unmappable", prettyPrintChars(new char[]{unmappable}), + "replacement", prettyPrintBytes(replacement)); + return "Unexpected `ArrayEncoder::encodeFromLatin1` output! " + context; + }); + } + + static String prettyPrintChars(char[] cs) { + return IntStream.range(0, cs.length) + .mapToObj(i -> String.format("U+%04X", (int) cs[i])) + .collect(Collectors.joining(", ", "[", "]")); + } + + static String prettyPrintBytes(byte[] bs) { + return IntStream.range(0, bs.length) + .mapToObj(i -> String.format("0x%02X", bs[i] & 0xFF)) + .collect(Collectors.joining(", ", "[", "]")); + } + +} diff --git a/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java new file mode 100644 index 00000000000..c61e85d6698 --- /dev/null +++ b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import sun.nio.cs.ArrayEncoder; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8364365 + * @summary Verifies `CodingErrorAction.REPLACE` behaviour of all available + * character set encoders while encoding a UTF-16 character + * @modules java.base/jdk.internal.access + * java.base/sun.nio.cs + * @build TestEncoderReplaceLatin1 + * @run junit/timeout=10 TestEncoderReplaceUTF16 + * @run junit/timeout=10/othervm -XX:-CompactStrings TestEncoderReplaceUTF16 + */ + +class TestEncoderReplaceUTF16 { + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + /** + * Character sets known to be absent of non-Latin-1 {@linkplain CoderResult#isUnmappable() unmappable} characters. + */ + private static final Set CHARSETS_WITHOUT_UNMAPPABLE = Set.of( + "CESU-8", + "EUC-JP", + "GB18030", + "ISO-2022-JP", + "ISO-2022-JP-2", + "ISO-2022-KR", + "ISO-8859-1", + "US-ASCII", + "UTF-16", + "UTF-16BE", + "UTF-16LE", + "UTF-32", + "UTF-32BE", + "UTF-32LE", + "UTF-8", + "x-euc-jp-linux", + "x-EUC-TW", + "x-eucJP-Open", + "x-IBM29626C", + "x-IBM33722", + "x-IBM964", + "x-ISCII91", + "x-ISO-2022-CN-CNS", + "x-ISO-2022-CN-GB", + "x-MS932_0213", + "x-SJIS_0213", + "x-UTF-16LE-BOM", + "X-UTF-32BE-BOM", + "X-UTF-32LE-BOM", + "x-windows-50220", + "x-windows-50221", + "x-windows-iso2022jp"); + + @ParameterizedTest + @MethodSource("TestEncoderReplaceLatin1#charsets") + void testEncoderReplace(Charset charset) { + + // Create an encoder + CharsetEncoder encoder = createEncoder(charset); + if (encoder == null) { + return; + } + + // Find an unmappable character to test the `REPLACE` action. + char[] unmappable = findUnmappableNonLatin1(encoder); + if (unmappable == null) { + return; + } + + // Configure the `REPLACE` action + byte[] unmappableUTF16Bytes = utf16Bytes(unmappable); + byte[] replacement = TestEncoderReplaceLatin1.findCustomReplacement(encoder, unmappableUTF16Bytes); + if (replacement == null) { + return; + } + encoder.onUnmappableCharacter(CodingErrorAction.REPLACE).replaceWith(replacement); + + // Verify the replacement + System.err.println("Verifying replacement... " + Map.of( + "unmappable", TestEncoderReplaceLatin1.prettyPrintChars(unmappable), + "unmappableUTF16Bytes", TestEncoderReplaceLatin1.prettyPrintBytes(unmappableUTF16Bytes), + "replacement", TestEncoderReplaceLatin1.prettyPrintBytes(replacement))); + TestEncoderReplaceLatin1.testCharsetEncoderReplace(encoder, unmappable, replacement); + testArrayEncoderUTF16Replace(encoder, unmappableUTF16Bytes, replacement); + + } + + private static CharsetEncoder createEncoder(Charset charset) { + try { + return charset.newEncoder(); + } catch (UnsupportedOperationException _) { + System.err.println("Could not create the character encoder!"); + } + return null; + } + + /** + * Finds an {@linkplain CoderResult#isUnmappable() unmappable} non-Latin-1 {@code char[]} for the given encoder. + */ + private static char[] findUnmappableNonLatin1(CharsetEncoder encoder) { + + // Fast-path for characters sets known to be absent of unmappable non-Latin-1 characters + if (CHARSETS_WITHOUT_UNMAPPABLE.contains(encoder.charset().name())) { + System.err.println("Character set is known to be absent of unmappable non-Latin-1 characters!"); + return null; + } + + // Try to find a single-`char` unmappable + for (int i = 0xFF; i <= 0xFFFF; i++) { + char c = (char) i; + // Skip the surrogate, as a single dangling surrogate `char` should + // trigger a "malformed" error, instead of "unmappable" + if (Character.isSurrogate(c)) { + continue; + } + boolean unmappable = !encoder.canEncode(c); + if (unmappable) { + return new char[]{c}; + } + } + + // Try to find a double-`char` (i.e., surrogate pair) unmappable + int[] nonBmpRange = {0x10000, 0x10FFFF}; + for (int i = nonBmpRange[0]; i < nonBmpRange[1]; i++) { + char[] cs = Character.toChars(i); + if (!encoder.canEncode(new String(cs))) + return cs; + } + + System.err.println("Could not find an unmappable character!"); + return null; + } + + private static byte[] utf16Bytes(char[] cs) { + int sl = cs.length; + byte[] sa = new byte[sl << 1]; + for (int i = 0; i < sl; i++) { + JLA.uncheckedPutCharUTF16(sa, i, cs[i]); + } + return sa; + } + + /** + * Verifies {@linkplain CoderResult#isUnmappable() unmappable} character + * {@linkplain CodingErrorAction#REPLACE replacement} using {@link + * ArrayEncoder#encodeFromUTF16(byte[], int, int, byte[]) + * ArrayEncoder::encodeFromUTF16}. + */ + private static void testArrayEncoderUTF16Replace(CharsetEncoder encoder, byte[] unmappableUTF16Bytes, byte[] replacement) { + if (!(encoder instanceof ArrayEncoder arrayEncoder)) { + System.err.println("Encoder is not of type `ArrayEncoder`, skipping the `ArrayEncoder::encodeFromUTF16` test."); + return; + } + byte[] da = new byte[replacement.length]; + int dp = arrayEncoder.encodeFromUTF16(unmappableUTF16Bytes, 0, unmappableUTF16Bytes.length >>> 1, da); + assertTrue(dp == replacement.length && Arrays.equals(da, replacement), () -> { + Object context = Map.of( + "dp", dp, + "da", TestEncoderReplaceLatin1.prettyPrintBytes(da), + "unmappableUTF16Bytes", TestEncoderReplaceLatin1.prettyPrintBytes(unmappableUTF16Bytes), + "replacement", TestEncoderReplaceLatin1.prettyPrintBytes(replacement)); + return "Unexpected `ArrayEncoder::encodeFromUTF16` output! " + context; + }); + } + +} From f28126ebc2f792f0d64bbe6e841d9fafb433b7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 11 Aug 2025 08:18:28 +0000 Subject: [PATCH 032/471] 8365050: Too verbose warning in os::commit_memory_limit() on Windows Reviewed-by: dholmes, mbaesken --- src/hotspot/os/windows/os_windows.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index f5067757125..ffa22bd0365 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3297,13 +3297,28 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi } size_t os::commit_memory_limit() { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; - BOOL res = QueryInformationJobObject(nullptr, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli), nullptr); - + BOOL is_in_job_object = false; + BOOL res = IsProcessInJob(GetCurrentProcess(), nullptr, &is_in_job_object); if (!res) { char buf[512]; size_t buf_len = os::lasterror(buf, sizeof(buf)); - warning("Attempt to query job object information failed: %s", buf_len != 0 ? buf : ""); + warning("Attempt to determine whether the process is running in a job failed for commit limit: %s", buf_len != 0 ? buf : ""); + + // Conservatively assume no limit when there was an error calling IsProcessInJob. + return SIZE_MAX; + } + + if (!is_in_job_object) { + // Not limited by a Job Object + return SIZE_MAX; + } + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; + res = QueryInformationJobObject(nullptr, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli), nullptr); + if (!res) { + char buf[512]; + size_t buf_len = os::lasterror(buf, sizeof(buf)); + warning("Attempt to query job object information failed for commit limit: %s", buf_len != 0 ? buf : ""); // Conservatively assume no limit when there was an error calling QueryInformationJobObject. return SIZE_MAX; From 10762d408bba9ce0945100847a8674e7eb7fa75e Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Mon, 11 Aug 2025 08:19:02 +0000 Subject: [PATCH 033/471] 8365044: Missing copyright header in Contextual.java Reviewed-by: egahlin --- .../share/classes/jdk/jfr/Contextual.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Contextual.java b/src/jdk.jfr/share/classes/jdk/jfr/Contextual.java index 92deeb8d562..e1cf0544e6c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Contextual.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Contextual.java @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package jdk.jfr; import java.lang.annotation.ElementType; From 0c39228ec1c8c6eadafb54567c94ad5f19f27f7a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 11 Aug 2025 09:42:12 +0000 Subject: [PATCH 034/471] 8364767: G1: Remove use of CollectedHeap::_soft_ref_policy Reviewed-by: tschatzl, sangheki --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 8 +------- src/hotspot/share/gc/g1/g1FullGCScope.cpp | 6 +----- src/hotspot/share/gc/g1/g1FullGCScope.hpp | 4 ++-- src/hotspot/share/gc/g1/g1VMOperations.cpp | 4 +++- src/hotspot/share/gc/shared/softRefPolicy.hpp | 17 ----------------- src/hotspot/share/prims/whitebox.cpp | 6 ------ 6 files changed, 7 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index b9b12f628eb..e5266a527f0 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -848,12 +848,9 @@ void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs, size_t allocation_word_size) { assert_at_safepoint_on_vm_thread(); - const bool do_clear_all_soft_refs = clear_all_soft_refs || - soft_ref_policy()->should_clear_all_soft_refs(); - G1FullGCMark gc_mark; GCTraceTime(Info, gc) tm("Pause Full", nullptr, gc_cause(), true); - G1FullCollector collector(this, do_clear_all_soft_refs, do_maximal_compaction, gc_mark.tracer()); + G1FullCollector collector(this, clear_all_soft_refs, do_maximal_compaction, gc_mark.tracer()); collector.prepare_collection(); collector.collect(); @@ -986,9 +983,6 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { return result; } - assert(!soft_ref_policy()->should_clear_all_soft_refs(), - "Flag should have been handled and cleared prior to this point"); - // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.cpp b/src/hotspot/share/gc/g1/g1FullGCScope.cpp index 5879442b82b..8b92d51a8a3 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.cpp @@ -40,6 +40,7 @@ G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, bool do_maximal_compaction, G1FullGCTracer* tracer) : _rm(), + _should_clear_soft_refs(clear_soft), _do_maximal_compaction(do_maximal_compaction), _g1h(G1CollectedHeap::heap()), _svc_marker(SvcGCMarker::FULL), @@ -47,17 +48,12 @@ G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, _tracer(tracer), _active(), _tracer_mark(&_timer, _tracer), - _soft_refs(clear_soft, _g1h->soft_ref_policy()), _monitoring_scope(monitoring_support), _heap_printer(_g1h), _region_compaction_threshold(do_maximal_compaction ? G1HeapRegion::GrainWords : (1 - MarkSweepDeadRatio / 100.0) * G1HeapRegion::GrainWords) { } -bool G1FullGCScope::should_clear_soft_refs() { - return _soft_refs.should_clear(); -} - STWGCTimer* G1FullGCScope::timer() { return &_timer; } diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.hpp b/src/hotspot/share/gc/g1/g1FullGCScope.hpp index f7362d20d4f..ab5a48f3574 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.hpp @@ -47,6 +47,7 @@ public: // Class used to group scoped objects used in the Full GC together. class G1FullGCScope : public StackObj { ResourceMark _rm; + bool _should_clear_soft_refs; bool _do_maximal_compaction; G1CollectedHeap* _g1h; SvcGCMarker _svc_marker; @@ -54,7 +55,6 @@ class G1FullGCScope : public StackObj { G1FullGCTracer* _tracer; IsSTWGCActiveMark _active; G1FullGCJFRTracerMark _tracer_mark; - ClearedAllSoftRefs _soft_refs; G1FullGCMonitoringScope _monitoring_scope; G1HeapPrinterMark _heap_printer; size_t _region_compaction_threshold; @@ -65,7 +65,7 @@ public: bool do_maximal_compaction, G1FullGCTracer* tracer); - bool should_clear_soft_refs(); + bool should_clear_soft_refs() const { return _should_clear_soft_refs; } bool do_maximal_compaction() { return _do_maximal_compaction; } STWGCTimer* timer(); diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 6ddeba3d2e2..6757172b625 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -50,7 +50,9 @@ bool VM_G1CollectFull::skip_operation() const { void VM_G1CollectFull::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); GCCauseSetter x(g1h, _gc_cause); - g1h->do_full_collection(false /* clear_all_soft_refs */, + bool clear_all_soft_refs = _gc_cause == GCCause::_metadata_GC_clear_soft_refs || + _gc_cause == GCCause::_wb_full_gc; + g1h->do_full_collection(clear_all_soft_refs /* clear_all_soft_refs */, false /* do_maximal_compaction */, size_t(0) /* allocation_word_size */); } diff --git a/src/hotspot/share/gc/shared/softRefPolicy.hpp b/src/hotspot/share/gc/shared/softRefPolicy.hpp index b725b843d2d..fe2706288f7 100644 --- a/src/hotspot/share/gc/shared/softRefPolicy.hpp +++ b/src/hotspot/share/gc/shared/softRefPolicy.hpp @@ -58,21 +58,4 @@ class SoftRefPolicy { } }; -class ClearedAllSoftRefs : public StackObj { - bool _clear_all_soft_refs; - SoftRefPolicy* _soft_ref_policy; - public: - ClearedAllSoftRefs(bool clear_all_soft_refs, SoftRefPolicy* soft_ref_policy) : - _clear_all_soft_refs(clear_all_soft_refs), - _soft_ref_policy(soft_ref_policy) {} - - ~ClearedAllSoftRefs() { - if (_clear_all_soft_refs) { - _soft_ref_policy->cleared_all_soft_refs(); - } - } - - bool should_clear() { return _clear_all_soft_refs; } -}; - #endif // SHARE_GC_SHARED_SOFTREFPOLICY_HPP diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index be5d9d3d8a1..68fab39b23a 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1502,12 +1502,6 @@ WB_END WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true); Universe::heap()->collect(GCCause::_wb_full_gc); -#if INCLUDE_G1GC - if (UseG1GC) { - // Needs to be cleared explicitly for G1 GC. - Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(false); - } -#endif // INCLUDE_G1GC WB_END WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o)) From 1fc0b01601af454a0e871afce8ae0c9da1358f13 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 11 Aug 2025 09:44:49 +0000 Subject: [PATCH 035/471] 8361142: Improve custom hooks for makefiles Reviewed-by: erikj --- make/CompileJavaModules.gmk | 2 +- make/CreateJmods.gmk | 2 +- make/Images.gmk | 1 + make/Main.gmk | 2 +- make/MainSupport.gmk | 2 +- make/ModuleWrapper.gmk | 17 +++++++++++------ make/common/JavaCompilation.gmk | 6 +++++- make/common/Modules.gmk | 20 +++++++++++++++++--- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 1e26fb2b529..c6e8fab3038 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -85,7 +85,7 @@ CreateHkTargets = \ ################################################################################ # Include module specific build settings -THIS_SNIPPET := modules/$(MODULE)/Java.gmk +THIS_SNIPPET := $(call GetModuleSnippetName, Java) ifneq ($(wildcard $(THIS_SNIPPET)), ) include MakeSnippetStart.gmk diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index 40bceda69a9..a26042fb0d5 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -184,7 +184,7 @@ endif ################################################################################ # Include module specific build settings -THIS_SNIPPET := modules/$(MODULE)/Jmod.gmk +THIS_SNIPPET := $(call GetModuleSnippetName, Jmod) ifneq ($(wildcard $(THIS_SNIPPET)), ) include MakeSnippetStart.gmk diff --git a/make/Images.gmk b/make/Images.gmk index 22e3e43cb1f..34d81081d29 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -270,6 +270,7 @@ endif # Since debug symbols are not included in the jmod files, they need to be copied # in manually after generating the images. +# These variables are read by SetupCopyDebuginfo ALL_JDK_MODULES := $(JDK_MODULES) ALL_JRE_MODULES := $(sort $(JRE_MODULES), $(foreach m, $(JRE_MODULES), \ $(call FindTransitiveDepsForModule, $m))) diff --git a/make/Main.gmk b/make/Main.gmk index d9433e722f0..e9f0b5bb9eb 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -1407,7 +1407,7 @@ CLEAN_SUPPORT_DIRS += demos CLEAN_SUPPORT_DIR_TARGETS := $(addprefix clean-, $(CLEAN_SUPPORT_DIRS)) CLEAN_TESTS += hotspot-jtreg-native jdk-jtreg-native lib CLEAN_TEST_TARGETS += $(addprefix clean-test-, $(CLEAN_TESTS)) -CLEAN_PHASES := gensrc java native include +CLEAN_PHASES += gensrc java native include CLEAN_PHASE_TARGETS := $(addprefix clean-, $(CLEAN_PHASES)) CLEAN_MODULE_TARGETS := $(addprefix clean-, $(ALL_MODULES)) # Construct targets of the form clean-$module-$phase diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk index d8dc894c1e9..ee5bb324f8f 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -149,7 +149,7 @@ endef ################################################################################ -PHASE_MAKEDIRS := $(TOPDIR)/make +PHASE_MAKEDIRS += $(TOPDIR)/make # Helper macro for DeclareRecipesForPhase # Declare a recipe for calling the module and phase specific makefile. diff --git a/make/ModuleWrapper.gmk b/make/ModuleWrapper.gmk index b3ddf940e00..2db77b9ea32 100644 --- a/make/ModuleWrapper.gmk +++ b/make/ModuleWrapper.gmk @@ -34,18 +34,23 @@ include MakeFileStart.gmk ################################################################################ include CopyFiles.gmk +include Modules.gmk MODULE_SRC := $(TOPDIR)/src/$(MODULE) -# Define the snippet for MakeSnippetStart/End -THIS_SNIPPET := modules/$(MODULE)/$(MAKEFILE_PREFIX).gmk +################################################################################ +# Include module specific build settings -include MakeSnippetStart.gmk +THIS_SNIPPET := $(call GetModuleSnippetName, $(MAKEFILE_PREFIX)) -# Include the file being wrapped. -include $(THIS_SNIPPET) +ifneq ($(wildcard $(THIS_SNIPPET)), ) + include MakeSnippetStart.gmk -include MakeSnippetEnd.gmk + # Include the file being wrapped. + include $(THIS_SNIPPET) + + include MakeSnippetEnd.gmk +endif ifeq ($(MAKEFILE_PREFIX), Lib) # We need to keep track of what libraries are generated/needed by this diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index c5a74413de1..99672d59884 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -178,6 +178,10 @@ define SetupJavaCompilationBody $1_SAFE_NAME := $$(strip $$(subst /,_, $1)) + ifeq ($$($1_LOG_ACTION), ) + $1_LOG_ACTION := Compiling + endif + ifeq ($$($1_SMALL_JAVA), ) # If unspecified, default to true $1_SMALL_JAVA := true @@ -472,7 +476,7 @@ define SetupJavaCompilationBody # list of files. $$($1_FILELIST): $$($1_SRCS) $$($1_VARDEPS_FILE) $$(call MakeDir, $$(@D)) - $$(call LogWarn, Compiling up to $$(words $$($1_SRCS)) files for $1) + $$(call LogWarn, $$($1_LOG_ACTION) up to $$(words $$($1_SRCS)) files for $1) $$(eval $$(call ListPathsSafely, $1_SRCS, $$($1_FILELIST))) # Create a $$($1_MODFILELIST) file with significant modified dependencies diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 725424d7618..2880504676a 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -33,7 +33,7 @@ include $(TOPDIR)/make/conf/module-loader-map.conf # Append platform-specific and upgradeable modules PLATFORM_MODULES += $(PLATFORM_MODULES_$(OPENJDK_TARGET_OS)) \ - $(UPGRADEABLE_PLATFORM_MODULES) + $(UPGRADEABLE_PLATFORM_MODULES) $(CUSTOM_UPGRADEABLE_PLATFORM_MODULES) ################################################################################ # Setup module sets for docs @@ -216,7 +216,7 @@ endif # Find dependencies ("requires") for a given module. # Param 1: Module to find dependencies for. FindDepsForModule = \ - $(DEPS_$(strip $1)) + $(filter-out $(IMPORT_MODULES), $(DEPS_$(strip $1))) # Find dependencies ("requires") transitively in 3 levels for a given module. # Param 1: Module to find dependencies for. @@ -254,7 +254,8 @@ FindTransitiveIndirectDepsForModules = \ # Upgradeable modules are those that are either defined as upgradeable or that # require an upradeable module. FindAllUpgradeableModules = \ - $(sort $(filter-out $(MODULES_FILTER), $(UPGRADEABLE_PLATFORM_MODULES))) + $(sort $(filter-out $(MODULES_FILTER), \ + $(UPGRADEABLE_PLATFORM_MODULES) $(CUSTOM_UPGRADEABLE_PLATFORM_MODULES))) ################################################################################ @@ -316,6 +317,19 @@ define ReadImportMetaData $$(eval $$(call ReadSingleImportMetaData, $$m))) endef +################################################################################ +# Get a full snippet path for the current module and a given base name. +# +# Param 1 - The base name of the snippet file to include +GetModuleSnippetName = \ + $(if $(CUSTOM_MODULE_MAKE_ROOT), \ + $(if $(wildcard $(CUSTOM_MODULE_MAKE_ROOT)/$(MODULE)/$(strip $1).gmk), \ + $(CUSTOM_MODULE_MAKE_ROOT)/$(MODULE)/$(strip $1).gmk, \ + $(wildcard modules/$(MODULE)/$(strip $1).gmk) \ + ), \ + $(wildcard modules/$(MODULE)/$(strip $1).gmk) \ + ) + ################################################################################ endif # include guard From 8b5bb013557478c9ceb49f94f22600d5901f4eee Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 11 Aug 2025 10:28:59 +0000 Subject: [PATCH 036/471] 8364987: javac fails with an exception when looking for diamond creation Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Analyzer.java | 2 +- .../tools/javac/analyzer/Diamond.java | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java index 1aea9f77a20..f45e8500000 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java @@ -240,7 +240,7 @@ public class Analyzer { @Override List rewrite(JCNewClass oldTree) { - if (oldTree.clazz.hasTag(TYPEAPPLY)) { + if (oldTree.clazz.hasTag(TYPEAPPLY) && !oldTree.type.isErroneous()) { JCNewClass nc = copier.copy(oldTree); ((JCTypeApply)nc.clazz).arguments = List.nil(); return List.of(nc); diff --git a/test/langtools/tools/javac/analyzer/Diamond.java b/test/langtools/tools/javac/analyzer/Diamond.java index cee8d096cbd..5f77745beaf 100644 --- a/test/langtools/tools/javac/analyzer/Diamond.java +++ b/test/langtools/tools/javac/analyzer/Diamond.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8349132 + * @bug 8349132 8364987 * @summary Check behavior of the diamond analyzer * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -139,4 +139,43 @@ public class Diamond extends TestRunner { } } + @Test //JDK-8364987: + public void testNoCrashErroneousTypes(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + public class Test { + void t() { + L l = new L(); + } + static class L { } + } + """); + + Files.createDirectories(classes); + + var out = new JavacTask(tb) + .options("-XDfind=diamond", + "-XDshould-stop.at=FLOW", + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + var expectedOut = List.of( + "Test.java:3:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Test.L, Test.L)", + "1 error" + ); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + } From fd766b27b9f862075a415780901c242a7d48c26f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 11 Aug 2025 10:49:47 +0000 Subject: [PATCH 037/471] 8364541: Parallel: Support allocation in old generation when heap is almost full Reviewed-by: phh, tschatzl --- .../share/gc/parallel/parallelScavengeHeap.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 2359ab9e158..c6a9a312e5c 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -310,11 +310,13 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, return result; } - // If certain conditions hold, try allocating from the old gen. - if (!is_tlab && !should_alloc_in_eden(size)) { - result = old_gen()->cas_allocate_noexpand(size); - if (result != nullptr) { - return result; + // Try allocating from the old gen for non-TLAB in certain scenarios. + if (!is_tlab) { + if (!should_alloc_in_eden(size) || _is_heap_almost_full) { + result = old_gen()->cas_allocate_noexpand(size); + if (result != nullptr) { + return result; + } } } } From a60e523f88e7022abe80725b82a8b16a87a377e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Maillard?= Date: Mon, 11 Aug 2025 11:15:34 +0000 Subject: [PATCH 038/471] 8349191: Test compiler/ciReplay/TestIncrementalInlining.java failed Reviewed-by: mhaessig, dfenacci, chagedorn --- src/hotspot/share/opto/printinlining.cpp | 5 ++++- test/hotspot/jtreg/ProblemList.txt | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/printinlining.cpp b/src/hotspot/share/opto/printinlining.cpp index be51c08fcfb..fe039623764 100644 --- a/src/hotspot/share/opto/printinlining.cpp +++ b/src/hotspot/share/opto/printinlining.cpp @@ -46,7 +46,10 @@ void InlinePrinter::print_on(outputStream* tty) const { if (!is_enabled()) { return; } - _root.dump(tty, -1); + // using stringStream prevents interleaving with multiple compile threads + stringStream ss; + _root.dump(&ss, -1); + tty->print_raw(ss.freeze()); } InlinePrinter::IPInlineSite* InlinePrinter::locate(JVMState* state, ciMethod* callee) { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 88b8f2d6941..7026b6f79d6 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -75,9 +75,6 @@ compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all compiler/interpreter/Test6833129.java 8335266 generic-i586 -compiler/ciReplay/TestInliningProtectionDomain.java 8349191 generic-all -compiler/ciReplay/TestIncrementalInlining.java 8349191 generic-all - compiler/c2/TestVerifyConstraintCasts.java 8355574 generic-all compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 From 43cfd80c1c0493f2f50ffd75461ca75a002e0127 Mon Sep 17 00:00:00 2001 From: Darragh Clarke Date: Mon, 11 Aug 2025 11:57:08 +0000 Subject: [PATCH 039/471] 8352502: Response message is null if expect 100 assertion fails with non 100 Reviewed-by: dfuchs --- .../classes/java/net/HttpURLConnection.java | 4 + .../www/protocol/http/HttpURLConnection.java | 5 + ...tionExpectContinueResponseMessageTest.java | 196 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 test/jdk/java/net/HttpURLConnection/HttpUrlConnectionExpectContinueResponseMessageTest.java diff --git a/src/java.base/share/classes/java/net/HttpURLConnection.java b/src/java.base/share/classes/java/net/HttpURLConnection.java index d9e9b738617..c0ae12dfdba 100644 --- a/src/java.base/share/classes/java/net/HttpURLConnection.java +++ b/src/java.base/share/classes/java/net/HttpURLConnection.java @@ -556,6 +556,10 @@ public abstract class HttpURLConnection extends URLConnection { * @return the HTTP response message, or {@code null} */ public String getResponseMessage() throws IOException { + // If the responseMessage is already set then return it + if (responseMessage != null) { + return responseMessage; + } getResponseCode(); return responseMessage; } diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 857c2f6ad6d..aee9670ce26 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1080,6 +1080,11 @@ public class HttpURLConnection extends java.net.HttpURLConnection { if (logger.isLoggable(PlatformLogger.Level.FINE)) { logger.fine("response code received " + responseCode); } + if (sa.length > 2) + responseMessage = String.join(" ", Arrays.copyOfRange(sa, 2, sa.length)); + if (logger.isLoggable(PlatformLogger.Level.FINE)) { + logger.fine("response message received " + responseMessage); + } } catch (NumberFormatException numberFormatException) { } } diff --git a/test/jdk/java/net/HttpURLConnection/HttpUrlConnectionExpectContinueResponseMessageTest.java b/test/jdk/java/net/HttpURLConnection/HttpUrlConnectionExpectContinueResponseMessageTest.java new file mode 100644 index 00000000000..06aa9319161 --- /dev/null +++ b/test/jdk/java/net/HttpURLConnection/HttpUrlConnectionExpectContinueResponseMessageTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that Response Message gets set even if a non 100 response + * gets return when Expect Continue is set + * @bug 8352502 + * @library /test/lib + * @run junit/othervm -Djdk.internal.httpclient.debug=true + * -Djdk.httpclient.HttpClient.log=all + * HttpUrlConnectionExpectContinueResponseMessageTest + */ + +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.Socket; +import java.net.ServerSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class HttpUrlConnectionExpectContinueResponseMessageTest { + class Control { + volatile ServerSocket serverSocket = null; + volatile boolean stop = false; + volatile String response = null; + volatile Socket acceptingSocket = null; + volatile String testPath = null; + } + + private Thread serverThread = null; + private volatile Control control; + static final Logger logger; + + static { + logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); + logger.setLevel(Level.ALL); + Logger.getLogger("").getHandlers()[0].setLevel(Level.ALL); + } + + public Object[][] args() { + return new Object[][]{ + // Expected Status Code, Status Line, Expected responseMessage + { 404, "HTTP/1.1 404 Not Found", "Not Found" }, + { 405, "HTTP/1.1 405 Method Not Allowed", "Method Not Allowed" }, + { 401, "HTTP/1.1 401 Unauthorized", "Unauthorized"} + }; + } + + @BeforeAll + public void startServerSocket() throws Exception { + Control control = this.control = new Control(); + + control.serverSocket = new ServerSocket(); + control.serverSocket.setReuseAddress(true); + control.serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + Runnable runnable = () -> { + while (!control.stop) { + try { + Socket socket = control.serverSocket.accept(); + String path = getPath(socket); + + OutputStream outputStream; + if (path.equals(control.testPath)) { + control.acceptingSocket = socket; + outputStream = control.acceptingSocket.getOutputStream(); + + // send a wrong response and then shutdown + outputStream.write(control.response.getBytes()); + outputStream.flush(); + control.acceptingSocket.shutdownOutput(); + } else { + // stray request showed up, return 500 and close socket + outputStream = socket.getOutputStream(); + outputStream.write("HTTP/1.1 500 Internal Server Error\r\n".getBytes()); + outputStream.write("Connection: close\r\n".getBytes()); + outputStream.write("Content-Length: 0\r\n".getBytes()); + outputStream.write("\r\n".getBytes()); + outputStream.flush(); + socket.close(); + } + } catch (Exception e) { + // Any exceptions will be ignored + } + } + }; + serverThread = new Thread(runnable); + serverThread.start(); + } + + private static String getPath(Socket socket) throws IOException { + InputStream inputStream = socket.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder reqBuilder = new StringBuilder(); + String line = null; + while (!(line = reader.readLine()).isEmpty()) { + reqBuilder.append(line + "\r\n"); + } + String req = reqBuilder.toString(); + StringTokenizer tokenizer = new StringTokenizer(req); + String method = tokenizer.nextToken(); + String path = tokenizer.nextToken(); + return path; + } + + @AfterAll + public void stopServerSocket() throws Exception { + Control control = this.control; + control.stop = true; + control.serverSocket.close(); + serverThread.join(); + } + + @ParameterizedTest + @MethodSource("args") + public void test(int expectedCode, String statusLine, String expectedMessage) throws Exception { + String body = "Testing: " + expectedCode; + Control control = this.control; + control.response = statusLine + "\r\n" + + "Content-Length: 0\r\n" + + "\r\n"; + control.testPath = "/ContinueResponseMessageTest/" + expectedCode; + + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(control.serverSocket.getLocalPort()) + .path(control.testPath) + .toURL(); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Connection", "Close"); + connection.setRequestProperty("Expect", "100-Continue"); + + try { + connection.setFixedLengthStreamingMode(body.getBytes().length); + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(body.getBytes()); + outputStream.close(); + } catch (Exception ex) { + // server returning 4xx responses can result in exceptions + // but we can just swallow them + } + + int responseCode = connection.getResponseCode(); + String responseMessage = connection.getResponseMessage(); + assertTrue(responseCode == expectedCode, + String.format("Expected %s response, instead received %s", expectedCode, responseCode)); + assertTrue(expectedMessage.equals(responseMessage), + String.format("Expected Response Message %s, instead received %s", + expectedMessage, responseMessage)); + control.acceptingSocket.close(); + } +} From 0ad919c1e54895b000b58f6a1b54d79f76970845 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 11 Aug 2025 12:22:52 +0000 Subject: [PATCH 040/471] 8352067: Remove the NMT treap and replace its uses with the utilities red-black tree Reviewed-by: jsjolen, ayang --- src/hotspot/share/nmt/memoryFileTracker.cpp | 8 +- src/hotspot/share/nmt/nmtTreap.hpp | 447 ------------------ src/hotspot/share/nmt/regionsTree.cpp | 4 +- src/hotspot/share/nmt/regionsTree.hpp | 2 +- src/hotspot/share/nmt/regionsTree.inline.hpp | 4 +- src/hotspot/share/nmt/vmatree.cpp | 40 +- src/hotspot/share/nmt/vmatree.hpp | 20 +- src/hotspot/share/opto/printinlining.cpp | 18 +- src/hotspot/share/opto/printinlining.hpp | 4 +- src/hotspot/share/utilities/rbTree.hpp | 15 + src/hotspot/share/utilities/rbTree.inline.hpp | 43 +- test/hotspot/gtest/nmt/test_nmt_treap.cpp | 364 -------------- test/hotspot/gtest/nmt/test_vmatree.cpp | 60 +-- test/hotspot/gtest/utilities/test_rbtree.cpp | 63 ++- 14 files changed, 200 insertions(+), 892 deletions(-) delete mode 100644 src/hotspot/share/nmt/nmtTreap.hpp delete mode 100644 test/hotspot/gtest/nmt/test_nmt_treap.cpp diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index 677cd174650..55f1cb64626 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -64,12 +64,12 @@ void MemoryFileTracker::print_report_on(const MemoryFile* file, outputStream* st stream->print_cr("Memory map of %s", file->_descriptive_name); stream->cr(); - VMATree::TreapNode* prev = nullptr; + const VMATree::TNode* prev = nullptr; #ifdef ASSERT - VMATree::TreapNode* broken_start = nullptr; - VMATree::TreapNode* broken_end = nullptr; + const VMATree::TNode* broken_start = nullptr; + const VMATree::TNode* broken_end = nullptr; #endif - file->_tree.visit_in_order([&](VMATree::TreapNode* current) { + file->_tree.visit_in_order([&](const VMATree::TNode* current) { if (prev == nullptr) { // Must be first node. prev = current; diff --git a/src/hotspot/share/nmt/nmtTreap.hpp b/src/hotspot/share/nmt/nmtTreap.hpp deleted file mode 100644 index 13e759cbd3a..00000000000 --- a/src/hotspot/share/nmt/nmtTreap.hpp +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_NMT_NMTTREAP_HPP -#define SHARE_NMT_NMTTREAP_HPP - -#include "runtime/os.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/macros.hpp" -#include "utilities/powerOfTwo.hpp" -#include - -// A Treap is a self-balanced binary tree where each node is equipped with a -// priority. It adds the invariant that the priority of a parent P is strictly larger -// larger than the priority of its children. When priorities are randomly -// assigned the tree is balanced. -// All operations are defined through merge and split, which are each other's inverse. -// merge(left_treap, right_treap) => treap where left_treap <= right_treap -// split(treap, key) => (left_treap, right_treap) where left_treap <= right_treap -// Recursion is used in these, but the depth of the call stack is the depth of -// the tree which is O(log n) so we are safe from stack overflow. -// TreapNode has LEQ nodes on the left, GT nodes on the right. -// -// COMPARATOR must have a static function `cmp(a,b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// ALLOCATOR must check for oom and exit, as Treap currently does not handle the allocation -// failing. - -template -class Treap { - friend class NMTVMATreeTest; - friend class NMTTreapTest; - friend class VMTWithVMATreeTest; -public: - class TreapNode { - friend Treap; - uint64_t _priority; - const K _key; - V _value; - - TreapNode* _left; - TreapNode* _right; - - public: - TreapNode(const K& k, uint64_t p) : _priority(p), _key(k), _left(nullptr), _right(nullptr) {} - - TreapNode(const K& k, const V& v, uint64_t p) - : _priority(p), - _key(k), - _value(v), - _left(nullptr), - _right(nullptr) { - } - - const K& key() const { return _key; } - V& val() { return _value; } - - TreapNode* left() const { return _left; } - TreapNode* right() const { return _right; } - }; - -private: - ALLOCATOR _allocator; - TreapNode* _root; - - // A random number - static constexpr const uint64_t _initial_seed = 0xC8DD2114AE0543A3; - uint64_t _prng_seed; - int _node_count; - - uint64_t prng_next() { - uint64_t first_half = os::next_random(_prng_seed); - uint64_t second_half = os::next_random(_prng_seed >> 32); - _prng_seed = first_half | (second_half << 32); - return _prng_seed; - } - - struct node_pair { - TreapNode* left; - TreapNode* right; - }; - - enum SplitMode { - LT, // < - LEQ // <= - }; - - // Split tree at head into two trees, SplitMode decides where EQ values go. - // We have SplitMode because it makes remove() trivial to implement. - static node_pair split(TreapNode* head, const K& key, SplitMode mode = LEQ DEBUG_ONLY(COMMA int recur_count = 0)) { - assert(recur_count < 200, "Call-stack depth should never exceed 200"); - - if (head == nullptr) { - return {nullptr, nullptr}; - } - if ((COMPARATOR::cmp(head->_key, key) <= 0 && mode == LEQ) || (COMPARATOR::cmp(head->_key, key) < 0 && mode == LT)) { - node_pair p = split(head->_right, key, mode DEBUG_ONLY(COMMA recur_count + 1)); - head->_right = p.left; - return node_pair{head, p.right}; - } else { - node_pair p = split(head->_left, key, mode DEBUG_ONLY(COMMA recur_count + 1)); - head->_left = p.right; - return node_pair{p.left, head}; - } - } - - // Invariant: left is a treap whose keys are LEQ to the keys in right. - static TreapNode* merge(TreapNode* left, TreapNode* right DEBUG_ONLY(COMMA int recur_count = 0)) { - assert(recur_count < 200, "Call-stack depth should never exceed 200"); - - if (left == nullptr) return right; - if (right == nullptr) return left; - - if (left->_priority > right->_priority) { - // We need - // LEFT - // | - // RIGHT - // for the invariant re: priorities to hold. - left->_right = merge(left->_right, right DEBUG_ONLY(COMMA recur_count + 1)); - return left; - } else { - // We need - // RIGHT - // | - // LEFT - // for the invariant re: priorities to hold. - right->_left = merge(left, right->_left DEBUG_ONLY(COMMA recur_count + 1)); - return right; - } - } - - static TreapNode* find(TreapNode* node, const K& k DEBUG_ONLY(COMMA int recur_count = 0)) { - if (node == nullptr) { - return nullptr; - } - - int key_cmp_k = COMPARATOR::cmp(node->key(), k); - - if (key_cmp_k == 0) { // key EQ k - return node; - } - - if (key_cmp_k < 0) { // key LT k - return find(node->right(), k DEBUG_ONLY(COMMA recur_count + 1)); - } else { // key GT k - return find(node->left(), k DEBUG_ONLY(COMMA recur_count + 1)); - } - } - -#ifdef ASSERT - void verify_self() { - // A balanced binary search tree should have a depth on the order of log(N). - // We take the ceiling of log_2(N + 1) * 3 as our maximum bound. - // For comparison, a RB-tree has a proven max depth of log_2(N + 1) * 2. - const int expected_maximum_depth = ceil(log2i(this->_node_count+1) * 3); - // Find the maximum depth through DFS and ensure that the priority invariant holds. - int maximum_depth_found = 0; - - struct DFS { - int depth; - uint64_t parent_prio; - TreapNode* n; - }; - GrowableArrayCHeap to_visit; - constexpr const uint64_t positive_infinity = 0xFFFFFFFFFFFFFFFF; - - to_visit.push({0, positive_infinity, this->_root}); - while (!to_visit.is_empty()) { - DFS head = to_visit.pop(); - if (head.n == nullptr) continue; - maximum_depth_found = MAX2(maximum_depth_found, head.depth); - - assert(head.parent_prio >= head.n->_priority, "broken priority invariant"); - - to_visit.push({head.depth + 1, head.n->_priority, head.n->left()}); - to_visit.push({head.depth + 1, head.n->_priority, head.n->right()}); - } - assert(maximum_depth_found - expected_maximum_depth <= 3, - "depth unexpectedly large for treap of node count %d, was: %d, expected between %d and %d", - _node_count, maximum_depth_found, expected_maximum_depth - 3, expected_maximum_depth); - - // Visit everything in order, see that the key ordering is monotonically increasing. - TreapNode* last_seen = nullptr; - bool failed = false; - int seen_count = 0; - this->visit_in_order([&](TreapNode* node) { - seen_count++; - if (last_seen == nullptr) { - last_seen = node; - return true; - } - if (COMPARATOR::cmp(last_seen->key(), node->key()) > 0) { - failed = false; - } - last_seen = node; - return true; - }); - assert(seen_count == _node_count, "the number of visited nodes do not match with the number of stored nodes"); - assert(!failed, "keys was not monotonically strongly increasing when visiting in order"); - } -#endif // ASSERT - -public: - NONCOPYABLE(Treap); - - Treap() - : _allocator(), - _root(nullptr), - _prng_seed(_initial_seed), - _node_count(0) { - static_assert(std::is_trivially_destructible::value, "must be"); - } - - ~Treap() { - this->remove_all(); - } - - int size() { - return _node_count; - } - - void upsert(const K& k, const V& v) { - TreapNode* found = find(_root, k); - if (found != nullptr) { - // Already exists, update value. - found->_value = v; - return; - } - _node_count++; - // Doesn't exist, make node - void* node_place = _allocator.allocate(sizeof(TreapNode)); - uint64_t prio = prng_next(); - TreapNode* node = new (node_place) TreapNode(k, v, prio); - - // (LEQ_k, GT_k) - node_pair split_up = split(this->_root, k); - // merge(merge(LEQ_k, EQ_k), GT_k) - this->_root = merge(merge(split_up.left, node), split_up.right); - } - - void remove(const K& k) { - // (LEQ_k, GT_k) - node_pair first_split = split(this->_root, k, LEQ); - // (LT_k, GEQ_k) == (LT_k, EQ_k) since it's from LEQ_k and keys are unique. - node_pair second_split = split(first_split.left, k, LT); - - if (second_split.right != nullptr) { - // The key k existed, we delete it. - _node_count--; - second_split.right->_value.~V(); - _allocator.free(second_split.right); - } - // Merge together everything - _root = merge(second_split.left, first_split.right); - } - - // Delete all nodes. - void remove_all() { - _node_count = 0; - GrowableArrayCHeap to_delete; - to_delete.push(_root); - - while (!to_delete.is_empty()) { - TreapNode* head = to_delete.pop(); - if (head == nullptr) continue; - to_delete.push(head->_left); - to_delete.push(head->_right); - head->_value.~V(); - _allocator.free(head); - } - _root = nullptr; - } - - TreapNode* closest_leq(const K& key) { - TreapNode* candidate = nullptr; - TreapNode* pos = _root; - while (pos != nullptr) { - int cmp_r = COMPARATOR::cmp(pos->key(), key); - if (cmp_r == 0) { // Exact match - candidate = pos; - break; // Can't become better than that. - } - if (cmp_r < 0) { - // Found a match, try to find a better one. - candidate = pos; - pos = pos->_right; - } else if (cmp_r > 0) { - pos = pos->_left; - } - } - return candidate; - } - - struct FindResult { - FindResult(TreapNode* node, bool new_node) : node(node), new_node(new_node) {} - TreapNode* const node; - bool const new_node; - }; - - // Finds the node for the given k in the tree or inserts a new node with the default constructed value. - FindResult find(const K& k) { - if (TreapNode* found = find(_root, k)) { - return FindResult(found, false); - } - _node_count++; - // Doesn't exist, make node - void* node_place = _allocator.allocate(sizeof(TreapNode)); - uint64_t prio = prng_next(); - TreapNode* node = new (node_place) TreapNode(k, prio); - - // (LEQ_k, GT_k) - node_pair split_up = split(this->_root, k); - // merge(merge(LEQ_k, EQ_k), GT_k) - this->_root = merge(merge(split_up.left, node), split_up.right); - return FindResult(node, true); - } - - TreapNode* closest_gt(const K& key) { - TreapNode* candidate = nullptr; - TreapNode* pos = _root; - while (pos != nullptr) { - int cmp_r = COMPARATOR::cmp(pos->key(), key); - if (cmp_r > 0) { - // Found a match, try to find a better one. - candidate = pos; - pos = pos->_left; - } else if (cmp_r <= 0) { - pos = pos->_right; - } - } - return candidate; - } - - struct Range { - TreapNode* start; - TreapNode* end; - Range(TreapNode* start, TreapNode* end) - : start(start), end(end) {} - }; - - // Return the range [start, end) - // where start->key() <= addr < end->key(). - // Failure to find the range leads to start and/or end being null. - Range find_enclosing_range(K addr) { - TreapNode* start = closest_leq(addr); - TreapNode* end = closest_gt(addr); - return Range(start, end); - } - - // Visit all TreapNodes in ascending key order. - template - void visit_in_order(F f) const { - GrowableArrayCHeap to_visit; - TreapNode* head = _root; - while (!to_visit.is_empty() || head != nullptr) { - while (head != nullptr) { - to_visit.push(head); - head = head->left(); - } - head = to_visit.pop(); - if (!f(head)) { - return; - } - head = head->right(); - } - } - - // Visit all TreapNodes in ascending order whose keys are in range [from, to). - template - void visit_range_in_order(const K& from, const K& to, F f) { - assert(COMPARATOR::cmp(from, to) <= 0, "from must be less or equal to to"); - GrowableArrayCHeap to_visit; - TreapNode* head = _root; - while (!to_visit.is_empty() || head != nullptr) { - while (head != nullptr) { - int cmp_from = COMPARATOR::cmp(head->key(), from); - to_visit.push(head); - if (cmp_from >= 0) { - head = head->left(); - } else { - // We've reached a node which is strictly less than from - // We don't need to visit any further to the left. - break; - } - } - head = to_visit.pop(); - const int cmp_from = COMPARATOR::cmp(head->key(), from); - const int cmp_to = COMPARATOR::cmp(head->key(), to); - if (cmp_from >= 0 && cmp_to < 0) { - if (!f(head)) { - return; - } - } - if (cmp_to < 0) { - head = head->right(); - } else { - head = nullptr; - } - } - } -}; - -class TreapCHeapAllocator { -public: - void* allocate(size_t sz) { - void* allocation = os::malloc(sz, mtNMT); - if (allocation == nullptr) { - vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "treap failed allocation"); - } - return allocation; - } - - void free(void* ptr) { - os::free(ptr); - } -}; - -template -using TreapCHeap = Treap; - -#endif //SHARE_NMT_NMTTREAP_HPP diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index 09686f52067..370c69a2485 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -48,8 +48,8 @@ void RegionsTree::NodeHelper::print_on(outputStream* st) { } void RegionsTree::print_on(outputStream* st) { - visit_in_order([&](Node* node) { - NodeHelper curr(node); + visit_in_order([&](const Node* node) { + NodeHelper curr(const_cast(node)); curr.print_on(st); return true; }); diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index 7fdb4e6fd39..bf2ab711b2d 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -45,7 +45,7 @@ class RegionsTree : public VMATree { SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); SummaryDiff uncommit_region(address addr, size_t size); - using Node = VMATree::TreapNode; + using Node = VMATree::TNode; class NodeHelper { Node* _node; diff --git a/src/hotspot/share/nmt/regionsTree.inline.hpp b/src/hotspot/share/nmt/regionsTree.inline.hpp index f1b7319f5ca..665f4a93c88 100644 --- a/src/hotspot/share/nmt/regionsTree.inline.hpp +++ b/src/hotspot/share/nmt/regionsTree.inline.hpp @@ -52,8 +52,8 @@ void RegionsTree::visit_reserved_regions(F func) { NodeHelper begin_node, prev; size_t rgn_size = 0; - visit_in_order([&](Node* node) { - NodeHelper curr(node); + visit_in_order([&](const Node* node) { + NodeHelper curr(const_cast(node)); if (prev.is_valid()) { rgn_size += curr.distance_from(prev); } else { diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index a60c30c812d..4f6f8e12185 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -204,7 +204,7 @@ void VMATree::compute_summary_diff(const SingleDiff::delta region_size, // update the region state between n1 and n2. Since n1 and n2 are pointers, any update of them will be visible from tree. // If n1 is noop, it can be removed because its left region (n1->val().in) is already decided and its right state (n1->val().out) is decided here. // The state of right of n2 (n2->val().out) cannot be decided here yet. -void VMATree::update_region(TreapNode* n1, TreapNode* n2, const RequestInfo& req, SummaryDiff& diff) { +void VMATree::update_region(TNode* n1, TNode* n2, const RequestInfo& req, SummaryDiff& diff) { assert(n1 != nullptr,"sanity"); assert(n2 != nullptr,"sanity"); //.........n1......n2...... @@ -261,8 +261,8 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy }; stA.out.set_commit_stack(NativeCallStackStorage::invalid); stB.in.set_commit_stack(NativeCallStackStorage::invalid); - VMATreap::Range rA = _tree.find_enclosing_range(_A); - VMATreap::Range rB = _tree.find_enclosing_range(_B); + VMARBTree::Range rA = _tree.find_enclosing_range(_A); + VMARBTree::Range rB = _tree.find_enclosing_range(_B); // nodes: .....X.......Y...Z......W........U // request: A------------------B @@ -320,24 +320,24 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy // Meaning that whenever any of one item in this sequence is changed, the rest of the consequent items to // be checked/changed. - TreapNode* X = rA.start; - TreapNode* Y = rA.end; - TreapNode* W = rB.start; - TreapNode* U = rB.end; - TreapNode nA{_A, stA, 0}; // the node that represents A - TreapNode nB{_B, stB, 0}; // the node that represents B - TreapNode* A = &nA; - TreapNode* B = &nB; - auto upsert_if= [&](TreapNode* node) { + TNode* X = rA.start; + TNode* Y = rA.end; + TNode* W = rB.start; + TNode* U = rB.end; + TNode nA{_A, stA}; // the node that represents A + TNode nB{_B, stB}; // the node that represents B + TNode* A = &nA; + TNode* B = &nB; + auto upsert_if= [&](TNode* node) { if (!node->val().is_noop()) { _tree.upsert(node->key(), node->val()); } }; // update region between n1 and n2 - auto update = [&](TreapNode* n1, TreapNode* n2) { + auto update = [&](TNode* n1, TNode* n2) { update_region(n1, n2, req, diff); }; - auto remove_if = [&](TreapNode* node) -> bool{ + auto remove_if = [&](TNode* node) -> bool{ if (node->val().is_noop()) { _tree.remove(node->key()); return true; @@ -347,8 +347,8 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy GrowableArrayCHeap to_be_removed; // update regions in range A to B auto update_loop = [&]() { - TreapNode* prev = nullptr; - _tree.visit_range_in_order(_A + 1, _B + 1, [&](TreapNode* curr) { + TNode* prev = nullptr; + _tree.visit_range_in_order(_A + 1, _B + 1, [&](TNode* curr) { if (prev != nullptr) { update_region(prev, curr, req, diff); // during visit, structure of the tree should not be changed @@ -362,7 +362,7 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy }); }; // update region of [A,T) - auto update_A = [&](TreapNode* T) { + auto update_A = [&](TNode* T) { A->val().out = A->val().in; update(A, T); }; @@ -650,7 +650,7 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy #ifdef ASSERT void VMATree::print_on(outputStream* out) { - visit_in_order([&](TreapNode* current) { + visit_in_order([&](const TNode* current) { out->print("%zu (%s) - %s [%d, %d]-> ", current->key(), NMTUtil::tag_to_name(out_state(current).mem_tag()), statetype_to_string(out_state(current).type()), current->val().out.reserved_stack(), current->val().out.committed_stack()); return true; @@ -660,11 +660,11 @@ void VMATree::print_on(outputStream* out) { #endif VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, const MemTag tag) { - auto pos = [](TreapNode* n) { return n->key(); }; + auto pos = [](TNode* n) { return n->key(); }; position from = start; position end = from+size; size_t remsize = size; - VMATreap::Range range(nullptr, nullptr); + VMARBTree::Range range(nullptr, nullptr); // Find the next range to adjust and set range, remsize and from // appropriately. If it returns false, there is no valid next range. diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 7f52b406309..d2acabdae07 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -29,9 +29,9 @@ #include "nmt/memTag.hpp" #include "nmt/memTag.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" -#include "nmt/nmtTreap.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/rbTree.inline.hpp" #include // A VMATree stores a sequence of points on the natural number line. @@ -193,17 +193,21 @@ private: }; public: - using VMATreap = TreapCHeap; - using TreapNode = VMATreap::TreapNode; + using VMARBTree = RBTreeCHeap; + using TNode = RBNode; private: - VMATreap _tree; + VMARBTree _tree; - static IntervalState& in_state(TreapNode* node) { + static IntervalState& in_state(TNode* node) { return node->val().in; } - static IntervalState& out_state(TreapNode* node) { + static IntervalState& out_state(TNode* node) { + return node->val().out; + } + + static const IntervalState& out_state(const TNode* node) { return node->val().out; } @@ -281,7 +285,7 @@ public: SIndex get_new_reserve_callstack(const SIndex existinting_stack, const StateType ex, const RequestInfo& req) const; SIndex get_new_commit_callstack(const SIndex existinting_stack, const StateType ex, const RequestInfo& req) const; void compute_summary_diff(const SingleDiff::delta region_size, const MemTag t1, const StateType& ex, const RequestInfo& req, const MemTag new_tag, SummaryDiff& diff) const; - void update_region(TreapNode* n1, TreapNode* n2, const RequestInfo& req, SummaryDiff& diff); + void update_region(TNode* n1, TNode* n2, const RequestInfo& req, SummaryDiff& diff); int state_to_index(const StateType st) const { return st == StateType::Released ? 0 : @@ -325,6 +329,6 @@ public: void visit_range_in_order(const position& from, const position& to, F f) { _tree.visit_range_in_order(from, to, f); } - VMATreap& tree() { return _tree; } + VMARBTree& tree() { return _tree; } }; #endif diff --git a/src/hotspot/share/opto/printinlining.cpp b/src/hotspot/share/opto/printinlining.cpp index fe039623764..06d14a7f3af 100644 --- a/src/hotspot/share/opto/printinlining.cpp +++ b/src/hotspot/share/opto/printinlining.cpp @@ -71,21 +71,25 @@ InlinePrinter::IPInlineSite* InlinePrinter::locate(JVMState* state, ciMethod* ca } InlinePrinter::IPInlineSite& InlinePrinter::IPInlineSite::at_bci(int bci, ciMethod* callee) { - auto find_result = _children.find(bci); - IPInlineSite& child = find_result.node->val(); + RBTreeCHeap::Cursor cursor = _children.cursor(bci); - if (find_result.new_node) { - assert(callee != nullptr, "an inline call is missing in the chain up to the root"); - child.set_source(callee, bci); - } else { // We already saw a call at this site before + if (cursor.found()) { // We already saw a call at this site before + IPInlineSite& child = cursor.node()->val(); if (callee != nullptr && callee != child._method) { outputStream* stream = child.add(InliningResult::SUCCESS); stream->print("callee changed to "); CompileTask::print_inline_inner_method_info(stream, callee); } + return child; } - return child; + assert(callee != nullptr, "an inline call is missing in the chain up to the root"); + + RBNode* node = _children.allocate_node(bci); + _children.insert_at_cursor(node, cursor); + node->val().set_source(callee, bci); + + return node->val(); } outputStream* InlinePrinter::IPInlineSite::add(InliningResult result) { diff --git a/src/hotspot/share/opto/printinlining.hpp b/src/hotspot/share/opto/printinlining.hpp index 57f4b51858e..3bf09bc921f 100644 --- a/src/hotspot/share/opto/printinlining.hpp +++ b/src/hotspot/share/opto/printinlining.hpp @@ -26,9 +26,9 @@ #define PRINTINLINING_HPP #include "memory/allocation.hpp" -#include "nmt/nmtTreap.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" +#include "utilities/rbTree.inline.hpp" class JVMState; class ciMethod; @@ -77,7 +77,7 @@ private: ciMethod* _method; int _bci; GrowableArrayCHeap _attempts; - TreapCHeap _children; + RBTreeCHeap _children; public: IPInlineSite(ciMethod* method, int bci) : _method(method), _bci(bci) {} diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 761148d1c89..405fa3e9ae9 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -167,6 +167,7 @@ public: template class AbstractRBTree { friend class RBTreeTest; + friend class NMTVMATreeTest; typedef AbstractRBTree TreeType; public: @@ -404,13 +405,21 @@ public: } // Visit all RBNodes in ascending order, calling f on each node. + // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template void visit_in_order(F f) const; + template + void visit_in_order(F f); + // Visit all RBNodes in ascending order whose keys are in range [from, to], calling f on each node. + // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template void visit_range_in_order(const K& from, const K& to, F f) const; + template + void visit_range_in_order(const K &from, const K &to, F f); + // Verifies that the tree is correct and holds rb-properties // If not using a key comparator (when using IntrusiveRBTree for example), // A second `cmp` must exist in COMPARATOR (see top of file). @@ -457,6 +466,12 @@ public: free_node(old_node); } + RBNode* allocate_node(const K& key) { + void* node_place = _allocator.allocate(sizeof(RBNode)); + assert(node_place != nullptr, "rb-tree allocator must exit on failure"); + return new (node_place) RBNode(key); + } + RBNode* allocate_node(const K& key, const V& val) { void* node_place = _allocator.allocate(sizeof(RBNode)); assert(node_place != nullptr, "rb-tree allocator must exit on failure"); diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 1c3fdfb0dd7..365786f7fc1 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -85,7 +85,7 @@ inline IntrusiveRBNode* IntrusiveRBNode::rotate_right() { inline const IntrusiveRBNode* IntrusiveRBNode::prev() const { const IntrusiveRBNode* node = this; - if (_left != nullptr) { // right subtree exists + if (_left != nullptr) { // left subtree exists node = _left; while (node->_right != nullptr) { node = node->_right; @@ -599,7 +599,21 @@ template inline void AbstractRBTree::visit_in_order(F f) const { const NodeType* node = leftmost(); while (node != nullptr) { - f(node); + if (!f(node)) { + return; + } + node = node->next(); + } +} + +template +template +inline void AbstractRBTree::visit_in_order(F f) { + NodeType* node = leftmost(); + while (node != nullptr) { + if (!f(node)) { + return; + } node = node->next(); } } @@ -618,7 +632,30 @@ inline void AbstractRBTree::visit_range_in_order(const const NodeType* end = next(cursor_end).node(); while (start != end) { - f(start); + if (!f(start)) { + return; + } + start = start->next(); + } +} + +template +template +inline void AbstractRBTree::visit_range_in_order(const K& from, const K& to, F f) { + assert_key_leq(from, to); + if (_root == nullptr) { + return; + } + + Cursor cursor_start = cursor(from); + Cursor cursor_end = cursor(to); + NodeType* start = cursor_start.found() ? cursor_start.node() : next(cursor_start).node(); + NodeType* end = next(cursor_end).node(); + + while (start != end) { + if (!f(start)) { + return; + } start = start->next(); } } diff --git a/test/hotspot/gtest/nmt/test_nmt_treap.cpp b/test/hotspot/gtest/nmt/test_nmt_treap.cpp deleted file mode 100644 index bc8c24b592f..00000000000 --- a/test/hotspot/gtest/nmt/test_nmt_treap.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "memory/resourceArea.hpp" -#include "nmt/nmtTreap.hpp" -#include "nmt/virtualMemoryTracker.hpp" -#include "runtime/os.hpp" -#include "unittest.hpp" -class NMTTreapTest : public testing::Test { -public: - struct Cmp { - static int cmp(int a, int b) { - return a - b; - } - }; - - struct CmpInverse { - static int cmp(int a, int b) { - return b - a; - } - }; - - struct FCmp { - static int cmp(float a, float b) { - if (a < b) return -1; - if (a == b) return 0; - return 1; - } - }; - -#ifdef ASSERT - template - void verify_it(Treap& t) { - t.verify_self(); - } -#endif // ASSERT - -public: - void inserting_duplicates_results_in_one_value() { - constexpr const int up_to = 10; - GrowableArrayCHeap nums_seen(up_to, up_to, 0); - TreapCHeap treap; - - for (int i = 0; i < up_to; i++) { - treap.upsert(i, i); - treap.upsert(i, i); - treap.upsert(i, i); - treap.upsert(i, i); - treap.upsert(i, i); - } - - treap.visit_in_order([&](TreapCHeap::TreapNode* node) { - nums_seen.at(node->key())++; - return true; - }); - for (int i = 0; i < up_to; i++) { - EXPECT_EQ(1, nums_seen.at(i)); - } - } - - void treap_ought_not_leak() { - struct LeakCheckedAllocator { - int allocations; - - LeakCheckedAllocator() - : allocations(0) { - } - - void* allocate(size_t sz) { - void* allocation = os::malloc(sz, mtTest); - if (allocation == nullptr) { - vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "treap failed allocation"); - } - ++allocations; - return allocation; - } - - void free(void* ptr) { - --allocations; - os::free(ptr); - } - }; - - constexpr const int up_to = 10; - { - Treap treap; - for (int i = 0; i < up_to; i++) { - treap.upsert(i, i); - } - EXPECT_EQ(up_to, treap._allocator.allocations); - for (int i = 0; i < up_to; i++) { - treap.remove(i); - } - EXPECT_EQ(0, treap._allocator.allocations); - EXPECT_EQ(nullptr, treap._root); - } - - { - Treap treap; - for (int i = 0; i < up_to; i++) { - treap.upsert(i, i); - } - treap.remove_all(); - EXPECT_EQ(0, treap._allocator.allocations); - EXPECT_EQ(nullptr, treap._root); - } - } - - void test_find() { - struct Empty {}; - TreapCHeap treap; - using Node = TreapCHeap::TreapNode; - - Node* n = nullptr; - auto test = [&](float f) { - EXPECT_EQ(nullptr, treap.find(treap._root, f)); - treap.upsert(f, Empty{}); - Node* n = treap.find(treap._root, f); - EXPECT_NE(nullptr, n); - EXPECT_EQ(f, n->key()); - }; - - test(1.0f); - test(5.0f); - test(0.0f); - } -}; - -TEST_VM_F(NMTTreapTest, InsertingDuplicatesResultsInOneValue) { - this->inserting_duplicates_results_in_one_value(); -} - -TEST_VM_F(NMTTreapTest, TreapOughtNotLeak) { - this->treap_ought_not_leak(); -} - -TEST_VM_F(NMTTreapTest, TestVisitors) { - { // Tests with 'default' ordering (ascending) - TreapCHeap treap; - using Node = TreapCHeap::TreapNode; - - treap.visit_range_in_order(0, 100, [&](Node* x) { - EXPECT_TRUE(false) << "Empty treap has no nodes to visit"; - return true; - }); - - // Single-element set - treap.upsert(1, 0); - int count = 0; - treap.visit_range_in_order(0, 100, [&](Node* x) { - count++; - return true; - }); - EXPECT_EQ(1, count); - - count = 0; - treap.visit_in_order([&](Node* x) { - count++; - return true; - }); - EXPECT_EQ(1, count); - - // Add an element outside of the range that should not be visited on the right side and - // one on the left side. - treap.upsert(101, 0); - treap.upsert(-1, 0); - count = 0; - treap.visit_range_in_order(0, 100, [&](Node* x) { - count++; - return true; - }); - EXPECT_EQ(1, count); - - count = 0; - treap.visit_in_order([&](Node* x) { - count++; - return true; - }); - EXPECT_EQ(3, count); - - // Visiting empty range [0, 0) == {} - treap.upsert(0, 0); // This node should not be visited. - treap.visit_range_in_order(0, 0, [&](Node* x) { - EXPECT_TRUE(false) << "Empty visiting range should not visit any node"; - return true; - }); - - treap.remove_all(); - for (int i = 0; i < 11; i++) { - treap.upsert(i, 0); - } - - ResourceMark rm; - GrowableArray seen; - treap.visit_range_in_order(0, 10, [&](Node* x) { - seen.push(x->key()); - return true; - }); - EXPECT_EQ(10, seen.length()); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(i, seen.at(i)); - } - - seen.clear(); - treap.visit_in_order([&](Node* x) { - seen.push(x->key()); - return true; - }); - EXPECT_EQ(11, seen.length()); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(i, seen.at(i)); - } - - seen.clear(); - treap.visit_range_in_order(10, 12, [&](Node* x) { - seen.push(x->key()); - return true; - }); - EXPECT_EQ(1, seen.length()); - EXPECT_EQ(10, seen.at(0)); - } - { // Test with descending ordering - TreapCHeap treap; - using Node = TreapCHeap::TreapNode; - - for (int i = 0; i < 10; i++) { - treap.upsert(i, 0); - } - ResourceMark rm; - GrowableArray seen; - treap.visit_range_in_order(9, -1, [&](Node* x) { - seen.push(x->key()); - return true; - }); - EXPECT_EQ(10, seen.length()); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(10-i-1, seen.at(i)); - } - seen.clear(); - - treap.visit_in_order([&](Node* x) { - seen.push(x->key()); - return true; - }); - EXPECT_EQ(10, seen.length()); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(10 - i - 1, seen.at(i)); - } - } -} - -TEST_VM_F(NMTTreapTest, TestFind) { - test_find(); -} - -TEST_VM_F(NMTTreapTest, TestClosestLeq) { - using Node = TreapCHeap::TreapNode; - { - TreapCHeap treap; - Node* n = treap.closest_leq(0); - EXPECT_EQ(nullptr, n); - - treap.upsert(0, 0); - n = treap.closest_leq(0); - EXPECT_EQ(0, n->key()); - - treap.upsert(-1, -1); - n = treap.closest_leq(0); - EXPECT_EQ(0, n->key()); - - treap.upsert(6, 0); - n = treap.closest_leq(6); - EXPECT_EQ(6, n->key()); - - n = treap.closest_leq(-2); - EXPECT_EQ(nullptr, n); - } -} - -#ifdef ASSERT - -TEST_VM_F(NMTTreapTest, VerifyItThroughStressTest) { - { // Repeatedly verify a treap of moderate size - TreapCHeap treap; - constexpr const int ten_thousand = 10000; - for (int i = 0; i < ten_thousand; i++) { - int r = os::random(); - if (r % 2 == 0) { - treap.upsert(i, i); - } else { - treap.remove(i); - } - if (i % 100 == 0) { - verify_it(treap); - } - } - for (int i = 0; i < ten_thousand; i++) { - int r = os::random(); - if (r % 2 == 0) { - treap.upsert(i, i); - } else { - treap.remove(i); - } - if (i % 100 == 0) { - verify_it(treap); - } - } - } - { // Make a very large treap and verify at the end - struct Nothing {}; - TreapCHeap treap; - constexpr const int one_hundred_thousand = 100000; - for (int i = 0; i < one_hundred_thousand; i++) { - treap.upsert(i, Nothing()); - } - verify_it(treap); - } -} -struct NTD { - static bool has_run_destructor; - ~NTD() { - has_run_destructor = true; - } -}; - -bool NTD::has_run_destructor = false; - -TEST_VM_F(NMTTreapTest, ValueDestructorsAreRun) { - TreapCHeap treap; - NTD ntd; - treap.upsert(0, ntd); - treap.remove(0); - EXPECT_TRUE(NTD::has_run_destructor); - NTD::has_run_destructor = false; - { - TreapCHeap treap; - NTD ntd; - treap.upsert(0, ntd); - } - EXPECT_TRUE(NTD::has_run_destructor); -} - -#endif // ASSERT diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index b43bfc58c69..cc4493a0e0f 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -31,7 +31,7 @@ #include "unittest.hpp" using Tree = VMATree; -using TNode = Tree::TreapNode; +using TNode = Tree::TNode; using NCS = NativeCallStackStorage; class NMTVMATreeTest : public testing::Test { @@ -54,16 +54,16 @@ public: // Utilities - VMATree::TreapNode* treap_root(VMATree& tree) { - return tree._tree._root; + VMATree::TNode* rbtree_root(VMATree& tree) { + return static_cast(tree._tree._root); } - VMATree::VMATreap& treap(VMATree& tree) { + VMATree::VMARBTree& rbtree(VMATree& tree) { return tree._tree; } - VMATree::TreapNode* find(VMATree::VMATreap& treap, const VMATree::position key) { - return treap.find(treap._root, key); + VMATree::TNode* find(VMATree::VMARBTree& rbtree, const VMATree::position key) { + return rbtree.find_node(key); } NativeCallStack make_stack(size_t a) { @@ -71,17 +71,17 @@ public: return stack; } - VMATree::StateType in_type_of(VMATree::TreapNode* x) { + VMATree::StateType in_type_of(VMATree::TNode* x) { return x->val().in.type(); } - VMATree::StateType out_type_of(VMATree::TreapNode* x) { + VMATree::StateType out_type_of(VMATree::TNode* x) { return x->val().out.type(); } int count_nodes(Tree& tree) { int count = 0; - treap(tree).visit_in_order([&](TNode* x) { + rbtree(tree).visit_in_order([&](TNode* x) { ++count; return true; }); @@ -123,14 +123,14 @@ public: for (int i = 0; i < 10; i++) { tree.release_mapping(i * 100, 100); } - EXPECT_EQ(nullptr, treap_root(tree)); + EXPECT_EQ(nullptr, rbtree_root(tree)); // Other way around tree.reserve_mapping(0, 100 * 10, rd); for (int i = 9; i >= 0; i--) { tree.release_mapping(i * 100, 100); } - EXPECT_EQ(nullptr, treap_root(tree)); + EXPECT_EQ(nullptr, rbtree_root(tree)); } // Committing in a whole reserved range results in 2 nodes @@ -140,7 +140,7 @@ public: for (int i = 0; i < 10; i++) { tree.commit_mapping(i * 100, 100, rd); } - treap(tree).visit_in_order([&](TNode* x) { + rbtree(tree).visit_in_order([&](TNode* x) { VMATree::StateType in = in_type_of(x); VMATree::StateType out = out_type_of(x); EXPECT_TRUE((in == VMATree::StateType::Released && out == VMATree::StateType::Committed) || @@ -166,7 +166,7 @@ public: }; int i = 0; - treap(tree).visit_in_order([&](TNode* x) { + rbtree(tree).visit_in_order([&](TNode* x) { if (i < 16) { found[i] = x->key(); } @@ -199,7 +199,7 @@ public: }; void call_update_region(const UpdateCallInfo upd) { - VMATree::TreapNode n1{upd.req.A, {}, 0}, n2{upd.req.B, {}, 0}; + VMATree::TNode n1{upd.req.A, {}}, n2{upd.req.B, {}}; n1.val().out= upd.ex_st; n2.val().in = n1.val().out; Tree tree; @@ -264,7 +264,7 @@ public: template void check_tree(Tree& tree, const ExpectedTree& et, int line_no) { - using Node = VMATree::TreapNode; + using Node = VMATree::TNode; auto left_released = [&](Node n) -> bool { return n.val().in.type() == VMATree::StateType::Released and n.val().in.mem_tag() == mtNone; @@ -274,7 +274,7 @@ public: n.val().out.mem_tag() == mtNone; }; for (int i = 0; i < N; i++) { - VMATree::VMATreap::Range r = tree.tree().find_enclosing_range(et.nodes[i]); + VMATree::VMARBTree::Range r = tree.tree().find_enclosing_range(et.nodes[i]); ASSERT_TRUE(r.start != nullptr); Node node = *r.start; ASSERT_EQ(node.key(), (VMATree::position)et.nodes[i]) << "at line " << line_no; @@ -354,7 +354,7 @@ TEST_VM_F(NMTVMATreeTest, DuplicateReserve) { tree.reserve_mapping(100, 100, rd); tree.reserve_mapping(100, 100, rd); EXPECT_EQ(2, count_nodes(tree)); - VMATree::VMATreap::Range r = tree.tree().find_enclosing_range(110); + VMATree::VMARBTree::Range r = tree.tree().find_enclosing_range(110); EXPECT_EQ(100, (int)(r.end->key() - r.start->key())); } @@ -369,7 +369,7 @@ TEST_VM_F(NMTVMATreeTest, UseTagInplace) { // post-cond: 0---20**30--40**70----100 tree.commit_mapping(20, 50, rd_None_cs1, true); tree.uncommit_mapping(30, 10, rd_None_cs1); - tree.visit_in_order([&](TNode* node) { + tree.visit_in_order([&](const TNode* node) { if (node->key() != 100) { EXPECT_EQ(mtTest, node->val().out.mem_tag()) << "failed at: " << node->key(); if (node->key() != 20 && node->key() != 40) { @@ -410,9 +410,9 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { VMATree::RegionData rd_NMT_cs1{si[1], mtNMT}; tree.commit_mapping(50, 50, rd_NMT_cs1); tree.reserve_mapping(0, 100, rd_Test_cs0); - treap(tree).visit_in_order([&](TNode* x) { + rbtree(tree).visit_in_order([&](const TNode* x) { EXPECT_TRUE(x->key() == 0 || x->key() == 100); - if (x->key() == 0) { + if (x->key() == 0UL) { EXPECT_EQ(x->val().out.reserved_regiondata().mem_tag, mtTest); } return true; @@ -438,7 +438,7 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { tree.reserve_mapping(0, 500000, rd_NMT_cs0); tree.release_mapping(0, 500000); - EXPECT_EQ(nullptr, treap_root(tree)); + EXPECT_EQ(nullptr, rbtree_root(tree)); } { // A committed region inside of/replacing a reserved region @@ -448,7 +448,7 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { Tree tree; tree.reserve_mapping(0, 100, rd_NMT_cs0); tree.commit_mapping(0, 100, rd_Test_cs1); - treap(tree).visit_range_in_order(0, 99999, [&](TNode* x) { + rbtree(tree).visit_range_in_order(0, 99999, [&](TNode* x) { if (x->key() == 0) { EXPECT_EQ(mtTest, x->val().out.reserved_regiondata().mem_tag); } @@ -463,9 +463,9 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { Tree tree; VMATree::RegionData rd_NMT_cs0{si[0], mtNMT}; tree.reserve_mapping(0, 0, rd_NMT_cs0); - EXPECT_EQ(nullptr, treap_root(tree)); + EXPECT_EQ(nullptr, rbtree_root(tree)); tree.commit_mapping(0, 0, rd_NMT_cs0); - EXPECT_EQ(nullptr, treap_root(tree)); + EXPECT_EQ(nullptr, rbtree_root(tree)); } } @@ -483,14 +483,14 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { auto expect_equivalent_form = [&](auto& expected, VMATree& tree, int line_no) { // With auto& our arrays do not deteriorate to pointers but are kept as testrange[N] // so this actually works! - int len = sizeof(expected) / sizeof(testrange); + size_t len = sizeof(expected) / sizeof(testrange); VMATree::position previous_to = 0; - for (int i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { testrange expect = expected[i]; assert(previous_to == 0 || previous_to <= expect.from, "the expected list must be sorted"); previous_to = expect.to; - VMATree::VMATreap::Range found = tree.tree().find_enclosing_range(expect.from); + VMATree::VMARBTree::Range found = tree.tree().find_enclosing_range(expect.from); ASSERT_NE(nullptr, found.start); ASSERT_NE(nullptr, found.end); // Same region @@ -993,10 +993,10 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { ASSERT_LE(end, SimpleVMATracker::num_pages); SimpleVMATracker::Info endi = tr->pages[end]; - VMATree::VMATreap& treap = this->treap(tree); - VMATree::TreapNode* startn = find(treap, start * page_size); + VMATree::VMARBTree& rbtree = this->rbtree(tree); + VMATree::TNode* startn = find(rbtree, start * page_size); ASSERT_NE(nullptr, startn); - VMATree::TreapNode* endn = find(treap, (end * page_size) + page_size); + VMATree::TNode* endn = find(rbtree, (end * page_size) + page_size); ASSERT_NE(nullptr, endn); const NativeCallStack& start_stack = ncss.get(startn->val().out.reserved_stack()); diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index c47e6cb2d58..e1be83bfd58 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -129,6 +129,7 @@ public: rbtree_const.visit_in_order([&](const RBTreeIntNode* node) { nums_seen.at(node->key())++; + return true; }); for (int i = 0; i < up_to; i++) { EXPECT_EQ(1, nums_seen.at(i)); @@ -210,6 +211,7 @@ public: rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) { EXPECT_TRUE(false) << "Empty rbtree has no nodes to visit"; + return true; }); // Single-element set @@ -217,14 +219,21 @@ public: int count = 0; rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) { count++; + return true; }); EXPECT_EQ(1, count); count = 0; rbtree_const.visit_in_order([&](const Node* x) { count++; + return true; }); EXPECT_EQ(1, count); + rbtree.visit_in_order([&](const Node* x) { + count++; + return true; + }); + EXPECT_EQ(2, count); // Add an element outside of the range that should not be visited on the right side and // one on the left side. @@ -233,21 +242,62 @@ public: count = 0; rbtree_const.visit_range_in_order(0, 100, [&](const Node* x) { count++; + return true; }); EXPECT_EQ(1, count); + rbtree.visit_range_in_order(0, 100, [&](const Node* x) { + count++; + return true; + }); + EXPECT_EQ(2, count); count = 0; rbtree_const.visit_in_order([&](const Node* x) { count++; + return true; }); EXPECT_EQ(3, count); + rbtree.visit_in_order([&](const Node* x) { + count++; + return true; + }); + EXPECT_EQ(6, count); count = 0; rbtree.upsert(0, 0); rbtree_const.visit_range_in_order(0, 0, [&](const Node* x) { count++; + return true; }); EXPECT_EQ(1, count); + rbtree.visit_range_in_order(0, 0, [&](const Node* x) { + count++; + return true; + }); + EXPECT_EQ(2, count); + + // Test exiting visit early + rbtree.remove_all(); + for (int i = 0; i < 11; i++) { + rbtree.upsert(i, 0); + } + + count = 0; + rbtree_const.visit_in_order([&](const Node* x) { + if (x->key() >= 6) return false; + count++; + return true; + }); + EXPECT_EQ(6, count); + + count = 0; + rbtree_const.visit_range_in_order(6, 10, [&](const Node* x) { + if (x->key() >= 6) return false; + count++; + return true; + }); + + EXPECT_EQ(0, count); rbtree.remove_all(); for (int i = 0; i < 11; i++) { @@ -258,6 +308,7 @@ public: GrowableArray seen; rbtree_const.visit_range_in_order(0, 9, [&](const Node* x) { seen.push(x->key()); + return true; }); EXPECT_EQ(10, seen.length()); for (int i = 0; i < 10; i++) { @@ -267,6 +318,7 @@ public: seen.clear(); rbtree_const.visit_in_order([&](const Node* x) { seen.push(x->key()); + return true; }); EXPECT_EQ(11, seen.length()); for (int i = 0; i < 10; i++) { @@ -276,6 +328,7 @@ public: seen.clear(); rbtree_const.visit_range_in_order(10, 12, [&](const Node* x) { seen.push(x->key()); + return true; }); EXPECT_EQ(1, seen.length()); EXPECT_EQ(10, seen.at(0)); @@ -292,6 +345,7 @@ public: GrowableArray seen; rbtree_const.visit_range_in_order(9, -1, [&](const Node* x) { seen.push(x->key()); + return true; }); EXPECT_EQ(10, seen.length()); for (int i = 0; i < 10; i++) { @@ -301,6 +355,7 @@ public: rbtree_const.visit_in_order([&](const Node* x) { seen.push(x->key()); + return true; }); EXPECT_EQ(10, seen.length()); for (int i = 0; i < 10; i++) { @@ -320,9 +375,12 @@ public: {4, 4}, {6, 6}, {6, 7}, {7, 7}}; for (const int (&test_case)[2] : test_cases) { - rbtree.visit_range_in_order(test_case[0], test_case[1], [&](const Node* x) { - FAIL() << "Range should not visit nodes"; + bool visited = false; + rbtree.visit_range_in_order(test_case[0], test_case[1], [&](const Node* x) -> bool { + visited = true; + return true; }); + EXPECT_FALSE(visited); } } @@ -515,6 +573,7 @@ public: // After deleting, values should have remained consistant rbtree.visit_in_order([&](const Node* node) { EXPECT_EQ(node, node->val()); + return true; }); } From 23985c29b44b489472dcd3aad2cb98d9ce003a7b Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 11 Aug 2025 14:12:55 +0000 Subject: [PATCH 041/471] 8357979: Compile jdk.internal.vm.ci targeting the Boot JDK version Reviewed-by: erikj, dnsimon --- make/CompileJavaModules.gmk | 1 + make/autoconf/boot-jdk.m4 | 6 ++---- make/autoconf/spec.gmk.template | 5 ++--- make/common/JavaCompilation.gmk | 11 ++++++++--- make/modules/jdk.internal.vm.ci/Java.gmk | 2 ++ 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index c6e8fab3038..54d063a7a71 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -115,6 +115,7 @@ $(eval $(call SetupJavaCompilation, $(MODULE), \ EXCLUDE_FILES := $(EXCLUDE_FILES), \ EXCLUDE_PATTERNS := -files, \ KEEP_ALL_TRANSLATIONS := $(KEEP_ALL_TRANSLATIONS), \ + TARGET_RELEASE := $(TARGET_RELEASE), \ JAVAC_FLAGS := \ $(DOCLINT) \ $(JAVAC_FLAGS) \ diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index feb16c7d179..4ba1f9f2089 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -395,11 +395,9 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], # When compiling code to be executed by the Boot JDK, force compatibility with the # oldest supported bootjdk. - OLDEST_BOOT_JDK=`$ECHO $DEFAULT_ACCEPTABLE_BOOT_VERSIONS \ + OLDEST_BOOT_JDK_VERSION=`$ECHO $DEFAULT_ACCEPTABLE_BOOT_VERSIONS \ | $TR " " "\n" | $SORT -n | $HEAD -n1` - # -Xlint:-options is added to avoid "warning: [options] system modules path not set in conjunction with -source" - BOOT_JDK_SOURCETARGET="-source $OLDEST_BOOT_JDK -target $OLDEST_BOOT_JDK -Xlint:-options" - AC_SUBST(BOOT_JDK_SOURCETARGET) + AC_SUBST(OLDEST_BOOT_JDK_VERSION) # Check if the boot jdk is 32 or 64 bit if $JAVA -version 2>&1 | $GREP -q "64-Bit"; then diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index e720916d88a..c96b730c6fa 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -393,9 +393,8 @@ EXTERNAL_BUILDJDK := @EXTERNAL_BUILDJDK@ # Whether the boot jdk jar supports --date=TIMESTAMP BOOT_JDK_JAR_SUPPORTS_DATE := @BOOT_JDK_JAR_SUPPORTS_DATE@ -# When compiling Java source to be run by the boot jdk -# use these extra flags, eg -source 6 -target 6 -BOOT_JDK_SOURCETARGET := @BOOT_JDK_SOURCETARGET@ +# The oldest supported boot jdk version +OLDEST_BOOT_JDK_VERSION := @OLDEST_BOOT_JDK_VERSION@ # Information about the build system NUM_CORES := @NUM_CORES@ diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 99672d59884..33f5d10535a 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -38,10 +38,15 @@ include JarArchive.gmk ### # Create classes that can run on the bootjdk -TARGET_RELEASE_BOOTJDK := $(BOOT_JDK_SOURCETARGET) +# -Xlint:-options is added to avoid the warning +# "system modules path not set in conjunction with -source" +TARGET_RELEASE_BOOTJDK := -source $(OLDEST_BOOT_JDK_VERSION) \ + -target $(OLDEST_BOOT_JDK_VERSION) -Xlint:-options -# Create classes that can be used in (or be a part of) the new jdk we're building -TARGET_RELEASE_NEWJDK := -source $(JDK_SOURCE_TARGET_VERSION) -target $(JDK_SOURCE_TARGET_VERSION) +# Create classes that can be used in (or be a part of) the new jdk we're +# building +TARGET_RELEASE_NEWJDK := -source $(JDK_SOURCE_TARGET_VERSION) \ + -target $(JDK_SOURCE_TARGET_VERSION) # Create classes that can be used in JDK 8, for legacy support TARGET_RELEASE_JDK8 := --release 8 diff --git a/make/modules/jdk.internal.vm.ci/Java.gmk b/make/modules/jdk.internal.vm.ci/Java.gmk index cb569bb8817..75a52a3128d 100644 --- a/make/modules/jdk.internal.vm.ci/Java.gmk +++ b/make/modules/jdk.internal.vm.ci/Java.gmk @@ -33,4 +33,6 @@ DISABLED_WARNINGS_java += dangling-doc-comments this-escape JAVAC_FLAGS += -parameters -XDstringConcat=inline +TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK) + ################################################################################ From bdb1646a1e39bae0535efe3f593e7fc0545e4114 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 11 Aug 2025 15:37:31 +0000 Subject: [PATCH 042/471] 8364611: (process) Child process SIGPIPE signal disposition should be default Reviewed-by: erikj, rriggs --- make/test/JtregNativeJdk.gmk | 3 +- src/java.base/unix/native/libjava/childproc.c | 5 ++ .../TestChildSignalDisposition.java | 70 ++++++++++++++++ .../exePrintSignalDisposition.c | 79 +++++++++++++++++++ .../libChangeSignalDisposition.c | 40 ++++++++++ 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java create mode 100644 test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c create mode 100644 test/jdk/java/lang/ProcessBuilder/childSignalDisposition/libChangeSignalDisposition.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index f5970527648..7578d4a50d0 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -62,7 +62,8 @@ BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libGetXSpace := java.base:libjava ifeq ($(call isTargetOs, windows), true) BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c \ libExplicitAttach.c libImplicitAttach.c \ - exelauncher.c libFDLeaker.c exeFDLeakTester.c + exelauncher.c libFDLeaker.c exeFDLeakTester.c \ + libChangeSignalDisposition.c exePrintSignalDisposition.c BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerTest := $(LIBCXX) BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 93d2200a465..c4b5a2d7b29 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -426,6 +426,11 @@ childProcess(void *arg) sigprocmask(SIG_SETMASK, &unblock_signals, NULL); } + // Children should be started with default signal disposition for SIGPIPE + if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { + goto WhyCantJohnnyExec; + } + JDK_execvpe(p->mode, p->argv[0], p->argv, p->envv); WhyCantJohnnyExec: diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java new file mode 100644 index 00000000000..50fe054ee34 --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=posix_spawn + * @bug 8364611 + * @summary Check that childs start with SIG_DFL as SIGPIPE disposition + * @requires os.family != "windows" + * @library /test/lib + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:ChangeSignalDisposition TestChildSignalDisposition + */ + +/** + * @test id=fork + * @bug 8364611 + * @summary Check that childs start with SIG_DFL as SIGPIPE disposition + * @requires os.family != "windows" + * @library /test/lib + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:ChangeSignalDisposition TestChildSignalDisposition + */ + +/** + * @test id=vfork + * @bug 8364611 + * @summary Check that childs start with SIG_DFL as SIGPIPE disposition + * @requires os.family == "linux" + * @library /test/lib + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:ChangeSignalDisposition TestChildSignalDisposition + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +public class TestChildSignalDisposition { + // This test has two native parts: + // - a library injected into the JVM with -agentlib changes signal disposition of the VM process for SIGPIPE to + // SIG_IGN + // - a small native executable that prints out, in its main function, all signal handler dispositions, to be executed + // as a child process. + // + // What should happen: In child process, SIGPIPE should be set to default. + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createNativeTestProcessBuilder("PrintSignalDisposition"); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.shouldHaveExitValue(0); + output.shouldNotMatch("SIGPIPE: +ignore"); + output.shouldNotMatch("SIGPIPE: +block"); + output.shouldMatch("SIGPIPE: +default"); + output.reportDiagnosticSummary(); + } +} diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c new file mode 100644 index 00000000000..5a96c2556fc --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "jvmti.h" +#include +#include +#include + +static const struct { int sig; const char* name; } signals[] = { + { SIGABRT, "SIGABRT" }, { SIGALRM, "SIGALRM" }, { SIGBUS, "SIGBUS" }, { SIGCHLD, "SIGCHLD" }, { SIGCONT, "SIGCONT" }, + { SIGFPE, "SIGFPE" }, { SIGHUP, "SIGHUP" }, { SIGILL, "SIGILL" }, { SIGINT, "SIGINT" }, { SIGKILL, "SIGKILL" }, + { SIGPIPE, "SIGPIPE" }, { SIGQUIT, "SIGQUIT" }, { SIGSEGV, "SIGSEGV" }, { SIGSTOP, "SIGSTOP" }, { SIGTERM, "SIGTERM" }, + { SIGTSTP, "SIGTSTP" }, { SIGTTIN, "SIGTTIN" }, { SIGTTOU, "SIGTTOU" }, { SIGUSR1, "SIGUSR1" }, { SIGUSR2, "SIGUSR2" }, +#ifdef SIGPOLL + { SIGPOLL, "SIGPOLL" }, +#endif + { SIGPROF, "SIGPROF" }, { SIGSYS, "SIGSYS" }, { SIGTRAP, "SIGTRAP" }, { SIGURG, "SIGURG" }, { SIGVTALRM, "SIGVTALRM" }, + { SIGXCPU, "SIGXCPU" }, { SIGXFSZ, "SIGXFSZ" }, { -1, NULL } +}; + +int main(int argc, char** argv) { + + printf("PID: %d\n", getpid()); + + sigset_t current_mask; + sigemptyset(¤t_mask); + if (sigprocmask(SIG_BLOCK /* ignored */, NULL, ¤t_mask) != 0) { + printf("sigprocmask %d\n", errno); + return -1; + } + + for (int n = 0; signals[n].sig != -1; n++) { + printf("%s: ", signals[n].name); + if (sigismember(¤t_mask, signals[n].sig)) { + printf("blocked "); + } + struct sigaction act; + if (sigaction(signals[n].sig, NULL, &act) != 0) { + printf("sigaction %d\n", errno); + printf("\n"); + continue; + } + const void* const handler = (act.sa_flags & SA_SIGINFO ? + (void*)act.sa_sigaction : (void*)act.sa_handler); + if (handler == (void*)SIG_DFL) { + printf("default "); + } else if (handler == (void*)SIG_IGN) { + printf("ignore "); + } else if (handler == (void*)SIG_HOLD) { + printf("hold "); + } else { + printf("%p ", handler); + } + printf("%X %X\n", act.sa_flags, act.sa_mask); + } + + return 0; +} diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/libChangeSignalDisposition.c b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/libChangeSignalDisposition.c new file mode 100644 index 00000000000..83365bb79c6 --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/libChangeSignalDisposition.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "jvmti.h" +#include +#include + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + + if (signal(SIGPIPE, SIG_IGN) != SIG_ERR) { + printf("changed signal disposition for SIGPIPE to SIG_IGN\n"); + } else { + printf("FAILED to change signal disposition for SIGPIPE to SIG_IGN (%d)\n", errno); + return JNI_ERR; + } + + return JNI_OK; +} From e9e331b2a957180dac2e9ce19a58d0a57d2f5dae Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 11 Aug 2025 17:10:10 +0000 Subject: [PATCH 043/471] 8365238: 'jfr' feature requires 'services' with 'custom' build variant Reviewed-by: erikj, shade, ihse --- make/autoconf/jvm-features.m4 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index 668de019469..234d7b74268 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -513,6 +513,10 @@ AC_DEFUN([JVM_FEATURES_VERIFY], [ variant=$1 + if JVM_FEATURES_IS_ACTIVE(jfr) && ! JVM_FEATURES_IS_ACTIVE(services); then + AC_MSG_ERROR([Specified JVM feature 'jfr' requires feature 'services' for variant '$variant']) + fi + if JVM_FEATURES_IS_ACTIVE(jvmci) && ! (JVM_FEATURES_IS_ACTIVE(compiler1) || \ JVM_FEATURES_IS_ACTIVE(compiler2)); then AC_MSG_ERROR([Specified JVM feature 'jvmci' requires feature 'compiler2' or 'compiler1' for variant '$variant']) From 958383d69c8742fdb78c28ad856559367c3513d7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 11 Aug 2025 18:49:37 +0000 Subject: [PATCH 044/471] 8364501: Compiler shutdown crashes on access to deleted CompileTask Reviewed-by: kvn, mhaessig --- src/hotspot/share/compiler/compileBroker.cpp | 22 +++++++++++++------- src/hotspot/share/compiler/compileTask.cpp | 1 + src/hotspot/share/compiler/compileTask.hpp | 3 ++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 59f41f1c0dc..36663ab1088 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -371,6 +371,7 @@ void CompileQueue::delete_all() { // Iterate over all tasks in the compile queue while (current != nullptr) { + CompileTask* next = current->next(); if (!current->is_blocking()) { // Non-blocking task. No one is waiting for it, delete it now. delete current; @@ -379,7 +380,7 @@ void CompileQueue::delete_all() { // to delete the task. We cannot delete it here, because we do not // coordinate with waiters. We will notify the waiters later. } - current = current->next(); + current = next; } _first = nullptr; _last = nullptr; @@ -504,6 +505,8 @@ void CompileQueue::remove(CompileTask* task) { assert(task == _last, "Sanity"); _last = task->prev(); } + task->set_next(nullptr); + task->set_prev(nullptr); --_size; ++_total_removed; } @@ -1728,17 +1731,22 @@ void CompileBroker::wait_for_completion(CompileTask* task) { // It is harmless to check this status without the lock, because // completion is a stable property. - if (!task->is_complete() && is_compilation_disabled_forever()) { - // Task is not complete, and we are exiting for compilation shutdown. - // The task can still be executed by some compiler thread, therefore - // we cannot delete it. This will leave task allocated, which leaks it. - // At this (degraded) point, it is less risky to abandon the task, - // rather than attempting a more complicated deletion protocol. + if (!task->is_complete()) { + // Task is not complete, likely because we are exiting for compilation + // shutdown. The task can still be reached through the queue, or executed + // by some compiler thread. There is no coordination with either MCQ lock + // holders or compilers, therefore we cannot delete the task. + // + // This will leave task allocated, which leaks it. At this (degraded) point, + // it is less risky to abandon the task, rather than attempting a more + // complicated deletion protocol. free_task = false; } if (free_task) { assert(task->is_complete(), "Compilation should have completed"); + assert(task->next() == nullptr && task->prev() == nullptr, + "Completed task should not be in the queue"); // By convention, the waiter is responsible for deleting a // blocking CompileTask. Since there is only one waiter ever diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index c5f1c789039..e3b640372a3 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -74,6 +74,7 @@ CompileTask::CompileTask(int compile_id, _arena_bytes = 0; _next = nullptr; + _prev = nullptr; Atomic::add(&_active_tasks, 1, memory_order_relaxed); } diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 148bdd28009..2cc5e9afe3c 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -101,7 +101,8 @@ class CompileTask : public CHeapObj { #endif int _comp_level; int _num_inlined_bytecodes; - CompileTask* _next, *_prev; + CompileTask* _next; + CompileTask* _prev; // Fields used for logging why the compilation was initiated: jlong _time_queued; // time when task was enqueued jlong _time_started; // time when compilation started From 8cd79752c6426780c6772eafe296aa5b713b2b64 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 11 Aug 2025 18:50:39 +0000 Subject: [PATCH 045/471] 8364761: (aio) AsynchronousChannelGroup.execute doesn't check null command Reviewed-by: alanb, vyazici --- .../nio/ch/AsynchronousChannelGroupImpl.java | 4 +- .../AsynchronousChannelGroup/AsExecutor.java | 80 ++++++++++++------- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java index d69869975a5..3472b18322d 100644 --- a/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,7 @@ import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.spi.AsynchronousChannelProvider; import java.io.IOException; import java.io.FileDescriptor; +import java.util.Objects; import java.util.Queue; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; @@ -299,6 +300,7 @@ abstract class AsynchronousChannelGroupImpl */ @Override public final void execute(Runnable task) { + Objects.requireNonNull(task, "task"); executeOnPooledThread(task); } } diff --git a/test/jdk/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java b/test/jdk/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java index 02a8cbf3deb..a1564e4ff72 100644 --- a/test/jdk/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java +++ b/test/jdk/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -23,49 +23,75 @@ /* * @test - * @bug 4607272 + * @bug 4607272 8364761 * @summary tests tasks can be submitted to a channel group's thread pool. - * @run main AsExecutor + * @run junit AsExecutor */ +import java.io.IOException; import java.nio.channels.AsynchronousChannelGroup; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; public class AsExecutor { + private static ThreadFactory factory; - public static void main(String[] args) throws Exception { - // create channel groups - ThreadFactory factory = Executors.defaultThreadFactory(); - AsynchronousChannelGroup group1 = AsynchronousChannelGroup - .withFixedThreadPool(5, factory); - AsynchronousChannelGroup group2 = AsynchronousChannelGroup - .withCachedThreadPool(Executors.newCachedThreadPool(factory), 0); - AsynchronousChannelGroup group3 = AsynchronousChannelGroup - .withThreadPool(Executors.newFixedThreadPool(10, factory)); + @BeforeAll + public static void createThreadFactory() { + factory = Executors.defaultThreadFactory(); + } + private static Stream channelGroups() throws IOException { + List list = new ArrayList(); + list.add(Arguments.of(AsynchronousChannelGroup + .withFixedThreadPool(5, factory))); + list.add(Arguments.of(AsynchronousChannelGroup + .withCachedThreadPool(Executors.newCachedThreadPool(factory), 0))); + list.add(Arguments.of(AsynchronousChannelGroup + .withThreadPool(Executors.newFixedThreadPool(10, factory)))); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("channelGroups") + public void simpleTask(AsynchronousChannelGroup group) + throws InterruptedException + { try { - // execute simple tasks - testSimpleTask(group1); - testSimpleTask(group2); - testSimpleTask(group3); + Executor executor = (Executor)group; + final CountDownLatch latch = new CountDownLatch(1); + executor.execute(new Runnable() { + public void run() { + latch.countDown(); + } + }); + latch.await(); } finally { - group1.shutdown(); - group2.shutdown(); - group3.shutdown(); + group.shutdown(); } } - static void testSimpleTask(AsynchronousChannelGroup group) throws Exception { + @ParameterizedTest + @MethodSource("channelGroups") + public void nullTask(AsynchronousChannelGroup group) { Executor executor = (Executor)group; - final CountDownLatch latch = new CountDownLatch(1); - executor.execute(new Runnable() { - public void run() { - latch.countDown(); - } - }); - latch.await(); + try { + assertThrows(NullPointerException.class, + () -> executor.execute(null)); + } finally { + group.shutdown(); + } } } From 9593730a23f465d26ba7b310d5b0c5d3b4ee4326 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 11 Aug 2025 23:45:24 +0000 Subject: [PATCH 046/471] 8362376: Use @Stable annotation in Java FDLIBM implementation Reviewed-by: liach, rgiulietti --- .../share/classes/java/lang/FdLibm.java | 51 +++++++++++-------- test/jdk/java/lang/StrictMath/ExpTests.java | 8 ++- test/jdk/java/lang/StrictMath/PowTests.java | 19 ++++++- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/lang/FdLibm.java b/src/java.base/share/classes/java/lang/FdLibm.java index 70d728a16db..73e1da46af4 100644 --- a/src/java.base/share/classes/java/lang/FdLibm.java +++ b/src/java.base/share/classes/java/lang/FdLibm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.vm.annotation.Stable; + /** * Port of the "Freely Distributable Math Library", version 5.3, from * C to Java. @@ -451,8 +453,10 @@ final class FdLibm { */ private static final double pio4 = 0x1.921fb54442d18p-1, // 7.85398163397448278999e-01 - pio4lo= 0x1.1a62633145c07p-55, // 3.06161699786838301793e-17 - T[] = { + pio4lo= 0x1.1a62633145c07p-55; // 3.06161699786838301793e-17 + @Stable + private static final double[] + T = { 0x1.5555555555563p-2, // 3.33333333333334091986e-01 0x1.111111110fe7ap-3, // 1.33333333333201242699e-01 0x1.ba1ba1bb341fep-5, // 5.39682539762260521377e-02 @@ -546,6 +550,7 @@ final class FdLibm { /* * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi */ + @Stable private static final int[] two_over_pi = { 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, @@ -560,6 +565,7 @@ final class FdLibm { 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, }; + @Stable private static final int[] npio2_hw = { 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, 0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, @@ -807,8 +813,10 @@ final class FdLibm { * to produce the hexadecimal values shown. */ + @Stable private static final int init_jk[] = {2, 3, 4, 6}; // initial value for jk + @Stable private static final double PIo2[] = { 0x1.921fb4p0, // 1.57079625129699707031e+00 0x1.4442dp-24, // 7.54978941586159635335e-08 @@ -1232,6 +1240,7 @@ final class FdLibm { static final class Atan { private Atan() {throw new UnsupportedOperationException();} + @Stable private static final double atanhi[] = { 0x1.dac670561bb4fp-2, // atan(0.5)hi 4.63647609000806093515e-01 0x1.921fb54442d18p-1, // atan(1.0)hi 7.85398163397448278999e-01 @@ -1239,6 +1248,7 @@ final class FdLibm { 0x1.921fb54442d18p0, // atan(inf)hi 1.57079632679489655800e+00 }; + @Stable private static final double atanlo[] = { 0x1.a2b7f222f65e2p-56, // atan(0.5)lo 2.26987774529616870924e-17 0x1.1a62633145c07p-55, // atan(1.0)lo 3.06161699786838301793e-17 @@ -1246,6 +1256,7 @@ final class FdLibm { 0x1.1a62633145c07p-54, // atan(inf)lo 6.12323399573676603587e-17 }; + @Stable private static final double aT[] = { 0x1.555555555550dp-2, // 3.33333333333329318027e-01 -0x1.999999998ebc4p-3, // -1.99999999998764832476e-01 @@ -2245,12 +2256,8 @@ final class FdLibm { // Compute ss = s_h + s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) - final double BP[] = {1.0, - 1.5}; - final double DP_H[] = {0.0, - 0x1.2b80_34p-1}; // 5.84962487220764160156e-01 - final double DP_L[] = {0.0, - 0x1.cfde_b43c_fd006p-27};// 1.35003920212974897128e-08 + final double DP_H = 0x1.2b80_34p-1; // 5.84962487220764160156e-01 + final double DP_L = 0x1.cfde_b43c_fd006p-27; // 1.35003920212974897128e-08 // Poly coefs for (3/2)*(log(x)-2s-2/3*s**3 final double L1 = 0x1.3333_3333_33303p-1; // 5.99999999999994648725e-01 @@ -2259,15 +2266,17 @@ final class FdLibm { final double L4 = 0x1.1746_0a91_d4101p-2; // 2.72728123808534006489e-01 final double L5 = 0x1.d864_a93c_9db65p-3; // 2.30660745775561754067e-01 final double L6 = 0x1.a7e2_84a4_54eefp-3; // 2.06975017800338417784e-01 - u = x_abs - BP[k]; // BP[0]=1.0, BP[1]=1.5 - v = 1.0 / (x_abs + BP[k]); + + double BP_k = 1.0 + 0.5*k; // BP[0]=1.0, BP[1]=1.5 + u = x_abs - BP_k; + v = 1.0 / (x_abs + BP_k); ss = u * v; s_h = ss; s_h = __LO(s_h, 0); // t_h=x_abs + BP[k] High t_h = 0.0; t_h = __HI(t_h, ((ix >> 1) | 0x20000000) + 0x00080000 + (k << 18) ); - t_l = x_abs - (t_h - BP[k]); + t_l = x_abs - (t_h - BP_k); s_l = v * ((u - s_h * t_h) - s_h * t_l); // Compute log(x_abs) s2 = ss * ss; @@ -2285,12 +2294,12 @@ final class FdLibm { p_h = __LO(p_h, 0); p_l = v - (p_h - u); z_h = CP_H * p_h; // CP_H + CP_L = 2/(3*log2) - z_l = CP_L * p_h + p_l * CP + DP_L[k]; + z_l = CP_L * p_h + p_l * CP + DP_L*k; // log2(x_abs) = (ss + ..)*2/(3*log2) = n + DP_H + z_h + z_l t = (double)n; - t1 = (((z_h + z_l) + DP_H[k]) + t); + t1 = (((z_h + z_l) + DP_H*k) + t); t1 = __LO(t1, 0); - t2 = z_l - (((t1 - t) - DP_H[k]) - z_h); + t2 = z_l - (((t1 - t) - DP_H*k) - z_h); } // Split up y into (y1 + y2) and compute (y1 + y2) * (t1 + t2) @@ -2430,13 +2439,13 @@ final class FdLibm { static final class Exp { private Exp() {throw new UnsupportedOperationException();} - private static final double[] half = {0.5, -0.5,}; private static final double huge = 1.0e+300; private static final double twom1000= 0x1.0p-1000; // 9.33263618503218878990e-302 = 2^-1000 private static final double o_threshold= 0x1.62e42fefa39efp9; // 7.09782712893383973096e+02 private static final double u_threshold= -0x1.74910d52d3051p9; // -7.45133219101941108420e+02; - private static final double[] ln2HI ={ 0x1.62e42feep-1, // 6.93147180369123816490e-01 - -0x1.62e42feep-1}; // -6.93147180369123816490e-01 + private static final double ln2HI = 0x1.62e42feep-1; // 6.93147180369123816490e-01 + + @Stable private static final double[] ln2LO ={ 0x1.a39ef35793c76p-33, // 1.90821492927058770002e-10 -0x1.a39ef35793c76p-33}; // -1.90821492927058770002e-10 private static final double invln2 = 0x1.71547652b82fep0; // 1.44269504088896338700e+00 @@ -2478,13 +2487,13 @@ final class FdLibm { /* argument reduction */ if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ - hi = x - ln2HI[xsb]; + hi = x - ln2HI*(1 - 2*xsb); /* +/- ln2HI */ lo=ln2LO[xsb]; k = 1 - xsb - xsb; } else { - k = (int)(invln2 * x + half[xsb]); + k = (int)(invln2 * x + 0.5 * (1 - 2*xsb) /* +/- 0.5 */ ); t = k; - hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */ + hi = x - t*ln2HI; /* t*ln2HI is exact here */ lo = t*ln2LO[0]; } x = hi - lo; diff --git a/test/jdk/java/lang/StrictMath/ExpTests.java b/test/jdk/java/lang/StrictMath/ExpTests.java index 9f7d2d1ffd0..c36314a48fa 100644 --- a/test/jdk/java/lang/StrictMath/ExpTests.java +++ b/test/jdk/java/lang/StrictMath/ExpTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8139688 + * @bug 8139688 8362376 * @key randomness * @library /test/lib * @build jdk.test.lib.RandomFactory @@ -87,6 +87,10 @@ public class ExpTests { {-0x1.49f33ad2c1c58p+9, 0x1.f3ccc815431b6p-953}, {+0x1.fce66609f7428p+5, 0x1.b59724cb0bc4cp91}, {-0x1.49f33ad2c1c58p+9, 0x1.f3ccc815431b6p-953}, + + // Test values near 0.5*ln*(2) and 1.5*ln(2) to check refactoring + {0.34657359027997275, 1.4142135623730951}, + {1.0397207708399183, 2.828427124746191}, }; for(double[] testCase: testCases) diff --git a/test/jdk/java/lang/StrictMath/PowTests.java b/test/jdk/java/lang/StrictMath/PowTests.java index 2936dfdf247..4b68c5bdcd6 100644 --- a/test/jdk/java/lang/StrictMath/PowTests.java +++ b/test/jdk/java/lang/StrictMath/PowTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8136874 + * @bug 8136874 8362376 * @summary Tests for StrictMath.pow */ @@ -283,6 +283,21 @@ public class PowTests { 0x1.ffffffffffd9fp1023, // 1.7976931348621944E308 }, + // Check refactoring, abs(y) < 2^31, x < sqrt(3/2), x < sqrt(3) + {1.2, // x < sqrt(3/2) + 5.0, + 2.4883199999999994 + }, + + {1.4142135623730951, // sqrt(3/2) < x < sqrt(3) + 5.0, + 5.656854249492382 + }, + + {2.23606797749979, // x > sqrt(3) + 5.0, + 55.901699437494756 + }, }; for (double[] testCase: testCases) From 6927fc3904eb239bd43ab7c581d479c00a6a4af2 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 12 Aug 2025 01:25:35 +0000 Subject: [PATCH 047/471] 8365200: RISC-V: compiler/loopopts/superword/TestGeneralizedReductions.java fails with Zvbb and vlen=128 Reviewed-by: fyang, fjiang --- .../loopopts/superword/TestGeneralizedReductions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestGeneralizedReductions.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestGeneralizedReductions.java index bda0979a70b..6c2f0d825b9 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestGeneralizedReductions.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestGeneralizedReductions.java @@ -160,13 +160,13 @@ public class TestGeneralizedReductions { @Test @IR(applyIfCPUFeatureOr = {"avx2", "true"}, - applyIfAnd = {"SuperWordReductions", "true","UsePopCountInstruction", "true"}, + applyIfAnd = {"SuperWordReductions", "true", "UsePopCountInstruction", "true"}, applyIfPlatform = {"64-bit", "true"}, counts = {IRNode.ADD_REDUCTION_VI, ">= 1", IRNode.POPCOUNT_VL, ">= 1"}) @IR(applyIfPlatform = {"riscv64", "true"}, applyIfCPUFeatureOr = {"zvbb", "true"}, - applyIfAnd = {"SuperWordReductions", "true","UsePopCountInstruction", "true"}, + applyIfAnd = {"SuperWordReductions", "true", "UsePopCountInstruction", "true", "MaxVectorSize", ">=32"}, counts = {IRNode.ADD_REDUCTION_VI, ">= 1", IRNode.POPCOUNT_VL, ">= 1"}) private static long testMapReductionOnGlobalAccumulator(long[] array) { From 72d3a2a9773b2a3fe0351e0acb7b10c0751d23d8 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 12 Aug 2025 03:15:49 +0000 Subject: [PATCH 048/471] 8308349: missing working directory option for launcher when invoked from shortcuts Reviewed-by: almatvee --- .../jpackage/internal/DesktopIntegration.java | 18 ++ .../jpackage/internal/LinuxFromParams.java | 8 +- .../internal/resources/template.desktop | 1 + .../jdk/jpackage/internal/Arguments.java | 41 ++- .../jdk/jpackage/internal/FromParams.java | 30 ++- .../LauncherShortcutStartupDirectory.java | 9 +- .../jpackage/internal/model/ParseUtils.java | 59 +++++ .../resources/MainResources.properties | 2 + .../jdk/jpackage/internal/WinFromParams.java | 4 +- .../internal/WixAppImageFragmentBuilder.java | 3 + .../jdk/jpackage/test/AdditionalLauncher.java | 4 + .../jdk/jpackage/test/LauncherShortcut.java | 12 +- .../jdk/jpackage/test/LinuxHelper.java | 3 + .../jpackage/test/WinShortcutVerifier.java | 12 +- .../jpackage/share/AddLShortcutTest.java | 242 ++++++++++++------ test/jdk/tools/jpackage/share/ErrorTest.java | 12 + 16 files changed, 352 insertions(+), 108 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ParseUtils.java diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 476ca3201ce..dad9917c48f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -46,6 +46,7 @@ import javax.imageio.ImageIO; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.model.FileAssociation; +import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.Package; @@ -237,6 +238,23 @@ final class DesktopIntegration extends ShellCustomAction { data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName()); data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo( installedLayout.launchersDirectory().resolve(launcher.executableNameWithSuffix()).toString())); + data.put("STARTUP_DIRECTORY", launcher.shortcut() + .flatMap(LauncherShortcut::startupDirectory) + .map(startupDirectory -> { + switch (startupDirectory) { + case DEFAULT -> { + return (Path)null; + } + case APP_DIR -> { + return installedLayout.appDirectory(); + } + default -> { + throw new AssertionError(); + } + } + }).map(str -> { + return "Path=" + str; + }).orElse(null)); return data; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index 6967dea111e..ced77b1aa68 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -109,12 +109,8 @@ final class LinuxFromParams { static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( LinuxFromParams::createLinuxDebPackage); - private static final BundlerParamInfo LINUX_SHORTCUT_HINT = new BundlerParamInfo<>( - Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(), - Boolean.class, - params -> false, - (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s) - ); + private static final BundlerParamInfo LINUX_SHORTCUT_HINT = createStringBundlerParam( + Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId()); private static final BundlerParamInfo LINUX_CATEGORY = createStringBundlerParam( Arguments.CLIOptions.LINUX_CATEGORY.getId()); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop index bd645b77669..de7df568454 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop @@ -2,6 +2,7 @@ Name=APPLICATION_NAME Comment=APPLICATION_DESCRIPTION Exec=APPLICATION_LAUNCHER +STARTUP_DIRECTORY Icon=APPLICATION_ICON Terminal=false Type=Application diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index 4700231a162..f9a5429a8bf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -37,6 +37,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.ResourceBundle; @@ -348,16 +349,13 @@ public class Arguments { WIN_UPDATE_URL ("win-update-url", OptionCategories.PLATFORM_WIN), - WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-menu", true); - }), + WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN, + createArgumentWithOptionalValueAction("win-menu")), WIN_MENU_GROUP ("win-menu-group", OptionCategories.PLATFORM_WIN), - WIN_SHORTCUT_HINT ("win-shortcut", - OptionCategories.PLATFORM_WIN, () -> { - setOptionValue("win-shortcut", true); - }), + WIN_SHORTCUT_HINT ("win-shortcut", OptionCategories.PLATFORM_WIN, + createArgumentWithOptionalValueAction("win-shortcut")), WIN_SHORTCUT_PROMPT ("win-shortcut-prompt", OptionCategories.PLATFORM_WIN, () -> { @@ -396,10 +394,8 @@ public class Arguments { LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps", OptionCategories.PLATFORM_LINUX), - LINUX_SHORTCUT_HINT ("linux-shortcut", - OptionCategories.PLATFORM_LINUX, () -> { - setOptionValue("linux-shortcut", true); - }), + LINUX_SHORTCUT_HINT ("linux-shortcut", OptionCategories.PLATFORM_LINUX, + createArgumentWithOptionalValueAction("linux-shortcut")), LINUX_MENU_GROUP ("linux-menu-group", OptionCategories.PLATFORM_LINUX); @@ -478,9 +474,32 @@ public class Arguments { context().pos++; } + private static void prevArg() { + Objects.checkIndex(context().pos, context().argList.size()); + context().pos--; + } + private static boolean hasNextArg() { return context().pos < context().argList.size(); } + + private static Runnable createArgumentWithOptionalValueAction(String option) { + Objects.requireNonNull(option); + return () -> { + nextArg(); + if (hasNextArg()) { + var value = getArg(); + if (value.startsWith("-")) { + prevArg(); + setOptionValue(option, true); + } else { + setOptionValue(option, value); + } + } else { + setOptionValue(option, true); + } + }; + } } enum OptionCategories { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 34818fafc94..d4ea595969a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -52,6 +52,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; import java.nio.file.Path; @@ -69,6 +70,7 @@ import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.ParseUtils; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.function.ThrowingFunction; @@ -171,11 +173,11 @@ final class FromParams { } static Optional findLauncherShortcut( - BundlerParamInfo shortcutParam, + BundlerParamInfo shortcutParam, Map mainParams, Map launcherParams) { - Optional launcherValue; + Optional launcherValue; if (launcherParams == mainParams) { // The main launcher launcherValue = Optional.empty(); @@ -183,17 +185,19 @@ final class FromParams { launcherValue = shortcutParam.findIn(launcherParams); } - return launcherValue.map(withShortcut -> { - if (withShortcut) { - return Optional.of(LauncherShortcutStartupDirectory.DEFAULT); - } else { - return Optional.empty(); - } - }).or(() -> { - return shortcutParam.findIn(mainParams).map(_ -> { - return Optional.of(LauncherShortcutStartupDirectory.DEFAULT); - }); - }).map(LauncherShortcut::new); + return launcherValue.map(ParseUtils::parseLauncherShortcutForAddLauncher).or(() -> { + return Optional.ofNullable(mainParams.get(shortcutParam.getID())).map(toFunction(value -> { + if (value instanceof Boolean) { + return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT); + } else { + try { + return ParseUtils.parseLauncherShortcutForMainLauncher((String)value); + } catch (IllegalArgumentException ex) { + throw I18N.buildConfigException("error.invalid-option-value", value, "--" + shortcutParam.getID()).create(); + } + } + })); + }); } private static ApplicationLaunchers createLaunchers( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java index c604b00c3e2..c6ceb1af40d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java @@ -41,7 +41,14 @@ public enum LauncherShortcutStartupDirectory { * On Linux, it indicates that a shortcut doesn't have the startup directory * configured explicitly. */ - DEFAULT("true"); + DEFAULT("true"), + + /** + * The 'app' directory in the installed application app image. This is the + * directory that is referenced with {@link ApplicationLayout#appDirectory()} + * method. + */ + APP_DIR("app-dir"); LauncherShortcutStartupDirectory(String stringValue) { this.stringValue = Objects.requireNonNull(stringValue); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ParseUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ParseUtils.java new file mode 100644 index 00000000000..411e487d9e0 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ParseUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.model; + +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Collection of functions to create instances of types defined in this package from strings. + */ +public final class ParseUtils { + + private ParseUtils() { + } + + public static LauncherShortcut parseLauncherShortcutForMainLauncher(String str) { + return parse(str, LauncherShortcutStartupDirectory.APP_DIR).map(LauncherShortcut::new).orElseThrow(IllegalArgumentException::new); + } + + public static LauncherShortcut parseLauncherShortcutForAddLauncher(String str) { + return parse(str, LauncherShortcutStartupDirectory.values()).map(LauncherShortcut::new).orElseGet(() -> { + if (Boolean.valueOf(str)) { + return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT); + } else { + return new LauncherShortcut(); + } + }); + } + + private static Optional parse(String str, LauncherShortcutStartupDirectory... recognizedValues) { + Objects.requireNonNull(str); + return Stream.of(recognizedValues).filter(v -> { + return str.equals(v.asStringValue()); + }).findFirst(); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index ae225e15ea2..684a97bc1bd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -82,6 +82,8 @@ error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage error.invalid-install-dir=Invalid installation directory "{0}" +error.invalid-option-value=Invalid value "{0}" of option {1} + MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\ Advice to fix: {2} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index 15d8d2f83b0..e2259535058 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -105,10 +105,10 @@ final class WinFromParams { static final BundlerParamInfo MSI_PACKAGE = createPackageBundlerParam( WinFromParams::createWinMsiPackage); - private static final BundlerParamInfo WIN_MENU_HINT = createBooleanBundlerParam( + private static final BundlerParamInfo WIN_MENU_HINT = createStringBundlerParam( Arguments.CLIOptions.WIN_MENU_HINT.getId()); - private static final BundlerParamInfo WIN_SHORTCUT_HINT = createBooleanBundlerParam( + private static final BundlerParamInfo WIN_SHORTCUT_HINT = createStringBundlerParam( Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId()); public static final BundlerParamInfo CONSOLE_HINT = createBooleanBundlerParam( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index ea4d9eee19a..63be18a5ee8 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -474,6 +474,9 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { case DEFAULT -> { return INSTALLDIR; } + case APP_DIR -> { + return installedAppImage.appDirectory(); + } default -> { throw new AssertionError(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 07c8e06856f..50222d89ceb 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -54,6 +54,10 @@ public final class AdditionalLauncher { setPersistenceHandler(null); } + public String name() { + return name; + } + public AdditionalLauncher withVerifyActions(Action... actions) { verifyActions.addAll(List.of(actions)); return this; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java index 15bb3ea0333..1ee3b8d47b0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherShortcut.java @@ -44,6 +44,7 @@ public enum LauncherShortcut { public enum StartupDirectory { DEFAULT("true"), + APP_DIR("app-dir"), ; StartupDirectory(String stringValue) { @@ -79,7 +80,7 @@ public enum LauncherShortcut { private final String stringValue; - private final static Map VALUE_MAP = + private static final Map VALUE_MAP = Stream.of(values()).collect(toMap(StartupDirectory::asStringValue, x -> x)); } @@ -147,7 +148,14 @@ public enum LauncherShortcut { private Optional findMainLauncherShortcut(JPackageCommand cmd) { if (cmd.hasArgument(optionName())) { - return Optional.of(StartupDirectory.DEFAULT); + var value = Optional.ofNullable(cmd.getArgumentValue(optionName())).filter(optionValue -> { + return !optionValue.startsWith("-"); + }); + if (value.isPresent()) { + return value.flatMap(StartupDirectory::parse); + } else { + return Optional.of(StartupDirectory.DEFAULT); + } } else { return Optional.empty(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index e8f6273b18b..caec0e315c4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -514,6 +514,9 @@ public final class LinuxHelper { case DEFAULT -> { return (Path)null; } + case APP_DIR -> { + return cmd.pathToPackageFile(appLayout.appDirectory()); + } default -> { throw new AssertionError(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java index cca904e017e..27e94366e69 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java @@ -213,7 +213,17 @@ public final class WinShortcutVerifier { final var installDir = Path.of(installRoot.getMsiPropertyName()).resolve(getInstallationSubDirectory(cmd)); final Function workDir = startupDirectory -> { - return installDir; + switch (startupDirectory) { + case DEFAULT -> { + return installDir; + } + case APP_DIR -> { + return ApplicationLayout.windowsAppImage().resolveAt(installDir).appDirectory(); + } + default -> { + throw new IllegalArgumentException(); + } + } }; if (winMenu.isPresent()) { diff --git a/test/jdk/tools/jpackage/share/AddLShortcutTest.java b/test/jdk/tools/jpackage/share/AddLShortcutTest.java index 7d7d8b50c1d..9c50c6ffc98 100644 --- a/test/jdk/tools/jpackage/share/AddLShortcutTest.java +++ b/test/jdk/tools/jpackage/share/AddLShortcutTest.java @@ -28,16 +28,21 @@ import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.AdditionalLauncher; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.FileAssociations; +import jdk.jpackage.test.HelloApp; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.LauncherShortcut; import jdk.jpackage.test.LauncherShortcut.InvokeShortcutSpec; import jdk.jpackage.test.LauncherShortcut.StartupDirectory; @@ -63,6 +68,7 @@ import jdk.jpackage.test.WinShortcutVerifier; * @key jpackagePlatformPackage * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* + * @requires (os.family != "mac") * @requires (jpackage.test.SQETest != null) * @compile -Xlint:all -Werror AddLShortcutTest.java * @run main/othervm/timeout=540 -Xmx512m @@ -76,6 +82,7 @@ import jdk.jpackage.test.WinShortcutVerifier; * @key jpackagePlatformPackage * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* + * @requires (os.family != "mac") * @requires (jpackage.test.SQETest == null) * @compile -Xlint:all -Werror AddLShortcutTest.java * @run main/othervm/timeout=1080 -Xmx512m @@ -85,7 +92,7 @@ import jdk.jpackage.test.WinShortcutVerifier; public class AddLShortcutTest { - @Test + @Test(ifNotOS = OperatingSystem.MACOS) public void test() { // Configure several additional launchers with each combination of // possible shortcut hints in add-launcher property file. @@ -93,6 +100,8 @@ public class AddLShortcutTest { // will have shortcuts while other launchers with some properties set // to "false" will have none. + final var packageName = MethodHandles.lookup().lookupClass().getSimpleName(); + PackageTest packageTest = new PackageTest().configureHelloApp(); packageTest.addInitializer(cmd -> { cmd.addArguments("--arguments", "Duke", "--arguments", "is", @@ -102,11 +111,14 @@ public class AddLShortcutTest { } else if (TKit.isLinux()) { cmd.addArguments("--linux-shortcut"); } + + cmd.setArgumentValue("--name", packageName); + + var addLauncherApp = TKit.TEST_SRC_ROOT.resolve("apps/PrintEnv.java"); + HelloApp.createBundle(JavaAppDesc.parse(addLauncherApp + "*another.jar:Welcome"), cmd.inputDir()); }); - new FileAssociations( - MethodHandles.lookup().lookupClass().getSimpleName()).applyTo( - packageTest); + new FileAssociations(packageName).applyTo(packageTest); new AdditionalLauncher("Foo") .setDefaultArguments("yep!") @@ -131,11 +143,16 @@ public class AddLShortcutTest { .setShortcuts(true, false) .applyTo(packageTest); - new AdditionalLauncher("Launcher5") - .setDefaultArguments() + var launcher5 = new AdditionalLauncher("Launcher5") + .setDefaultArguments("--print-workdir") .setIcon(GOLDEN_ICON) - .setShortcuts(false, true) - .applyTo(packageTest); + .setShortcut(LauncherShortcut.LINUX_SHORTCUT, StartupDirectory.APP_DIR) + .setShortcut(LauncherShortcut.WIN_DESKTOP_SHORTCUT, StartupDirectory.APP_DIR) + .setShortcut(LauncherShortcut.WIN_START_MENU_SHORTCUT, null) + .setProperty("main-jar", "another.jar") + .setProperty("main-class", "Welcome"); + + new ShortcutStartupDirectoryVerifier(packageName).add(launcher5).applyTo(packageTest); packageTest.run(); } @@ -190,10 +207,50 @@ public class AddLShortcutTest { predefinedAppImage[0] = cmd.outputBundle(); }).addInitializer(cmd -> { + cfgs[0].applyToMainLauncher(cmd); cmd.removeArgumentWithValue("--input"); cmd.setArgumentValue("--name", "AddLShortcutDir2Test"); cmd.addArguments("--app-image", predefinedAppImage[0]); - cfgs[0].applyToMainLauncher(cmd); + }).run(RunnablePackageTest.Action.CREATE_AND_UNPACK); + } + + @Test(ifNotOS = OperatingSystem.MACOS) + @Parameter(value = "DEFAULT") + @Parameter(value = "APP_DIR") + public void testLastArg(StartupDirectory startupDirectory) { + final List shortcutArgs = new ArrayList<>(); + if (TKit.isLinux()) { + shortcutArgs.add("--linux-shortcut"); + } else if (TKit.isWindows()) { + shortcutArgs.add("--win-shortcut"); + } else { + TKit.assertUnexpected("Unsupported platform"); + } + + if (startupDirectory == StartupDirectory.APP_DIR) { + shortcutArgs.add(startupDirectory.asStringValue()); + } + + Path[] predefinedAppImage = new Path[1]; + + new PackageTest().addRunOnceInitializer(() -> { + var cmd = JPackageCommand.helloAppImage() + .setArgumentValue("--name", "foo") + .setFakeRuntime(); + + cmd.execute(); + + predefinedAppImage[0] = cmd.outputBundle(); + }).addInitializer(cmd -> { + cmd.removeArgumentWithValue("--input"); + cmd.setArgumentValue("--name", "AddLShortcutDir3Test"); + cmd.addArguments("--app-image", predefinedAppImage[0]); + cmd.ignoreDefaultVerbose(true); + }).addInitializer(cmd -> { + cmd.addArguments(shortcutArgs); + }).addBundleVerifier(cmd -> { + TKit.assertEquals(shortcutArgs.getLast(), cmd.getAllArguments().getLast(), + "Check the last argument of jpackage command line"); }).run(RunnablePackageTest.Action.CREATE_AND_UNPACK); } @@ -207,6 +264,7 @@ public class AddLShortcutTest { @Test(ifNotOS = OperatingSystem.MACOS) @Parameter(value = "DEFAULT") + @Parameter(value = "APP_DIR") public void testInvokeShortcuts(StartupDirectory startupDirectory) { var testApp = TKit.TEST_SRC_ROOT.resolve("apps/PrintEnv.java"); @@ -219,82 +277,118 @@ public class AddLShortcutTest { cmd.addArguments("--arguments", "--print-workdir"); }).addInitializer(JPackageCommand::ignoreFakeRuntime).addHelloAppInitializer(testApp + "*Hello"); - var shortcutStartupDirectoryVerifier = new ShortcutStartupDirectoryVerifier(name, "a"); - - shortcutStartupDirectoryVerifier.applyTo(test, startupDirectory); - - test.addInstallVerifier(cmd -> { - if (!cmd.isPackageUnpacked("Not invoking launcher shortcuts")) { - Collection invokeShortcutSpecs; - if (TKit.isLinux()) { - invokeShortcutSpecs = LinuxHelper.getInvokeShortcutSpecs(cmd); - } else if (TKit.isWindows()) { - invokeShortcutSpecs = WinShortcutVerifier.getInvokeShortcutSpecs(cmd); - } else { - throw new UnsupportedOperationException(); - } - shortcutStartupDirectoryVerifier.verify(invokeShortcutSpecs); - } - }); + new ShortcutStartupDirectoryVerifier(name).add("a", startupDirectory).applyTo(test); test.run(); } - private record ShortcutStartupDirectoryVerifier(String packageName, String launcherName) { - ShortcutStartupDirectoryVerifier { - Objects.requireNonNull(packageName); - Objects.requireNonNull(launcherName); + private static final class ShortcutStartupDirectoryVerifier { + + ShortcutStartupDirectoryVerifier(String packageName) { + this.packageName = Objects.requireNonNull(packageName); } - void applyTo(PackageTest test, StartupDirectory startupDirectory) { - var al = new AdditionalLauncher(launcherName); - al.setShortcut(shortcut(), Objects.requireNonNull(startupDirectory)); - al.addJavaOptions(String.format("-Djpackage.test.appOutput=${%s}/%s", - outputDirVarName(), expectedOutputFilename())); - al.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(test); - } + void applyTo(PackageTest test) { + verifiers.values().forEach(verifier -> { + verifier.applyTo(test); + }); + test.addInstallVerifier(cmd -> { + if (!cmd.isPackageUnpacked("Not invoking launcher shortcuts")) { + Collection invokeShortcutSpecs; + if (TKit.isLinux()) { + invokeShortcutSpecs = LinuxHelper.getInvokeShortcutSpecs(cmd); + } else if (TKit.isWindows()) { + invokeShortcutSpecs = WinShortcutVerifier.getInvokeShortcutSpecs(cmd); + } else { + throw new UnsupportedOperationException(); + } - void verify(Collection invokeShortcutSpecs) throws IOException { + var invokeShortcutSpecsMap = invokeShortcutSpecs.stream().collect(Collectors.groupingBy(InvokeShortcutSpec::launcherName)); - TKit.trace(String.format("Verify shortcut [%s]", launcherName)); - - var expectedOutputFile = Path.of(System.getenv(outputDirVarName())).resolve(expectedOutputFilename()); - - TKit.deleteIfExists(expectedOutputFile); - - var invokeShortcutSpec = invokeShortcutSpecs.stream().filter(v -> { - return launcherName.equals(v.launcherName()); - }).findAny().orElseThrow(); - - invokeShortcutSpec.execute(); - - // On Linux, "gtk-launch" is used to launch a .desktop file. It is async and there is no - // way to make it wait for exit of a process it triggers. - TKit.waitForFileCreated(expectedOutputFile, Duration.ofSeconds(10), Duration.ofSeconds(3)); - - TKit.assertFileExists(expectedOutputFile); - var actualStr = Files.readAllLines(expectedOutputFile).getFirst(); - - var outputPrefix = "$CD="; - - TKit.assertTrue(actualStr.startsWith(outputPrefix), "Check output starts with '" + outputPrefix+ "' string"); - - invokeShortcutSpec.expectedWorkDirectory().ifPresent(expectedWorkDirectory -> { - TKit.assertEquals( - expectedWorkDirectory, - Path.of(actualStr.substring(outputPrefix.length())), - String.format("Check work directory of %s of launcher [%s]", - invokeShortcutSpec.shortcut().propertyName(), - invokeShortcutSpec.launcherName())); + for (var e : verifiers.entrySet()) { + e.getValue().verify(invokeShortcutSpecsMap.get(e.getKey())); + } + } }); } - private String expectedOutputFilename() { - return String.format("%s-%s.out", packageName, launcherName); + ShortcutStartupDirectoryVerifier add(String launcherName, StartupDirectory startupDirectory) { + return add(new AdditionalLauncher(launcherName) + .setShortcut(shortcut(), Objects.requireNonNull(Objects.requireNonNull(startupDirectory)))); } - private String outputDirVarName() { + ShortcutStartupDirectoryVerifier add(AdditionalLauncher addLauncher) { + var launcherVerifier = new LauncherVerifier(addLauncher); + verifiers.put(launcherVerifier.launcherName(), launcherVerifier); + return this; + } + + + private final class LauncherVerifier { + + private LauncherVerifier(AdditionalLauncher addLauncher) { + this.addLauncher = Objects.requireNonNull(addLauncher); + } + + private String launcherName() { + return addLauncher.name(); + } + + private void applyTo(PackageTest test) { + addLauncher.addJavaOptions(String.format("-Djpackage.test.appOutput=${%s}/%s", + outputDirVarName(), expectedOutputFilename())); + addLauncher.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(test); + } + + private void verify(Collection invokeShortcutSpecs) throws IOException { + Objects.requireNonNull(invokeShortcutSpecs); + if (invokeShortcutSpecs.isEmpty()) { + throw new IllegalArgumentException(); + } + + TKit.trace(String.format("Verify shortcut [%s]", launcherName())); + + var expectedOutputFile = Path.of(System.getenv(outputDirVarName())).resolve(expectedOutputFilename()); + + TKit.deleteIfExists(expectedOutputFile); + + var invokeShortcutSpec = invokeShortcutSpecs.stream().filter(v -> { + return launcherName().equals(v.launcherName()); + }).findAny().orElseThrow(); + + invokeShortcutSpec.execute(); + + // On Linux, "gtk-launch" is used to launch a .desktop file. It is async and there is no + // way to make it wait for exit of a process it triggers. + TKit.waitForFileCreated(expectedOutputFile, Duration.ofSeconds(10), Duration.ofSeconds(3)); + + TKit.assertFileExists(expectedOutputFile); + var actualStr = Files.readAllLines(expectedOutputFile).getFirst(); + + var outputPrefix = "$CD="; + + TKit.assertTrue(actualStr.startsWith(outputPrefix), "Check output starts with '" + outputPrefix+ "' string"); + + invokeShortcutSpec.expectedWorkDirectory().ifPresent(expectedWorkDirectory -> { + TKit.assertEquals( + expectedWorkDirectory, + Path.of(actualStr.substring(outputPrefix.length())), + String.format("Check work directory of %s of launcher [%s]", + invokeShortcutSpec.shortcut().propertyName(), + invokeShortcutSpec.launcherName())); + }); + } + + private String expectedOutputFilename() { + return String.format("%s-%s.out", packageName, launcherName()); + } + + private final AdditionalLauncher addLauncher; + } + + + private static String outputDirVarName() { if (TKit.isLinux()) { return "HOME"; } else if (TKit.isWindows()) { @@ -304,7 +398,7 @@ public class AddLShortcutTest { } } - private LauncherShortcut shortcut() { + private static LauncherShortcut shortcut() { if (TKit.isLinux()) { return LauncherShortcut.LINUX_SHORTCUT; } else if (TKit.isWindows()) { @@ -313,6 +407,10 @@ public class AddLShortcutTest { throw new UnsupportedOperationException(); } } + + private final String packageName; + // Keep the order + private final Map verifiers = new LinkedHashMap<>(); } diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index c352decc0f3..2d3d61de864 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -576,6 +576,9 @@ public final class ErrorTest { ); }).flatMap(x -> x).map(TestSpec.Builder::create).toList()); + invalidShortcut(testCases::add, "--win-menu"); + invalidShortcut(testCases::add, "--win-shortcut"); + return toTestArgs(testCases.stream()); } @@ -642,6 +645,8 @@ public final class ErrorTest { .error("error.rpm-invalid-value-for-package-name.advice") ).map(TestSpec.Builder::create).toList()); + invalidShortcut(testCases::add, "--linux-shortcut"); + return toTestArgs(testCases.stream()); } @@ -697,6 +702,13 @@ public final class ErrorTest { duplicateAddArgs(builder, accumulator, "--mac-sign"); } + private static void invalidShortcut(Consumer accumulator, String shortcutOption) { + Objects.requireNonNull(shortcutOption); + Stream.of("true", "false", "").map(value -> { + return testSpec().nativeType().addArgs(shortcutOption, value).error("error.invalid-option-value", value, shortcutOption).create(); + }).forEach(accumulator); + } + private record UnsupportedPlatformOption(String name, Optional value) { UnsupportedPlatformOption { Objects.requireNonNull(name); From d78fa5a9f6254e2e93e75c693efba75e09736749 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 12 Aug 2025 07:16:57 +0000 Subject: [PATCH 049/471] 8365240: [asan] exclude some tests when using asan enabled binaries Reviewed-by: lmesnik, sspitsyn --- .../vmTestbase/nsk/jvmti/Allocate/alloc001/alloc001.java | 4 +++- test/jdk/tools/launcher/TooSmallStackSize.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/alloc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/alloc001.java index eafbbf8b05f..e9f4ee7c4f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/alloc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/alloc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -43,6 +43,8 @@ * * @comment Not run on AIX as it does not support ulimit -v * @requires os.family != "aix" + * @comment Do not run with asan enabled because asan has issues with ulimit + * @requires !vm.asan * @run main/native nsk.jvmti.Allocate.alloc001.alloc001 */ diff --git a/test/jdk/tools/launcher/TooSmallStackSize.java b/test/jdk/tools/launcher/TooSmallStackSize.java index 8485f115d6e..8133dbf4550 100644 --- a/test/jdk/tools/launcher/TooSmallStackSize.java +++ b/test/jdk/tools/launcher/TooSmallStackSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -26,6 +26,8 @@ * @bug 6762191 8222334 * @summary Setting stack size to 16K causes segmentation fault * @compile TooSmallStackSize.java + * @comment VM fails to launch with minimum allowed stack size of 136k when asan is enabled + * @requires !vm.asan * @run main TooSmallStackSize */ From db12f1934a659843d9cc77f4f21e67ebf9fa94e6 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 12 Aug 2025 08:03:18 +0000 Subject: [PATCH 050/471] 8364280: NMTCommittedVirtualMemoryTracker.test_committed_virtualmemory_region_vm fails with assertion "negative distance" Reviewed-by: gziemski, jsjolen --- .../runtime/test_committed_virtualmemory.cpp | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index cd47e3a4e17..caf685f587b 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -43,10 +43,16 @@ public: // snapshot current stack usage VirtualMemoryTracker::Instance::snapshot_thread_stacks(); - ReservedMemoryRegion rmr_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region(stack_end); + ReservedMemoryRegion rmr_found; + { + MemTracker::NmtVirtualMemoryLocker vml; + rmr_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region(stack_end); + } + ASSERT_TRUE(rmr_found.is_valid()); ASSERT_EQ(rmr_found.base(), stack_end); + int i = 0; address i_addr = (address)&i; bool found_i_addr = false; @@ -54,18 +60,20 @@ public: // stack grows downward address stack_top = stack_end + stack_size; bool found_stack_top = false; - VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr_found, [&](const CommittedMemoryRegion& cmr) { - if (cmr.base() + cmr.size() == stack_top) { - EXPECT_TRUE(cmr.size() <= stack_size); - found_stack_top = true; - } - if(i_addr < stack_top && i_addr >= cmr.base()) { - found_i_addr = true; - } - i++; - return true; - }); - + { + MemTracker::NmtVirtualMemoryLocker vml; + VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr_found, [&](const CommittedMemoryRegion& cmr) { + if (cmr.base() + cmr.size() == stack_top) { + EXPECT_TRUE(cmr.size() <= stack_size); + found_stack_top = true; + } + if (i_addr < stack_top && i_addr >= cmr.base()) { + found_i_addr = true; + } + i++; + return true; + }); + } // stack and guard pages may be contiguous as one region ASSERT_TRUE(i >= 1); From 5a442197d21e1dfb89cdbf5f0ad5596869ab333a Mon Sep 17 00:00:00 2001 From: Johny Jose Date: Tue, 12 Aug 2025 08:26:42 +0000 Subject: [PATCH 051/471] 7191877: TEST_BUG: java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java failing intermittently Reviewed-by: smarks, coffeys --- test/jdk/ProblemList.txt | 2 - .../checkLeaseInfoLeak/CheckLeaseLeak.java | 98 ++++++++----------- .../checkLeaseInfoLeak/LeaseLeakClient.java | 3 +- 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 84555a6edfb..02eef5888e0 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -615,8 +615,6 @@ java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java 7140992 generi java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-all -java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 7191877 generic-all - java/rmi/registry/readTest/CodebaseTest.java 8173324 windows-all java/rmi/registry/multipleRegistries/MultipleRegistries.java 8268182 macosx-all diff --git a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java index 2370dcd35c4..4de6598a0f4 100644 --- a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java +++ b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -54,12 +54,11 @@ import java.rmi.*; import java.rmi.server.*; -import sun.rmi.transport.*; -import sun.rmi.*; import java.util.Map; import java.io.*; import java.lang.reflect.*; import java.rmi.registry.*; +import sun.rmi.transport.*; public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { public CheckLeaseLeak() throws RemoteException { } @@ -102,8 +101,6 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { System.err.println("Created client: " + i); JavaVM jvm = new JavaVM("LeaseLeakClient", - " -Djava.security.policy=" + - TestParams.defaultPolicy + " -Drmi.registry.port=" + registryPort, ""); @@ -128,8 +125,8 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { } } - /* numLeft should be 2 - if 11 there is a problem. */ - if (numLeft > 2) { + /* numLeft should be 4 - if 11 there is a problem. */ + if (numLeft > 4) { TestLibrary.bomb("Too many objects in DGCImpl.leaseTable: "+ numLeft); } else { @@ -156,57 +153,51 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { Field f; try { - f = (Field) java.security.AccessController.doPrivileged - (new java.security.PrivilegedExceptionAction() { - public Object run() throws Exception { + ObjID dgcID = new ObjID(DGC_ID); + /* + * Construct an ObjectEndpoint containing DGC's + * ObjID. + */ + Class oeClass = + Class.forName("sun.rmi.transport.ObjectEndpoint"); + Class[] constrParams = + new Class[]{ ObjID.class, Transport.class }; + Constructor oeConstructor = + oeClass.getDeclaredConstructor(constrParams); + oeConstructor.setAccessible(true); + Object oe = + oeConstructor.newInstance( + new Object[]{ dgcID, null }); - ObjID dgcID = new ObjID(DGC_ID); + /* + * Get Target that contains DGCImpl in ObjectTable + */ + Class objTableClass = + Class.forName("sun.rmi.transport.ObjectTable"); + Class getTargetParams[] = new Class[] { oeClass }; + Method objTableGetTarget = + objTableClass.getDeclaredMethod("getTarget", + getTargetParams); + objTableGetTarget.setAccessible(true); + Target dgcTarget = (Target) + objTableGetTarget.invoke(null, new Object[]{ oe }); - /* - * Construct an ObjectEndpoint containing DGC's - * ObjID. - */ - Class oeClass = - Class.forName("sun.rmi.transport.ObjectEndpoint"); - Class[] constrParams = - new Class[]{ ObjID.class, Transport.class }; - Constructor oeConstructor = - oeClass.getDeclaredConstructor(constrParams); - oeConstructor.setAccessible(true); - Object oe = - oeConstructor.newInstance( - new Object[]{ dgcID, null }); - - /* - * Get Target that contains DGCImpl in ObjectTable - */ - Class objTableClass = - Class.forName("sun.rmi.transport.ObjectTable"); - Class getTargetParams[] = new Class[] { oeClass }; - Method objTableGetTarget = - objTableClass.getDeclaredMethod("getTarget", - getTargetParams); - objTableGetTarget.setAccessible(true); - Target dgcTarget = (Target) - objTableGetTarget.invoke(null, new Object[]{ oe }); - - /* get the DGCImpl from its Target */ - Method targetGetImpl = - dgcTarget.getClass().getDeclaredMethod + /* get the DGCImpl from its Target */ + Method targetGetImpl = + dgcTarget.getClass().getDeclaredMethod ("getImpl", null); - targetGetImpl.setAccessible(true); - dgcImpl[0] = - (Remote) targetGetImpl.invoke(dgcTarget, null); + targetGetImpl.setAccessible(true); + dgcImpl[0] = + (Remote) targetGetImpl.invoke(dgcTarget, null); - /* Get the lease table from the DGCImpl. */ - Field reflectedLeaseTable = - dgcImpl[0].getClass().getDeclaredField + /* Get the lease table from the DGCImpl. */ + Field reflectedLeaseTable = + dgcImpl[0].getClass().getDeclaredField ("leaseTable"); - reflectedLeaseTable.setAccessible(true); + reflectedLeaseTable.setAccessible(true); + + f = reflectedLeaseTable; - return reflectedLeaseTable; - } - }); /** * This is the leaseTable that will fill up with LeaseInfo @@ -217,9 +208,6 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { numLeaseInfosLeft = leaseTable.size(); } catch(Exception e) { - if (e instanceof java.security.PrivilegedActionException) - e = ((java.security.PrivilegedActionException) e). - getException(); TestLibrary.bomb(e); } diff --git a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/LeaseLeakClient.java b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/LeaseLeakClient.java index d9cf9fa9e96..dd24b819146 100644 --- a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/LeaseLeakClient.java +++ b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/LeaseLeakClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,6 @@ import java.rmi.registry.*; public class LeaseLeakClient { public static void main(String args[]) { - TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager"); try { LeaseLeak leaseLeak = null; From b81f4faed7180e51aa966a9bf2f84ba755c6736d Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Tue, 12 Aug 2025 08:34:26 +0000 Subject: [PATCH 052/471] 8360037: Refactor ImageReader in preparation for Valhalla support Reviewed-by: alanb, rriggs, jpai --- .../jdk/internal/jimage/ImageReader.java | 1019 ++++++++--------- .../jdk/internal/jrtfs/ExplodedImage.java | 6 +- .../jdk/internal/jrtfs/JrtFileAttributes.java | 8 +- .../jdk/internal/jrtfs/JrtFileSystem.java | 26 +- .../jdk/internal/jrtfs/SystemImage.java | 1 - .../internal/module/SystemModuleFinders.java | 115 +- .../jdk/internal/jimage/ImageReaderTest.java | 279 +++++ .../jdk/internal/jimage/JImageReadTest.java | 38 +- .../ImageReaderDuplicateChildNodesTest.java | 10 +- .../internal/jrtfs/ImageReaderBenchmark.java | 4 +- 10 files changed, 880 insertions(+), 626 deletions(-) create mode 100644 test/jdk/jdk/internal/jimage/ImageReaderTest.java diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index f12c39f3e81..79e718c76e5 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -25,16 +25,14 @@ package jdk.internal.jimage; import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.nio.file.Files; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -42,9 +40,36 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; /** + * A view over the entries of a jimage file with a unified namespace suitable + * for file system use. The jimage entries (resources, module and package + * information) are mapped into a unified hierarchy of named nodes, which serve + * as the underlying structure for {@code JrtFileSystem} and other utilities. + * + *

Entries in jimage are expressed as one of three {@link Node} types; + * resource nodes, directory nodes and link nodes. + * + *

When remapping jimage entries, jimage location names (e.g. {@code + * "/java.base/java/lang/Integer.class"}) are prefixed with {@code "/modules"} + * to form the names of resource nodes. This aligns with the naming of module + * entries in jimage (e.g. "/modules/java.base/java/lang"), which appear as + * directory nodes in {@code ImageReader}. + * + *

Package entries (e.g. {@code "/packages/java.lang"} appear as directory + * nodes containing link nodes, which resolve back to the root directory of the + * module in which that package exists (e.g. {@code "/modules/java.base"}). + * Unlike other nodes, the jimage file does not contain explicit entries for + * link nodes, and their existence is derived only from the contents of the + * parent directory. + * + *

While similar to {@code BasicImageReader}, this class is not a conceptual + * subtype of it, and deliberately hides types such as {@code ImageLocation} to + * give a focused API based only on nodes. + * * @implNote This class needs to maintain JDK 8 source compatibility. * * It is used internally in the JDK to implement jimage/jrtfs access, @@ -60,6 +85,10 @@ public final class ImageReader implements AutoCloseable { this.reader = reader; } + /** + * Opens an image reader for a jimage file at the specified path, using the + * given byte order. + */ public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { Objects.requireNonNull(imagePath); Objects.requireNonNull(byteOrder); @@ -67,6 +96,10 @@ public final class ImageReader implements AutoCloseable { return SharedImageReader.open(imagePath, byteOrder); } + /** + * Opens an image reader for a jimage file at the specified path, using the + * platform native byte order. + */ public static ImageReader open(Path imagePath) throws IOException { return open(imagePath, ByteOrder.nativeOrder()); } @@ -92,146 +125,113 @@ public final class ImageReader implements AutoCloseable { } } - // directory management interface - public Directory getRootDirectory() throws IOException { - ensureOpen(); - return reader.getRootDirectory(); - } - - + /** + * Finds the node with the given name. + * + * @param name a node name of the form {@code "/modules//...} or + * {@code "/packages//...}. + * @return a node representing a resource, directory or symbolic link. + */ public Node findNode(String name) throws IOException { ensureOpen(); return reader.findNode(name); } + /** + * Returns a copy of the content of a resource node. The buffer returned by + * this method is not cached by the node, and each call returns a new array + * instance. + * + * @throws IOException if the content cannot be returned (including if the + * given node is not a resource node). + */ public byte[] getResource(Node node) throws IOException { ensureOpen(); return reader.getResource(node); } - public byte[] getResource(Resource rs) throws IOException { - ensureOpen(); - return reader.getResource(rs); - } - - public ImageHeader getHeader() { - requireOpen(); - return reader.getHeader(); - } - + /** + * Releases a (possibly cached) {@link ByteBuffer} obtained via + * {@link #getResourceBuffer(Node)}. + * + *

Note that no testing is performed to check whether the buffer about + * to be released actually came from a call to {@code getResourceBuffer()}. + */ public static void releaseByteBuffer(ByteBuffer buffer) { BasicImageReader.releaseByteBuffer(buffer); } - public String getName() { + /** + * Returns the content of a resource node in a possibly cached byte buffer. + * Callers of this method must call {@link #releaseByteBuffer(ByteBuffer)} + * when they are finished with it. + */ + public ByteBuffer getResourceBuffer(Node node) { requireOpen(); - return reader.getName(); - } - - public ByteOrder getByteOrder() { - requireOpen(); - return reader.getByteOrder(); - } - - public Path getImagePath() { - requireOpen(); - return reader.getImagePath(); - } - - public ImageStringsReader getStrings() { - requireOpen(); - return reader.getStrings(); - } - - public ImageLocation findLocation(String mn, String rn) { - requireOpen(); - return reader.findLocation(mn, rn); - } - - public boolean verifyLocation(String mn, String rn) { - requireOpen(); - return reader.verifyLocation(mn, rn); - } - - public ImageLocation findLocation(String name) { - requireOpen(); - return reader.findLocation(name); - } - - public String[] getEntryNames() { - requireOpen(); - return reader.getEntryNames(); - } - - public String[] getModuleNames() { - requireOpen(); - int off = "/modules/".length(); - return reader.findNode("/modules") - .getChildren() - .stream() - .map(Node::getNameString) - .map(s -> s.substring(off, s.length())) - .toArray(String[]::new); - } - - public long[] getAttributes(int offset) { - requireOpen(); - return reader.getAttributes(offset); - } - - public String getString(int offset) { - requireOpen(); - return reader.getString(offset); - } - - public byte[] getResource(String name) { - requireOpen(); - return reader.getResource(name); - } - - public byte[] getResource(ImageLocation loc) { - requireOpen(); - return reader.getResource(loc); - } - - public ByteBuffer getResourceBuffer(ImageLocation loc) { - requireOpen(); - return reader.getResourceBuffer(loc); - } - - public InputStream getResourceStream(ImageLocation loc) { - requireOpen(); - return reader.getResourceStream(loc); + if (!node.isResource()) { + throw new IllegalArgumentException("Not a resource node: " + node); + } + return reader.getResourceBuffer(node.getLocation()); } private static final class SharedImageReader extends BasicImageReader { - static final int SIZE_OF_OFFSET = Integer.BYTES; - - static final Map OPEN_FILES = new HashMap<>(); + private static final Map OPEN_FILES = new HashMap<>(); + private static final String MODULES_ROOT = "/modules"; + private static final String PACKAGES_ROOT = "/packages"; + // There are >30,000 nodes in a complete jimage tree, and even relatively + // common tasks (e.g. starting up javac) load somewhere in the region of + // 1000 classes. Thus, an initial capacity of 2000 is a reasonable guess. + private static final int INITIAL_NODE_CACHE_CAPACITY = 2000; // List of openers for this shared image. - final Set openers; + private final Set openers = new HashSet<>(); - // attributes of the .jimage file. jimage file does not contain + // Attributes of the jimage file. The jimage file does not contain // attributes for the individual resources (yet). We use attributes // of the jimage file itself (creation, modification, access times). - // Iniitalized lazily, see {@link #imageFileAttributes()}. - BasicFileAttributes imageFileAttributes; + private final BasicFileAttributes imageFileAttributes; - // directory management implementation - final HashMap nodes; - volatile Directory rootDir; - - Directory packagesDir; - Directory modulesDir; + // Cache of all user visible nodes, guarded by synchronizing 'this' instance. + private final Map nodes; + // Used to classify ImageLocation instances without string comparison. + private final int modulesStringOffset; + private final int packagesStringOffset; private SharedImageReader(Path imagePath, ByteOrder byteOrder) throws IOException { super(imagePath, byteOrder); - this.openers = new HashSet<>(); - this.nodes = new HashMap<>(); + this.imageFileAttributes = Files.readAttributes(imagePath, BasicFileAttributes.class); + this.nodes = new HashMap<>(INITIAL_NODE_CACHE_CAPACITY); + // Pick stable jimage names from which to extract string offsets (we cannot + // use "/modules" or "/packages", since those have a module offset of zero). + this.modulesStringOffset = getModuleOffset("/modules/java.base"); + this.packagesStringOffset = getModuleOffset("/packages/java.lang"); + + // Node creation is very lazy, so we can just make the top-level directories + // now without the risk of triggering the building of lots of other nodes. + Directory packages = newDirectory(PACKAGES_ROOT); + nodes.put(packages.getName(), packages); + Directory modules = newDirectory(MODULES_ROOT); + nodes.put(modules.getName(), modules); + + Directory root = newDirectory("/"); + root.setChildren(Arrays.asList(packages, modules)); + nodes.put(root.getName(), root); } - public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { + /** + * Returns the offset of the string denoting the leading "module" segment in + * the given path (e.g. {@code /}). We can't just pass in the + * {@code /} string here because that has a module offset of zero. + */ + private int getModuleOffset(String path) { + ImageLocation location = findLocation(path); + assert location != null : "Cannot find expected jimage location: " + path; + int offset = location.getModuleOffset(); + assert offset != 0 : "Invalid module offset for jimage location: " + path; + return offset; + } + + private static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { Objects.requireNonNull(imagePath); Objects.requireNonNull(byteOrder); @@ -264,7 +264,6 @@ public final class ImageReader implements AutoCloseable { if (openers.isEmpty()) { close(); nodes.clear(); - rootDir = null; if (!OPEN_FILES.remove(this.getImagePath(), this)) { throw new IOException("image file not found in open list"); @@ -273,448 +272,412 @@ public final class ImageReader implements AutoCloseable { } } - void addOpener(ImageReader reader) { - synchronized (OPEN_FILES) { - openers.add(reader); + /** + * Returns a node with the given name, or null if no resource or directory of + * that name exists. + * + *

This is the only public API by which anything outside this class can access + * {@code Node} instances either directly, or by resolving symbolic links. + * + *

Note also that there is no reentrant calling back to this method from within + * the node handling code. + * + * @param name an absolute, {@code /}-separated path string, prefixed with either + * "/modules" or "/packages". + */ + synchronized Node findNode(String name) { + Node node = nodes.get(name); + if (node == null) { + // We cannot get the root paths ("/modules" or "/packages") here + // because those nodes are already in the nodes cache. + if (name.startsWith(MODULES_ROOT + "/")) { + node = buildModulesNode(name); + } else if (name.startsWith(PACKAGES_ROOT + "/")) { + node = buildPackagesNode(name); + } + if (node != null) { + nodes.put(node.getName(), node); + } + } else if (!node.isCompleted()) { + // Only directories can be incomplete. + assert node instanceof Directory : "Invalid incomplete node: " + node; + completeDirectory((Directory) node); } - } - - boolean removeOpener(ImageReader reader) { - synchronized (OPEN_FILES) { - return openers.remove(reader); - } - } - - // directory management interface - Directory getRootDirectory() { - return buildRootDirectory(); + assert node == null || node.isCompleted() : "Incomplete node: " + node; + return node; } /** - * Lazily build a node from a name. + * Builds a node in the "/modules/..." namespace. + * + *

Called by {@link #findNode(String)} if a {@code /modules/...} node + * is not present in the cache. */ - synchronized Node buildNode(String name) { - Node n; - boolean isPackages = name.startsWith("/packages"); - boolean isModules = !isPackages && name.startsWith("/modules"); - - if (!(isModules || isPackages)) { - return null; - } - + private Node buildModulesNode(String name) { + assert name.startsWith(MODULES_ROOT + "/") : "Invalid module node name: " + name; + // Returns null for non-directory resources, since the jimage name does not + // start with "/modules" (e.g. "/java.base/java/lang/Object.class"). ImageLocation loc = findLocation(name); - - if (loc != null) { // A sub tree node - if (isPackages) { - n = handlePackages(name, loc); - } else { // modules sub tree - n = handleModulesSubTree(name, loc); - } - } else { // Asking for a resource? /modules/java.base/java/lang/Object.class - if (isModules) { - n = handleResource(name); - } else { - // Possibly ask for /packages/java.lang/java.base - // although /packages/java.base not created - n = handleModuleLink(name); - } + if (loc != null) { + assert name.equals(loc.getFullName()) : "Mismatched location for directory: " + name; + assert isModulesSubdirectory(loc) : "Invalid modules directory: " + name; + return completeModuleDirectory(newDirectory(name), loc); } - return n; - } - - synchronized Directory buildRootDirectory() { - Directory root = rootDir; // volatile read - if (root != null) { - return root; - } - - root = newDirectory(null, "/"); - root.setIsRootDir(); - - // /packages dir - packagesDir = newDirectory(root, "/packages"); - packagesDir.setIsPackagesDir(); - - // /modules dir - modulesDir = newDirectory(root, "/modules"); - modulesDir.setIsModulesDir(); - - root.setCompleted(true); - return rootDir = root; + // Now try the non-prefixed resource name, but be careful to avoid false + // positives for names like "/modules/modules/xxx" which could return a + // location of a directory entry. + loc = findLocation(name.substring(MODULES_ROOT.length())); + return loc != null && isResource(loc) ? newResource(name, loc) : null; } /** - * To visit sub tree resources. + * Builds a node in the "/packages/..." namespace. + * + *

Called by {@link #findNode(String)} if a {@code /packages/...} node + * is not present in the cache. */ - interface LocationVisitor { - void visit(ImageLocation loc); - } - - void visitLocation(ImageLocation loc, LocationVisitor visitor) { - byte[] offsets = getResource(loc); - ByteBuffer buffer = ByteBuffer.wrap(offsets); - buffer.order(getByteOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { - int offset = intBuffer.get(i); - ImageLocation pkgLoc = getLocation(offset); - visitor.visit(pkgLoc); - } - } - - void visitPackageLocation(ImageLocation loc) { - // Retrieve package name - String pkgName = getBaseExt(loc); - // Content is array of offsets in Strings table - byte[] stringsOffsets = getResource(loc); - ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets); - buffer.order(getByteOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - // For each module, create a link node. - for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) { - // skip empty state, useless. - intBuffer.get(i); - i++; - int offset = intBuffer.get(i); - String moduleName = getString(offset); - Node targetNode = findNode("/modules/" + moduleName); - if (targetNode != null) { - String pkgDirName = packagesDir.getName() + "/" + pkgName; - Directory pkgDir = (Directory) nodes.get(pkgDirName); - newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode); - } - } - } - - Node handlePackages(String name, ImageLocation loc) { - long size = loc.getUncompressedSize(); - Node n = null; - // Only possibilities are /packages, /packages/package/module - if (name.equals("/packages")) { - visitLocation(loc, (childloc) -> { - findNode(childloc.getFullName()); - }); - packagesDir.setCompleted(true); - n = packagesDir; + private Node buildPackagesNode(String name) { + // There are only locations for the root "/packages" or "/packages/xxx" + // directories, but not the symbolic links below them (the links can be + // entirely derived from the name information in the parent directory). + // However, unlike resources this means that we do not have a constant + // time lookup for link nodes when creating them. + int packageStart = PACKAGES_ROOT.length() + 1; + int packageEnd = name.indexOf('/', packageStart); + if (packageEnd == -1) { + ImageLocation loc = findLocation(name); + return loc != null ? completePackageDirectory(newDirectory(name), loc) : null; } else { - if (size != 0) { // children are offsets to module in StringsTable - String pkgName = getBaseExt(loc); - Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName); - visitPackageLocation(loc); - pkgDir.setCompleted(true); - n = pkgDir; - } else { // Link to module - String pkgName = loc.getParent(); - String modName = getBaseExt(loc); - Node targetNode = findNode("/modules/" + modName); - if (targetNode != null) { - String pkgDirName = packagesDir.getName() + "/" + pkgName; - Directory pkgDir = (Directory) nodes.get(pkgDirName); - Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode); - n = linkNode; + // We cannot assume that the parent directory exists for a link node, since + // the given name is untrusted and could reference a non-existent link. + // However, if the parent directory is present, we can conclude that the + // given name was not a valid link (or else it would already be cached). + String dirName = name.substring(0, packageEnd); + if (!nodes.containsKey(dirName)) { + ImageLocation loc = findLocation(dirName); + // If the parent location doesn't exist, the link node cannot exist. + if (loc != null) { + nodes.put(dirName, completePackageDirectory(newDirectory(dirName), loc)); + // When the parent is created its child nodes are created and cached, + // but this can still return null if given name wasn't a valid link. + return nodes.get(name); } } } - return n; + return null; } - // Asking for /packages/package/module although - // /packages// not yet created, need to create it - // prior to return the link to module node. - Node handleModuleLink(String name) { - // eg: unresolved /packages/package/module - // Build /packages/package node - Node ret = null; - String radical = "/packages/"; - String path = name; - if (path.startsWith(radical)) { - int start = radical.length(); - int pkgEnd = path.indexOf('/', start); - if (pkgEnd != -1) { - String pkg = path.substring(start, pkgEnd); - String pkgPath = radical + pkg; - Node n = findNode(pkgPath); - // If not found means that this is a symbolic link such as: - // /packages/java.util/java.base/java/util/Vector.class - // and will be done by a retry of the filesystem - for (Node child : n.getChildren()) { - if (child.name.equals(name)) { - ret = child; - break; - } - } - } + /** Completes a directory by ensuring its child list is populated correctly. */ + private void completeDirectory(Directory dir) { + String name = dir.getName(); + // Since the node exists, we can assert that its name starts with + // either "/modules" or "/packages", making differentiation easy. + // It also means that the name is valid, so it must yield a location. + assert name.startsWith(MODULES_ROOT) || name.startsWith(PACKAGES_ROOT); + ImageLocation loc = findLocation(name); + assert loc != null && name.equals(loc.getFullName()) : "Invalid location for name: " + name; + // We cannot use 'isXxxSubdirectory()' methods here since we could + // be given a top-level directory (for which that test doesn't work). + // The string MUST start "/modules" or "/packages" here. + if (name.charAt(1) == 'm') { + completeModuleDirectory(dir, loc); + } else { + completePackageDirectory(dir, loc); } - return ret; + assert dir.isCompleted() : "Directory must be complete by now: " + dir; } - Node handleModulesSubTree(String name, ImageLocation loc) { - Node n; - assert (name.equals(loc.getFullName())); - Directory dir = makeDirectories(name); - visitLocation(loc, (childloc) -> { - String path = childloc.getFullName(); - if (path.startsWith("/modules")) { // a package - makeDirectories(path); - } else { // a resource - makeDirectories(childloc.buildName(true, true, false)); - // if we have already created a resource for this name previously, then don't - // recreate it - if (!nodes.containsKey(childloc.getFullName(true))) { - newResource(dir, childloc); - } + /** + * Completes a modules directory by setting the list of child nodes. + * + *

The given directory can be the top level {@code /modules} directory, + * so it is NOT safe to use {@code isModulesSubdirectory(loc)} here. + */ + private Directory completeModuleDirectory(Directory dir, ImageLocation loc) { + assert dir.getName().equals(loc.getFullName()) : "Mismatched location for directory: " + dir; + List children = createChildNodes(loc, childLoc -> { + if (isModulesSubdirectory(childLoc)) { + return nodes.computeIfAbsent(childLoc.getFullName(), this::newDirectory); + } else { + // Add "/modules" prefix to image location paths to get node names. + String resourceName = childLoc.getFullName(true); + return nodes.computeIfAbsent(resourceName, n -> newResource(n, childLoc)); } }); - dir.setCompleted(true); - n = dir; - return n; - } - - Node handleResource(String name) { - Node n = null; - if (!name.startsWith("/modules/")) { - return null; - } - // Make sure that the thing that follows "/modules/" is a module name. - int moduleEndIndex = name.indexOf('/', "/modules/".length()); - if (moduleEndIndex == -1) { - return null; - } - ImageLocation moduleLoc = findLocation(name.substring(0, moduleEndIndex)); - if (moduleLoc == null || moduleLoc.getModuleOffset() == 0) { - return null; - } - - String locationPath = name.substring("/modules".length()); - ImageLocation resourceLoc = findLocation(locationPath); - if (resourceLoc != null) { - Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); - Resource res = newResource(dir, resourceLoc); - n = res; - } - return n; - } - - String getBaseExt(ImageLocation loc) { - String base = loc.getBase(); - String ext = loc.getExtension(); - if (ext != null && !ext.isEmpty()) { - base = base + "." + ext; - } - return base; - } - - synchronized Node findNode(String name) { - buildRootDirectory(); - Node n = nodes.get(name); - if (n == null || !n.isCompleted()) { - n = buildNode(name); - } - return n; - } - - /** - * Returns the file attributes of the image file. - */ - BasicFileAttributes imageFileAttributes() { - BasicFileAttributes attrs = imageFileAttributes; - if (attrs == null) { - try { - Path file = getImagePath(); - attrs = Files.readAttributes(file, BasicFileAttributes.class); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - imageFileAttributes = attrs; - } - return attrs; - } - - Directory newDirectory(Directory parent, String name) { - Directory dir = Directory.create(parent, name, imageFileAttributes()); - nodes.put(dir.getName(), dir); + dir.setChildren(children); return dir; } - Resource newResource(Directory parent, ImageLocation loc) { - Resource res = Resource.create(parent, loc, imageFileAttributes()); - nodes.put(res.getName(), res); - return res; - } - - LinkNode newLinkNode(Directory dir, String name, Node link) { - LinkNode linkNode = LinkNode.create(dir, name, link); - nodes.put(linkNode.getName(), linkNode); - return linkNode; - } - - Directory makeDirectories(String parent) { - Directory last = rootDir; - for (int offset = parent.indexOf('/', 1); - offset != -1; - offset = parent.indexOf('/', offset + 1)) { - String dir = parent.substring(0, offset); - last = makeDirectory(dir, last); + /** + * Completes a package directory by setting the list of child nodes. + * + *

The given directory can be the top level {@code /packages} directory, + * so it is NOT safe to use {@code isPackagesSubdirectory(loc)} here. + */ + private Directory completePackageDirectory(Directory dir, ImageLocation loc) { + assert dir.getName().equals(loc.getFullName()) : "Mismatched location for directory: " + dir; + // The only directories in the "/packages" namespace are "/packages" or + // "/packages/". However, unlike "/modules" directories, the + // location offsets mean different things. + List children; + if (dir.getName().equals(PACKAGES_ROOT)) { + // Top-level directory just contains a list of subdirectories. + children = createChildNodes(loc, c -> nodes.computeIfAbsent(c.getFullName(), this::newDirectory)); + } else { + // A package directory's content is array of offset PAIRS in the + // Strings table, but we only need the 2nd value of each pair. + IntBuffer intBuffer = getOffsetBuffer(loc); + int offsetCount = intBuffer.capacity(); + assert (offsetCount & 0x1) == 0 : "Offset count must be even: " + offsetCount; + children = new ArrayList<>(offsetCount / 2); + // Iterate the 2nd offset in each pair (odd indices). + for (int i = 1; i < offsetCount; i += 2) { + String moduleName = getString(intBuffer.get(i)); + children.add(nodes.computeIfAbsent( + dir.getName() + "/" + moduleName, + n -> newLinkNode(n, MODULES_ROOT + "/" + moduleName))); + } } - return makeDirectory(parent, last); - + // This only happens once and "completes" the directory. + dir.setChildren(children); + return dir; } - Directory makeDirectory(String dir, Directory last) { - Directory nextDir = (Directory) nodes.get(dir); - if (nextDir == null) { - nextDir = newDirectory(last, dir); + /** + * Creates the list of child nodes for a {@code Directory} based on a given + * + *

Note: This cannot be used for package subdirectories as they have + * child offsets stored differently to other directories. + */ + private List createChildNodes(ImageLocation loc, Function newChildFn) { + IntBuffer offsets = getOffsetBuffer(loc); + int childCount = offsets.capacity(); + List children = new ArrayList<>(childCount); + for (int i = 0; i < childCount; i++) { + children.add(newChildFn.apply(getLocation(offsets.get(i)))); } - return nextDir; + return children; } - byte[] getResource(Node node) throws IOException { + /** Helper to extract the integer offset buffer from a directory location. */ + private IntBuffer getOffsetBuffer(ImageLocation dir) { + assert !isResource(dir) : "Not a directory: " + dir.getFullName(); + byte[] offsets = getResource(dir); + ByteBuffer buffer = ByteBuffer.wrap(offsets); + buffer.order(getByteOrder()); + return buffer.asIntBuffer(); + } + + /** + * Efficiently determines if an image location is a resource. + * + *

A resource must have a valid module associated with it, so its + * module offset must be non-zero, and not equal to the offsets for + * "/modules/..." or "/packages/..." entries. + */ + private boolean isResource(ImageLocation loc) { + int moduleOffset = loc.getModuleOffset(); + return moduleOffset != 0 + && moduleOffset != modulesStringOffset + && moduleOffset != packagesStringOffset; + } + + /** + * Determines if an image location is a directory in the {@code /modules} + * namespace (if so, the location name is the node name). + * + *

In jimage, every {@code ImageLocation} under {@code /modules/} is a + * directory and has the same value for {@code getModule()}, and {@code + * getModuleOffset()}. + */ + private boolean isModulesSubdirectory(ImageLocation loc) { + return loc.getModuleOffset() == modulesStringOffset; + } + + /** + * Creates an "incomplete" directory node with no child nodes set. + * Directories need to be "completed" before they are returned by + * {@link #findNode(String)}. + */ + private Directory newDirectory(String name) { + return new Directory(name, imageFileAttributes); + } + + /** + * Creates a new resource from an image location. This is the only case + * where the image location name does not match the requested node name. + * In image files, resource locations are NOT prefixed by {@code /modules}. + */ + private Resource newResource(String name, ImageLocation loc) { + assert name.equals(loc.getFullName(true)) : "Mismatched location for resource: " + name; + return new Resource(name, loc, imageFileAttributes); + } + + /** + * Creates a new link node pointing at the given target name. + * + *

Note that target node is resolved each time {@code resolve()} is called, + * so if a link node is retained after its reader is closed, it will fail. + */ + private LinkNode newLinkNode(String name, String targetName) { + return new LinkNode(name, () -> findNode(targetName), imageFileAttributes); + } + + /** Returns the content of a resource node. */ + private byte[] getResource(Node node) throws IOException { + // We could have been given a non-resource node here. if (node.isResource()) { return super.getResource(node.getLocation()); } throw new IOException("Not a resource: " + node); } - - byte[] getResource(Resource rs) throws IOException { - return super.getResource(rs.getLocation()); - } } - // jimage file does not store directory structure. We build nodes - // using the "path" strings found in the jimage file. - // Node can be a directory or a resource + /** + * A directory, resource or symbolic link. + * + *

Node Equality

+ * + * Nodes are identified solely by their name, and it is not valid to attempt + * to compare nodes from different reader instances. Different readers may + * produce nodes with the same names, but different contents. + * + *

Furthermore, since a {@link ImageReader} provides "perfect" caching of + * nodes, equality of nodes from the same reader is equivalent to instance + * identity. + */ public abstract static class Node { - private static final int ROOT_DIR = 0b0000_0000_0000_0001; - private static final int PACKAGES_DIR = 0b0000_0000_0000_0010; - private static final int MODULES_DIR = 0b0000_0000_0000_0100; - - private int flags; private final String name; private final BasicFileAttributes fileAttrs; - private boolean completed; + /** + * Creates an abstract {@code Node}, which is either a resource, directory + * or symbolic link. + * + *

This constructor is only non-private so it can be used by the + * {@code ExplodedImage} class, and must not be used otherwise. + */ protected Node(String name, BasicFileAttributes fileAttrs) { this.name = Objects.requireNonNull(name); this.fileAttrs = Objects.requireNonNull(fileAttrs); } + // A node is completed when all its direct children have been built. + // As such, non-directory nodes are always complete. + boolean isCompleted() { + return true; + } + + // Only resources can return a location. + ImageLocation getLocation() { + throw new IllegalStateException("not a resource: " + getName()); + } + /** - * A node is completed when all its direct children have been built. + * Returns the name of this node (e.g. {@code + * "/modules/java.base/java/lang/Object.class"} or {@code + * "/packages/java.lang"}). * - * @return + *

Note that for resource nodes this is NOT the underlying jimage + * resource name (it is prefixed with {@code "/modules"}). */ - public boolean isCompleted() { - return completed; - } - - public void setCompleted(boolean completed) { - this.completed = completed; - } - - public final void setIsRootDir() { - flags |= ROOT_DIR; - } - - public final boolean isRootDir() { - return (flags & ROOT_DIR) != 0; - } - - public final void setIsPackagesDir() { - flags |= PACKAGES_DIR; - } - - public final boolean isPackagesDir() { - return (flags & PACKAGES_DIR) != 0; - } - - public final void setIsModulesDir() { - flags |= MODULES_DIR; - } - - public final boolean isModulesDir() { - return (flags & MODULES_DIR) != 0; - } - public final String getName() { return name; } + /** + * Returns file attributes for this node. The value returned may be the + * same for all nodes, and should not be relied upon for accuracy. + */ public final BasicFileAttributes getFileAttributes() { return fileAttrs; } - // resolve this Node (if this is a soft link, get underlying Node) + /** + * Resolves a symbolic link to its target node. If this code is not a + * symbolic link, then it resolves to itself. + */ public final Node resolveLink() { return resolveLink(false); } + /** + * Resolves a symbolic link to its target node. If this code is not a + * symbolic link, then it resolves to itself. + */ public Node resolveLink(boolean recursive) { return this; } - // is this a soft link Node? + /** Returns whether this node is a symbolic link. */ public boolean isLink() { return false; } + /** + * Returns whether this node is a directory. Directory nodes can have + * {@link #getChildNames()} invoked to get the fully qualified names + * of any child nodes. + */ public boolean isDirectory() { return false; } - public List getChildren() { - throw new IllegalArgumentException("not a directory: " + getNameString()); - } - + /** + * Returns whether this node is a resource. Resource nodes can have + * their contents obtained via {@link ImageReader#getResource(Node)} + * or {@link ImageReader#getResourceBuffer(Node)}. + */ public boolean isResource() { return false; } - public ImageLocation getLocation() { - throw new IllegalArgumentException("not a resource: " + getNameString()); + /** + * Returns the fully qualified names of any child nodes for a directory. + * + *

By default, this method throws {@link IllegalStateException} and + * is overridden for directories. + */ + public Stream getChildNames() { + throw new IllegalStateException("not a directory: " + getName()); } + /** + * Returns the uncompressed size of this node's content. If this node is + * not a resource, this method returns zero. + */ public long size() { return 0L; } + /** + * Returns the compressed size of this node's content. If this node is + * not a resource, this method returns zero. + */ public long compressedSize() { return 0L; } + /** + * Returns the extension string of a resource node. If this node is not + * a resource, this method returns null. + */ public String extension() { return null; } - public long contentOffset() { - return 0L; - } - - public final FileTime creationTime() { - return fileAttrs.creationTime(); - } - - public final FileTime lastAccessTime() { - return fileAttrs.lastAccessTime(); - } - - public final FileTime lastModifiedTime() { - return fileAttrs.lastModifiedTime(); - } - - public final String getNameString() { - return name; - } - @Override public final String toString() { - return getNameString(); + return getName(); } + /** See Node Equality. */ @Override public final int hashCode() { return name.hashCode(); } + /** See Node Equality. */ @Override public final boolean equals(Object other) { if (this == other) { @@ -729,21 +692,40 @@ public final class ImageReader implements AutoCloseable { } } - // directory node - directory has full path name without '/' at end. - static final class Directory extends Node { - private final List children; + /** + * Directory node (referenced from a full path, without a trailing '/'). + * + *

Directory nodes have two distinct states: + *

    + *
  • Incomplete: The child list has not been set. + *
  • Complete: The child list has been set. + *
+ * + *

When a directory node is returned by {@link ImageReader#findNode(String)} + * it is always complete, but this DOES NOT mean that its child nodes are + * complete yet. + * + *

To avoid users being able to access incomplete child nodes, the + * {@code Node} API offers only a way to obtain child node names, forcing + * callers to invoke {@code findNode()} if they need to access the child + * node itself. + * + *

This approach allows directories to be implemented lazily with respect + * to child nodes, while retaining efficiency when child nodes are accessed + * (since any incomplete nodes will be created and placed in the node cache + * when the parent was first returned to the user). + */ + private static final class Directory extends Node { + // Monotonic reference, will be set to the unmodifiable child list exactly once. + private List children = null; private Directory(String name, BasicFileAttributes fileAttrs) { super(name, fileAttrs); - children = new ArrayList<>(); } - static Directory create(Directory parent, String name, BasicFileAttributes fileAttrs) { - Directory d = new Directory(name, fileAttrs); - if (parent != null) { - parent.addChild(d); - } - return d; + @Override + boolean isCompleted() { + return children != null; } @Override @@ -752,46 +734,41 @@ public final class ImageReader implements AutoCloseable { } @Override - public List getChildren() { - return Collections.unmodifiableList(children); - } - - void addChild(Node node) { - assert !children.contains(node) : "Child " + node + " already added"; - children.add(node); - } - - public void walk(Consumer consumer) { - consumer.accept(this); - for (Node child : children) { - if (child.isDirectory()) { - ((Directory)child).walk(consumer); - } else { - consumer.accept(child); - } + public Stream getChildNames() { + if (children != null) { + return children.stream().map(Node::getName); } + throw new IllegalStateException("Cannot get child nodes of an incomplete directory: " + getName()); + } + + private void setChildren(List children) { + assert this.children == null : this + ": Cannot set child nodes twice!"; + this.children = Collections.unmodifiableList(children); } } - - // "resource" is .class or any other resource (compressed/uncompressed) in a jimage. - // full path of the resource is the "name" of the resource. - static class Resource extends Node { + /** + * Resource node (e.g. a ".class" entry, or any other data resource). + * + *

Resources are leaf nodes referencing an underlying image location. They + * are lightweight, and do not cache their contents. + * + *

Unlike directories (where the node name matches the jimage path for the + * corresponding {@code ImageLocation}), resource node names are NOT the same + * as the corresponding jimage path. The difference is that node names for + * resources are prefixed with "/modules", which is missing from the + * equivalent jimage path. + */ + private static class Resource extends Node { private final ImageLocation loc; - private Resource(ImageLocation loc, BasicFileAttributes fileAttrs) { - super(loc.getFullName(true), fileAttrs); + private Resource(String name, ImageLocation loc, BasicFileAttributes fileAttrs) { + super(name, fileAttrs); this.loc = loc; } - static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { - Resource rs = new Resource(loc, fileAttrs); - parent.addChild(rs); - return rs; - } - @Override - public boolean isCompleted() { - return true; + ImageLocation getLocation() { + return loc; } @Override @@ -799,11 +776,6 @@ public final class ImageReader implements AutoCloseable { return true; } - @Override - public ImageLocation getLocation() { - return loc; - } - @Override public long size() { return loc.getUncompressedSize(); @@ -818,36 +790,29 @@ public final class ImageReader implements AutoCloseable { public String extension() { return loc.getExtension(); } - - @Override - public long contentOffset() { - return loc.getContentOffset(); - } } - // represents a soft link to another Node - static class LinkNode extends Node { - private final Node link; + /** + * Link node (a symbolic link to a top-level modules directory). + * + *

Link nodes resolve their target by invoking a given supplier, and do + * not cache the result. Since nodes are cached by the {@code ImageReader}, + * this means that only the first call to {@link #resolveLink(boolean)} + * could do any significant work. + */ + private static class LinkNode extends Node { + private final Supplier link; - private LinkNode(String name, Node link) { - super(name, link.getFileAttributes()); + private LinkNode(String name, Supplier link, BasicFileAttributes fileAttrs) { + super(name, fileAttrs); this.link = link; } - static LinkNode create(Directory parent, String name, Node link) { - LinkNode ln = new LinkNode(name, link); - parent.addChild(ln); - return ln; - } - - @Override - public boolean isCompleted() { - return true; - } - @Override public Node resolveLink(boolean recursive) { - return (recursive && link instanceof LinkNode) ? ((LinkNode)link).resolveLink(true) : link; + // No need to use or propagate the recursive flag, since the target + // cannot possibly be a link node (links only point to directories). + return link.get(); } @Override diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java index e2c17f8ca25..87a00da4393 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java @@ -119,9 +119,9 @@ class ExplodedImage extends SystemImage { } @Override - public List getChildren() { + public Stream getChildNames() { if (!isDirectory()) - throw new IllegalArgumentException("not a directory: " + getNameString()); + throw new IllegalArgumentException("not a directory: " + getName()); if (children == null) { List list = new ArrayList<>(); try (DirectoryStream stream = Files.newDirectoryStream(path)) { @@ -138,7 +138,7 @@ class ExplodedImage extends SystemImage { } children = list; } - return children; + return children.stream().map(Node::getName); } @Override diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java index f0804b58c1c..e1eb1115260 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -49,7 +49,7 @@ final class JrtFileAttributes implements BasicFileAttributes { //-------- basic attributes -------- @Override public FileTime creationTime() { - return node.creationTime(); + return node.getFileAttributes().creationTime(); } @Override @@ -69,12 +69,12 @@ final class JrtFileAttributes implements BasicFileAttributes { @Override public FileTime lastAccessTime() { - return node.lastAccessTime(); + return node.getFileAttributes().lastAccessTime(); } @Override public FileTime lastModifiedTime() { - return node.lastModifiedTime(); + return node.getFileAttributes().lastModifiedTime(); } @Override diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java index 9a8d9d22dfa..6530bd1f90a 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java @@ -54,7 +54,6 @@ import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.UserPrincipalLookupService; import java.nio.file.spi.FileSystemProvider; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -64,7 +63,6 @@ import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; import jdk.internal.jimage.ImageReader.Node; -import static java.util.stream.Collectors.toList; /** * jrt file system implementation built on System jimage files. @@ -225,19 +223,19 @@ class JrtFileSystem extends FileSystem { throw new NotDirectoryException(path.getName()); } if (filter == null) { - return node.getChildren() - .stream() - .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName()))) - .iterator(); + return node.getChildNames() + .map(child -> (Path) (path.resolve(new JrtPath(this, child).getFileName()))) + .iterator(); } - return node.getChildren() - .stream() - .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName()))) - .filter(p -> { try { return filter.accept(p); - } catch (IOException x) {} - return false; - }) - .iterator(); + return node.getChildNames() + .map(child -> (Path) (path.resolve(new JrtPath(this, child).getFileName()))) + .filter(p -> { + try { + return filter.accept(p); + } catch (IOException x) {} + return false; + }) + .iterator(); } // returns the content of the file resource specified by the path diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java index 88cdf724e7d..6813c7e627f 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java @@ -58,7 +58,6 @@ abstract class SystemImage { if (modulesImageExists) { // open a .jimage and build directory structure final ImageReader image = ImageReader.open(moduleImageFile); - image.getRootDirectory(); return new SystemImage() { @Override Node findNode(String path) throws IOException { diff --git a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java index c520e6e636a..09ad3dc456d 100644 --- a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java +++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,6 @@ import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.reflect.Constructor; import java.net.URI; -import java.net.URLConnection; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; @@ -54,7 +53,6 @@ import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReaderFactory; import jdk.internal.access.JavaNetUriAccess; @@ -210,7 +208,7 @@ public final class SystemModuleFinders { } /** - * Parses the module-info.class of all module in the runtime image and + * Parses the {@code module-info.class} of all modules in the runtime image and * returns a ModuleFinder to find the modules. * * @apiNote The returned ModuleFinder is thread safe. @@ -219,20 +217,16 @@ public final class SystemModuleFinders { // parse the module-info.class in every module Map nameToAttributes = new HashMap<>(); Map nameToHash = new HashMap<>(); - ImageReader reader = SystemImage.reader(); - for (String mn : reader.getModuleNames()) { - ImageLocation loc = reader.findLocation(mn, "module-info.class"); - ModuleInfo.Attributes attrs - = ModuleInfo.read(reader.getResourceBuffer(loc), null); - nameToAttributes.put(mn, attrs); + allModuleAttributes().forEach(attrs -> { + nameToAttributes.put(attrs.descriptor().name(), attrs); ModuleHashes hashes = attrs.recordedHashes(); if (hashes != null) { for (String name : hashes.names()) { nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name)); } } - } + }); // create a ModuleReference for each module Set mrefs = new HashSet<>(); @@ -253,6 +247,40 @@ public final class SystemModuleFinders { return new SystemModuleFinder(mrefs, nameToModule); } + /** + * Parses the {@code module-info.class} of all modules in the runtime image and + * returns a stream of {@link ModuleInfo.Attributes Attributes} for them. The + * returned attributes are in no specific order. + */ + private static Stream allModuleAttributes() { + // System-wide image reader. + ImageReader reader = SystemImage.reader(); + try { + return reader.findNode("/modules") + .getChildNames() + .map(mn -> readModuleAttributes(reader, mn)); + } catch (IOException e) { + throw new Error("Error reading root /modules entry", e); + } + } + + /** + * Returns the module's "module-info", returning a holder for its class file + * attributes. Every module is required to have a valid {@code module-info.class}. + */ + private static ModuleInfo.Attributes readModuleAttributes(ImageReader reader, String moduleName) { + Exception err = null; + try { + ImageReader.Node node = reader.findNode(moduleName + "/module-info.class"); + if (node != null && node.isResource()) { + return ModuleInfo.read(reader.getResourceBuffer(node), null); + } + } catch (IOException | UncheckedIOException e) { + err = e; + } + throw new Error("Missing or invalid module-info.class for module: " + moduleName, err); + } + /** * A ModuleFinder that finds module in an array or set of modules. */ @@ -382,34 +410,18 @@ public final class SystemModuleFinders { this.module = module; } - /** - * Returns the ImageLocation for the given resource, {@code null} - * if not found. - */ - private ImageLocation findImageLocation(String name) throws IOException { - Objects.requireNonNull(name); - if (closed) - throw new IOException("ModuleReader is closed"); - ImageReader imageReader = SystemImage.reader(); - if (imageReader != null) { - return imageReader.findLocation(module, name); - } else { - // not an images build - return null; - } - } - /** * Returns {@code true} if the given resource exists, {@code false} * if not found. */ - private boolean containsImageLocation(String name) throws IOException { - Objects.requireNonNull(name); + private boolean containsResource(String resourcePath) throws IOException { + Objects.requireNonNull(resourcePath); if (closed) throw new IOException("ModuleReader is closed"); ImageReader imageReader = SystemImage.reader(); if (imageReader != null) { - return imageReader.verifyLocation(module, name); + ImageReader.Node node = imageReader.findNode("/modules" + resourcePath); + return node != null && node.isResource(); } else { // not an images build return false; @@ -418,8 +430,9 @@ public final class SystemModuleFinders { @Override public Optional find(String name) throws IOException { - if (containsImageLocation(name)) { - URI u = JNUA.create("jrt", "/" + module + "/" + name); + String resourcePath = "/" + module + "/" + name; + if (containsResource(resourcePath)) { + URI u = JNUA.create("jrt", resourcePath); return Optional.of(u); } else { return Optional.empty(); @@ -442,14 +455,25 @@ public final class SystemModuleFinders { } } + /** + * Returns the node for the given resource if found. If the name references + * a non-resource node, then {@code null} is returned. + */ + private ImageReader.Node findResource(ImageReader reader, String name) throws IOException { + Objects.requireNonNull(name); + if (closed) { + throw new IOException("ModuleReader is closed"); + } + String nodeName = "/modules/" + module + "/" + name; + ImageReader.Node node = reader.findNode(nodeName); + return (node != null && node.isResource()) ? node : null; + } + @Override public Optional read(String name) throws IOException { - ImageLocation location = findImageLocation(name); - if (location != null) { - return Optional.of(SystemImage.reader().getResourceBuffer(location)); - } else { - return Optional.empty(); - } + ImageReader reader = SystemImage.reader(); + return Optional.ofNullable(findResource(reader, name)) + .map(reader::getResourceBuffer); } @Override @@ -481,7 +505,7 @@ public final class SystemModuleFinders { private static class ModuleContentSpliterator implements Spliterator { final String moduleRoot; final Deque stack; - Iterator iterator; + Iterator iterator; ModuleContentSpliterator(String module) throws IOException { moduleRoot = "/modules/" + module; @@ -502,13 +526,10 @@ public final class SystemModuleFinders { private String next() throws IOException { for (;;) { while (iterator.hasNext()) { - ImageReader.Node node = iterator.next(); - String name = node.getName(); + String name = iterator.next(); + ImageReader.Node node = SystemImage.reader().findNode(name); if (node.isDirectory()) { - // build node - ImageReader.Node dir = SystemImage.reader().findNode(name); - assert dir.isDirectory(); - stack.push(dir); + stack.push(node); } else { // strip /modules/$MODULE/ prefix return name.substring(moduleRoot.length() + 1); @@ -520,7 +541,7 @@ public final class SystemModuleFinders { } else { ImageReader.Node dir = stack.poll(); assert dir.isDirectory(); - iterator = dir.getChildren().iterator(); + iterator = dir.getChildNames().iterator(); } } } diff --git a/test/jdk/jdk/internal/jimage/ImageReaderTest.java b/test/jdk/jdk/internal/jimage/ImageReaderTest.java new file mode 100644 index 00000000000..6bdf0cf479a --- /dev/null +++ b/test/jdk/jdk/internal/jimage/ImageReaderTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.jimage.ImageReader; +import jdk.internal.jimage.ImageReader.Node; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.util.JarBuilder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.opentest4j.TestSkippedException; +import tests.Helper; +import tests.JImageGenerator; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; + +/* + * @test + * @summary Tests for ImageReader. + * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jimage + * @library /test/jdk/tools/lib + * /test/lib + * @build tests.* + * @run junit/othervm ImageReaderTest + */ + +/// Using PER_CLASS lifecycle means the (expensive) image file is only build once. +/// There is no mutable test instance state to worry about. +@TestInstance(PER_CLASS) +public class ImageReaderTest { + + private static final Map> IMAGE_ENTRIES = Map.of( + "modfoo", Arrays.asList( + "com.foo.Alpha", + "com.foo.Beta", + "com.foo.bar.Gamma"), + "modbar", Arrays.asList( + "com.bar.One", + "com.bar.Two")); + private final Path image = buildJImage(IMAGE_ENTRIES); + + @ParameterizedTest + @ValueSource(strings = { + "/", + "/modules", + "/modules/modfoo", + "/modules/modbar", + "/modules/modfoo/com", + "/modules/modfoo/com/foo", + "/modules/modfoo/com/foo/bar"}) + public void testModuleDirectories_expected(String name) throws IOException { + try (ImageReader reader = ImageReader.open(image)) { + assertDir(reader, name); + } + } + + @ParameterizedTest + @ValueSource(strings = { + "", + "//", + "/modules/", + "/modules/unknown", + "/modules/modbar/", + "/modules/modfoo//com", + "/modules/modfoo/com/"}) + public void testModuleNodes_absent(String name) throws IOException { + try (ImageReader reader = ImageReader.open(image)) { + assertAbsent(reader, name); + } + } + + @Test + public void testModuleResources() throws IOException { + try (ImageReader reader = ImageReader.open(image)) { + assertNode(reader, "/modules/modfoo/com/foo/Alpha.class"); + assertNode(reader, "/modules/modbar/com/bar/One.class"); + + ImageClassLoader loader = new ImageClassLoader(reader, IMAGE_ENTRIES.keySet()); + assertEquals("Class: com.foo.Alpha", loader.loadAndGetToString("modfoo", "com.foo.Alpha")); + assertEquals("Class: com.foo.Beta", loader.loadAndGetToString("modfoo", "com.foo.Beta")); + assertEquals("Class: com.foo.bar.Gamma", loader.loadAndGetToString("modfoo", "com.foo.bar.Gamma")); + assertEquals("Class: com.bar.One", loader.loadAndGetToString("modbar", "com.bar.One")); + } + } + + @Test + public void testPackageDirectories() throws IOException { + try (ImageReader reader = ImageReader.open(image)) { + Node root = assertDir(reader, "/packages"); + Set pkgNames = root.getChildNames().collect(Collectors.toSet()); + assertTrue(pkgNames.contains("/packages/com")); + assertTrue(pkgNames.contains("/packages/com.foo")); + assertTrue(pkgNames.contains("/packages/com.bar")); + + // Even though no classes exist directly in the "com" package, it still + // creates a directory with links back to all the modules which contain it. + Set comLinks = assertDir(reader, "/packages/com").getChildNames().collect(Collectors.toSet()); + assertTrue(comLinks.contains("/packages/com/modfoo")); + assertTrue(comLinks.contains("/packages/com/modbar")); + } + } + + @Test + public void testPackageLinks() throws IOException { + try (ImageReader reader = ImageReader.open(image)) { + Node moduleFoo = assertDir(reader, "/modules/modfoo"); + Node moduleBar = assertDir(reader, "/modules/modbar"); + assertSame(assertLink(reader, "/packages/com.foo/modfoo").resolveLink(), moduleFoo); + assertSame(assertLink(reader, "/packages/com.bar/modbar").resolveLink(), moduleBar); + } + } + + private static ImageReader.Node assertNode(ImageReader reader, String name) throws IOException { + ImageReader.Node node = reader.findNode(name); + assertNotNull(node, "Could not find node: " + name); + return node; + } + + private static ImageReader.Node assertDir(ImageReader reader, String name) throws IOException { + ImageReader.Node dir = assertNode(reader, name); + assertTrue(dir.isDirectory(), "Node was not a directory: " + name); + return dir; + } + + private static ImageReader.Node assertLink(ImageReader reader, String name) throws IOException { + ImageReader.Node link = assertNode(reader, name); + assertTrue(link.isLink(), "Node was not a symbolic link: " + name); + return link; + } + + private static void assertAbsent(ImageReader reader, String name) throws IOException { + assertNull(reader.findNode(name), "Should not be able to find node: " + name); + } + + /// Builds a jimage file with the specified class entries. The classes in the built + /// image can be loaded and executed to return their names via `toString()` to confirm + /// the correct bytes were returned. + public static Path buildJImage(Map> entries) { + Helper helper = getHelper(); + Path outDir = helper.createNewImageDir("test"); + JImageGenerator.JLinkTask jlink = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(outDir); + + Path jarDir = helper.getJarDir(); + entries.forEach((module, classes) -> { + JarBuilder jar = new JarBuilder(jarDir.resolve(module + ".jar").toString()); + String moduleInfo = "module " + module + " {}"; + jar.addEntry("module-info.class", InMemoryJavaCompiler.compile("module-info", moduleInfo)); + + classes.forEach(fqn -> { + int lastDot = fqn.lastIndexOf('.'); + String pkg = fqn.substring(0, lastDot); + String cls = fqn.substring(lastDot + 1); + + String path = fqn.replace('.', '/') + ".class"; + String source = String.format( + """ + package %s; + public class %s { + public String toString() { + return "Class: %s"; + } + } + """, pkg, cls, fqn); + jar.addEntry(path, InMemoryJavaCompiler.compile(fqn, source)); + }); + try { + jar.build(); + } catch (IOException e) { + throw new RuntimeException(e); + } + jlink.addMods(module); + }); + return jlink.call().assertSuccess().resolve("lib", "modules"); + } + + /// Returns the helper for building JAR and jimage files. + private static Helper getHelper() { + try { + Helper helper = Helper.newHelper(); + if (helper == null) { + throw new TestSkippedException("Cannot create test helper (exploded image?)"); + } + return helper; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /// Loads and performs actions on classes stored in a given `ImageReader`. + private static class ImageClassLoader extends ClassLoader { + private final ImageReader reader; + private final Set testModules; + + private ImageClassLoader(ImageReader reader, Set testModules) { + this.reader = reader; + this.testModules = testModules; + } + + @FunctionalInterface + public interface ClassAction { + R call(Class cls) throws T; + } + + String loadAndGetToString(String module, String fqn) { + return loadAndCall(module, fqn, c -> c.getDeclaredConstructor().newInstance().toString()); + } + + R loadAndCall(String module, String fqn, ClassAction action) { + Class cls = findClass(module, fqn); + assertNotNull(cls, "Could not load class: " + module + "/" + fqn); + try { + return action.call(cls); + } catch (Exception e) { + fail("Class loading failed", e); + return null; + } + } + + @Override + protected Class findClass(String module, String fqn) { + assumeTrue(testModules.contains(module), "Can only load classes in modules: " + testModules); + String name = "/modules/" + module + "/" + fqn.replace('.', '/') + ".class"; + Class cls = findLoadedClass(fqn); + if (cls == null) { + try { + ImageReader.Node node = reader.findNode(name); + if (node != null && node.isResource()) { + byte[] classBytes = reader.getResource(node); + cls = defineClass(fqn, classBytes, 0, classBytes.length); + resolveClass(cls); + return cls; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return null; + } + } +} diff --git a/test/jdk/jdk/internal/jimage/JImageReadTest.java b/test/jdk/jdk/internal/jimage/JImageReadTest.java index ea700d03a4f..35fb2adb687 100644 --- a/test/jdk/jdk/internal/jimage/JImageReadTest.java +++ b/test/jdk/jdk/internal/jimage/JImageReadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -49,6 +49,9 @@ import org.testng.annotations.Test; import org.testng.Assert; import org.testng.TestNG; +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; + @Test public class JImageReadTest { @@ -333,32 +336,21 @@ public class JImageReadTest { */ @Test static void test5_imageReaderEndianness() throws IOException { - ImageReader nativeReader = ImageReader.open(imageFile); - Assert.assertEquals(nativeReader.getByteOrder(), ByteOrder.nativeOrder()); - - try { - ImageReader leReader = ImageReader.open(imageFile, ByteOrder.LITTLE_ENDIAN); - Assert.assertEquals(leReader.getByteOrder(), ByteOrder.LITTLE_ENDIAN); - leReader.close(); - } catch (IOException io) { - // IOException expected if LITTLE_ENDIAN not the nativeOrder() - Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN); + // Will be opened with native byte order. + try (ImageReader nativeReader = ImageReader.open(imageFile)) { + // Just ensure something works as expected. + Assert.assertNotNull(nativeReader.findNode("/")); + } catch (IOException expected) { + Assert.fail("Reader should be openable with native byte order."); } - try { - ImageReader beReader = ImageReader.open(imageFile, ByteOrder.BIG_ENDIAN); - Assert.assertEquals(beReader.getByteOrder(), ByteOrder.BIG_ENDIAN); - beReader.close(); - } catch (IOException io) { - // IOException expected if LITTLE_ENDIAN not the nativeOrder() - Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.BIG_ENDIAN); - } - - nativeReader.close(); + // Reader should not be openable with the wrong byte order. + ByteOrder otherOrder = ByteOrder.nativeOrder() == BIG_ENDIAN ? LITTLE_ENDIAN : BIG_ENDIAN; + Assert.assertThrows(IOException.class, () -> ImageReader.open(imageFile, otherOrder)); } - // main method to run standalone from jtreg - @Test(enabled=false) + // main method to run standalone from jtreg + @Test(enabled = false) @Parameters({"x"}) @SuppressWarnings("raw_types") public static void main(@Optional String[] args) { diff --git a/test/jdk/tools/jimage/ImageReaderDuplicateChildNodesTest.java b/test/jdk/tools/jimage/ImageReaderDuplicateChildNodesTest.java index bec32bee0f8..8656a4a3d00 100644 --- a/test/jdk/tools/jimage/ImageReaderDuplicateChildNodesTest.java +++ b/test/jdk/tools/jimage/ImageReaderDuplicateChildNodesTest.java @@ -68,17 +68,17 @@ public class ImageReaderDuplicateChildNodesTest { + " in " + imagePath); } // now verify that the parent node which is a directory, doesn't have duplicate children - final List children = parent.getChildren(); - if (children == null || children.isEmpty()) { + final List childNames = parent.getChildNames().toList(); + if (childNames.isEmpty()) { throw new RuntimeException("ImageReader did not return any child resources under " + integersParentResource + " in " + imagePath); } final Set uniqueChildren = new HashSet<>(); - for (final ImageReader.Node child : children) { - final boolean unique = uniqueChildren.add(child); + for (final String childName : childNames) { + final boolean unique = uniqueChildren.add(reader.findNode(childName)); if (!unique) { throw new RuntimeException("ImageReader returned duplicate child resource " - + child + " under " + parent + " from image " + imagePath); + + childName + " under " + parent + " from image " + imagePath); } } } diff --git a/test/micro/org/openjdk/bench/jdk/internal/jrtfs/ImageReaderBenchmark.java b/test/micro/org/openjdk/bench/jdk/internal/jrtfs/ImageReaderBenchmark.java index c58a4dc33b2..4f97e12171f 100644 --- a/test/micro/org/openjdk/bench/jdk/internal/jrtfs/ImageReaderBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/internal/jrtfs/ImageReaderBenchmark.java @@ -195,9 +195,9 @@ public class ImageReaderBenchmark { static long countAllNodes(ImageReader reader, Node node) { long count = 1; if (node.isDirectory()) { - count += node.getChildren().stream().mapToLong(n -> { + count += node.getChildNames().mapToLong(n -> { try { - return countAllNodes(reader, reader.findNode(n.getName())); + return countAllNodes(reader, reader.findNode(n)); } catch (IOException e) { throw new RuntimeException(e); } From f155f7d6e50c702f65858774cfd02ef60aa9cad5 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Tue, 12 Aug 2025 08:45:02 +0000 Subject: [PATCH 053/471] 8364141: Remove LockingMode related code from x86 Reviewed-by: aboldtch, dholmes, coleenp --- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 16 +- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 2 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 79 +---- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 272 +++--------------- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 7 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 169 ++--------- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 15 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 79 +---- .../x86/templateInterpreterGenerator_x86.cpp | 25 +- src/hotspot/cpu/x86/x86_64.ad | 27 -- 10 files changed, 91 insertions(+), 600 deletions(-) diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 0176ff967ce..a30bbe08c55 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -413,11 +413,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ jmp(*stub->entry()); - } else { - __ unlock_object(rdi, rsi, rax, *stub->entry()); - } + __ unlock_object(rdi, rsi, rax, *stub->entry()); __ bind(*stub->continuation()); } @@ -2733,15 +2729,9 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register obj = op->obj_opr()->as_register(); // may not be an oop Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); - if (LockingMode == LM_MONITOR) { - if (op->info() != nullptr) { - add_debug_info_for_null_check_here(op->info()); - __ null_check(obj); - } - __ jmp(*op->stub()->entry()); - } else if (op->code() == lir_lock) { + if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - Register tmp = LockingMode == LM_LIGHTWEIGHT ? op->scratch_opr()->as_register() : noreg; + Register tmp = op->scratch_opr()->as_register(); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry()); if (op->info() != nullptr) { diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 3bd86d9b7e5..1fdfcc4f9cd 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -289,7 +289,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { // this CodeEmitInfo must not have the xhandlers because here the // object is already locked (xhandlers expect object to be unlocked) CodeEmitInfo* info = state_for(x, x->state(), true); - LIR_Opr tmp = LockingMode == LM_LIGHTWEIGHT ? new_register(T_ADDRESS) : LIR_OprFact::illegalOpr; + LIR_Opr tmp = new_register(T_ADDRESS); monitor_enter(obj.result(), lock, syncTempOpr(), tmp, x->monitor_no(), info_for_exception, info); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index c9d103768b8..36efeafa940 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -42,8 +42,6 @@ #include "utilities/globalDefinitions.hpp" int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction"); assert_different_registers(hdr, obj, disp_hdr, tmp); int null_check_offset = -1; @@ -55,93 +53,20 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); - } else if (LockingMode == LM_LEGACY) { - Label done; - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj, rscratch1); - testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - - // Load object header - movptr(hdr, Address(obj, hdr_offset)); - // and mark it as unlocked - orptr(hdr, markWord::unlocked_value); - // save unlocked object header into the displaced header location on the stack - movptr(Address(disp_hdr, 0), hdr); - // test if object header is still the same (i.e. unlocked), and if so, store the - // displaced header address in the object header - if it is not the same, get the - // object header instead - MacroAssembler::lock(); // must be immediately before cmpxchg! - cmpxchgptr(disp_hdr, Address(obj, hdr_offset)); - // if the object header was the same, we're done - jcc(Assembler::equal, done); - // if the object header was not the same, it is now in the hdr register - // => test if it is a stack pointer into the same stack (recursive locking), i.e.: - // - // 1) (hdr & aligned_mask) == 0 - // 2) rsp <= hdr - // 3) hdr <= rsp + page_size - // - // these 3 tests can be done by evaluating the following expression: - // - // (hdr - rsp) & (aligned_mask - page_size) - // - // assuming both the stack pointer and page_size have their least - // significant 2 bits cleared and page_size is a power of 2 - subptr(hdr, rsp); - andptr(hdr, aligned_mask - (int)os::vm_page_size()); - // for recursive locking, the result is zero => save it in the displaced header - // location (null in the displaced hdr location indicates recursive locking) - movptr(Address(disp_hdr, 0), hdr); - // otherwise we don't care about the result and handle locking via runtime call - jcc(Assembler::notZero, slow_case); - // done - bind(done); - inc_held_monitor_count(); - } + lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); return null_check_offset; } void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction"); assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); - Label done; - - if (LockingMode != LM_LIGHTWEIGHT) { - // load displaced header - movptr(hdr, Address(disp_hdr, 0)); - // if the loaded hdr is null we had recursive locking - testptr(hdr, hdr); - // if we had recursive locking, we are done - jcc(Assembler::zero, done); - } // load object movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); verify_oop(obj); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj, disp_hdr, hdr, slow_case); - } else if (LockingMode == LM_LEGACY) { - // test if object header is pointing to the displaced header, and if so, restore - // the displaced header in the object - if the object header is not pointing to - // the displaced header, get the object header instead - MacroAssembler::lock(); // must be immediately before cmpxchg! - cmpxchgptr(hdr, Address(obj, hdr_offset)); - // if the object header was not pointing to the displaced header, - // we do unlocking via runtime call - jcc(Assembler::notEqual, slow_case); - // done - bind(done); - dec_held_monitor_count(); - } + lightweight_unlock(obj, disp_hdr, hdr, slow_case); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index b5b65171e32..8c3f33e0aca 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -219,244 +219,11 @@ inline Assembler::AvxVectorLen C2_MacroAssembler::vector_length_encoding(int vle // obj: object to lock -// box: on-stack box address (displaced header location) - KILLED -// rax,: tmp -- KILLED -// scr: tmp -- KILLED -void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, - Register scrReg, Register cx1Reg, Register cx2Reg, Register thread, - Metadata* method_data) { - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_lock_lightweight"); - // Ensure the register assignments are disjoint - assert(tmpReg == rax, ""); - assert(cx1Reg == noreg, ""); - assert(cx2Reg == noreg, ""); - assert_different_registers(objReg, boxReg, tmpReg, scrReg); - - // Possible cases that we'll encounter in fast_lock - // ------------------------------------------------ - // * Inflated - // -- unlocked - // -- Locked - // = by self - // = by other - // * neutral - // * stack-locked - // -- by self - // = sp-proximity test hits - // = sp-proximity test generates false-negative - // -- by other - // - - Label IsInflated, DONE_LABEL, NO_COUNT, COUNT; - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmpReg, objReg, scrReg); - testb(Address(tmpReg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, DONE_LABEL); - } - - movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // [FETCH] - testptr(tmpReg, markWord::monitor_value); // inflated vs stack-locked|neutral - jcc(Assembler::notZero, IsInflated); - - if (LockingMode == LM_MONITOR) { - // Clear ZF so that we take the slow path at the DONE label. objReg is known to be not 0. - testptr(objReg, objReg); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Attempt stack-locking ... - orptr (tmpReg, markWord::unlocked_value); - movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS - lock(); - cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg - jcc(Assembler::equal, COUNT); // Success - - // Recursive locking. - // The object is stack-locked: markword contains stack pointer to BasicLock. - // Locked by current thread if difference with current SP is less than one page. - subptr(tmpReg, rsp); - // Next instruction set ZFlag == 1 (Success) if difference is less then one page. - andptr(tmpReg, (int32_t) (7 - (int)os::vm_page_size()) ); - movptr(Address(boxReg, 0), tmpReg); - } - jmp(DONE_LABEL); - - bind(IsInflated); - // The object is inflated. tmpReg contains pointer to ObjectMonitor* + markWord::monitor_value - - // Unconditionally set box->_displaced_header = markWord::unused_mark(). - // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. - movptr(Address(boxReg, 0), checked_cast(markWord::unused_mark().value())); - - // It's inflated and we use scrReg for ObjectMonitor* in this section. - movptr(boxReg, Address(r15_thread, JavaThread::monitor_owner_id_offset())); - movq(scrReg, tmpReg); - xorq(tmpReg, tmpReg); - lock(); - cmpxchgptr(boxReg, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - - // Propagate ICC.ZF from CAS above into DONE_LABEL. - jccb(Assembler::equal, COUNT); // CAS above succeeded; propagate ZF = 1 (success) - - cmpptr(boxReg, rax); // Check if we are already the owner (recursive lock) - jccb(Assembler::notEqual, NO_COUNT); // If not recursive, ZF = 0 at this point (fail) - incq(Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - xorq(rax, rax); // Set ZF = 1 (success) for recursive lock, denoting locking success - bind(DONE_LABEL); - - // ZFlag == 1 count in fast path - // ZFlag == 0 count in slow path - jccb(Assembler::notZero, NO_COUNT); // jump if ZFlag == 0 - - bind(COUNT); - if (LockingMode == LM_LEGACY) { - // Count monitors in fast path - increment(Address(thread, JavaThread::held_monitor_count_offset())); - } - xorl(tmpReg, tmpReg); // Set ZF == 1 - - bind(NO_COUNT); - - // At NO_COUNT the icc ZFlag is set as follows ... - // fast_unlock uses the same protocol. - // ZFlag == 1 -> Success - // ZFlag == 0 -> Failure - force control through the slow path -} - -// obj: object to unlock -// box: box address (displaced header location), killed. Must be EAX. -// tmp: killed, cannot be obj nor box. -// -// Some commentary on balanced locking: -// -// fast_lock and fast_unlock are emitted only for provably balanced lock sites. -// Methods that don't have provably balanced locking are forced to run in the -// interpreter - such methods won't be compiled to use fast_lock and fast_unlock. -// The interpreter provides two properties: -// I1: At return-time the interpreter automatically and quietly unlocks any -// objects acquired the current activation (frame). Recall that the -// interpreter maintains an on-stack list of locks currently held by -// a frame. -// I2: If a method attempts to unlock an object that is not held by the -// the frame the interpreter throws IMSX. -// -// Lets say A(), which has provably balanced locking, acquires O and then calls B(). -// B() doesn't have provably balanced locking so it runs in the interpreter. -// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O -// is still locked by A(). -// -// The only other source of unbalanced locking would be JNI. The "Java Native Interface: -// Programmer's Guide and Specification" claims that an object locked by jni_monitorenter -// should not be unlocked by "normal" java-level locking and vice-versa. The specification -// doesn't specify what will occur if a program engages in such mixed-mode locking, however. -// Arguably given that the spec legislates the JNI case as undefined our implementation -// could reasonably *avoid* checking owner in fast_unlock(). -// In the interest of performance we elide m->Owner==Self check in unlock. -// A perfectly viable alternative is to elide the owner check except when -// Xcheck:jni is enabled. - -void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg) { - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); - assert(boxReg == rax, ""); - assert_different_registers(objReg, boxReg, tmpReg); - - Label DONE_LABEL, Stacked, COUNT, NO_COUNT; - - if (LockingMode == LM_LEGACY) { - cmpptr(Address(boxReg, 0), NULL_WORD); // Examine the displaced header - jcc (Assembler::zero, COUNT); // 0 indicates recursive stack-lock - } - movptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Examine the object's markword - if (LockingMode != LM_MONITOR) { - testptr(tmpReg, markWord::monitor_value); // Inflated? - jcc(Assembler::zero, Stacked); - } - - // It's inflated. - - // Despite our balanced locking property we still check that m->_owner == Self - // as java routines or native JNI code called by this thread might - // have released the lock. - // - // If there's no contention try a 1-0 exit. That is, exit without - // a costly MEMBAR or CAS. See synchronizer.cpp for details on how - // we detect and recover from the race that the 1-0 exit admits. - // - // Conceptually fast_unlock() must execute a STST|LDST "release" barrier - // before it STs null into _owner, releasing the lock. Updates - // to data protected by the critical section must be visible before - // we drop the lock (and thus before any other thread could acquire - // the lock and observe the fields protected by the lock). - // IA32's memory-model is SPO, so STs are ordered with respect to - // each other and there's no need for an explicit barrier (fence). - // See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html. - Label LSuccess, LNotRecursive; - - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); - jccb(Assembler::equal, LNotRecursive); - - // Recursive inflated unlock - decrement(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jmpb(LSuccess); - - bind(LNotRecursive); - - // Set owner to null. - // Release to satisfy the JMM - movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(entry_list)), NULL_WORD); - jccb(Assembler::zero, LSuccess); // If so we are done. - - // Check if there is a successor. - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); - jccb(Assembler::notZero, LSuccess); // If so we are done. - - // Save the monitor pointer in the current thread, so we can try to - // reacquire the lock in SharedRuntime::monitor_exit_helper(). - andptr(tmpReg, ~(int32_t)markWord::monitor_value); - movptr(Address(r15_thread, JavaThread::unlocked_inflated_monitor_offset()), tmpReg); - - orl (boxReg, 1); // set ICC.ZF=0 to indicate failure - jmpb (DONE_LABEL); - - bind (LSuccess); - testl (boxReg, 0); // set ICC.ZF=1 to indicate success - jmpb (DONE_LABEL); - - if (LockingMode == LM_LEGACY) { - bind (Stacked); - movptr(tmpReg, Address (boxReg, 0)); // re-fetch - lock(); - cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box - // Intentional fall-thru into DONE_LABEL - } - - bind(DONE_LABEL); - - // ZFlag == 1 count in fast path - // ZFlag == 0 count in slow path - jccb(Assembler::notZero, NO_COUNT); - - bind(COUNT); - - if (LockingMode == LM_LEGACY) { - // Count monitors in fast path - decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); - } - - xorl(tmpReg, tmpReg); // Set ZF == 1 - - bind(NO_COUNT); -} - +// box: on-stack box address -- KILLED +// rax: tmp -- KILLED +// t : tmp -- KILLED void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register rax_reg, Register t, Register thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(rax_reg == rax, "Used for CAS"); assert_different_registers(obj, box, rax_reg, t, thread); @@ -616,8 +383,39 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist // C2 uses the value of ZF to determine the continuation. } +// obj: object to lock +// rax: tmp -- KILLED +// t : tmp - cannot be obj nor rax -- KILLED +// +// Some commentary on balanced locking: +// +// fast_lock and fast_unlock are emitted only for provably balanced lock sites. +// Methods that don't have provably balanced locking are forced to run in the +// interpreter - such methods won't be compiled to use fast_lock and fast_unlock. +// The interpreter provides two properties: +// I1: At return-time the interpreter automatically and quietly unlocks any +// objects acquired in the current activation (frame). Recall that the +// interpreter maintains an on-stack list of locks currently held by +// a frame. +// I2: If a method attempts to unlock an object that is not held by the +// frame the interpreter throws IMSX. +// +// Lets say A(), which has provably balanced locking, acquires O and then calls B(). +// B() doesn't have provably balanced locking so it runs in the interpreter. +// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O +// is still locked by A(). +// +// The only other source of unbalanced locking would be JNI. The "Java Native Interface +// Specification" states that an object locked by JNI's MonitorEnter should not be +// unlocked by "normal" java-level locking and vice-versa. The specification doesn't +// specify what will occur if a program engages in such mixed-mode locking, however. +// Arguably given that the spec legislates the JNI case as undefined our implementation +// could reasonably *avoid* checking owner in fast_unlock(). +// In the interest of performance we elide m->Owner==Self check in unlock. +// A perfectly viable alternative is to elide the owner check except when +// Xcheck:jni is enabled. + void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(reg_rax == rax, "Used for CAS"); assert_different_registers(obj, reg_rax, t); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index e1652213688..950fcb75290 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -34,12 +34,7 @@ public: Assembler::AvxVectorLen vector_length_encoding(int vlen_in_bytes); // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. - // See full description in macroAssembler_x86.cpp. - void fast_lock(Register obj, Register box, Register tmp, - Register scr, Register cx1, Register cx2, Register thread, - Metadata* method_data); - void fast_unlock(Register obj, Register box, Register tmp); - + // See full description in c2_MacroAssembler_x86.cpp. void fast_lock_lightweight(Register obj, Register box, Register rax_reg, Register t, Register thread); void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 92233ee0d07..a6b4efbe4f2 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1024,100 +1024,25 @@ void InterpreterMacroAssembler::get_method_counters(Register method, void InterpreterMacroAssembler::lock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } else { - Label count_locking, done, slow_case; + Label done, slow_case; - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register tmp_reg = rbx; - const Register obj_reg = c_rarg3; // Will contain the oop - const Register rklass_decode_tmp = rscratch1; + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register tmp_reg = rbx; + const Register obj_reg = c_rarg3; // Will contain the oop - const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); + // Load object pointer into obj_reg + movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load object pointer into obj_reg - movptr(obj_reg, Address(lock_reg, obj_offset)); + lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); + jmp(done); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); - } else if (LockingMode == LM_LEGACY) { - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp_reg, obj_reg, rklass_decode_tmp); - testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } + bind(slow_case); - // Load immediate 1 into swap_reg %rax - movl(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax - orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // Save (object->mark() | 1) into BasicLock's displaced header - movptr(Address(lock_reg, mark_offset), swap_reg); - - assert(lock_offset == 0, - "displaced header must be first word in BasicObjectLock"); - - lock(); - cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - jcc(Assembler::zero, count_locking); - - const int zero_bits = 7; - - // Fast check for recursive lock. - // - // Can apply the optimization only if this is a stack lock - // allocated in this thread. For efficiency, we can focus on - // recently allocated stack locks (instead of reading the stack - // base and checking whether 'mark' points inside the current - // thread stack): - // 1) (mark & zero_bits) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // - // Warning: rsp + os::pagesize can overflow the stack base. We must - // neither apply the optimization for an inflated lock allocated - // just above the thread stack (this is why condition 1 matters) - // nor apply the optimization if the stack lock is inside the stack - // of another thread. The latter is avoided even in case of overflow - // because we have guard pages at the end of all stacks. Hence, if - // we go over the stack base and hit the stack of another thread, - // this should not be in a writeable area that could contain a - // stack lock allocated by that thread. As a consequence, a stack - // lock less than page size away from rsp is guaranteed to be - // owned by the current thread. - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (zero_bits - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant bits clear. - // NOTE: the mark is in swap_reg %rax as the result of cmpxchg - subptr(swap_reg, rsp); - andptr(swap_reg, zero_bits - (int)os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - movptr(Address(lock_reg, mark_offset), swap_reg); - jcc(Assembler::notZero, slow_case); - - bind(count_locking); - inc_held_monitor_count(); - } - jmp(done); - - bind(slow_case); - - // Call the runtime routine for slow case - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - bind(done); - } + // Call the runtime routine for slow case + call_VM_preemptable(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + bind(done); } @@ -1136,63 +1061,31 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { void InterpreterMacroAssembler::unlock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Label count_locking, done, slow_case; + Label done, slow_case; - const Register swap_reg = rax; // Must use rax for cmpxchg instruction - const Register header_reg = c_rarg2; // Will contain the old oopMark - const Register obj_reg = c_rarg3; // Will contain the oop + const Register swap_reg = rax; // Must use rax for cmpxchg instruction + const Register header_reg = c_rarg2; // Will contain the old oopMark + const Register obj_reg = c_rarg3; // Will contain the oop - save_bcp(); // Save in case of exception + save_bcp(); // Save in case of exception - if (LockingMode != LM_LIGHTWEIGHT) { - // Convert from BasicObjectLock structure to object and BasicLock - // structure Store the BasicLock address into %rax - lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset())); - } + // Load oop into obj_reg(%c_rarg3) + movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load oop into obj_reg(%c_rarg3) - movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); + // Free entry + movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD); - // Free entry - movptr(Address(lock_reg, BasicObjectLock::obj_offset()), NULL_WORD); + lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); + jmp(done); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj_reg, swap_reg, header_reg, slow_case); - } else if (LockingMode == LM_LEGACY) { - // Load the old header from BasicLock structure - movptr(header_reg, Address(swap_reg, - BasicLock::displaced_header_offset_in_bytes())); + bind(slow_case); + // Call the runtime routine for slow case. + movptr(Address(lock_reg, BasicObjectLock::obj_offset()), obj_reg); // restore obj + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - // Test for recursion - testptr(header_reg, header_reg); + bind(done); - // zero for recursive case - jcc(Assembler::zero, count_locking); - - // Atomic swap back the old header - lock(); - cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // zero for simple unlock of a stack-lock case - jcc(Assembler::notZero, slow_case); - - bind(count_locking); - dec_held_monitor_count(); - } - jmp(done); - - bind(slow_case); - // Call the runtime routine for slow case. - movptr(Address(lock_reg, BasicObjectLock::obj_offset()), obj_reg); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - - bind(done); - - restore_bcp(); - } + restore_bcp(); } void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index b8a4b829159..17fdfa61d36 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -59,17 +59,10 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas __ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - if (LockingMode == LM_LIGHTWEIGHT) { - if (!UseObjectMonitorTable) { - // check if monitor - __ testptr(result, markWord::monitor_value); - __ jcc(Assembler::notZero, slowCase); - } - } else { - // check if locked - __ testptr(result, markWord::unlocked_value); - __ jcc(Assembler::zero, slowCase); + if (!UseObjectMonitorTable) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); } // get hash diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 7c7ca61f1ae..d60f535fefc 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2133,7 +2133,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // We use the same pc/oopMap repeatedly when we call out Label native_return; - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // For convenience we use the pc we want to resume to in case of preemption on Object.wait. __ set_last_Java_frame(rsp, noreg, native_return, rscratch1); } else { @@ -2174,16 +2174,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register swap_reg = rax; // Must use rax for cmpxchg instruction const Register obj_reg = rbx; // Will contain the oop const Register lock_reg = r13; // Address of compiler lock object (BasicLock) - const Register old_hdr = r13; // value of old header at unlock time Label slow_path_lock; Label lock_done; if (method->is_synchronized()) { - Label count_mon; - - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mov(oop_handle_reg, c_rarg1); @@ -2194,47 +2189,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ movptr(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_MONITOR) { - __ jmp(slow_path_lock); - } else if (LockingMode == LM_LEGACY) { - // Load immediate 1 into swap_reg %rax - __ movl(swap_reg, 1); - - // Load (object->mark() | 1) into swap_reg %rax - __ orptr(swap_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - - // Save (object->mark() | 1) into BasicLock's displaced header - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - - // src -> dest iff dest == rax else rax <- dest - __ lock(); - __ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::equal, count_mon); - - // Hmm should this move to the slow path code area??? - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) rsp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - rsp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %rax as the result of cmpxchg - - __ subptr(swap_reg, rsp); - __ andptr(swap_reg, 3 - (int)os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - __ movptr(Address(lock_reg, mark_word_offset), swap_reg); - __ jcc(Assembler::notEqual, slow_path_lock); - - __ bind(count_mon); - __ inc_held_monitor_count(); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(lock_reg, obj_reg, swap_reg, rscratch1, slow_path_lock); - } + __ lightweight_lock(lock_reg, obj_reg, swap_reg, rscratch1, slow_path_lock); // Slow path will re-enter here __ bind(lock_done); @@ -2322,7 +2277,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // change thread state __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // Check preemption for Object.wait() __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); __ cmpptr(rscratch1, NULL_WORD); @@ -2354,38 +2309,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Get locked oop from the handle we passed to jni __ movptr(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_LEGACY) { - Label not_recur; - // Simple recursive lock? - __ cmpptr(Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size), NULL_WORD); - __ jcc(Assembler::notEqual, not_recur); - __ dec_held_monitor_count(); - __ jmpb(fast_done); - __ bind(not_recur); - } - // Must save rax if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - if (LockingMode == LM_MONITOR) { - __ jmp(slow_path_unlock); - } else if (LockingMode == LM_LEGACY) { - // get address of the stack lock - __ lea(rax, Address(rsp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ movptr(old_hdr, Address(rax, 0)); - - // Atomic swap old header if oop still contains the stack lock - __ lock(); - __ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ jcc(Assembler::notEqual, slow_path_unlock); - __ dec_held_monitor_count(); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); - } + __ lightweight_unlock(obj_reg, swap_reg, lock_reg, slow_path_unlock); // slow path re-enters here __ bind(unlock_done); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index bd061d45fbd..47ef0aef2bb 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1017,21 +1017,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // change thread state __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); - if (LockingMode != LM_LEGACY) { - // Check preemption for Object.wait() - Label not_preempted; - __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); - __ cmpptr(rscratch1, NULL_WORD); - __ jccb(Assembler::equal, not_preempted); - __ movptr(Address(r15_thread, JavaThread::preempt_alternate_return_offset()), NULL_WORD); - __ jmp(rscratch1); - __ bind(native_return); - __ restore_after_resume(true /* is_native */); - __ bind(not_preempted); - } else { - // any pc will do so just use this one for LM_LEGACY to keep code together. - __ bind(native_return); - } + // Check preemption for Object.wait() + Label not_preempted; + __ movptr(rscratch1, Address(r15_thread, JavaThread::preempt_alternate_return_offset())); + __ cmpptr(rscratch1, NULL_WORD); + __ jccb(Assembler::equal, not_preempted); + __ movptr(Address(r15_thread, JavaThread::preempt_alternate_return_offset()), NULL_WORD); + __ jmp(rscratch1); + __ bind(native_return); + __ restore_after_resume(true /* is_native */); + __ bind(not_preempted); // reset_last_Java_frame __ reset_last_Java_frame(true); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 5b5292fbde2..932dc9e1ca7 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -14073,33 +14073,7 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ // ============================================================================ // inlined locking and unlocking -instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastLock object box)); - effect(TEMP tmp, TEMP scr, USE_KILL box); - ins_cost(300); - format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr" %} - ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, - $scr$$Register, noreg, noreg, r15_thread, nullptr); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastUnlock object box)); - effect(TEMP tmp, USE_KILL box); - ins_cost(300); - format %{ "fastunlock $object,$box\t! kills $box,$tmp" %} - ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); - %} - ins_pipe(pipe_slow); -%} - instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI rax_reg, rRegP tmp) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastLock object box)); effect(TEMP rax_reg, TEMP tmp, USE_KILL box); ins_cost(300); @@ -14111,7 +14085,6 @@ instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_Re %} instruct cmpFastUnlockLightweight(rFlagsReg cr, rRegP object, rax_RegP rax_reg, rRegP tmp) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastUnlock object rax_reg)); effect(TEMP tmp, USE_KILL rax_reg); ins_cost(300); From 3c0eed8e476e4da540e4ea44ee966f278e04a067 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Tue, 12 Aug 2025 08:45:36 +0000 Subject: [PATCH 054/471] 8364406: Remove LockingMode related code from aarch64 Reviewed-by: aph, dholmes --- src/hotspot/cpu/aarch64/aarch64.ad | 34 --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 14 +- .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 81 +------ .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 208 ------------------ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 3 - .../cpu/aarch64/interp_masm_aarch64.cpp | 171 +++----------- .../cpu/aarch64/macroAssembler_aarch64.cpp | 2 - .../cpu/aarch64/sharedRuntime_aarch64.cpp | 75 +------ .../templateInterpreterGenerator_aarch64.cpp | 27 +-- 9 files changed, 52 insertions(+), 563 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 517da8066de..9697ac31350 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -16281,41 +16281,8 @@ instruct branchLoopEnd(cmpOp cmp, rFlagsReg cr, label lbl) // ============================================================================ // inlined locking and unlocking -instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3) -%{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastLock object box)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - - ins_cost(5 * INSN_COST); - format %{ "fastlock $object,$box\t! kills $tmp,$tmp2,$tmp3" %} - - ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); - %} - - ins_pipe(pipe_serial); -%} - -instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2) -%{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastUnlock object box)); - effect(TEMP tmp, TEMP tmp2); - - ins_cost(5 * INSN_COST); - format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2" %} - - ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register); - %} - - ins_pipe(pipe_serial); -%} - instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP tmp2, TEMP tmp3); @@ -16331,7 +16298,6 @@ instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastUnlock object box)); effect(TEMP tmp, TEMP tmp2, TEMP tmp3); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 31f1e97002a..bdba957d1df 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -410,11 +410,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::r0_opr); stub = new MonitorExitStub(FrameMap::r0_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ b(*stub->entry()); - } else { - __ unlock_object(r5, r4, r0, r6, *stub->entry()); - } + __ unlock_object(r5, r4, r0, r6, *stub->entry()); __ bind(*stub->continuation()); } @@ -2484,13 +2480,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); - if (LockingMode == LM_MONITOR) { - if (op->info() != nullptr) { - add_debug_info_for_null_check_here(op->info()); - __ null_check(obj, -1); - } - __ b(*op->stub()->entry()); - } else if (op->code() == lir_lock) { + if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index b0f9d6d6c41..8a79274b2ff 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -60,8 +60,6 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); int null_check_offset = -1; @@ -72,95 +70,20 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); - } else if (LockingMode == LM_LEGACY) { + lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); - tst(hdr, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - - Label done; - // Load object header - ldr(hdr, Address(obj, hdr_offset)); - // and mark it as unlocked - orr(hdr, hdr, markWord::unlocked_value); - // save unlocked object header into the displaced header location on the stack - str(hdr, Address(disp_hdr, 0)); - // test if object header is still the same (i.e. unlocked), and if so, store the - // displaced header address in the object header - if it is not the same, get the - // object header instead - lea(rscratch2, Address(obj, hdr_offset)); - cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/nullptr); - // if the object header was the same, we're done - // if the object header was not the same, it is now in the hdr register - // => test if it is a stack pointer into the same stack (recursive locking), i.e.: - // - // 1) (hdr & aligned_mask) == 0 - // 2) sp <= hdr - // 3) hdr <= sp + page_size - // - // these 3 tests can be done by evaluating the following expression: - // - // (hdr - sp) & (aligned_mask - page_size) - // - // assuming both the stack pointer and page_size have their least - // significant 2 bits cleared and page_size is a power of 2 - mov(rscratch1, sp); - sub(hdr, hdr, rscratch1); - ands(hdr, hdr, aligned_mask - (int)os::vm_page_size()); - // for recursive locking, the result is zero => save it in the displaced header - // location (null in the displaced hdr location indicates recursive locking) - str(hdr, Address(disp_hdr, 0)); - // otherwise we don't care about the result and handle locking via runtime call - cbnz(hdr, slow_case); - // done - bind(done); - inc_held_monitor_count(rscratch1); - } return null_check_offset; } void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - const int aligned_mask = BytesPerWord -1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); - Label done; - - if (LockingMode != LM_LIGHTWEIGHT) { - // load displaced header - ldr(hdr, Address(disp_hdr, 0)); - // if the loaded hdr is null we had recursive locking - // if we had recursive locking, we are done - cbz(hdr, done); - } // load object ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); verify_oop(obj); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj, hdr, temp, rscratch2, slow_case); - } else if (LockingMode == LM_LEGACY) { - // test if object header is pointing to the displaced header, and if so, restore - // the displaced header in the object - if the object header is not pointing to - // the displaced header, get the object header instead - // if the object header was not pointing to the displaced header, - // we do unlocking via runtime call - if (hdr_offset) { - lea(rscratch1, Address(obj, hdr_offset)); - cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case); - } else { - cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case); - } - // done - bind(done); - dec_held_monitor_count(rscratch1); - } + lightweight_unlock(obj, hdr, temp, rscratch2, slow_case); } diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index e87cb478c8f..b1562c54f4e 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -147,215 +147,8 @@ address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register return pc(); } -void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register tmpReg, - Register tmp2Reg, Register tmp3Reg) { - Register oop = objectReg; - Register box = boxReg; - Register disp_hdr = tmpReg; - Register tmp = tmp2Reg; - Label cont; - Label object_has_monitor; - Label count, no_count; - - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_lock_lightweight"); - assert_different_registers(oop, box, tmp, disp_hdr, rscratch2); - - // Load markWord from object into displaced_header. - ldr(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, oop); - ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); - tst(tmp, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, cont); - } - - // Check for existing monitor - tbnz(disp_hdr, exact_log2(markWord::monitor_value), object_has_monitor); - - if (LockingMode == LM_MONITOR) { - tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. - b(cont); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Set tmp to be (markWord of object | UNLOCK_VALUE). - orr(tmp, disp_hdr, markWord::unlocked_value); - - // Initialize the box. (Must happen before we update the object mark!) - str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // Compare object markWord with an unlocked value (tmp) and if - // equal exchange the stack address of our box with object markWord. - // On failure disp_hdr contains the possibly locked markWord. - cmpxchg(oop, tmp, box, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, disp_hdr); - br(Assembler::EQ, cont); - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object, will have now locked it will continue at label cont - - // Check if the owner is self by comparing the value in the - // markWord of object (disp_hdr) with the stack pointer. - mov(rscratch1, sp); - sub(disp_hdr, disp_hdr, rscratch1); - mov(tmp, (address) (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - // If condition is true we are cont and hence we can store 0 as the - // displaced header in the box, which indicates that it is a recursive lock. - ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result - str(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); - b(cont); - } - - // Handle existing monitor. - bind(object_has_monitor); - - // Try to CAS owner (no owner => current thread's _monitor_owner_id). - ldr(rscratch2, Address(rthread, JavaThread::monitor_owner_id_offset())); - add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset())-markWord::monitor_value)); - cmpxchg(tmp, zr, rscratch2, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, tmp3Reg); // Sets flags for result - - // Store a non-null value into the box to avoid looking like a re-entrant - // lock. The fast-path monitor unlock code checks for - // markWord::monitor_value so use markWord::unused_mark which has the - // relevant bit set, and also matches ObjectSynchronizer::enter. - mov(tmp, (address)markWord::unused_mark().value()); - str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - br(Assembler::EQ, cont); // CAS success means locking succeeded - - cmp(tmp3Reg, rscratch2); - br(Assembler::NE, cont); // Check for recursive locking - - // Recursive lock case - increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1); - // flag == EQ still from the cmp above, checking if this is a reentrant lock - - bind(cont); - // flag == EQ indicates success - // flag == NE indicates failure - br(Assembler::NE, no_count); - - bind(count); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(rscratch1); - } - - bind(no_count); -} - -void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Register tmpReg, - Register tmp2Reg) { - Register oop = objectReg; - Register box = boxReg; - Register disp_hdr = tmpReg; - Register owner_addr = tmpReg; - Register tmp = tmp2Reg; - Label cont; - Label object_has_monitor; - Label count, no_count; - Label unlocked; - - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); - assert_different_registers(oop, box, tmp, disp_hdr); - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - ldr(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // If the displaced header is 0, we have a recursive unlock. - cmp(disp_hdr, zr); - br(Assembler::EQ, cont); - } - - // Handle existing monitor. - ldr(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); - tbnz(tmp, exact_log2(markWord::monitor_value), object_has_monitor); - - if (LockingMode == LM_MONITOR) { - tst(oop, oop); // Set NE to indicate 'failure' -> take slow-path. We know that oop != 0. - b(cont); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Check if it is still a light weight lock, this is is true if we - // see the stack address of the basicLock in the markWord of the - // object. - - cmpxchg(oop, box, disp_hdr, Assembler::xword, /*acquire*/ false, - /*release*/ true, /*weak*/ false, tmp); - b(cont); - } - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // Handle existing monitor. - bind(object_has_monitor); - STATIC_ASSERT(markWord::monitor_value <= INT_MAX); - add(tmp, tmp, -(int)markWord::monitor_value); // monitor - - ldr(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - - Label notRecursive; - cbz(disp_hdr, notRecursive); - - // Recursive lock - sub(disp_hdr, disp_hdr, 1u); - str(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - cmp(disp_hdr, disp_hdr); // Sets flags for result - b(cont); - - bind(notRecursive); - - // Compute owner address. - lea(owner_addr, Address(tmp, ObjectMonitor::owner_offset())); - - // Set owner to null. - // Release to satisfy the JMM - stlr(zr, owner_addr); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - ldr(rscratch1, Address(tmp, ObjectMonitor::entry_list_offset())); - cmp(rscratch1, zr); - br(Assembler::EQ, cont); // If so we are done. - - // Check if there is a successor. - ldr(rscratch1, Address(tmp, ObjectMonitor::succ_offset())); - cmp(rscratch1, zr); - br(Assembler::NE, unlocked); // If so we are done. - - // Save the monitor pointer in the current thread, so we can try to - // reacquire the lock in SharedRuntime::monitor_exit_helper(). - str(tmp, Address(rthread, JavaThread::unlocked_inflated_monitor_offset())); - - cmp(zr, rthread); // Set Flag to NE => slow path - b(cont); - - bind(unlocked); - cmp(zr, zr); // Set Flag to EQ => fast path - - // Intentional fall-through - - bind(cont); - // flag == EQ indicates success - // flag == NE indicates failure - br(Assembler::NE, no_count); - - bind(count); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(rscratch1); - } - - bind(no_count); -} - void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register t1, Register t2, Register t3) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert_different_registers(obj, box, t1, t2, t3, rscratch2); // Handle inflated monitor. @@ -512,7 +305,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register t1, Register t2, Register t3) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert_different_registers(obj, box, t1, t2, t3); // Handle inflated monitor. diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 233f600cb14..0403a27910f 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -51,9 +51,6 @@ FloatRegister vmul3, FloatRegister vpow, FloatRegister vpowm, BasicType eltype); - // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. - void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); - void fast_unlock(Register object, Register box, Register tmp, Register tmp2); // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file. void fast_lock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); void fast_unlock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index e14829b7c89..607912e6e49 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -691,104 +691,27 @@ void InterpreterMacroAssembler::leave_jfr_critical_section() { void InterpreterMacroAssembler::lock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } else { - Label count, done; - const Register swap_reg = r0; - const Register tmp = c_rarg2; - const Register obj_reg = c_rarg3; // Will contain the oop - const Register tmp2 = c_rarg4; - const Register tmp3 = c_rarg5; + const Register tmp = c_rarg2; + const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp2 = c_rarg4; + const Register tmp3 = c_rarg5; - const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); + // Load object pointer into obj_reg %c_rarg3 + ldr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - Label slow_case; + Label slow_case, done; + lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); + b(done); - // Load object pointer into obj_reg %c_rarg3 - ldr(obj_reg, Address(lock_reg, obj_offset)); + bind(slow_case); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); - b(done); - } else if (LockingMode == LM_LEGACY) { + // Call the runtime routine for slow case + call_VM_preemptable(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); - tst(tmp, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - - // Load (object->mark() | 1) into swap_reg - ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - orr(swap_reg, rscratch1, 1); - - // Save (object->mark() | 1) into BasicLock's displaced header - str(swap_reg, Address(lock_reg, mark_offset)); - - assert(lock_offset == 0, - "displached header must be first word in BasicObjectLock"); - - Label fail; - cmpxchg_obj_header(swap_reg, lock_reg, obj_reg, rscratch1, count, /*fallthrough*/nullptr); - - // Fast check for recursive lock. - // - // Can apply the optimization only if this is a stack lock - // allocated in this thread. For efficiency, we can focus on - // recently allocated stack locks (instead of reading the stack - // base and checking whether 'mark' points inside the current - // thread stack): - // 1) (mark & 7) == 0, and - // 2) sp <= mark < mark + os::pagesize() - // - // Warning: sp + os::pagesize can overflow the stack base. We must - // neither apply the optimization for an inflated lock allocated - // just above the thread stack (this is why condition 1 matters) - // nor apply the optimization if the stack lock is inside the stack - // of another thread. The latter is avoided even in case of overflow - // because we have guard pages at the end of all stacks. Hence, if - // we go over the stack base and hit the stack of another thread, - // this should not be in a writeable area that could contain a - // stack lock allocated by that thread. As a consequence, a stack - // lock less than page size away from sp is guaranteed to be - // owned by the current thread. - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - sp) & (7 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 3 bits clear. - // NOTE: the mark is in swap_reg %r0 as the result of cmpxchg - // NOTE2: aarch64 does not like to subtract sp from rn so take a - // copy - mov(rscratch1, sp); - sub(swap_reg, swap_reg, rscratch1); - ands(swap_reg, swap_reg, (uint64_t)(7 - (int)os::vm_page_size())); - - // Save the test result, for recursive case, the result is zero - str(swap_reg, Address(lock_reg, mark_offset)); - br(Assembler::NE, slow_case); - - bind(count); - inc_held_monitor_count(rscratch1); - b(done); - } - bind(slow_case); - - // Call the runtime routine for slow case - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - - bind(done); - } + bind(done); } @@ -807,57 +730,29 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Label count, done; + const Register swap_reg = r0; + const Register header_reg = c_rarg2; // Will contain the old oopMark + const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock - const Register swap_reg = r0; - const Register header_reg = c_rarg2; // Will contain the old oopMark - const Register obj_reg = c_rarg3; // Will contain the oop - const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock + save_bcp(); // Save in case of exception - save_bcp(); // Save in case of exception + // Load oop into obj_reg(%c_rarg3) + ldr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - if (LockingMode != LM_LIGHTWEIGHT) { - // Convert from BasicObjectLock structure to object and BasicLock - // structure Store the BasicLock address into %r0 - lea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset())); - } + // Free entry + str(zr, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load oop into obj_reg(%c_rarg3) - ldr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); + Label slow_case, done; + lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); + b(done); - // Free entry - str(zr, Address(lock_reg, BasicObjectLock::obj_offset())); - - Label slow_case; - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); - b(done); - } else if (LockingMode == LM_LEGACY) { - // Load the old header from BasicLock structure - ldr(header_reg, Address(swap_reg, - BasicLock::displaced_header_offset_in_bytes())); - - // Test for recursion - cbz(header_reg, count); - - // Atomic swap back the old header - cmpxchg_obj_header(swap_reg, header_reg, obj_reg, rscratch1, count, &slow_case); - - bind(count); - dec_held_monitor_count(rscratch1); - b(done); - } - - bind(slow_case); - // Call the runtime routine for slow case. - str(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - bind(done); - restore_bcp(); - } + bind(slow_case); + // Call the runtime routine for slow case. + str(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); // restore obj + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + bind(done); + restore_bcp(); } void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 6ae6861e38b..e51b3c530de 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -7097,7 +7097,6 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) { // - t1, t2, t3: temporary registers, will be destroyed // - slow: branched to if locking fails, absolute offset may larger than 32KB (imm14 encoding). void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(basic_lock, obj, t1, t2, t3, rscratch1); Label push; @@ -7157,7 +7156,6 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe // - t1, t2, t3: temporary registers // - slow: branched to if unlocking fails, absolute offset may larger than 32KB (imm14 encoding). void MacroAssembler::lightweight_unlock(Register obj, Register t1, Register t2, Register t3, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); // cmpxchg clobbers rscratch1. assert_different_registers(obj, t1, t2, t3, rscratch1); diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 00f97ed04e4..748c3e8fb11 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1721,7 +1721,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // We use the same pc/oopMap repeatedly when we call out. Label native_return; - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // For convenience we use the pc we want to resume to in case of preemption on Object.wait. __ set_last_Java_frame(sp, noreg, native_return, rscratch1); } else { @@ -1776,44 +1776,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ ldr(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_MONITOR) { - __ b(slow_path_lock); - } else if (LockingMode == LM_LEGACY) { - // Load (object->mark() | 1) into swap_reg %r0 - __ ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ orr(swap_reg, rscratch1, 1); - - // Save (object->mark() | 1) into BasicLock's displaced header - __ str(swap_reg, Address(lock_reg, mark_word_offset)); - - // src -> dest iff dest == r0 else r0 <- dest - __ cmpxchg_obj_header(r0, lock_reg, obj_reg, rscratch1, count, /*fallthrough*/nullptr); - - // Hmm should this move to the slow path code area??? - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) sp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - sp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg %r0 as the result of cmpxchg - - __ sub(swap_reg, sp, swap_reg); - __ neg(swap_reg, swap_reg); - __ ands(swap_reg, swap_reg, 3 - (int)os::vm_page_size()); - - // Save the test result, for recursive case, the result is zero - __ str(swap_reg, Address(lock_reg, mark_word_offset)); - __ br(Assembler::NE, slow_path_lock); - - __ bind(count); - __ inc_held_monitor_count(rscratch1); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); - } + __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); // Slow path will re-enter here __ bind(lock_done); @@ -1888,7 +1851,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // Check preemption for Object.wait() __ ldr(rscratch1, Address(rthread, JavaThread::preempt_alternate_return_offset())); __ cbz(rscratch1, native_return); @@ -1917,48 +1880,18 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Get locked oop from the handle we passed to jni __ ldr(obj_reg, Address(oop_handle_reg, 0)); - Label done, not_recursive; - - if (LockingMode == LM_LEGACY) { - // Simple recursive lock? - __ ldr(rscratch1, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - __ cbnz(rscratch1, not_recursive); - __ dec_held_monitor_count(rscratch1); - __ b(done); - } - - __ bind(not_recursive); - // Must save r0 if if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - if (LockingMode == LM_MONITOR) { - __ b(slow_path_unlock); - } else if (LockingMode == LM_LEGACY) { - // get address of the stack lock - __ lea(r0, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ ldr(old_hdr, Address(r0, 0)); - - // Atomic swap old header if oop still contains the stack lock - Label count; - __ cmpxchg_obj_header(r0, old_hdr, obj_reg, rscratch1, count, &slow_path_unlock); - __ bind(count); - __ dec_held_monitor_count(rscratch1); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, ""); - __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); - } + __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); // slow path re-enters here __ bind(unlock_done); if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { restore_native_result(masm, ret_type, stack_slots); } - - __ bind(done); } Label dtrace_method_exit, dtrace_method_exit_done; diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 6593406902f..c1eabed8ade 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1478,22 +1478,17 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); - if (LockingMode != LM_LEGACY) { - // Check preemption for Object.wait() - Label not_preempted; - __ ldr(rscratch1, Address(rthread, JavaThread::preempt_alternate_return_offset())); - __ cbz(rscratch1, not_preempted); - __ str(zr, Address(rthread, JavaThread::preempt_alternate_return_offset())); - __ br(rscratch1); - __ bind(native_return); - __ restore_after_resume(true /* is_native */); - // reload result_handler - __ ldr(result_handler, Address(rfp, frame::interpreter_frame_result_handler_offset*wordSize)); - __ bind(not_preempted); - } else { - // any pc will do so just use this one for LM_LEGACY to keep code together. - __ bind(native_return); - } + // Check preemption for Object.wait() + Label not_preempted; + __ ldr(rscratch1, Address(rthread, JavaThread::preempt_alternate_return_offset())); + __ cbz(rscratch1, not_preempted); + __ str(zr, Address(rthread, JavaThread::preempt_alternate_return_offset())); + __ br(rscratch1); + __ bind(native_return); + __ restore_after_resume(true /* is_native */); + // reload result_handler + __ ldr(result_handler, Address(rfp, frame::interpreter_frame_result_handler_offset*wordSize)); + __ bind(not_preempted); // reset_last_Java_frame __ reset_last_Java_frame(true); From 16e461ef31628ab47cd8484cdfc970c0008b97ba Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 12 Aug 2025 08:52:37 +0000 Subject: [PATCH 055/471] 8365122: G1: Minor clean up of G1SurvivorRegions Reviewed-by: sangheki, kbarrett --- src/hotspot/share/gc/g1/g1Policy.cpp | 16 +++++----------- src/hotspot/share/gc/g1/g1SurvivorRegions.cpp | 15 ++++++--------- src/hotspot/share/gc/g1/g1SurvivorRegions.hpp | 11 ++++++----- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 3bbc64e0fe7..bb54d344ca0 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -508,12 +508,9 @@ uint G1Policy::calculate_desired_eden_length_before_mixed(double base_time_ms, } double G1Policy::predict_survivor_regions_evac_time() const { - const GrowableArray* survivor_regions = _g1h->survivor()->regions(); double survivor_regions_evac_time = predict_young_region_other_time_ms(_g1h->survivor()->length()); - for (GrowableArrayIterator it = survivor_regions->begin(); - it != survivor_regions->end(); - ++it) { - survivor_regions_evac_time += predict_region_copy_time_ms(*it, _g1h->collector_state()->in_young_only_phase()); + for (G1HeapRegion* r : _g1h->survivor()->regions()) { + survivor_regions_evac_time += predict_region_copy_time_ms(r, _g1h->collector_state()->in_young_only_phase()); } return survivor_regions_evac_time; @@ -1461,16 +1458,13 @@ uint G1Policy::calc_max_old_cset_length() const { void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { start_adding_survivor_regions(); - for (GrowableArrayIterator it = survivors->regions()->begin(); - it != survivors->regions()->end(); - ++it) { - G1HeapRegion* curr = *it; - set_region_survivor(curr); + for (G1HeapRegion* r : survivors->regions()) { + set_region_survivor(r); // The region is a non-empty survivor so let's add it to // the incremental collection set for the next evacuation // pause. - _collection_set->add_survivor_regions(curr); + _collection_set->add_survivor_regions(r); } stop_adding_survivor_regions(); diff --git a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp index edd4f35d5ed..4aa752e5823 100644 --- a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp +++ b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp @@ -28,18 +28,18 @@ #include "utilities/growableArray.hpp" G1SurvivorRegions::G1SurvivorRegions() : - _regions(new (mtGC) GrowableArray(8, mtGC)), + _regions(8, mtGC), _used_bytes(0), _regions_on_node() {} uint G1SurvivorRegions::add(G1HeapRegion* hr) { assert(hr->is_survivor(), "should be flagged as survivor region"); - _regions->append(hr); + _regions.append(hr); return _regions_on_node.add(hr); } uint G1SurvivorRegions::length() const { - return (uint)_regions->length(); + return (uint)_regions.length(); } uint G1SurvivorRegions::regions_on_node(uint node_index) const { @@ -47,17 +47,14 @@ uint G1SurvivorRegions::regions_on_node(uint node_index) const { } void G1SurvivorRegions::convert_to_eden() { - for (GrowableArrayIterator it = _regions->begin(); - it != _regions->end(); - ++it) { - G1HeapRegion* hr = *it; - hr->set_eden_pre_gc(); + for (G1HeapRegion* r : _regions) { + r->set_eden_pre_gc(); } clear(); } void G1SurvivorRegions::clear() { - _regions->clear(); + _regions.clear(); _used_bytes = 0; _regions_on_node.clear(); } diff --git a/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp b/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp index cc6bbc44fa8..0532ee12162 100644 --- a/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp +++ b/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp @@ -27,16 +27,17 @@ #include "gc/g1/g1RegionsOnNodes.hpp" #include "runtime/globals.hpp" +#include "utilities/growableArray.hpp" template class GrowableArray; class G1HeapRegion; +// Set of current survivor regions. class G1SurvivorRegions { -private: - GrowableArray* _regions; - volatile size_t _used_bytes; - G1RegionsOnNodes _regions_on_node; + GrowableArray _regions; + volatile size_t _used_bytes; + G1RegionsOnNodes _regions_on_node; public: G1SurvivorRegions(); @@ -50,7 +51,7 @@ public: uint length() const; uint regions_on_node(uint node_index) const; - const GrowableArray* regions() const { + const GrowableArray& regions() const { return _regions; } From 95b7a8b3e300bf40a2a5bdf8ca8310485db363e6 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 12 Aug 2025 11:29:43 +0000 Subject: [PATCH 056/471] 8365237: Remove unused SoftRefPolicy::_all_soft_refs_clear Reviewed-by: tschatzl, kbarrett --- .../share/gc/shared/gcVMOperations.cpp | 5 ----- .../share/gc/shared/gcVMOperations.hpp | 9 -------- src/hotspot/share/gc/shared/softRefPolicy.hpp | 21 +------------------ 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 19a81504722..1299f64995f 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -62,11 +62,6 @@ void VM_Verify::doit() { Universe::verify(); } -VM_GC_Operation::~VM_GC_Operation() { - CollectedHeap* ch = Universe::heap(); - ch->soft_ref_policy()->set_all_soft_refs_clear(false); -} - const char* VM_GC_Operation::cause() const { return GCCause::to_string(_gc_cause); } diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp index 6752e0bc32d..0121a468b56 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -126,16 +126,7 @@ class VM_GC_Operation: public VM_Heap_Sync_Operation { _gc_cause = _cause; _full_gc_count_before = full_gc_count_before; - // In ParallelScavengeHeap::mem_allocate() collections can be - // executed within a loop and _all_soft_refs_clear can be set - // true after they have been cleared by a collection and another - // collection started so that _all_soft_refs_clear can be true - // when this collection is started. Don't assert that - // _all_soft_refs_clear have to be false here even though - // mutators have run. Soft refs will be cleared again in this - // collection. } - ~VM_GC_Operation(); virtual const char* cause() const; diff --git a/src/hotspot/share/gc/shared/softRefPolicy.hpp b/src/hotspot/share/gc/shared/softRefPolicy.hpp index fe2706288f7..1e8ec356c40 100644 --- a/src/hotspot/share/gc/shared/softRefPolicy.hpp +++ b/src/hotspot/share/gc/shared/softRefPolicy.hpp @@ -25,37 +25,18 @@ #ifndef SHARE_GC_SHARED_SOFTREFPOLICY_HPP #define SHARE_GC_SHARED_SOFTREFPOLICY_HPP -#include "memory/allocation.hpp" - class SoftRefPolicy { private: // Set to true when policy wants soft refs cleared. // Reset to false by gc after it clears all soft refs. bool _should_clear_all_soft_refs; - // Set to true by the GC if the just-completed gc cleared all - // softrefs. This is set to true whenever a gc clears all softrefs, and - // set to false each time gc returns to the mutator. For example, in the - // ParallelScavengeHeap case the latter would be done toward the end of - // mem_allocate() where it returns op.result() - bool _all_soft_refs_clear; - public: SoftRefPolicy() : - _should_clear_all_soft_refs(false), - _all_soft_refs_clear(false) {} + _should_clear_all_soft_refs(false) {} bool should_clear_all_soft_refs() { return _should_clear_all_soft_refs; } void set_should_clear_all_soft_refs(bool v) { _should_clear_all_soft_refs = v; } - - bool all_soft_refs_clear() { return _all_soft_refs_clear; } - void set_all_soft_refs_clear(bool v) { _all_soft_refs_clear = v; } - - // Called by the GC after Soft Refs have been cleared to indicate - // that the request in _should_clear_all_soft_refs has been fulfilled. - void cleared_all_soft_refs() { - _all_soft_refs_clear = true; - } }; #endif // SHARE_GC_SHARED_SOFTREFPOLICY_HPP From 19a76a45e9c8616414830c865801660bc6761e92 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 12 Aug 2025 11:58:37 +0000 Subject: [PATCH 057/471] 8365316: Remove unnecessary default arg value in gcVMOperations Reviewed-by: tschatzl --- src/hotspot/share/gc/shared/gcVMOperations.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp index 0121a468b56..5048bc3c1ed 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -117,8 +117,8 @@ class VM_GC_Operation: public VM_Heap_Sync_Operation { public: VM_GC_Operation(uint gc_count_before, GCCause::Cause _cause, - uint full_gc_count_before = 0, - bool full = false) : VM_Heap_Sync_Operation() { + uint full_gc_count_before, + bool full) : VM_Heap_Sync_Operation() { _full = full; _prologue_succeeded = false; _gc_count_before = gc_count_before; @@ -147,8 +147,8 @@ class VM_GC_Service_Operation : public VM_GC_Operation { public: VM_GC_Service_Operation(uint gc_count_before, GCCause::Cause _cause, - uint full_gc_count_before = 0, - bool full = false) : + uint full_gc_count_before, + bool full) : VM_GC_Operation(gc_count_before, _cause, full_gc_count_before, full) {} }; From 391ea151184c5621f263742605416c3ccd2c3d73 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 12 Aug 2025 13:16:54 +0000 Subject: [PATCH 058/471] 8365307: AIX make fails after JDK-8364611 Reviewed-by: clanger, asteiner --- .../childSignalDisposition/exePrintSignalDisposition.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c index 5a96c2556fc..8235cdc7410 100644 --- a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c @@ -72,7 +72,11 @@ int main(int argc, char** argv) { } else { printf("%p ", handler); } +#ifdef _AIX + printf("%X\n", act.sa_flags); +#else printf("%X %X\n", act.sa_flags, act.sa_mask); +#endif } return 0; From a382996bb496d50b4eb5a6be9f61e5c2f8aaae2d Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 12 Aug 2025 13:42:53 +0000 Subject: [PATCH 059/471] 8364993: JFR: Disable jdk.ModuleExport in default.jfc Reviewed-by: mgronlun --- src/jdk.jfr/share/conf/jfr/default.jfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 20051864895..463639d7f1e 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -762,7 +762,7 @@ - true + false endChunk From ad0fd13f2007c93d8a109626a627823f30e4c8d7 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 12 Aug 2025 16:20:00 +0000 Subject: [PATCH 060/471] 8364454: ProblemList runtime/cds/DeterministicDump.java on macos for JDK-8363986 Reviewed-by: ccheung --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 7026b6f79d6..37986c67dd8 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -97,6 +97,7 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all # :hotspot_runtime +runtime/cds/DeterministicDump.java 8363986 macosx-x64,macosx-aarch64 runtime/jni/terminatedThread/TestTerminatedThread.java 8317789 aix-ppc64 runtime/Monitor/SyncOnValueBasedClassTest.java 8340995 linux-s390x runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 From 4c03e5938df0a9cb10c2379af81163795dd3a086 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 12 Aug 2025 16:30:09 +0000 Subject: [PATCH 061/471] 8364750: Remove unused declaration in jvm.h Reviewed-by: shade --- src/hotspot/share/include/jvm.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index f97374553ca..4d39537e5a1 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -599,16 +599,6 @@ JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly); JNIEXPORT jobjectArray JNICALL JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly); - -/* Differs from JVM_GetClassModifiers in treatment of inner classes. - This returns the access flags for the class as specified in the - class file rather than searching the InnerClasses attribute (if - present) to find the source-level access flags. Only the values of - the low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be - valid. */ -JNIEXPORT jint JNICALL -JVM_GetClassAccessFlags(JNIEnv *env, jclass cls); - /* Nestmates - since JDK 11 */ JNIEXPORT jboolean JNICALL From d023982600f8bb19053f579710953aa29e0f30c5 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 12 Aug 2025 17:39:14 +0000 Subject: [PATCH 062/471] 8361209: (bf) Use CharSequence::getChars for StringCharBuffer bulk get methods Reviewed-by: rriggs, alanb --- .../classes/java/nio/StringCharBuffer.java | 10 ++- .../classes/java/nio/X-Buffer.java.template | 29 ++++++-- .../nio/StringCharBufferBulkTransfer.java | 72 +++++++++++++++++++ 3 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/nio/StringCharBufferBulkTransfer.java diff --git a/src/java.base/share/classes/java/nio/StringCharBuffer.java b/src/java.base/share/classes/java/nio/StringCharBuffer.java index a62e8023363..39cd6910f5d 100644 --- a/src/java.base/share/classes/java/nio/StringCharBuffer.java +++ b/src/java.base/share/classes/java/nio/StringCharBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -97,7 +97,13 @@ final class StringCharBuffer // package-private return str.charAt(index + offset); } - // ## Override bulk get methods for better performance + @Override + CharBuffer getArray(int index, char[] dst, int dstOffset, int length) { + // Note: the variable "offset" is defined and set in the superclass + int srcOffset = offset + index; + str.getChars(srcOffset, srcOffset + length, dst, dstOffset); + return this; + } public final CharBuffer put(char c) { throw new ReadOnlyBufferException(); diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template index c43004cc0ac..b2b96288d57 100644 --- a/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -950,12 +950,15 @@ public abstract sealed class $Type$Buffer return get(index, dst, 0, dst.length); } - private $Type$Buffer getArray(int index, $type$[] dst, int offset, int length) { - if ( + // + // This method does not perform bounds checking which it expects + // will have been done by the caller + // + $Type$Buffer getArray(int index, $type$[] dst, int offset, int length) { #if[char] - isAddressable() && + assert isAddressable(); #end[char] - ((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { + if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { long bufAddr = address + ((long)index << $LG_BYTES_PER_VALUE$); long dstOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$); @@ -1116,6 +1119,10 @@ public abstract sealed class $Type$Buffer return this; } + // + // This method does not perform bounds checking which it expects + // will have been done by the caller + // void putBuffer(int pos, $Type$Buffer src, int srcPos, int n) { #if[rw] Object srcBase = src.base(); @@ -1150,9 +1157,13 @@ public abstract sealed class $Type$Buffer #if[char] } else { // src.isAddressable() == false assert StringCharBuffer.class.isInstance(src); - int posMax = pos + n; - for (int i = pos, j = srcPos; i < posMax; i++, j++) - put(i, src.get(j)); + if (this.hb != null && src instanceof StringCharBuffer scb) { + scb.getArray(srcPos, this.hb, pos, n); + } else { + int posMax = pos + n; + for (int i = pos, j = srcPos; i < posMax; i++, j++) + put(i, src.get(j)); + } } #end[char] #else[rw] @@ -1342,6 +1353,10 @@ public abstract sealed class $Type$Buffer return put(index, src, 0, src.length); } + // + // This method does not perform bounds checking which it expects + // will have been done by the caller + // $Type$Buffer putArray(int index, $type$[] src, int offset, int length) { #if[rw] if ( diff --git a/test/micro/org/openjdk/bench/java/nio/StringCharBufferBulkTransfer.java b/test/micro/org/openjdk/bench/java/nio/StringCharBufferBulkTransfer.java new file mode 100644 index 00000000000..246116e4d43 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/nio/StringCharBufferBulkTransfer.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.nio; + +import java.nio.CharBuffer; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/** + * Benchmark for bulk get methods of a {@code CharBuffer} created from a + * {@code CharSequence}. + */ + +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(1) +public class StringCharBufferBulkTransfer { + private static final int LENGTH = 16384; + + char[] buf = new char[LENGTH]; + CharBuffer cb = CharBuffer.wrap(new String(buf)); + char[] dst = new char[LENGTH]; + CharBuffer cbw = CharBuffer.allocate(LENGTH); + + @Benchmark + public void absoluteBulkGet() { + cb.get(0, dst, 0, dst.length); + } + + @Benchmark + public void relativeBulkGet() { + cb.get(dst, 0, dst.length); + cb.position(0); + } + + @Benchmark + public void getChars() { + cb.getChars(0, LENGTH, dst, 0); + } + + @Benchmark + public void absoluteBulkPut() { + cbw.put(0, cb, 0, dst.length); + } +} From 87d734012e3130501bfd37b23cee7f5e0a3a476f Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 12 Aug 2025 17:44:34 +0000 Subject: [PATCH 063/471] 8364756: JFR: Improve slow tests Reviewed-by: mgronlun --- .../api/consumer/streaming/TestFilledChunks.java | 2 ++ .../consumer/streaming/TestStartMultiChunk.java | 4 ++-- .../event/runtime/StressJavaMonitorEvents.java | 2 +- test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java | 6 ++++-- .../jdk/jfr/jmx/streaming/TestRemoteDump.java | 16 ++++++++++------ test/jdk/jdk/jfr/jvm/TestWaste.java | 2 +- .../TestMultipleStartupRecordings.java | 8 -------- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestFilledChunks.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestFilledChunks.java index 423e3969af8..f435fe9747f 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestFilledChunks.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestFilledChunks.java @@ -26,6 +26,7 @@ package jdk.jfr.api.consumer.streaming; import java.util.Random; import jdk.jfr.Event; +import jdk.jfr.StackTrace; import jdk.jfr.consumer.RecordingStream; /** @@ -38,6 +39,7 @@ import jdk.jfr.consumer.RecordingStream; */ public class TestFilledChunks { + @StackTrace(false) static class FillEvent extends Event { String message; int value; diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestStartMultiChunk.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestStartMultiChunk.java index fbc27b051b0..71113631521 100644 --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestStartMultiChunk.java +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestStartMultiChunk.java @@ -44,7 +44,7 @@ import jdk.jfr.consumer.RecordingStream; */ public class TestStartMultiChunk { - @Period("10 s") + @Period("2 s") @Name("Zebra") static class ZebraEvent extends Event { } @@ -65,7 +65,7 @@ public class TestStartMultiChunk { CountDownLatch dogLatch = new CountDownLatch(1); CountDownLatch catLatch = new CountDownLatch(1); CountDownLatch mouseLatch = new CountDownLatch(1); - CountDownLatch zebraLatch = new CountDownLatch(3); + CountDownLatch zebraLatch = new CountDownLatch(2); FlightRecorder.addPeriodicEvent(ZebraEvent.class, () -> { ZebraEvent ze = new ZebraEvent(); diff --git a/test/jdk/jdk/jfr/event/runtime/StressJavaMonitorEvents.java b/test/jdk/jdk/jfr/event/runtime/StressJavaMonitorEvents.java index ed3b5454163..fa9bb0c18a2 100644 --- a/test/jdk/jdk/jfr/event/runtime/StressJavaMonitorEvents.java +++ b/test/jdk/jdk/jfr/event/runtime/StressJavaMonitorEvents.java @@ -52,7 +52,7 @@ import jdk.test.lib.thread.XRun; */ public class StressJavaMonitorEvents { - static final int RUN_TIME_MS = 10000; + static final int RUN_TIME_MS = 5000; static final int GC_EVERY_MS = 500; static final int THREADS = 4; static final int NUM_LOCKS = 1024; diff --git a/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java b/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java index b79fbc2bcf0..5f490594370 100644 --- a/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java +++ b/test/jdk/jdk/jfr/jmx/streaming/TestMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.management.MBeanServerConnection; import jdk.jfr.Event; +import jdk.jfr.StackTrace; import jdk.management.jfr.RemoteRecordingStream; /** @@ -45,6 +46,7 @@ import jdk.management.jfr.RemoteRecordingStream; */ public class TestMaxSize { + @StackTrace(false) static class Monkey extends Event { } @@ -92,7 +94,7 @@ public class TestMaxSize { m.commit(); } System.out.println("Emitted " + count + " events"); - Thread.sleep(1000); + Thread.sleep(100); } private static int fileCount(Path dir) throws IOException { diff --git a/test/jdk/jdk/jfr/jmx/streaming/TestRemoteDump.java b/test/jdk/jdk/jfr/jmx/streaming/TestRemoteDump.java index 9390857c09e..6731f3c44cf 100644 --- a/test/jdk/jdk/jfr/jmx/streaming/TestRemoteDump.java +++ b/test/jdk/jdk/jfr/jmx/streaming/TestRemoteDump.java @@ -97,7 +97,7 @@ public class TestRemoteDump { } } - private static List recordWithPolicy(String filename, Consumer policy) throws Exception { + private static List recordWithPolicy(String filename, boolean awaitEvents, Consumer policy) throws Exception { CountDownLatch latch1 = new CountDownLatch(1); CountDownLatch latch2 = new CountDownLatch(2); CountDownLatch latch3 = new CountDownLatch(3); @@ -111,14 +111,18 @@ public class TestRemoteDump { rs.startAsync(); DumpEvent e1 = new DumpEvent(); e1.commit(); - latch1.await(); + if (awaitEvents) { + latch1.await(); + } // Force chunk rotation try (Recording r = new Recording()) { r.start(); DumpEvent e2 = new DumpEvent(); e2.commit(); } - latch2.await(); + if (awaitEvents) { + latch2.await(); + } DumpEvent e3 = new DumpEvent(); e3.commit(); latch3.await(); @@ -129,7 +133,7 @@ public class TestRemoteDump { } private static void testSetMaxSize() throws Exception { - var events = recordWithPolicy("max-size.jfr", rs -> { + var events = recordWithPolicy("max-size.jfr", false, rs -> { // keeps all events for the dump rs.setMaxSize(100_000_000); }); @@ -140,7 +144,7 @@ public class TestRemoteDump { } private static void testSetMaxAge() throws Exception { - var events = recordWithPolicy("max-age.jfr", rs -> { + var events = recordWithPolicy("max-age.jfr", false, rs -> { // keeps all events for the dump rs.setMaxAge(Duration.ofDays(1)); }); @@ -151,7 +155,7 @@ public class TestRemoteDump { } private static void testSetNoPolicy() throws Exception { - var events = recordWithPolicy("no-policy.jfr", rs -> { + var events = recordWithPolicy("no-policy.jfr", true, rs -> { // use default policy, remove after consumption }); // Since latch3 have been triggered at least two events/chunks diff --git a/test/jdk/jdk/jfr/jvm/TestWaste.java b/test/jdk/jdk/jfr/jvm/TestWaste.java index c755ca4c3d0..4de14fc2461 100644 --- a/test/jdk/jdk/jfr/jvm/TestWaste.java +++ b/test/jdk/jdk/jfr/jvm/TestWaste.java @@ -61,7 +61,7 @@ public class TestWaste { try (Recording r = new Recording(c)) { // Old objects that are cleared out should not create waste r.enable("jdk.OldObjectSample") - .with("cutoff", "infinity") + .with("cutoff", "2 s") .withStackTrace(); // No stack trace waste from allocation sample r.enable("jdk.ObjectAllocationSample") diff --git a/test/jdk/jdk/jfr/startupargs/TestMultipleStartupRecordings.java b/test/jdk/jdk/jfr/startupargs/TestMultipleStartupRecordings.java index c70f9810568..bfa02fd8a74 100644 --- a/test/jdk/jdk/jfr/startupargs/TestMultipleStartupRecordings.java +++ b/test/jdk/jdk/jfr/startupargs/TestMultipleStartupRecordings.java @@ -74,13 +74,6 @@ public class TestMultipleStartupRecordings { test(pb, "Started recording 1", "Started recording 2", "Started recording 3"); } - private static void testDefault() throws Exception { - System.out.println("testDefault"); - launchUnary(null); - launchBinary(null, null); - launchTernary(null, null, null); - } - private static void testColonDelimited() throws Exception { launchBinary(":name=myrecording1,filename=myrecording1.jfr", ":filename=myrecording2.jfr,name=myrecording2"); } @@ -99,7 +92,6 @@ public class TestMultipleStartupRecordings { } public static void main(String[] args) throws Exception { - testDefault(); testColonDelimited(); testMixed(); testWithFlightRecorderOptions(); From 636c61a3868d9c01b672b3b45cda1e476acdc045 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 13 Aug 2025 01:24:39 +0000 Subject: [PATCH 064/471] 8365302: RISC-V: compiler/loopopts/superword/TestAlignVector.java fails when vlen=128 Reviewed-by: fyang, fjiang --- .../loopopts/superword/TestAlignVector.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java index 97a3c4ed037..322c36c39e1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -1063,8 +1063,16 @@ public class TestAlignVector { IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx2", "true", "rvv", "true"}) + applyIfCPUFeature = {"avx2", "true"}) // require avx to ensure vectors are larger than what unrolling produces + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + applyIf = {"MaxVectorSize", ">=32"}) static Object[] test13aIL(int[] a, long[] b) { for (int i = 0; i < RANGE; i++) { a[i]++; @@ -1175,8 +1183,16 @@ public class TestAlignVector { IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", IRNode.STORE_VECTOR, "> 0"}, applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx2", "true", "rvv", "true"}) + applyIfCPUFeature = {"avx2", "true"}) // require avx to ensure vectors are larger than what unrolling produces + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VL, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + applyIf = {"MaxVectorSize", ">=32"}) static Object[] test13bIL(int[] a, long[] b) { for (int i = 1; i < RANGE; i++) { a[i]++; From 25480f0011297ad209eca1b1b56bcf983ea4ee5d Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 13 Aug 2025 01:45:49 +0000 Subject: [PATCH 065/471] 8365184: sun/tools/jhsdb/HeapDumpTestWithActiveProcess.java Re-enable SerialGC flag on debuggee process Reviewed-by: lmesnik, cjplummer, sspitsyn --- test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java b/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java index 9e9a6c79c7b..6fbc96362a9 100644 --- a/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java +++ b/test/jdk/sun/tools/jhsdb/JShellHeapDumpTest.java @@ -162,12 +162,7 @@ public class JShellHeapDumpTest { long startTime = System.currentTimeMillis(); try { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jshell"); - if (doSleep) { - launcher.addVMArgs(Utils.getTestJavaOpts()); - } else { - // Don't allow use of SerialGC. See JDK-8313655. - launcher.addVMArgs(Utils.getFilteredTestJavaOpts("-XX:\\+UseSerialGC")); - } + launcher.addVMArgs(Utils.getTestJavaOpts()); ProcessBuilder pb = new ProcessBuilder(launcher.getCommand()); // Needed so we can properly parse the "Welcome to JShell" output. pb.command().add("-J-Duser.language=en"); From 72e22b4de59a18f83c75be9a51fd99726f77f6f6 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 13 Aug 2025 08:07:45 +0000 Subject: [PATCH 066/471] 8362885: A more formal way to mark javac's Flags that belong to a specific Symbol type only Reviewed-by: ihse, liach, vromero, mcimadamore, erikj --- make/ToolsLangtools.gmk | 2 +- .../tools/flagsgenerator/FlagsGenerator.java | 161 +++++++++++ .../propertiesparser/parser/MessageType.java | 4 +- make/modules/jdk.compiler/Gensrc.gmk | 33 ++- .../com/sun/tools/javac/code/Flags.java | 269 ++++++++++-------- .../com/sun/tools/javac/comp/Modules.java | 4 +- .../javac/diags/ArgTypeCompilerFactory.java | 4 +- .../tools/javac/flags/FlagsTest.java | 85 +++++- 8 files changed, 422 insertions(+), 140 deletions(-) create mode 100644 make/langtools/tools/flagsgenerator/FlagsGenerator.java diff --git a/make/ToolsLangtools.gmk b/make/ToolsLangtools.gmk index 4146652bf8b..1a764d6019b 100644 --- a/make/ToolsLangtools.gmk +++ b/make/ToolsLangtools.gmk @@ -36,7 +36,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TOOLS_LANGTOOLS, \ COMPILER := bootjdk, \ TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \ SRC := $(TOPDIR)/make/langtools/tools, \ - INCLUDES := compileproperties propertiesparser, \ + INCLUDES := compileproperties flagsgenerator propertiesparser, \ COPY := .properties, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes, \ )) diff --git a/make/langtools/tools/flagsgenerator/FlagsGenerator.java b/make/langtools/tools/flagsgenerator/FlagsGenerator.java new file mode 100644 index 00000000000..1c192d214de --- /dev/null +++ b/make/langtools/tools/flagsgenerator/FlagsGenerator.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package flagsgenerator; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.ElementFilter; +import javax.tools.ToolProvider; + +public class FlagsGenerator { + public static void main(String... args) throws IOException { + var compiler = ToolProvider.getSystemJavaCompiler(); + + try (var fm = compiler.getStandardFileManager(null, null, null)) { + JavacTask task = (JavacTask) compiler.getTask(null, null, d -> {}, null, null, fm.getJavaFileObjects(args[0])); + Trees trees = Trees.instance(task); + CompilationUnitTree cut = task.parse().iterator().next(); + + task.analyze(); + + TypeElement clazz = (TypeElement) trees.getElement(new TreePath(new TreePath(cut), cut.getTypeDecls().get(0))); + Map> flag2Names = new TreeMap<>(); + Map>> target2FlagBit2Fields = new EnumMap<>(FlagTarget.class); + Map customToString = new HashMap<>(); + Set noToString = new HashSet<>(); + + for (VariableElement field : ElementFilter.fieldsIn(clazz.getEnclosedElements())) { + String flagName = field.getSimpleName().toString(); + for (AnnotationMirror am : field.getAnnotationMirrors()) { + switch (am.getAnnotationType().toString()) { + case "com.sun.tools.javac.code.Flags.Use" -> { + long flagValue = ((Number) field.getConstantValue()).longValue(); + int flagBit = 63 - Long.numberOfLeadingZeros(flagValue); + + flag2Names.computeIfAbsent(flagBit, _ -> new ArrayList<>()) + .add(flagName); + + List originalTargets = (List) valueOfValueAttribute(am); + originalTargets.stream() + .map(value -> FlagTarget.valueOf(value.toString())) + .forEach(target -> target2FlagBit2Fields.computeIfAbsent(target, _ -> new HashMap<>()) + .computeIfAbsent(flagBit, _ -> new ArrayList<>()) + .add(flagName)); + } + case "com.sun.tools.javac.code.Flags.CustomToStringValue" -> { + customToString.put(flagName, (String) valueOfValueAttribute(am)); + } + case "com.sun.tools.javac.code.Flags.NoToStringValue" -> { + noToString.add(flagName); + } + } + } + } + + //verify there are no flag overlaps: + for (Entry>> targetAndFlag : target2FlagBit2Fields.entrySet()) { + for (Entry> flagAndFields : targetAndFlag.getValue().entrySet()) { + if (flagAndFields.getValue().size() > 1) { + throw new AssertionError("duplicate flag for target: " + targetAndFlag.getKey() + + ", flag: " + flagAndFields.getKey() + + ", flags fields: " + flagAndFields.getValue()); + } + } + } + + try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(Paths.get(args[1])))) { + out.println(""" + package com.sun.tools.javac.code; + + public enum FlagsEnum { + """); + for (Entry> e : flag2Names.entrySet()) { + String constantName = e.getValue().stream().collect(Collectors.joining("_OR_")); + String toString = e.getValue() + .stream() + .filter(n -> !noToString.contains(n)) + .map(n -> customToString.getOrDefault(n, n.toLowerCase(Locale.US))) + .collect(Collectors.joining(" or ")); + out.println(" " + constantName + "(1L<<" + e.getKey() + ", \"" + toString + "\"),"); + } + out.println(""" + ; + + private final long value; + private final String toString; + private FlagsEnum(long value, String toString) { + this.value = value; + this.toString = toString; + } + public long value() { + return value; + } + public String toString() { + return toString; + } + } + """); + } + } + } + + private static Object valueOfValueAttribute(AnnotationMirror am) { + return am.getElementValues() + .values() + .iterator() + .next() + .getValue(); + } + + private enum FlagTarget { + BLOCK, + CLASS, + METHOD, + MODULE, + PACKAGE, + TYPE_VAR, + VARIABLE; + } +} diff --git a/make/langtools/tools/propertiesparser/parser/MessageType.java b/make/langtools/tools/propertiesparser/parser/MessageType.java index ea518dc536b..a4ea0ddc3c0 100644 --- a/make/langtools/tools/propertiesparser/parser/MessageType.java +++ b/make/langtools/tools/propertiesparser/parser/MessageType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -76,7 +76,7 @@ public interface MessageType { ANNOTATION("annotation", "Compound", "com.sun.tools.javac.code.Attribute"), BOOLEAN("boolean", "boolean", null), COLLECTION("collection", "Collection", "java.util"), - FLAG("flag", "Flag", "com.sun.tools.javac.code.Flags"), + FLAG("flag", "FlagsEnum", "com.sun.tools.javac.code"), FRAGMENT("fragment", "Fragment", null), DIAGNOSTIC("diagnostic", "JCDiagnostic", "com.sun.tools.javac.util"), MODIFIER("modifier", "Modifier", "javax.lang.model.element"), diff --git a/make/modules/jdk.compiler/Gensrc.gmk b/make/modules/jdk.compiler/Gensrc.gmk index c6c5879745c..501ea37ae8b 100644 --- a/make/modules/jdk.compiler/Gensrc.gmk +++ b/make/modules/jdk.compiler/Gensrc.gmk @@ -41,17 +41,17 @@ $(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \ TARGETS += $(COMPILE_PROPERTIES) -################################################################################ -# -# Compile properties files into enum-like classes using the propertiesparser tool -# - # To avoid reevaluating the compilation setup for the tools each time this file # is included, the following trick is used to be able to declare a dependency on # the built tools. BUILD_TOOLS_LANGTOOLS := $(call SetupJavaCompilationCompileTarget, \ BUILD_TOOLS_LANGTOOLS, $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes) +################################################################################ +# +# Compile properties files into enum-like classes using the propertiesparser tool +# + TOOL_PARSEPROPERTIES_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \ propertiesparser.PropertiesParser @@ -76,3 +76,26 @@ $(eval $(call SetupExecute, PARSEPROPERTIES, \ TARGETS += $(PARSEPROPERTIES) ################################################################################ +# +# Generate FlagsEnum from Flags constants +# + +TOOL_FLAGSGENERATOR_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_tools_classes \ + flagsgenerator.FlagsGenerator + +FLAGS_SRC := \ + $(MODULE_SRC)/share/classes/com/sun/tools/javac/code/Flags.java + +FLAGS_OUT := \ + $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/com/sun/tools/javac/code/FlagsEnum.java + +$(eval $(call SetupExecute, FLAGSGENERATOR, \ + WARN := Generating FlagsEnum, \ + DEPS := $(FLAGS_SRC) $(BUILD_TOOLS_LANGTOOLS), \ + OUTPUT_FILE := $(FLAGS_OUT), \ + COMMAND := $(TOOL_FLAGSGENERATOR_CMD) $(FLAGS_SRC) $(FLAGS_OUT), \ +)) + +TARGETS += $(FLAGSGENERATOR) + +################################################################################ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java index 26f0d338a2e..5b59e47027e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java @@ -25,6 +25,8 @@ package com.sun.tools.javac.code; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.EnumSet; import java.util.Map; @@ -35,7 +37,6 @@ import java.util.stream.Collectors; import javax.lang.model.element.Modifier; import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.StringUtils; /** Access flags and other modifiers for Java classes and members. * @@ -51,7 +52,7 @@ public class Flags { public static String toString(long flags) { StringBuilder buf = new StringBuilder(); String sep = ""; - for (Flag flag : asFlagSet(flags)) { + for (FlagsEnum flag : asFlagSet(flags)) { buf.append(sep); buf.append(flag); sep = " "; @@ -59,12 +60,12 @@ public class Flags { return buf.toString(); } - public static EnumSet asFlagSet(long flags) { - EnumSet flagSet = EnumSet.noneOf(Flag.class); - for (Flag flag : Flag.values()) { - if ((flags & flag.value) != 0) { + public static EnumSet asFlagSet(long flags) { + EnumSet flagSet = EnumSet.noneOf(FlagsEnum.class); + for (FlagsEnum flag : FlagsEnum.values()) { + if ((flags & flag.value()) != 0) { flagSet.add(flag); - flags &= ~flag.value; + flags &= ~flag.value(); } } Assert.check(flags == 0); @@ -73,42 +74,67 @@ public class Flags { /* Standard Java flags. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int PUBLIC = 1; + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int PRIVATE = 1<<1; + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int PROTECTED = 1<<2; + @Use({FlagTarget.BLOCK, FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int STATIC = 1<<3; + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int FINAL = 1<<4; + @Use({FlagTarget.METHOD}) public static final int SYNCHRONIZED = 1<<5; + @Use({FlagTarget.VARIABLE}) public static final int VOLATILE = 1<<6; + @Use({FlagTarget.VARIABLE}) public static final int TRANSIENT = 1<<7; + @Use({FlagTarget.METHOD}) public static final int NATIVE = 1<<8; + @Use({FlagTarget.CLASS}) public static final int INTERFACE = 1<<9; + @Use({FlagTarget.CLASS, FlagTarget.METHOD}) public static final int ABSTRACT = 1<<10; + @Use({FlagTarget.CLASS, FlagTarget.METHOD}) public static final int STRICTFP = 1<<11; /* Flag that marks a symbol synthetic, added in classfile v49.0. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final int SYNTHETIC = 1<<12; /** Flag that marks attribute interfaces, added in classfile v49.0. */ + @Use({FlagTarget.CLASS}) public static final int ANNOTATION = 1<<13; /** An enumeration type or an enumeration constant, added in * classfile v49.0. */ + @Use({FlagTarget.CLASS, FlagTarget.VARIABLE}) public static final int ENUM = 1<<14; /** Added in SE8, represents constructs implicitly declared in source. */ + @Use({FlagTarget.MODULE, FlagTarget.VARIABLE}) public static final int MANDATED = 1<<15; + @NotFlag public static final int StandardFlags = 0x0fff; // Because the following access flags are overloaded with other // bit positions, we translate them when reading and writing class // files into unique bits positions: ACC_SYNTHETIC <-> SYNTHETIC, // for example. - public static final int ACC_SUPER = 0x0020; - public static final int ACC_BRIDGE = 0x0040; - public static final int ACC_VARARGS = 0x0080; - public static final int ACC_MODULE = 0x8000; + @Use({FlagTarget.CLASS}) + @NoToStringValue + public static final int ACC_SUPER = 1<<5; + @Use({FlagTarget.METHOD}) + @NoToStringValue + public static final int ACC_BRIDGE = 1<<6; + @Use({FlagTarget.METHOD}) + @NoToStringValue + public static final int ACC_VARARGS = 1<<7; + @Use({FlagTarget.CLASS}) + @NoToStringValue + public static final int ACC_MODULE = 1<<15; /* *************************************** * Internal compiler flags (no bits in the lower 16). @@ -116,25 +142,30 @@ public class Flags { /** Flag is set if symbol is deprecated. See also DEPRECATED_REMOVAL. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.MODULE, FlagTarget.PACKAGE, FlagTarget.TYPE_VAR, FlagTarget.VARIABLE}) public static final int DEPRECATED = 1<<17; /** Flag is set for a variable symbol if the variable's definition * has an initializer part. */ + @Use({FlagTarget.VARIABLE}) public static final int HASINIT = 1<<18; /** Class is an implicitly declared top level class. */ + @Use({FlagTarget.CLASS}) public static final int IMPLICIT_CLASS = 1<<19; /** Flag is set for compiler-generated anonymous method symbols * that `own' an initializer block. */ + @Use({FlagTarget.METHOD}) public static final int BLOCK = 1<<20; /** Flag is set for ClassSymbols that are being compiled from source. */ - public static final int FROM_SOURCE = 1<<21; //ClassSymbols + @Use({FlagTarget.CLASS}) + public static final int FROM_SOURCE = 1<<21; /** Flag is set for nested classes that do not access instance members * or `this' of an outer class and therefore don't need to be passed @@ -143,25 +174,30 @@ public class Flags { * todo: use this value for optimizing away this$n parameters in * other cases. */ + @Use({FlagTarget.CLASS, FlagTarget.VARIABLE}) public static final int NOOUTERTHIS = 1<<22; /** Flag is set for package symbols if a package has a member or * directory and therefore exists. */ + @Use({FlagTarget.CLASS, FlagTarget.PACKAGE}) public static final int EXISTS = 1<<23; /** Flag is set for compiler-generated compound classes * representing multiple variable bounds */ + @Use({FlagTarget.CLASS}) public static final int COMPOUND = 1<<24; /** Flag is set for class symbols if a class file was found for this class. */ + @Use({FlagTarget.CLASS}) public static final int CLASS_SEEN = 1<<25; /** Flag is set for class symbols if a source file was found for this * class. */ + @Use({FlagTarget.CLASS}) public static final int SOURCE_SEEN = 1<<26; /* State flags (are reset during compilation). @@ -172,242 +208,291 @@ public class Flags { * relations. Similarly for constructor call cycle detection in * Attr. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD}) public static final int LOCKED = 1<<27; /** Flag for class symbols is set and later re-set to indicate that a class * has been entered but has not yet been attributed. */ + @Use({FlagTarget.CLASS}) public static final int UNATTRIBUTED = 1<<28; /** Flag for synthesized default constructors of anonymous classes. */ - public static final int ANONCONSTR = 1<<29; //non-class members + @Use({FlagTarget.METHOD}) + public static final int ANONCONSTR = 1<<29; /** * Flag to indicate the superclasses of this ClassSymbol has been attributed. */ - public static final int SUPER_OWNER_ATTRIBUTED = 1<<29; //ClassSymbols + @Use({FlagTarget.CLASS}) + public static final int SUPER_OWNER_ATTRIBUTED = 1<<29; /** Flag for class symbols to indicate it has been checked and found * acyclic. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.TYPE_VAR}) public static final int ACYCLIC = 1<<30; /** Flag that marks bridge methods. */ + @Use({FlagTarget.METHOD}) public static final long BRIDGE = 1L<<31; /** Flag that marks formal parameters. */ + @Use({FlagTarget.VARIABLE}) public static final long PARAMETER = 1L<<33; /** Flag that marks varargs methods. */ + @Use({FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final long VARARGS = 1L<<34; /** Flag for annotation type symbols to indicate it has been * checked and found acyclic. */ + @Use({FlagTarget.CLASS}) public static final long ACYCLIC_ANN = 1L<<35; /** Flag that marks a generated default constructor. */ + @Use({FlagTarget.METHOD}) public static final long GENERATEDCONSTR = 1L<<36; /** Flag that marks a hypothetical method that need not really be * generated in the binary, but is present in the symbol table to * simplify checking for erasure clashes - also used for 292 poly sig methods. */ + @Use({FlagTarget.METHOD}) public static final long HYPOTHETICAL = 1L<<37; /** * Flag that marks an internal proprietary class. */ + @Use({FlagTarget.CLASS}) public static final long PROPRIETARY = 1L<<38; /** * Flag that marks a multi-catch parameter. */ + @Use({FlagTarget.VARIABLE}) public static final long UNION = 1L<<39; /** * Flags an erroneous TypeSymbol as viable for recovery. * TypeSymbols only. */ + @Use({FlagTarget.CLASS, FlagTarget.TYPE_VAR}) public static final long RECOVERABLE = 1L<<40; /** * Flag that marks an 'effectively final' local variable. */ + @Use({FlagTarget.VARIABLE}) public static final long EFFECTIVELY_FINAL = 1L<<41; /** * Flag that marks non-override equivalent methods with the same signature, * or a conflicting match binding (BindingSymbol). */ + @Use({FlagTarget.METHOD, FlagTarget.VARIABLE}) public static final long CLASH = 1L<<42; /** * Flag that marks either a default method or an interface containing default methods. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD}) public static final long DEFAULT = 1L<<43; // part of ExtendedStandardFlags, cannot be reused /** * Flag that marks class as auxiliary, ie a non-public class following * the public class in a source file, that could block implicit compilation. */ + @Use({FlagTarget.CLASS}) public static final long AUXILIARY = 1L<<44; /** * Flag that marks that a symbol is not available in the current profile */ + @Use({FlagTarget.CLASS}) public static final long NOT_IN_PROFILE = 1L<<45; /** * Flag that indicates that an override error has been detected by Check. */ + @Use({FlagTarget.METHOD}) public static final long BAD_OVERRIDE = 1L<<45; /** * Flag that indicates a signature polymorphic method (292). */ + @Use({FlagTarget.METHOD}) public static final long SIGNATURE_POLYMORPHIC = 1L<<46; /** * Flag that indicates that an inference variable is used in a 'throws' clause. */ + @Use({FlagTarget.TYPE_VAR}) public static final long THROWS = 1L<<47; /** * Flag to indicate sealed class/interface declaration. */ + @Use({FlagTarget.CLASS}) public static final long SEALED = 1L<<48; // part of ExtendedStandardFlags, cannot be reused /** * Flag that marks a synthetic method body for a lambda expression */ - public static final long LAMBDA_METHOD = 1L<<49; //MethodSymbols only + @Use({FlagTarget.METHOD}) + public static final long LAMBDA_METHOD = 1L<<49; /** * Flag that marks a synthetic local capture field in a local/anon class */ - public static final long LOCAL_CAPTURE_FIELD = 1L<<49; //VarSymbols only + @Use({FlagTarget.VARIABLE}) + public static final long LOCAL_CAPTURE_FIELD = 1L<<49; /** * Flag to control recursion in TransTypes */ + @Use({FlagTarget.CLASS}) public static final long TYPE_TRANSLATED = 1L<<50; /** * Flag to indicate class symbol is for module-info */ + @Use({FlagTarget.CLASS}) public static final long MODULE = 1L<<51; /** * Flag to indicate the given ModuleSymbol is an automatic module. */ - public static final long AUTOMATIC_MODULE = 1L<<52; //ModuleSymbols only + @Use({FlagTarget.MODULE}) + public static final long AUTOMATIC_MODULE = 1L<<52; /** * Flag to indicate the given PackageSymbol contains any non-.java and non-.class resources. */ - public static final long HAS_RESOURCE = 1L<<52; //PackageSymbols only + @Use({FlagTarget.PACKAGE}) + public static final long HAS_RESOURCE = 1L<<52; /** * Flag to indicate the given ParamSymbol has a user-friendly name filled. */ - public static final long NAME_FILLED = 1L<<52; //ParamSymbols only + @Use({FlagTarget.VARIABLE}) //ParamSymbols only + public static final long NAME_FILLED = 1L<<52; /** * Flag to indicate the given ModuleSymbol is a system module. */ - public static final long SYSTEM_MODULE = 1L<<53; //ModuleSymbols only + @Use({FlagTarget.MODULE}) + public static final long SYSTEM_MODULE = 1L<<53; /** * Flag to indicate the given ClassSymbol is a value based. */ - public static final long VALUE_BASED = 1L<<53; //ClassSymbols only + @Use({FlagTarget.CLASS}) + public static final long VALUE_BASED = 1L<<53; /** * Flag to indicate the given symbol has a @Deprecated annotation. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.MODULE, FlagTarget.PACKAGE, FlagTarget.TYPE_VAR, FlagTarget.VARIABLE}) public static final long DEPRECATED_ANNOTATION = 1L<<54; /** * Flag to indicate the given symbol has been deprecated and marked for removal. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.MODULE, FlagTarget.PACKAGE, FlagTarget.TYPE_VAR, FlagTarget.VARIABLE}) public static final long DEPRECATED_REMOVAL = 1L<<55; /** * Flag to indicate the API element in question is for a preview API. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.MODULE, FlagTarget.PACKAGE, FlagTarget.TYPE_VAR, FlagTarget.VARIABLE}) public static final long PREVIEW_API = 1L<<56; //any Symbol kind /** * Flag for synthesized default constructors of anonymous classes that have an enclosing expression. */ + @Use({FlagTarget.METHOD}) public static final long ANONCONSTR_BASED = 1L<<57; /** * Flag that marks finalize block as body-only, should not be copied into catch clauses. * Used to implement try-with-resources. */ - public static final long BODY_ONLY_FINALIZE = 1L<<17; //blocks only + @Use({FlagTarget.BLOCK}) + public static final long BODY_ONLY_FINALIZE = 1L<<17; /** * Flag to indicate the API element in question is for a preview API. */ + @Use({FlagTarget.CLASS, FlagTarget.METHOD, FlagTarget.MODULE, FlagTarget.PACKAGE, FlagTarget.TYPE_VAR, FlagTarget.VARIABLE}) public static final long PREVIEW_REFLECTIVE = 1L<<58; //any Symbol kind /** * Flag to indicate the given variable is a match binding variable. */ + @Use({FlagTarget.VARIABLE}) public static final long MATCH_BINDING = 1L<<59; /** * A flag to indicate a match binding variable whose scope extends after the current statement. */ + @Use({FlagTarget.VARIABLE}) public static final long MATCH_BINDING_TO_OUTER = 1L<<60; /** * Flag to indicate that a class is a record. The flag is also used to mark fields that are * part of the state vector of a record and to mark the canonical constructor */ - public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols + @Use({FlagTarget.CLASS, FlagTarget.VARIABLE, FlagTarget.METHOD}) + public static final long RECORD = 1L<<61; /** * Flag to mark a record constructor as a compact one */ - public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only + @Use({FlagTarget.METHOD}) + public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; /** * Flag to mark a record field that was not initialized in the compact constructor */ - public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only + @Use({FlagTarget.VARIABLE}) + public static final long UNINITIALIZED_FIELD= 1L<<51; /** Flag is set for compiler-generated record members, it could be applied to * accessors and fields */ - public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols + @Use({FlagTarget.METHOD, FlagTarget.VARIABLE}) + public static final int GENERATED_MEMBER = 1<<24; /** * Flag to indicate restricted method declaration. */ - public static final long RESTRICTED = 1L<<62; // MethodSymbols + @Use({FlagTarget.METHOD}) + public static final long RESTRICTED = 1L<<62; /** * Flag to indicate parameters that require identity. */ - public static final long REQUIRES_IDENTITY = 1L<<62; // VarSymbols (parameters) + @Use({FlagTarget.VARIABLE}) //ParamSymbols only + public static final long REQUIRES_IDENTITY = 1L<<62; /** * Flag to indicate type annotations have been queued for field initializers. */ - public static final long FIELD_INIT_TYPE_ANNOTATIONS_QUEUED = 1L<<53; // VarSymbols + @Use({FlagTarget.VARIABLE}) + public static final long FIELD_INIT_TYPE_ANNOTATIONS_QUEUED = 1L<<53; /** * Flag to indicate that the class/interface was declared with the non-sealed modifier. */ + @Use({FlagTarget.CLASS}) + @CustomToStringValue("non-sealed") public static final long NON_SEALED = 1L<<63; // part of ExtendedStandardFlags, cannot be reused /** @@ -422,6 +507,7 @@ public class Flags { /** Modifier masks. */ + @NotFlag public static final int AccessFlags = PUBLIC | PROTECTED | PRIVATE, LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC, @@ -438,6 +524,7 @@ public class Flags { SYNCHRONIZED | FINAL | STRICTFP, RecordMethodFlags = AccessFlags | ABSTRACT | STATIC | SYNCHRONIZED | FINAL | STRICTFP; + @NotFlag public static final long //NOTE: flags in ExtendedStandardFlags cannot be overlayed across Symbol kinds: ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED, @@ -491,91 +578,45 @@ public class Flags { return symbol.getConstValue() != null; } - - public enum Flag { - PUBLIC(Flags.PUBLIC), - PRIVATE(Flags.PRIVATE), - PROTECTED(Flags.PROTECTED), - STATIC(Flags.STATIC), - FINAL(Flags.FINAL), - SYNCHRONIZED(Flags.SYNCHRONIZED), - VOLATILE(Flags.VOLATILE), - TRANSIENT(Flags.TRANSIENT), - NATIVE(Flags.NATIVE), - INTERFACE(Flags.INTERFACE), - ABSTRACT(Flags.ABSTRACT), - DEFAULT(Flags.DEFAULT), - STRICTFP(Flags.STRICTFP), - BRIDGE(Flags.BRIDGE), - SYNTHETIC(Flags.SYNTHETIC), - ANNOTATION(Flags.ANNOTATION), - DEPRECATED(Flags.DEPRECATED), - HASINIT(Flags.HASINIT), - IMPLICIT_CLASS(Flags.IMPLICIT_CLASS), - BLOCK(Flags.BLOCK), - FROM_SOURCE(Flags.FROM_SOURCE), - ENUM(Flags.ENUM), - MANDATED(Flags.MANDATED), - NOOUTERTHIS(Flags.NOOUTERTHIS), - EXISTS(Flags.EXISTS), - COMPOUND(Flags.COMPOUND), - CLASS_SEEN(Flags.CLASS_SEEN), - SOURCE_SEEN(Flags.SOURCE_SEEN), - LOCKED(Flags.LOCKED), - UNATTRIBUTED(Flags.UNATTRIBUTED), - ANONCONSTR(Flags.ANONCONSTR), - ACYCLIC(Flags.ACYCLIC), - PARAMETER(Flags.PARAMETER), - VARARGS(Flags.VARARGS), - ACYCLIC_ANN(Flags.ACYCLIC_ANN), - GENERATEDCONSTR(Flags.GENERATEDCONSTR), - HYPOTHETICAL(Flags.HYPOTHETICAL), - PROPRIETARY(Flags.PROPRIETARY), - UNION(Flags.UNION), - EFFECTIVELY_FINAL(Flags.EFFECTIVELY_FINAL), - CLASH(Flags.CLASH), - AUXILIARY(Flags.AUXILIARY), - NOT_IN_PROFILE(Flags.NOT_IN_PROFILE), - BAD_OVERRIDE(Flags.BAD_OVERRIDE), - SIGNATURE_POLYMORPHIC(Flags.SIGNATURE_POLYMORPHIC), - THROWS(Flags.THROWS), - LAMBDA_METHOD(Flags.LAMBDA_METHOD), - TYPE_TRANSLATED(Flags.TYPE_TRANSLATED), - MODULE(Flags.MODULE), - AUTOMATIC_MODULE(Flags.AUTOMATIC_MODULE), - SYSTEM_MODULE(Flags.SYSTEM_MODULE), - DEPRECATED_ANNOTATION(Flags.DEPRECATED_ANNOTATION), - DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL), - HAS_RESOURCE(Flags.HAS_RESOURCE), - SEALED(Flags.SEALED), - ANONCONSTR_BASED(Flags.ANONCONSTR_BASED), - NAME_FILLED(Flags.NAME_FILLED), - PREVIEW_API(Flags.PREVIEW_API), - PREVIEW_REFLECTIVE(Flags.PREVIEW_REFLECTIVE), - MATCH_BINDING(Flags.MATCH_BINDING), - MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER), - RECORD(Flags.RECORD), - RECOVERABLE(Flags.RECOVERABLE), - RESTRICTED(Flags.RESTRICTED), - NON_SEALED(Flags.NON_SEALED) { - @Override - public String toString() { - return "non-sealed"; - } - }; - - Flag(long flag) { - this.value = flag; - this.lowercaseName = StringUtils.toLowerCase(name()); - } - - @Override - public String toString() { - return lowercaseName; - } - - final long value; - final String lowercaseName; + public enum FlagTarget { + /** This flag can appear the JCBlock. + */ + BLOCK, + /** This flag can appear on ClassSymbols. + */ + CLASS, + /** This flag can appear on ModuleSymbols. + */ + MODULE, + /** This flag can appear on PackageSymbols. + */ + PACKAGE, + /** This flag can appear on TypeVarSymbols. + */ + TYPE_VAR, + /** This flag can appear on MethodSymbols. + */ + METHOD, + /** This flag can appear on VarSymbols, includes + * including ParamSymbol, and BindingSymbol. + */ + VARIABLE; } + @Retention(RetentionPolicy.RUNTIME) + public @interface Use { + public FlagTarget[] value(); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface NotFlag {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface CustomToStringValue { + public String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface NoToStringValue { + } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 47066b24de9..4d0af014d83 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -62,7 +62,7 @@ import com.sun.tools.javac.code.Directive.RequiresDirective; import com.sun.tools.javac.code.Directive.RequiresFlag; import com.sun.tools.javac.code.Directive.UsesDirective; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Flags.Flag; +import com.sun.tools.javac.code.FlagsEnum; import com.sun.tools.javac.code.Kinds; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; @@ -825,7 +825,7 @@ public class Modules extends JCTree.Visitor { } if (tree.isStaticPhase) { if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) { - log.error(tree.pos(), Errors.ModNotAllowedHere(EnumSet.of(Flag.STATIC))); + log.error(tree.pos(), Errors.ModNotAllowedHere(EnumSet.of(FlagsEnum.STATIC))); } else { flags.add(RequiresFlag.STATIC_PHASE); } diff --git a/test/langtools/tools/javac/diags/ArgTypeCompilerFactory.java b/test/langtools/tools/javac/diags/ArgTypeCompilerFactory.java index e40109f99f3..823a0f01a7f 100644 --- a/test/langtools/tools/javac/diags/ArgTypeCompilerFactory.java +++ b/test/langtools/tools/javac/diags/ArgTypeCompilerFactory.java @@ -29,7 +29,7 @@ import javax.tools.*; import com.sun.tools.javac.api.*; import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart; import com.sun.tools.javac.api.Formattable.LocalizedString; -import com.sun.tools.javac.code.Flags.Flag; +import com.sun.tools.javac.code.FlagsEnum; import com.sun.tools.javac.code.Kinds.KindName; import com.sun.tools.javac.code.*; import com.sun.tools.javac.file.*; @@ -303,7 +303,7 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory { return "number"; if (o instanceof String) return "string"; - if (o instanceof Flag) + if (o instanceof FlagsEnum) return "modifier"; if (o instanceof KindName) return "symbol kind"; diff --git a/test/langtools/tools/javac/flags/FlagsTest.java b/test/langtools/tools/javac/flags/FlagsTest.java index 1dcb0606a65..a7a9051af33 100644 --- a/test/langtools/tools/javac/flags/FlagsTest.java +++ b/test/langtools/tools/javac/flags/FlagsTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, Google LLC. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. 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 @@ -23,28 +24,84 @@ /** * @test - * @bug 8211138 + * @bug 8211138 8362885 * @summary Missing Flag enum constants * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.code - * @run main FlagsTest + * @compile FlagsTest.java + * @run main/manual FlagsTest */ import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Flags.FlagTarget; +import com.sun.tools.javac.code.Flags.NotFlag; +import com.sun.tools.javac.code.Flags.Use; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class FlagsTest { - public static void main(String[] args) throws IllegalAccessException { - for (Field f : Flags.class.getFields()) { - if (!Modifier.isStatic(f.getModifiers())) { - continue; - } - long flag = ((Number) f.get(null)).longValue(); - try { - Flags.asFlagSet(flag); - } catch (AssertionError e) { - throw new AssertionError("missing Flags enum constant for: " + f.getName(), e); - } + + private static final int U2_SIZE = 16; + + public static void main(String[] args) throws Throwable { + findFreeFlags(); + } + + private static void findFreeFlags() throws Throwable { + Map>> target2Flag2Fields = computeTarget2Flag2Fields(); + + for (FlagTarget target : FlagTarget.values()) { + long freeFlags = ~collectFlags(target2Flag2Fields, target); + + printFreeFlags(target.name(), freeFlags); } } + + private static Map>> computeTarget2Flag2Fields() throws Throwable { + Map>> target2Flag2Fields = new HashMap<>(); + for (Field f : Flags.class.getFields()) { + if (f.isAnnotationPresent(NotFlag.class)) { + continue; + } + + Use use = f.getAnnotation(Use.class); + + if (use == null) { + throw new AssertionError("No @Use and no @NotFlag for: " + f.getName()); + } + + long flagValue = ((Number) f.get(null)).longValue(); + + for (FlagTarget target : use.value()) { + target2Flag2Fields.computeIfAbsent(target, _ -> new HashMap<>()) + .computeIfAbsent(flagValue, _ -> new ArrayList<>()) + .add(f); + } + } + return target2Flag2Fields; + } + + private static void printFreeFlags(String comment, long freeFlags) { + System.err.print("free flags for " + comment + ": "); + for (int bit = U2_SIZE; bit < Long.SIZE; bit++) { //lowest 16 bits are used in classfiles, never suggest adding anything there + if ((freeFlags & (1L << bit)) != 0) { + System.err.print("1L<<" + bit + " "); + } + } + System.err.println(); + } + + private static long collectFlags(Map>> target2Flag2Fields, FlagTarget... forTargets) { + long flags = 0; + + for (FlagTarget target : forTargets) { + for (long used : target2Flag2Fields.get(target).keySet()) { + flags |= used; + } + } + + return flags; + } } From e77cdd93ead5601fea4bb1bf1847835e1097b851 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 13 Aug 2025 08:47:08 +0000 Subject: [PATCH 067/471] 8364570: Remove LockingMode related code from riscv64 Reviewed-by: fyang, fjiang --- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 14 +- .../cpu/riscv/c1_MacroAssembler_riscv.cpp | 84 +------ .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 230 ------------------ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 7 +- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 152 +++--------- .../cpu/riscv/macroAssembler_riscv.cpp | 2 - src/hotspot/cpu/riscv/riscv.ad | 40 +-- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 75 +----- .../templateInterpreterGenerator_riscv.cpp | 27 +- 9 files changed, 55 insertions(+), 576 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 81b829bde9a..2a65270af92 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -339,11 +339,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::r10_opr); stub = new MonitorExitStub(FrameMap::r10_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ j(*stub->entry()); - } else { - __ unlock_object(x15, x14, x10, x16, *stub->entry()); - } + __ unlock_object(x15, x14, x10, x16, *stub->entry()); __ bind(*stub->continuation()); } @@ -1497,13 +1493,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); - if (LockingMode == LM_MONITOR) { - if (op->info() != nullptr) { - add_debug_info_for_null_check_here(op->info()); - __ null_check(obj, -1); - } - __ j(*op->stub()->entry()); - } else if (op->code() == lir_lock) { + if (op->code() == lir_lock) { assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 3ce764b1861..8198192f506 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -49,8 +49,6 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - const int aligned_mask = BytesPerWord - 1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); int null_check_offset = -1; @@ -61,97 +59,19 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - lbu(hdr, Address(hdr, Klass::misc_flags_offset())); - test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(temp, slow_case, /* is_far */ true); - } - - Label done; - // Load object header - ld(hdr, Address(obj, hdr_offset)); - // and mark it as unlocked - ori(hdr, hdr, markWord::unlocked_value); - // save unlocked object header into the displaced header location on the stack - sd(hdr, Address(disp_hdr, 0)); - // test if object header is still the same (i.e. unlocked), and if so, store the - // displaced header address in the object header - if it is not the same, get the - // object header instead - la(temp, Address(obj, hdr_offset)); - // if the object header was the same, we're done - cmpxchgptr(hdr, disp_hdr, temp, t1, done, /*fallthough*/nullptr); - // if the object header was not the same, it is now in the hdr register - // => test if it is a stack pointer into the same stack (recursive locking), i.e.: - // - // 1) (hdr & aligned_mask) == 0 - // 2) sp <= hdr - // 3) hdr <= sp + page_size - // - // these 3 tests can be done by evaluating the following expression: - // - // (hdr -sp) & (aligned_mask - page_size) - // - // assuming both the stack pointer and page_size have their least - // significant 2 bits cleared and page_size is a power of 2 - sub(hdr, hdr, sp); - mv(temp, aligned_mask - (int)os::vm_page_size()); - andr(hdr, hdr, temp); - // for recursive locking, the result is zero => save it in the displaced header - // location (null in the displaced hdr location indicates recursive locking) - sd(hdr, Address(disp_hdr, 0)); - // otherwise we don't care about the result and handle locking via runtime call - bnez(hdr, slow_case, /* is_far */ true); - - // done - bind(done); - inc_held_monitor_count(t0); - } + lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); return null_check_offset; } void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - const int aligned_mask = BytesPerWord - 1; - const int hdr_offset = oopDesc::mark_offset_in_bytes(); assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); - Label done; - - if (LockingMode != LM_LIGHTWEIGHT) { - // load displaced header - ld(hdr, Address(disp_hdr, 0)); - // if the loaded hdr is null we had recursive locking - // if we had recursive locking, we are done - beqz(hdr, done); - } // load object ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); verify_oop(obj); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj, hdr, temp, t1, slow_case); - } else if (LockingMode == LM_LEGACY) { - // test if object header is pointing to the displaced header, and if so, restore - // the displaced header in the object - if the object header is not pointing to - // the displaced header, get the object header instead - // if the object header was not pointing to the displaced header, - // we do unlocking via runtime call - if (hdr_offset) { - la(temp, Address(obj, hdr_offset)); - cmpxchgptr(disp_hdr, hdr, temp, t1, done, &slow_case); - } else { - cmpxchgptr(disp_hdr, hdr, obj, t1, done, &slow_case); - } - - // done - bind(done); - dec_held_monitor_count(t0); - } + lightweight_unlock(obj, hdr, temp, t1, slow_case); } // Defines obj, preserves var_size_in_bytes diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index bf71d2c68f1..aac2c98fc86 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -43,240 +43,11 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, - Register tmp1Reg, Register tmp2Reg, Register tmp3Reg, Register tmp4Reg) { - // Use cr register to indicate the fast_lock result: zero for success; non-zero for failure. - Register flag = t1; - Register oop = objectReg; - Register box = boxReg; - Register disp_hdr = tmp1Reg; - Register tmp = tmp2Reg; - Label object_has_monitor; - // Finish fast lock successfully. MUST branch to with flag == 0 - Label locked; - // Finish fast lock unsuccessfully. slow_path MUST branch to with flag != 0 - Label slow_path; - - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_lock_lightweight"); - assert_different_registers(oop, box, tmp, disp_hdr, flag, tmp3Reg, t0); - - mv(flag, 1); - - // Load markWord from object into displaced_header. - ld(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, oop); - lbu(tmp, Address(tmp, Klass::misc_flags_offset())); - test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(tmp, slow_path); - } - - // Check for existing monitor - test_bit(tmp, disp_hdr, exact_log2(markWord::monitor_value)); - bnez(tmp, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - j(slow_path); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Set tmp to be (markWord of object | UNLOCK_VALUE). - ori(tmp, disp_hdr, markWord::unlocked_value); - - // Initialize the box. (Must happen before we update the object mark!) - sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // Compare object markWord with an unlocked value (tmp) and if - // equal exchange the stack address of our box with object markWord. - // On failure disp_hdr contains the possibly locked markWord. - cmpxchg(/*memory address*/oop, /*expected value*/tmp, /*new value*/box, Assembler::int64, - Assembler::aq, Assembler::rl, /*result*/disp_hdr); - beq(disp_hdr, tmp, locked); - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object, will have now locked it will continue at label locked - // We did not see an unlocked object so try the fast recursive case. - - // Check if the owner is self by comparing the value in the - // markWord of object (disp_hdr) with the stack pointer. - sub(disp_hdr, disp_hdr, sp); - mv(tmp, (intptr_t) (~(os::vm_page_size()-1) | (uintptr_t)markWord::lock_mask_in_place)); - // If (mark & lock_mask) == 0 and mark - sp < page_size, we are stack-locking and goto label - // locked, hence we can store 0 as the displaced header in the box, which indicates that it - // is a recursive lock. - andr(tmp/*==0?*/, disp_hdr, tmp); - sd(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); - beqz(tmp, locked); - j(slow_path); - } - - // Handle existing monitor. - bind(object_has_monitor); - - // Try to CAS owner (no owner => current thread's _monitor_owner_id). - add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value)); - Register tid = tmp4Reg; - ld(tid, Address(xthread, JavaThread::monitor_owner_id_offset())); - cmpxchg(/*memory address*/tmp, /*expected value*/zr, /*new value*/tid, Assembler::int64, - Assembler::aq, Assembler::rl, /*result*/tmp3Reg); // cas succeeds if tmp3Reg == zr(expected) - - // Store a non-null value into the box to avoid looking like a re-entrant - // lock. The fast-path monitor unlock code checks for - // markWord::monitor_value so use markWord::unused_mark which has the - // relevant bit set, and also matches ObjectSynchronizer::slow_enter. - mv(tmp, (address)markWord::unused_mark().value()); - sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - beqz(tmp3Reg, locked); // CAS success means locking succeeded - - bne(tmp3Reg, tid, slow_path); // Check for recursive locking - - // Recursive lock case - increment(Address(disp_hdr, in_bytes(ObjectMonitor::recursions_offset()) - markWord::monitor_value), 1, tmp2Reg, tmp3Reg); - - bind(locked); - mv(flag, zr); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(t0); - } - -#ifdef ASSERT - // Check that locked label is reached with flag == 0. - Label flag_correct; - beqz(flag, flag_correct); - stop("Fast Lock Flag != 0"); -#endif - - bind(slow_path); -#ifdef ASSERT - // Check that slow_path label is reached with flag != 0. - bnez(flag, flag_correct); - stop("Fast Lock Flag == 0"); - bind(flag_correct); -#endif - // C2 uses the value of flag (0 vs !0) to determine the continuation. -} - -void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, - Register tmp1Reg, Register tmp2Reg) { - // Use cr register to indicate the fast_unlock result: zero for success; non-zero for failure. - Register flag = t1; - Register oop = objectReg; - Register box = boxReg; - Register disp_hdr = tmp1Reg; - Register owner_addr = tmp1Reg; - Register tmp = tmp2Reg; - Label object_has_monitor; - // Finish fast lock successfully. MUST branch to with flag == 0 - Label unlocked; - // Finish fast lock unsuccessfully. slow_path MUST branch to with flag != 0 - Label slow_path; - - assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); - assert_different_registers(oop, box, tmp, disp_hdr, flag, t0); - - mv(flag, 1); - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - ld(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); - - // If the displaced header is 0, we have a recursive unlock. - beqz(disp_hdr, unlocked); - } - - // Handle existing monitor. - ld(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); - test_bit(t0, tmp, exact_log2(markWord::monitor_value)); - bnez(t0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - j(slow_path); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Check if it is still a light weight lock, this is true if we - // see the stack address of the basicLock in the markWord of the - // object. - - cmpxchg(/*memory address*/oop, /*expected value*/box, /*new value*/disp_hdr, Assembler::int64, - Assembler::relaxed, Assembler::rl, /*result*/tmp); - beq(box, tmp, unlocked); // box == tmp if cas succeeds - j(slow_path); - } - - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - - // Handle existing monitor. - bind(object_has_monitor); - subi(tmp, tmp, (int)markWord::monitor_value); // monitor - ld(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - - Label notRecursive; - beqz(disp_hdr, notRecursive); // Will be 0 if not recursive. - - // Recursive lock - subi(disp_hdr, disp_hdr, 1); - sd(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset())); - j(unlocked); - - bind(notRecursive); - // Compute owner address. - la(owner_addr, Address(tmp, ObjectMonitor::owner_offset())); - - // Set owner to null. - // Release to satisfy the JMM - membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(owner_addr)); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - ld(t0, Address(tmp, ObjectMonitor::entry_list_offset())); - beqz(t0, unlocked); // If so we are done. - - // Check if there is a successor. - ld(t0, Address(tmp, ObjectMonitor::succ_offset())); - bnez(t0, unlocked); // If so we are done. - - // Save the monitor pointer in the current thread, so we can try to - // reacquire the lock in SharedRuntime::monitor_exit_helper(). - sd(tmp, Address(xthread, JavaThread::unlocked_inflated_monitor_offset())); - - mv(flag, 1); - j(slow_path); - - bind(unlocked); - mv(flag, zr); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(t0); - } - -#ifdef ASSERT - // Check that unlocked label is reached with flag == 0. - Label flag_correct; - beqz(flag, flag_correct); - stop("Fast Lock Flag != 0"); -#endif - - bind(slow_path); -#ifdef ASSERT - // Check that slow_path label is reached with flag != 0. - bnez(flag, flag_correct); - stop("Fast Lock Flag == 0"); - bind(flag_correct); -#endif - // C2 uses the value of flag (0 vs !0) to determine the continuation. -} - void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register tmp1, Register tmp2, Register tmp3, Register tmp4) { // Flag register, zero for success; non-zero for failure. Register flag = t1; - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert_different_registers(obj, box, tmp1, tmp2, tmp3, tmp4, flag, t0); mv(flag, 1); @@ -439,7 +210,6 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, // Flag register, zero for success; non-zero for failure. Register flag = t1; - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert_different_registers(obj, box, tmp1, tmp2, tmp3, flag, t0); mv(flag, 1); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 73fceea3805..309ef8d9d5e 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -49,11 +49,6 @@ const int STUB_THRESHOLD, Label *STUB, Label *DONE); public: - // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. - void fast_lock(Register object, Register box, - Register tmp1, Register tmp2, Register tmp3, Register tmp4); - void fast_unlock(Register object, Register box, Register tmp1, Register tmp2); - // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file. void fast_lock_lightweight(Register object, Register box, Register tmp1, Register tmp2, Register tmp3, Register tmp4); diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 92f7169f471..7c4b8444407 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -733,84 +733,26 @@ void InterpreterMacroAssembler::leave_jfr_critical_section() { void InterpreterMacroAssembler::lock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } else { - Label count, done; - const Register swap_reg = x10; - const Register tmp = c_rarg2; - const Register obj_reg = c_rarg3; // Will contain the oop - const Register tmp2 = c_rarg4; - const Register tmp3 = c_rarg5; + const Register tmp = c_rarg2; + const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp2 = c_rarg4; + const Register tmp3 = c_rarg5; - const int obj_offset = in_bytes(BasicObjectLock::obj_offset()); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); + // Load object pointer into obj_reg (c_rarg3) + ld(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - Label slow_case; + Label done, slow_case; + lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); + j(done); - // Load object pointer into obj_reg c_rarg3 - ld(obj_reg, Address(lock_reg, obj_offset)); + bind(slow_case); + // Call the runtime routine for slow case + call_VM_preemptable(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); - j(done); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - lbu(tmp, Address(tmp, Klass::misc_flags_offset())); - test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(tmp, slow_case); - } - - // Load (object->mark() | 1) into swap_reg - ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - ori(swap_reg, t0, 1); - - // Save (object->mark() | 1) into BasicLock's displaced header - sd(swap_reg, Address(lock_reg, mark_offset)); - - assert(lock_offset == 0, - "displached header must be first word in BasicObjectLock"); - - cmpxchg_obj_header(swap_reg, lock_reg, obj_reg, tmp, count, /*fallthrough*/nullptr); - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 7) == 0, and - // 2) sp <= mark < mark + os::pagesize() - // - // These 3 tests can be done by evaluating the following - // expression: ((mark - sp) & (7 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 3 bits clear. - // NOTE: the oopMark is in swap_reg x10 as the result of cmpxchg - sub(swap_reg, swap_reg, sp); - mv(t0, (int64_t)(7 - (int)os::vm_page_size())); - andr(swap_reg, swap_reg, t0); - - // Save the test result, for recursive case, the result is zero - sd(swap_reg, Address(lock_reg, mark_offset)); - bnez(swap_reg, slow_case); - - bind(count); - inc_held_monitor_count(t0); - j(done); - } - - bind(slow_case); - - // Call the runtime routine for slow case - call_VM_preemptable(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - - bind(done); - } + bind(done); } @@ -829,58 +771,30 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Label count, done; + const Register swap_reg = x10; + const Register header_reg = c_rarg2; // Will contain the old oopMark + const Register obj_reg = c_rarg3; // Will contain the oop + const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock - const Register swap_reg = x10; - const Register header_reg = c_rarg2; // Will contain the old oopMark - const Register obj_reg = c_rarg3; // Will contain the oop - const Register tmp_reg = c_rarg4; // Temporary used by lightweight_unlock + save_bcp(); // Save in case of exception - save_bcp(); // Save in case of exception + // Load oop into obj_reg (c_rarg3) + ld(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); - if (LockingMode != LM_LIGHTWEIGHT) { - // Convert from BasicObjectLock structure to object and BasicLock - // structure Store the BasicLock address into x10 - la(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset())); - } + // Free entry + sd(zr, Address(lock_reg, BasicObjectLock::obj_offset())); - // Load oop into obj_reg(c_rarg3) - ld(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); + Label done, slow_case; + lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); + j(done); - // Free entry - sd(zr, Address(lock_reg, BasicObjectLock::obj_offset())); + bind(slow_case); + // Call the runtime routine for slow case. + sd(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); // restore obj + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - Label slow_case; - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(obj_reg, header_reg, swap_reg, tmp_reg, slow_case); - j(done); - } else if (LockingMode == LM_LEGACY) { - // Load the old header from BasicLock structure - ld(header_reg, Address(swap_reg, - BasicLock::displaced_header_offset_in_bytes())); - - // Test for recursion - beqz(header_reg, count); - - // Atomic swap back the old header - cmpxchg_obj_header(swap_reg, header_reg, obj_reg, tmp_reg, count, &slow_case); - - bind(count); - dec_held_monitor_count(t0); - j(done); - } - - bind(slow_case); - // Call the runtime routine for slow case. - sd(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset())); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - - bind(done); - restore_bcp(); - } + bind(done); + restore_bcp(); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a4c44b0b1d1..453538e4a5a 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -6421,7 +6421,6 @@ void MacroAssembler::test_bit(Register Rd, Register Rs, uint32_t bit_pos) { // - tmp1, tmp2, tmp3: temporary registers, will be destroyed // - slow: branched to if locking fails void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(basic_lock, obj, tmp1, tmp2, tmp3, t0); Label push; @@ -6481,7 +6480,6 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe // - tmp1, tmp2, tmp3: temporary registers // - slow: branched to if unlocking fails void MacroAssembler::lightweight_unlock(Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, tmp1, tmp2, tmp3, t0); #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 8e7b772414a..7d204007898 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. // Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -11021,45 +11021,9 @@ instruct tlsLoadP(javaThread_RegP dst) // inlined locking and unlocking // using t1 as the 'flag' register to bridge the BoolNode producers and consumers -instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, - iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegPNoSp tmp4) -%{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastLock object box)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4); - - ins_cost(10 * DEFAULT_COST); - format %{ "fastlock $object,$box\t! kills $tmp1,$tmp2,$tmp3,$tmp4 #@cmpFastLock" %} - - ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, - $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register); - %} - - ins_pipe(pipe_serial); -%} - -// using t1 as the 'flag' register to bridge the BoolNode producers and consumers -instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) -%{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set cr (FastUnlock object box)); - effect(TEMP tmp1, TEMP tmp2); - - ins_cost(10 * DEFAULT_COST); - format %{ "fastunlock $object,$box\t! kills $tmp1, $tmp2, #@cmpFastUnlock" %} - - ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp1$$Register, $tmp2$$Register); - %} - - ins_pipe(pipe_serial); -%} - instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegPNoSp tmp4) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastLock object box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4); @@ -11074,10 +11038,10 @@ instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, ins_pipe(pipe_serial); %} +// using t1 as the 'flag' register to bridge the BoolNode producers and consumers instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set cr (FastUnlock object box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index c4e5a871a88..2cc1fb8eeff 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1637,7 +1637,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // We use the same pc/oopMap repeatedly when we call out. Label native_return; - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // For convenience we use the pc we want to resume to in case of preemption on Object.wait. __ set_last_Java_frame(sp, noreg, native_return, t0); } else { @@ -1679,8 +1679,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label lock_done; if (method->is_synchronized()) { - Label count; - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); // Get the handle (the 2nd argument) @@ -1693,42 +1691,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Load the oop from the handle __ ld(obj_reg, Address(oop_handle_reg, 0)); - if (LockingMode == LM_MONITOR) { - __ j(slow_path_lock); - } else if (LockingMode == LM_LEGACY) { - // Load (object->mark() | 1) into swap_reg % x10 - __ ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - __ ori(swap_reg, t0, 1); - - // Save (object->mark() | 1) into BasicLock's displaced header - __ sd(swap_reg, Address(lock_reg, mark_word_offset)); - - // src -> dest if dest == x10 else x10 <- dest - __ cmpxchg_obj_header(x10, lock_reg, obj_reg, lock_tmp, count, /*fallthrough*/nullptr); - - // Test if the oopMark is an obvious stack pointer, i.e., - // 1) (mark & 3) == 0, and - // 2) sp <= mark < mark + os::pagesize() - // These 3 tests can be done by evaluating the following - // expression: ((mark - sp) & (3 - os::vm_page_size())), - // assuming both stack pointer and pagesize have their - // least significant 2 bits clear. - // NOTE: the oopMark is in swap_reg % 10 as the result of cmpxchg - - __ sub(swap_reg, swap_reg, sp); - __ mv(t0, 3 - (int)os::vm_page_size()); - __ andr(swap_reg, swap_reg, t0); - - // Save the test result, for recursive case, the result is zero - __ sd(swap_reg, Address(lock_reg, mark_word_offset)); - __ bnez(swap_reg, slow_path_lock); - - __ bind(count); - __ inc_held_monitor_count(t0); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); - } + __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); // Slow path will re-enter here __ bind(lock_done); @@ -1789,7 +1752,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); __ sw(t0, Address(t1)); - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { // Check preemption for Object.wait() __ ld(t1, Address(xthread, JavaThread::preempt_alternate_return_offset())); __ beqz(t1, native_return); @@ -1818,48 +1781,18 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Get locked oop from the handle we passed to jni __ ld(obj_reg, Address(oop_handle_reg, 0)); - Label done, not_recursive; - - if (LockingMode == LM_LEGACY) { - // Simple recursive lock? - __ ld(t0, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - __ bnez(t0, not_recursive); - __ dec_held_monitor_count(t0); - __ j(done); - } - - __ bind(not_recursive); - // Must save x10 if if it is live now because cmpxchg must use it if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { save_native_result(masm, ret_type, stack_slots); } - if (LockingMode == LM_MONITOR) { - __ j(slow_path_unlock); - } else if (LockingMode == LM_LEGACY) { - // get address of the stack lock - __ la(x10, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); - // get old displaced header - __ ld(old_hdr, Address(x10, 0)); - - // Atomic swap old header if oop still contains the stack lock - Label count; - __ cmpxchg_obj_header(x10, old_hdr, obj_reg, lock_tmp, count, &slow_path_unlock); - __ bind(count); - __ dec_held_monitor_count(t0); - } else { - assert(LockingMode == LM_LIGHTWEIGHT, ""); - __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); - } + __ lightweight_unlock(obj_reg, old_hdr, swap_reg, lock_tmp, slow_path_unlock); // slow path re-enters here __ bind(unlock_done); if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { restore_native_result(masm, ret_type, stack_slots); } - - __ bind(done); } Label dtrace_method_exit, dtrace_method_exit_done; diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 21164107053..61f4aa3e722 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1253,22 +1253,17 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ mv(t0, _thread_in_Java); __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); - if (LockingMode != LM_LEGACY) { - // Check preemption for Object.wait() - Label not_preempted; - __ ld(t1, Address(xthread, JavaThread::preempt_alternate_return_offset())); - __ beqz(t1, not_preempted); - __ sd(zr, Address(xthread, JavaThread::preempt_alternate_return_offset())); - __ jr(t1); - __ bind(native_return); - __ restore_after_resume(true /* is_native */); - // reload result_handler - __ ld(result_handler, Address(fp, frame::interpreter_frame_result_handler_offset * wordSize)); - __ bind(not_preempted); - } else { - // any pc will do so just use this one for LM_LEGACY to keep code together. - __ bind(native_return); - } + // Check preemption for Object.wait() + Label not_preempted; + __ ld(t1, Address(xthread, JavaThread::preempt_alternate_return_offset())); + __ beqz(t1, not_preempted); + __ sd(zr, Address(xthread, JavaThread::preempt_alternate_return_offset())); + __ jr(t1); + __ bind(native_return); + __ restore_after_resume(true /* is_native */); + // reload result_handler + __ ld(result_handler, Address(fp, frame::interpreter_frame_result_handler_offset * wordSize)); + __ bind(not_preempted); // reset_last_Java_frame __ reset_last_Java_frame(true); From f3b34d32d6ea409f8c8f0382e8f01e746366f842 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Wed, 13 Aug 2025 10:52:54 +0000 Subject: [PATCH 068/471] 8359235: C1 compilation fails with "assert(is_single_stack() && !is_virtual()) failed: type check" Reviewed-by: thartmann, dlong --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 4 +- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 2 +- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 6 +- .../intrinsics/TestStack2RegSlotMismatch.java | 76 +++++++++++++++++++ 6 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/TestStack2RegSlotMismatch.java diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index bdba957d1df..d7e2ff2e88d 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -2813,7 +2813,7 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C return; } - __ lea(dest->as_register_lo(), as_Address(addr->as_address_ptr())); + __ lea(dest->as_pointer_register(), as_Address(addr->as_address_ptr())); } diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index f0d09edd0a9..ad26d494b2d 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -981,7 +981,7 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { CallingConvention* cc = frame_map()->c_calling_convention(&signature); const LIR_Opr result_reg = result_register_for(x->type()); - LIR_Opr addr = new_pointer_register(); + LIR_Opr addr = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(a), addr); crc.load_item_force(cc->at(0)); @@ -1058,7 +1058,7 @@ void LIRGenerator::do_update_CRC32C(Intrinsic* x) { CallingConvention* cc = frame_map()->c_calling_convention(&signature); const LIR_Opr result_reg = result_register_for(x->type()); - LIR_Opr addr = new_pointer_register(); + LIR_Opr addr = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(a), addr); crc.load_item_force(cc->at(0)); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 2a65270af92..f60be85a141 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1821,7 +1821,7 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C } LIR_Address* adr = addr->as_address_ptr(); - Register dst = dest->as_register_lo(); + Register dst = dest->as_pointer_register(); assert_different_registers(dst, t0); if (adr->base()->is_valid() && dst == adr->base()->as_pointer_register() && (!adr->index()->is_cpu_register())) { diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index e450c04c47d..88565d9136f 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -837,7 +837,7 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { CallingConvention* cc = frame_map()->c_calling_convention(&signature); const LIR_Opr result_reg = result_register_for(x->type()); - LIR_Opr addr = new_pointer_register(); + LIR_Opr addr = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(a), addr); crc.load_item_force(cc->at(0)); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 1fdfcc4f9cd..5459e8df229 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -961,7 +961,7 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { CallingConvention* cc = frame_map()->c_calling_convention(&signature); const LIR_Opr result_reg = result_register_for(x->type()); - LIR_Opr addr = new_pointer_register(); + LIR_Opr addr = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(a), addr); crc.load_item_force(cc->at(0)); @@ -1100,10 +1100,10 @@ void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { CallingConvention* cc = frame_map()->c_calling_convention(&signature); const LIR_Opr result_reg = result_register_for(x->type()); - LIR_Opr ptr_addr_a = new_pointer_register(); + LIR_Opr ptr_addr_a = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(addr_a), ptr_addr_a); - LIR_Opr ptr_addr_b = new_pointer_register(); + LIR_Opr ptr_addr_b = new_register(T_ADDRESS); __ leal(LIR_OprFact::address(addr_b), ptr_addr_b); __ move(ptr_addr_a, cc->at(0)); diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestStack2RegSlotMismatch.java b/test/hotspot/jtreg/compiler/intrinsics/TestStack2RegSlotMismatch.java new file mode 100644 index 00000000000..d2942f061db --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestStack2RegSlotMismatch.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8359235 + * @summary Test C1 stack2reg after fixing incorrect use of T_LONG in intrinsic + * @requires vm.debug == true & vm.compiler1.enabled + * @run main/othervm -XX:TieredStopAtLevel=1 + * -XX:C1MaxInlineSize=200 + * -XX:CompileThreshold=10 + * -XX:CompileCommand=compileonly,java.lang.invoke.LambdaFormEditor::putInCache + * compiler.intrinsics.TestStack2RegSlotMismatch + */ +package compiler.intrinsics; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; + +public class TestStack2RegSlotMismatch { + public static int target(int x, int y) { + return x + y; + } + + public static void main(String[] args) throws Throwable { + MethodHandle mh = MethodHandles.lookup().findStatic( + TestStack2RegSlotMismatch.class, + "target", + MethodType.methodType(int.class, int.class, int.class) + ); + List argsList = new ArrayList<>(); + int j = 0; + + for (int i = 0; i < 50; i++) { + mh = MethodHandles.dropArguments(mh, 0, int.class); + argsList.add(0); + argsList.add(1); + argsList.add(2); + Object result = mh.invokeWithArguments(argsList); + j += (int) result; + argsList.remove(argsList.size() - 1); + argsList.remove(argsList.size() - 1); + if (i % 5 == 0) { + Thread.sleep(1000); + } + } + + if (j == 150) { + System.out.println("passed"); + } else { + throw new Exception("TestStack2RegSlotMismatch Error"); + } + } +} \ No newline at end of file From 001aaa1e49f2692061cad44d68c9e81a27ea3b98 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Wed, 13 Aug 2025 12:45:48 +0000 Subject: [PATCH 069/471] 8365166: ARM32: missing os::fetch_bcp_from_context implementation Reviewed-by: shade --- src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 28b47877264..f4196d89fe3 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -209,8 +209,16 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { } intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { - Unimplemented(); - return nullptr; + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); +#if (FP_REG_NUM == 11) + assert(Rbcp == R7, "expected FP=R11, Rbcp=R7"); + return (intptr_t*)uc->uc_mcontext.arm_r7; +#else + assert(Rbcp == R11, "expected FP=R7, Rbcp=R11"); + return (intptr_t*)uc->uc_mcontext.arm_fp; // r11 +#endif } frame os::get_sender_for_C_frame(frame* fr) { From 899e13f40a70c98d1d393ba6c3973abcb36e1f00 Mon Sep 17 00:00:00 2001 From: Nikita Gubarkov Date: Wed, 13 Aug 2025 17:36:07 +0000 Subject: [PATCH 070/471] 8364434: Inconsistent BufferedContext state after GC Reviewed-by: jdv, azvegint, avu --- .../sun/java2d/pipe/BufferedContext.java | 60 ++++++++------ .../java/awt/ColorClass/WeakColorTest.java | 83 +++++++++++++++++++ 2 files changed, 118 insertions(+), 25 deletions(-) create mode 100644 test/jdk/java/awt/ColorClass/WeakColorTest.java diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/BufferedContext.java b/src/java.desktop/share/classes/sun/java2d/pipe/BufferedContext.java index e57b240bce5..83e63fc75d8 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/BufferedContext.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/BufferedContext.java @@ -100,11 +100,11 @@ public abstract class BufferedContext { */ protected static BufferedContext currentContext; - private Reference validSrcDataRef = new WeakReference<>(null); - private Reference validDstDataRef = new WeakReference<>(null); - private Reference validClipRef = new WeakReference<>(null); - private Reference validCompRef = new WeakReference<>(null); - private Reference validPaintRef = new WeakReference<>(null); + private Reference validSrcDataRef = null; + private Reference validDstDataRef = null; + private Reference validClipRef = null; + private Reference validCompRef = null; + private Reference validPaintRef = null; // renamed from isValidatedPaintAColor as part of a work around for 6764257 private boolean isValidatedPaintJustAColor; private int validatedRGB; @@ -213,20 +213,18 @@ public abstract class BufferedContext { updatePaint = true; isValidatedPaintJustAColor = true; } - } else if (validPaintRef.get() != paint) { + } else if (stateChanged(validPaintRef, paint)) { updatePaint = true; // this should be set when we are switching from paint to color // in which case this condition will be true isValidatedPaintJustAColor = false; } - final AccelSurface validatedSrcData = validSrcDataRef.get(); - final AccelSurface validatedDstData = validDstDataRef.get(); - if ((currentContext != this) || - (srcData != validatedSrcData) || - (dstData != validatedDstData)) + final boolean srcChanged = stateChanged(validSrcDataRef, srcData); + final boolean dstChanged = stateChanged(validDstDataRef, dstData); + if ((currentContext != this) || srcChanged || dstChanged) { - if (dstData != validatedDstData) { + if (dstChanged) { // the clip is dependent on the destination surface, so we // need to update it if we have a new destination surface updateClip = true; @@ -243,13 +241,13 @@ public abstract class BufferedContext { setSurfaces(srcData, dstData); currentContext = this; - validSrcDataRef = new WeakReference<>(srcData); - validDstDataRef = new WeakReference<>(dstData); + validSrcDataRef = wrapState(srcData); + validDstDataRef = wrapState(dstData); } // validate clip - final Region validatedClip = validClipRef.get(); - if ((clip != validatedClip) || updateClip) { + final Region validatedClip = validClipRef == null ? null : validClipRef.get(); + if (stateChanged(validClipRef, clip) || updateClip) { if (clip != null) { if (updateClip || validatedClip == null || @@ -264,13 +262,13 @@ public abstract class BufferedContext { } else { resetClip(); } - validClipRef = new WeakReference<>(clip); + validClipRef = wrapState(clip); } // validate composite (note that a change in the context flags // may require us to update the composite state, even if the // composite has not changed) - if ((comp != validCompRef.get()) || (flags != validatedFlags)) { + if (stateChanged(validCompRef, comp) || (flags != validatedFlags)) { if (comp != null) { setComposite(comp, flags); } else { @@ -279,7 +277,7 @@ public abstract class BufferedContext { // the paint state is dependent on the composite state, so make // sure we update the color below updatePaint = true; - validCompRef = new WeakReference<>(comp); + validCompRef = wrapState(comp); validatedFlags = flags; } @@ -313,7 +311,7 @@ public abstract class BufferedContext { } else { BufferedPaints.resetPaint(rq); } - validPaintRef = new WeakReference<>(paint); + validPaintRef = wrapState(paint); } // mark dstData dirty @@ -321,6 +319,18 @@ public abstract class BufferedContext { dstData.markDirty(); } + private static boolean stateChanged(Reference ref, T obj) { + // null ref means "true" null object + if (ref == null) return obj != null; + T old = ref.get(); + // null ref value means the object was GC'ed, return true in that case + return old == null || old != obj; + } + + private static Reference wrapState(T obj) { + return obj == null ? null : new WeakReference<>(obj); + } + private void setSurfaces(AccelSurface srcData, AccelSurface dstData) { @@ -434,11 +444,11 @@ public abstract class BufferedContext { resetComposite(); resetClip(); BufferedPaints.resetPaint(rq); - validSrcDataRef.clear(); - validDstDataRef.clear(); - validCompRef.clear(); - validClipRef.clear(); - validPaintRef.clear(); + validSrcDataRef = null; + validDstDataRef = null; + validCompRef = null; + validClipRef = null; + validPaintRef = null; isValidatedPaintJustAColor = false; xformInUse = false; } diff --git a/test/jdk/java/awt/ColorClass/WeakColorTest.java b/test/jdk/java/awt/ColorClass/WeakColorTest.java new file mode 100644 index 00000000000..d4adbc3f111 --- /dev/null +++ b/test/jdk/java/awt/ColorClass/WeakColorTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.lang.ref.WeakReference; + +import jtreg.SkippedException; + +/* + * @test + * @key headful + * @bug 8364434 + * @summary Check that garbage-collecting Color before accelerated painting is complete does not cause artifacts. + * @requires (os.family != "linux") + * @library /test/lib + * @run main/othervm -Xms16m -Xmx16m WeakColorTest + */ + +public class WeakColorTest { + public static void main(String[] args) throws Exception { + BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); // This image is full-black. + VolatileImage image = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration().createCompatibleVolatileImage(100, 100); + Graphics2D g = image.createGraphics(); + + // Create a new Color - we want it to be collected later. + g.setColor(new Color(255, 0, 0)); + WeakReference color = new WeakReference<>(g.getColor()); + + g.fillRect(0, 0, 100, 100); + + // Change color to prevent Graphics from keeping our Color alive. + g.setColor(Color.BLACK); + + // Force Color to be GC'ed. + final int MAX_ITERATIONS = 1000, ARRAY_SIZE = 1000000; + WeakReference array = null; + for (int i = 0;; i++) { + System.gc(); + if (color.get() == null) { + System.out.println("Color collected at: " + i); + break; + } else if (i >= MAX_ITERATIONS) { + throw new SkippedException("Color was not collected after " + MAX_ITERATIONS + " iterations"); + } + Object[] a = new Object[ARRAY_SIZE]; + a[0] = array; + array = new WeakReference<>(a); + } + + // Do a blit. If it succeeds, the resulting image will be full-black. + g.drawImage(bi, 0, 0, null); + g.dispose(); + + // We expect black. If it's red, then the blit must have failed. + int actualColor = image.getSnapshot().getRGB(50, 50); + if ((actualColor & 0xFFFFFF) != 0) throw new Error("Wrong color: 0x" + Integer.toHexString(actualColor)); + } +} From 38a261415dc29aae01c9b878d94cb302c60a3983 Mon Sep 17 00:00:00 2001 From: Srinivas Vamsi Parasa Date: Wed, 13 Aug 2025 17:53:05 +0000 Subject: [PATCH 071/471] 8365265: x86 short forward jump exceeds 8-bit offset in methodHandles_x86.cpp when using Intel APX Reviewed-by: shade, jbhateja, aph --- src/hotspot/cpu/x86/methodHandles_x86.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 0363cb04341..b921a157a52 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -137,7 +137,7 @@ void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Regist case vmIntrinsicID::_invokeBasic: // Require compiled LambdaForm class to be fully initialized. __ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); - __ jccb(Assembler::equal, L_ok); + __ jcc(Assembler::equal, L_ok); break; case vmIntrinsicID::_linkToStatic: @@ -154,7 +154,7 @@ void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Regist // init_state check failed, but it may be an abstract interface method __ load_unsigned_short(temp, Address(method, Method::access_flags_offset())); __ testl(temp, JVM_ACC_ABSTRACT); - __ jccb(Assembler::notZero, L_ok); + __ jcc(Assembler::notZero, L_ok); break; default: From ecbdd3405a1d46f555deb82098e1865b44601a1f Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 13 Aug 2025 18:24:56 +0000 Subject: [PATCH 072/471] 8361103: java_lang_Thread::async_get_stack_trace does not properly protect JavaThread Reviewed-by: sspitsyn, dholmes --- src/hotspot/share/classfile/javaClasses.cpp | 53 ++++++++++----------- src/hotspot/share/classfile/javaClasses.hpp | 2 +- src/hotspot/share/prims/jvm.cpp | 2 +- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 28bebee7d9a..5c41ea789b5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1899,33 +1899,29 @@ oop java_lang_Thread::park_blocker(oop java_thread) { return java_thread->obj_field_access(_park_blocker_offset); } -oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) { - ThreadsListHandle tlh(JavaThread::current()); - JavaThread* thread; - bool is_virtual = java_lang_VirtualThread::is_instance(java_thread); - if (is_virtual) { - oop carrier_thread = java_lang_VirtualThread::carrier_thread(java_thread); - if (carrier_thread == nullptr) { - return nullptr; - } - thread = java_lang_Thread::thread(carrier_thread); - } else { - thread = java_lang_Thread::thread(java_thread); - } - if (thread == nullptr) { +// Obtain stack trace for platform or mounted virtual thread. +// If jthread is a virtual thread and it has been unmounted (or remounted to different carrier) the method returns null. +// The caller (java.lang.VirtualThread) handles returned nulls via retry. +oop java_lang_Thread::async_get_stack_trace(jobject jthread, TRAPS) { + ThreadsListHandle tlh(THREAD); + JavaThread* java_thread = nullptr; + oop thread_oop; + + bool has_java_thread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop); + if (!has_java_thread) { return nullptr; } class GetStackTraceHandshakeClosure : public HandshakeClosure { public: - const Handle _java_thread; + const Handle _thread_h; int _depth; bool _retry_handshake; GrowableArray* _methods; GrowableArray* _bcis; - GetStackTraceHandshakeClosure(Handle java_thread) : - HandshakeClosure("GetStackTraceHandshakeClosure"), _java_thread(java_thread), _depth(0), _retry_handshake(false), + GetStackTraceHandshakeClosure(Handle thread_h) : + HandshakeClosure("GetStackTraceHandshakeClosure"), _thread_h(thread_h), _depth(0), _retry_handshake(false), _methods(nullptr), _bcis(nullptr) { } ~GetStackTraceHandshakeClosure() { @@ -1947,21 +1943,22 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) { return; } - JavaThread* thread = JavaThread::cast(th); + JavaThread* java_thread = JavaThread::cast(th); - if (!thread->has_last_Java_frame()) { + if (!java_thread->has_last_Java_frame()) { return; } bool carrier = false; - if (java_lang_VirtualThread::is_instance(_java_thread())) { - // if (thread->vthread() != _java_thread()) // We might be inside a System.executeOnCarrierThread - const ContinuationEntry* ce = thread->vthread_continuation(); - if (ce == nullptr || ce->cont_oop(thread) != java_lang_VirtualThread::continuation(_java_thread())) { - return; // not mounted + if (java_lang_VirtualThread::is_instance(_thread_h())) { + // Ensure _thread_h is still mounted to java_thread. + const ContinuationEntry* ce = java_thread->vthread_continuation(); + if (ce == nullptr || ce->cont_oop(java_thread) != java_lang_VirtualThread::continuation(_thread_h())) { + // Target thread has been unmounted. + return; } } else { - carrier = (thread->vthread_continuation() != nullptr); + carrier = (java_thread->vthread_continuation() != nullptr); } const int max_depth = MaxJavaStackTraceDepth; @@ -1973,7 +1970,7 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) { _bcis = new (mtInternal) GrowableArray(init_length, mtInternal); int total_count = 0; - for (vframeStream vfst(thread, false, false, carrier); // we don't process frames as we don't care about oops + for (vframeStream vfst(java_thread, false, false, carrier); // we don't process frames as we don't care about oops !vfst.at_end() && (max_depth == 0 || max_depth != total_count); vfst.next()) { @@ -1994,9 +1991,9 @@ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) { // Handshake with target ResourceMark rm(THREAD); HandleMark hm(THREAD); - GetStackTraceHandshakeClosure gsthc(Handle(THREAD, java_thread)); + GetStackTraceHandshakeClosure gsthc(Handle(THREAD, thread_oop)); do { - Handshake::execute(&gsthc, &tlh, thread); + Handshake::execute(&gsthc, &tlh, java_thread); } while (gsthc.read_reset_retry()); // Stop if no stack trace is found. diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index faa325d55dd..70fa519f0f0 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -463,7 +463,7 @@ class java_lang_Thread : AllStatic { static const char* thread_status_name(oop java_thread_oop); // Fill in current stack trace, can cause GC - static oop async_get_stack_trace(oop java_thread, TRAPS); + static oop async_get_stack_trace(jobject jthread, TRAPS); JFR_ONLY(static u2 jfr_epoch(oop java_thread);) JFR_ONLY(static void set_jfr_epoch(oop java_thread, u2 epoch);) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 005776b00c2..098bd729c0b 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2945,7 +2945,7 @@ JVM_ENTRY(jboolean, JVM_HoldsLock(JNIEnv* env, jclass threadClass, jobject obj)) JVM_END JVM_ENTRY(jobject, JVM_GetStackTrace(JNIEnv *env, jobject jthread)) - oop trace = java_lang_Thread::async_get_stack_trace(JNIHandles::resolve(jthread), THREAD); + oop trace = java_lang_Thread::async_get_stack_trace(jthread, THREAD); return JNIHandles::make_local(THREAD, trace); JVM_END From 4680dc983169d48fcf83eb50dc60e32e79d5d976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Wed, 13 Aug 2025 18:41:57 +0000 Subject: [PATCH 073/471] 8365264: Rename ResourceHashtable to HashTable Reviewed-by: iklam, ayang --- src/hotspot/share/asm/codeBuffer.hpp | 4 +- src/hotspot/share/cds/aotArtifactFinder.cpp | 4 +- src/hotspot/share/cds/aotClassLinker.hpp | 4 +- .../share/cds/aotConstantPoolResolver.hpp | 4 +- .../share/cds/aotReferenceObjSupport.cpp | 4 +- src/hotspot/share/cds/archiveBuilder.hpp | 8 +- src/hotspot/share/cds/archiveHeapLoader.cpp | 6 +- src/hotspot/share/cds/archiveHeapWriter.cpp | 2 +- src/hotspot/share/cds/archiveHeapWriter.hpp | 4 +- src/hotspot/share/cds/cdsHeapVerifier.hpp | 6 +- src/hotspot/share/cds/classListParser.hpp | 4 +- src/hotspot/share/cds/classListWriter.cpp | 2 +- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 2 +- src/hotspot/share/cds/heapShared.hpp | 12 +-- .../share/cds/lambdaProxyClassDictionary.hpp | 4 +- src/hotspot/share/cds/metaspaceShared.cpp | 4 +- src/hotspot/share/cds/regeneratedClasses.cpp | 4 +- .../share/classfile/bytecodeAssembler.hpp | 5 +- .../share/classfile/classFileParser.cpp | 8 +- .../share/classfile/classLoaderStats.hpp | 6 +- .../share/classfile/loaderConstraints.cpp | 4 +- src/hotspot/share/classfile/moduleEntry.cpp | 4 +- src/hotspot/share/classfile/moduleEntry.hpp | 4 +- src/hotspot/share/classfile/packageEntry.cpp | 4 +- src/hotspot/share/classfile/packageEntry.hpp | 4 +- src/hotspot/share/classfile/placeholders.cpp | 4 +- .../share/classfile/resolutionErrors.cpp | 4 +- src/hotspot/share/classfile/stringTable.cpp | 4 +- .../share/classfile/systemDictionary.cpp | 4 +- .../classfile/systemDictionaryShared.cpp | 5 +- src/hotspot/share/classfile/verifier.hpp | 4 +- src/hotspot/share/code/codeCache.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 2 +- src/hotspot/share/compiler/disassembler.cpp | 5 +- src/hotspot/share/gc/z/zVerify.cpp | 4 +- .../methodtracer/jfrClassFilterClosure.cpp | 2 +- .../methodtracer/jfrClassFilterClosure.hpp | 4 +- .../support/methodtracer/jfrMethodTracer.cpp | 2 +- src/hotspot/share/jfr/utilities/jfrSet.hpp | 4 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 6 +- src/hotspot/share/logging/logAsyncWriter.hpp | 6 +- src/hotspot/share/memory/metaspaceClosure.hpp | 4 +- .../share/nmt/nativeCallStackPrinter.hpp | 4 +- src/hotspot/share/oops/constantPool.hpp | 4 +- src/hotspot/share/oops/instanceKlass.cpp | 2 +- src/hotspot/share/oops/trainingData.hpp | 6 +- src/hotspot/share/opto/compile.cpp | 8 +- src/hotspot/share/opto/loopnode.hpp | 2 +- src/hotspot/share/opto/mempointer.cpp | 2 +- src/hotspot/share/opto/node.hpp | 2 +- .../share/opto/superwordVTransformBuilder.hpp | 2 +- src/hotspot/share/prims/foreignGlobals.cpp | 4 +- src/hotspot/share/prims/jvmtiTagMapTable.hpp | 8 +- src/hotspot/share/runtime/arguments.hpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 4 +- src/hotspot/share/runtime/synchronizer.hpp | 2 +- src/hotspot/share/runtime/threadSMR.cpp | 8 +- src/hotspot/share/runtime/vmOperations.cpp | 6 +- src/hotspot/share/services/heapDumper.cpp | 4 +- .../share/utilities/globalDefinitions.hpp | 2 +- .../{resourceHash.hpp => hashTable.hpp} | 48 +++++------ .../share/utilities/nativeCallStack.hpp | 2 +- src/hotspot/share/utilities/objectBitSet.hpp | 4 +- .../share/utilities/objectBitSet.inline.hpp | 4 +- ...esourceHash.hpp => resizableHashTable.hpp} | 28 +++---- .../gtest/runtime/test_os_reserve_between.cpp | 4 +- ...st_resourceHash.cpp => test_hashtable.cpp} | 82 +++++++++---------- 68 files changed, 214 insertions(+), 215 deletions(-) rename src/hotspot/share/utilities/{resourceHash.hpp => hashTable.hpp} (89%) rename src/hotspot/share/utilities/{resizeableResourceHash.hpp => resizableHashTable.hpp} (86%) rename test/hotspot/gtest/utilities/{test_resourceHash.cpp => test_hashtable.cpp} (82%) diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index ec9f347e334..57b4aaacdce 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -33,7 +33,7 @@ #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" #include "utilities/linkedlist.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" #include "utilities/macros.hpp" template @@ -541,7 +541,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { }; typedef LinkedListImpl Offsets; - typedef ResizeableResourceHashtable SharedTrampolineRequests; + typedef ResizeableHashTable SharedTrampolineRequests; private: enum { diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index adcc4bfb50a..a42d8882099 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -37,7 +37,7 @@ #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/trainingData.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" // All the classes that should be included in the AOT cache (in at least the "allocated" state) static GrowableArrayCHeap* _all_cached_classes = nullptr; @@ -47,7 +47,7 @@ static GrowableArrayCHeap* _all_cached_classes = nullptr; static GrowableArrayCHeap* _pending_aot_inited_classes = nullptr; static const int TABLE_SIZE = 15889; // prime number -using ClassesTable = ResourceHashtable; +using ClassesTable = HashTable; static ClassesTable* _seen_classes; // all classes that have been seen by AOTArtifactFinder static ClassesTable* _aot_inited_classes; // all classes that need to be AOT-initialized. diff --git a/src/hotspot/share/cds/aotClassLinker.hpp b/src/hotspot/share/cds/aotClassLinker.hpp index f15684a1ad2..7bbc9ce8138 100644 --- a/src/hotspot/share/cds/aotClassLinker.hpp +++ b/src/hotspot/share/cds/aotClassLinker.hpp @@ -31,8 +31,8 @@ #include "oops/oopsHierarchy.hpp" #include "utilities/exceptions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" class AOTLinkedClassTable; class InstanceKlass; @@ -69,7 +69,7 @@ enum class AOTLinkedClassCategory : int; // class AOTClassLinker : AllStatic { static const int TABLE_SIZE = 15889; // prime number - using ClassesTable = ResourceHashtable; + using ClassesTable = HashTable; // Classes loaded inside vmClasses::resolve_all() static ClassesTable* _vm_classes; diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.hpp b/src/hotspot/share/cds/aotConstantPoolResolver.hpp index bab9e263a22..e49d9d1ad0b 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.hpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.hpp @@ -31,8 +31,8 @@ #include "oops/oopsHierarchy.hpp" #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" class ConstantPool; class constantPoolHandle; @@ -53,7 +53,7 @@ template class GrowableArray; // if all of its supertypes are loaded from the CDS archive. class AOTConstantPoolResolver : AllStatic { static const int TABLE_SIZE = 15889; // prime number - using ClassesTable = ResourceHashtable ; + using ClassesTable = HashTable ; static ClassesTable* _processed_classes; #ifdef ASSERT diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.cpp b/src/hotspot/share/cds/aotReferenceObjSupport.cpp index a62e9c7735a..b43c766b8db 100644 --- a/src/hotspot/share/cds/aotReferenceObjSupport.cpp +++ b/src/hotspot/share/cds/aotReferenceObjSupport.cpp @@ -35,7 +35,7 @@ #include "oops/oopHandle.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/javaCalls.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" // Handling of java.lang.ref.Reference objects in the AOT cache // ============================================================ @@ -92,7 +92,7 @@ #if INCLUDE_CDS_JAVA_HEAP -class KeepAliveObjectsTable : public ResourceHashtable _src_obj_table; - ResizeableResourceHashtable _buffered_to_src_table; + ResizeableHashTable _src_obj_table; + ResizeableHashTable _buffered_to_src_table; GrowableArray* _klasses; GrowableArray* _symbols; unsigned int _entropy_seed; diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 181fa6b2bb4..673c4baa6f6 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -348,10 +348,10 @@ bool ArchiveHeapLoader::load_heap_region(FileMapInfo* mapinfo) { } class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure { - ResourceHashtable* _table; + HashTable* _table; public: - VerifyLoadedHeapEmbeddedPointers(ResourceHashtable* table) : _table(table) {} + VerifyLoadedHeapEmbeddedPointers(HashTable* table) : _table(table) {} virtual void do_oop(narrowOop* p) { // This should be called before the loaded region is modified, so all the embedded pointers @@ -411,7 +411,7 @@ void ArchiveHeapLoader::verify_loaded_heap() { log_info(aot, heap)("Verify all oops and pointers in loaded heap"); ResourceMark rm; - ResourceHashtable table; + HashTable table; VerifyLoadedHeapEmbeddedPointers verifier(&table); HeapWord* bottom = (HeapWord*)_loaded_heap_bottom; HeapWord* top = (HeapWord*)_loaded_heap_top; diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index db93027e348..b651da8418b 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -70,7 +70,7 @@ ArchiveHeapWriter::BufferOffsetToSourceObjectTable* ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr; -typedef ResourceHashtable< +typedef HashTable< size_t, // offset of a filler from ArchiveHeapWriter::buffer_bottom() size_t, // size of this filler (in bytes) 127, // prime number diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 1e1319cccc3..f8f55a745ee 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -32,8 +32,8 @@ #include "utilities/bitMap.hpp" #include "utilities/exceptions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" class MemRegion; @@ -152,7 +152,7 @@ private: }; static GrowableArrayCHeap* _source_objs_order; - typedef ResizeableResourceHashtable BufferOffsetToSourceObjectTable; static BufferOffsetToSourceObjectTable* _buffer_offset_to_source_obj_table; diff --git a/src/hotspot/share/cds/cdsHeapVerifier.hpp b/src/hotspot/share/cds/cdsHeapVerifier.hpp index c53f913e42b..811751e8ca2 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.hpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.hpp @@ -28,7 +28,7 @@ #include "cds/heapShared.hpp" #include "memory/iterator.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" class InstanceKlass; class Symbol; @@ -47,7 +47,7 @@ class CDSHeapVerifier : public KlassClosure { Symbol* _name; }; - ResourceHashtable ID2KlassTable; enum { diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index c1ac1b47b11..727cc03c216 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -66,7 +66,7 @@ void ClassListWriter::write(const InstanceKlass* k, const ClassFileStream* cfs) write_to_stream(k, w.stream(), cfs); } -class ClassListWriter::IDTable : public ResourceHashtable< +class ClassListWriter::IDTable : public HashTable< const InstanceKlass*, int, 15889, // prime number AnyObj::C_HEAP> {}; diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 0bb60dfbb29..0feed8682da 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -240,7 +240,7 @@ inline unsigned DumpTimeSharedClassTable_hash(T* const& k) { } } -using DumpTimeSharedClassTableBaseType = ResourceHashtable< +using DumpTimeSharedClassTableBaseType = HashTable< InstanceKlass*, DumpTimeClassInfo, 15889, // prime number diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 51572bcace7..ea9368c9277 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -367,7 +367,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra } } -class MetaspaceObjToOopHandleTable: public ResourceHashtable { diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index f4e86aa5895..c0e89809274 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -37,7 +37,7 @@ #include "oops/oopHandle.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" #if INCLUDE_CDS_JAVA_HEAP class DumpedInternedStrings; @@ -202,14 +202,14 @@ public: private: static const int INITIAL_TABLE_SIZE = 15889; // prime number static const int MAX_TABLE_SIZE = 1000000; - typedef ResizeableResourceHashtable ArchivedObjectCache; static ArchivedObjectCache* _archived_object_cache; class DumpTimeKlassSubGraphInfoTable - : public ResourceHashtable SeenObjectsTable; @@ -468,14 +468,14 @@ private: #if INCLUDE_CDS_JAVA_HEAP class DumpedInternedStrings : - public ResizeableResourceHashtable { public: DumpedInternedStrings(unsigned size, unsigned max_size) : - ResizeableResourceHashtable(size, max_size) {} diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp index 814dda80827..ff7acb15292 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp @@ -30,7 +30,7 @@ #include "classfile/javaClasses.hpp" #include "memory/metaspaceClosure.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" // This file contains *legacy* optimization for lambdas before JEP 483. May be removed in the future. // @@ -249,7 +249,7 @@ public: }; class DumpTimeLambdaProxyClassDictionary - : public ResourceHashtable @@ -178,7 +178,7 @@ class DumpClassListCLDClosure : public CLDClosure { static const int MAX_TABLE_SIZE = 61333; fileStream *_stream; - ResizeableResourceHashtable _dumped_classes; void dump(InstanceKlass* ik) { diff --git a/src/hotspot/share/cds/regeneratedClasses.cpp b/src/hotspot/share/cds/regeneratedClasses.cpp index b36f360b82a..ae14866cea5 100644 --- a/src/hotspot/share/cds/regeneratedClasses.cpp +++ b/src/hotspot/share/cds/regeneratedClasses.cpp @@ -32,9 +32,9 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" -using RegeneratedObjTable = ResourceHashtable; +using RegeneratedObjTable = HashTable; static RegeneratedObjTable* _regenerated_objs = nullptr; // InstanceKlass* and Method* orig_obj -> regen_obj static RegeneratedObjTable* _original_objs = nullptr; // InstanceKlass* and Method* regen_obj -> orig_obj static GrowableArrayCHeap* _regenerated_mirrors = nullptr; diff --git a/src/hotspot/share/classfile/bytecodeAssembler.hpp b/src/hotspot/share/classfile/bytecodeAssembler.hpp index fb51924a9c6..c0383a9678c 100644 --- a/src/hotspot/share/classfile/bytecodeAssembler.hpp +++ b/src/hotspot/share/classfile/bytecodeAssembler.hpp @@ -30,8 +30,7 @@ #include "oops/symbol.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" - +#include "utilities/hashTable.hpp" /** * Bytecode Assembler @@ -125,7 +124,7 @@ class BytecodeCPEntry { class BytecodeConstantPool : public ResourceObj { private: - typedef ResourceHashtable IndexHash; diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 9aca20ee29f..c678fa5e058 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -81,9 +81,9 @@ #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -#include "utilities/resourceHash.hpp" #include "utilities/utf8.hpp" #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" @@ -782,7 +782,7 @@ class NameSigHash: public ResourceObj { } }; -using NameSigHashtable = ResourceHashtable; @@ -849,7 +849,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream, // Check if there's any duplicates in interfaces ResourceMark rm(THREAD); // Set containing interface names - ResourceHashtable* interface_names = new ResourceHashtable(); + HashTable* interface_names = new HashTable(); for (index = 0; index < itfs_len; index++) { const InstanceKlass* const k = _local_interfaces->at(index); Symbol* interface_name = k->name(); @@ -2022,7 +2022,7 @@ void ClassFileParser::copy_localvariable_table(const ConstMethod* cm, ResourceMark rm(THREAD); - typedef ResourceHashtable LVT_HashTable; diff --git a/src/hotspot/share/classfile/classLoaderStats.hpp b/src/hotspot/share/classfile/classLoaderStats.hpp index 06d375b3e9b..23da6bff63c 100644 --- a/src/hotspot/share/classfile/classLoaderStats.hpp +++ b/src/hotspot/share/classfile/classLoaderStats.hpp @@ -25,15 +25,13 @@ #ifndef SHARE_CLASSFILE_CLASSLOADERSTATS_HPP #define SHARE_CLASSFILE_CLASSLOADERSTATS_HPP - #include "classfile/classLoaderData.hpp" #include "oops/klass.hpp" #include "oops/oop.hpp" #include "oops/oopsHierarchy.hpp" #include "runtime/vmOperation.hpp" #include "services/diagnosticCommand.hpp" -#include "utilities/resourceHash.hpp" - +#include "utilities/hashTable.hpp" class ClassLoaderStatsDCmd : public DCmd { public: @@ -105,7 +103,7 @@ protected: return hash; } - typedef ResourceHashtable StatsTable; diff --git a/src/hotspot/share/classfile/loaderConstraints.cpp b/src/hotspot/share/classfile/loaderConstraints.cpp index 21161f44326..13c1ff7319d 100644 --- a/src/hotspot/share/classfile/loaderConstraints.cpp +++ b/src/hotspot/share/classfile/loaderConstraints.cpp @@ -31,7 +31,7 @@ #include "oops/klass.inline.hpp" #include "oops/symbolHandle.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" // Overview // @@ -147,7 +147,7 @@ class ConstraintSet { // copied into hashtable as }; -using InternalLoaderConstraintTable = ResourceHashtable; +using InternalLoaderConstraintTable = HashTable; static InternalLoaderConstraintTable* _loader_constraint_table; void LoaderConstraint::extend_loader_constraint(Symbol* class_name, diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 7f9bf09aa51..ce887081cdb 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -45,9 +45,9 @@ #include "runtime/safepoint.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" #include "utilities/quickSort.hpp" -#include "utilities/resourceHash.hpp" ModuleEntry* ModuleEntryTable::_javabase_module = nullptr; @@ -403,7 +403,7 @@ void ModuleEntry::set_loader_data(ClassLoaderData* cld) { } #if INCLUDE_CDS_JAVA_HEAP -typedef ResourceHashtable< +typedef HashTable< const ModuleEntry*, ModuleEntry*, 557, // prime number diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 1ae504577e3..1074c88f010 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -31,9 +31,9 @@ #include "oops/symbolHandle.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -#include "utilities/resourceHash.hpp" #if INCLUDE_JFR #include "jfr/support/jfrTraceIdExtension.hpp" #endif @@ -233,7 +233,7 @@ class ModuleClosure: public StackObj { class ModuleEntryTable : public CHeapObj { private: static ModuleEntry* _javabase_module; - ResourceHashtable _table; public: diff --git a/src/hotspot/share/classfile/packageEntry.cpp b/src/hotspot/share/classfile/packageEntry.cpp index 9a21578630f..ea2e6cd1def 100644 --- a/src/hotspot/share/classfile/packageEntry.cpp +++ b/src/hotspot/share/classfile/packageEntry.cpp @@ -38,9 +38,9 @@ #include "runtime/java.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" #include "utilities/quickSort.hpp" -#include "utilities/resourceHash.hpp" PackageEntry::PackageEntry(Symbol* name, ModuleEntry* module) : _name(name), @@ -212,7 +212,7 @@ PackageEntryTable::~PackageEntryTable() { } #if INCLUDE_CDS_JAVA_HEAP -typedef ResourceHashtable< +typedef HashTable< const PackageEntry*, PackageEntry*, 557, // prime number diff --git a/src/hotspot/share/classfile/packageEntry.hpp b/src/hotspot/share/classfile/packageEntry.hpp index aa572dc15b2..84620785ebb 100644 --- a/src/hotspot/share/classfile/packageEntry.hpp +++ b/src/hotspot/share/classfile/packageEntry.hpp @@ -30,9 +30,9 @@ #include "oops/symbolHandle.hpp" #include "runtime/atomic.hpp" #include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -#include "utilities/resourceHash.hpp" #if INCLUDE_JFR #include "jfr/support/jfrTraceIdExtension.hpp" #endif @@ -233,7 +233,7 @@ public: // The PackageEntryTable is a Hashtable containing a list of all packages defined // by a particular class loader. Each package is represented as a PackageEntry node. class PackageEntryTable : public CHeapObj { - ResourceHashtable _table; public: PackageEntryTable(); diff --git a/src/hotspot/share/classfile/placeholders.cpp b/src/hotspot/share/classfile/placeholders.cpp index b2f1ed40106..f4c381eafdf 100644 --- a/src/hotspot/share/classfile/placeholders.cpp +++ b/src/hotspot/share/classfile/placeholders.cpp @@ -31,7 +31,7 @@ #include "oops/symbolHandle.hpp" #include "runtime/javaThread.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" class PlaceholderKey { SymbolHandle _name; @@ -49,7 +49,7 @@ class PlaceholderKey { }; const int _placeholder_table_size = 503; // Does this really have to be prime? -using InternalPlaceholderTable = ResourceHashtable; static InternalPlaceholderTable* _placeholders; diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index 03af71bc26f..25aa370d257 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -30,7 +30,7 @@ #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" class ResolutionErrorKey { ConstantPool* _cpool; @@ -53,7 +53,7 @@ class ResolutionErrorKey { } }; -using InternalResolutionErrorTable = ResourceHashtable; diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 957ecd8ebe8..cf5d98650ce 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -59,7 +59,7 @@ #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" #include "utilities/macros.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" #include "utilities/utf8.hpp" #if INCLUDE_G1GC #include "gc/g1/g1CollectedHeap.hpp" @@ -810,7 +810,7 @@ class StringTable::VerifyCompStrings : StackObj { return java_lang_String::equals(a, b); } - ResizeableResourceHashtable _table; public: size_t _errors; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index f482a5bb303..783ae9d35ba 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -111,10 +111,10 @@ class InvokeMethodKey : public StackObj { }; -using InvokeMethodIntrinsicTable = ResourceHashtable; static InvokeMethodIntrinsicTable* _invoke_method_intrinsic_table; -using InvokeMethodTypeTable = ResourceHashtable; +using InvokeMethodTypeTable = HashTable; static InvokeMethodTypeTable* _invoke_method_type_table; OopHandle SystemDictionary::_java_system_loader; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 7dd3a7d1bb2..1845c28d819 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -22,6 +22,7 @@ * */ + #include "cds/aotClassFilter.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" @@ -74,7 +75,7 @@ #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" #include "utilities/stringUtils.hpp" SystemDictionaryShared::ArchiveInfo SystemDictionaryShared::_static_archive; @@ -445,7 +446,7 @@ InstanceKlass* SystemDictionaryShared::find_or_load_shared_class( return k; } -class UnregisteredClassesTable : public ResourceHashtable< +class UnregisteredClassesTable : public HashTable< Symbol*, InstanceKlass*, 15889, // prime number AnyObj::C_HEAP> {}; diff --git a/src/hotspot/share/classfile/verifier.hpp b/src/hotspot/share/classfile/verifier.hpp index 7857d472705..87ea8bd2970 100644 --- a/src/hotspot/share/classfile/verifier.hpp +++ b/src/hotspot/share/classfile/verifier.hpp @@ -31,7 +31,7 @@ #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" // The verifier class class Verifier : AllStatic { @@ -270,7 +270,7 @@ class sig_as_verification_types : public ResourceObj { // This hashtable is indexed by the Utf8 constant pool indexes pointed to // by constant pool (Interface)Method_refs' NameAndType signature entries. -typedef ResourceHashtable +typedef HashTable method_signatures_table_type; // A new instance of this class is created for each class being verified diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index f7c86ce58fa..8f2932f6abc 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1185,7 +1185,7 @@ static void check_live_nmethods_dependencies(DepChange& changes) { // Turn off dependency tracing while actually testing dependencies. FlagSetting fs(Dependencies::_verify_in_progress, true); - typedef ResourceHashtable DepTable; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index d8cbf6b9e66..b8b3a70bf58 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -79,7 +79,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" #include "utilities/xmlstream.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmciRuntime.hpp" diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp index f8313db66aa..c79c15e0f32 100644 --- a/src/hotspot/share/compiler/disassembler.cpp +++ b/src/hotspot/share/compiler/disassembler.cpp @@ -22,6 +22,7 @@ * */ + #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.hpp" #include "ci/ciUtilities.hpp" @@ -40,7 +41,7 @@ #include "runtime/os.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" void* Disassembler::_library = nullptr; bool Disassembler::_tried_to_load_library = false; @@ -189,7 +190,7 @@ class decode_env { } }; - typedef ResourceHashtable< + typedef HashTable< address, SourceFileInfo, 15889, // prime number AnyObj::C_HEAP> SourceFileInfoTable; diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 68290c2c009..53cbcd0a421 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -51,8 +51,8 @@ #include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/hashTable.hpp" #include "utilities/preserveException.hpp" -#include "utilities/resourceHash.hpp" #include "utilities/vmError.hpp" #ifdef ASSERT @@ -516,7 +516,7 @@ void ZVerify::after_weak_processing() { // Remembered set verification // -typedef ResourceHashtable ZStoreBarrierBufferTable; +typedef HashTable ZStoreBarrierBufferTable; static ZStoreBarrierBufferTable* z_verify_store_barrier_buffer_table = nullptr; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp index 37f2d438bc6..dc2908e8a81 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.cpp @@ -33,7 +33,7 @@ #include "oops/instanceKlass.inline.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/growableArray.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" constexpr static unsigned int TABLE_SIZE = 1009; constexpr static unsigned int MAX_TABLE_SIZE = 0x3fffffff; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp index a23b27eb12a..6cf1b321f1e 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp @@ -40,7 +40,7 @@ template class GrowableArray; template class ResizeableResourceHashtable; + bool (*EQUALS)(K const&, K const&)> class ResizeableHashTable; // Knuth multiplicative hashing. inline uint32_t knuth_hash(const traceid& id) { @@ -48,7 +48,7 @@ inline uint32_t knuth_hash(const traceid& id) { return v * UINT32_C(2654435761); } -typedef ResizeableResourceHashtable* JfrMethodTracer::_instrumented_classes = nullptr; diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index b4dfc4f6240..40a5d73f370 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -27,7 +27,7 @@ #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrTypes.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" template class ConfigTraceID : public AllStatic { @@ -60,7 +60,7 @@ template class JfrSet : public CONFIG::STORAGE { public: typedef typename CONFIG::TYPE TYPE; - typedef ResizeableResourceHashtable HashMap; + typedef ResizeableHashTable HashMap; constexpr static bool is_cheap() { return CONFIG::alloc_type() == AnyObj::C_HEAP; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 753d673f54c..801a9bf8eb4 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -51,7 +51,7 @@ #include "runtime/flags/jvmFlag.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" #if INCLUDE_SHENANDOAHGC #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" @@ -437,8 +437,8 @@ JVMCIObjectArray CompilerToVM::initialize_intrinsics(JVMCI_TRAPS) { jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS) { JavaThread* THREAD = JavaThread::current(); // For exception macros. - ResourceHashtable longs; - ResourceHashtable longs; + HashTable strings; diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index 5ffd9dc7b33..a93b1ca58f6 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -29,10 +29,10 @@ #include "logging/logMessageBuffer.hpp" #include "memory/allocation.hpp" #include "runtime/mutex.hpp" -#include "runtime/os.inline.hpp" #include "runtime/nonJavaThread.hpp" +#include "runtime/os.inline.hpp" #include "runtime/semaphore.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" class LogFileStreamOutput; @@ -66,7 +66,7 @@ class AsyncLogWriter : public NonJavaThread { // account for dropped messages template - using AsyncLogMap = ResourceHashtable; diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index 8b419034093..c35363eb71f 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -33,7 +33,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" #include // The metadata hierarchy is separate from the oop hierarchy @@ -374,7 +374,7 @@ public: UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE) {} private: - ResizeableResourceHashtable _has_been_visited; }; diff --git a/src/hotspot/share/nmt/nativeCallStackPrinter.hpp b/src/hotspot/share/nmt/nativeCallStackPrinter.hpp index 78fd541fc98..12bd1176485 100644 --- a/src/hotspot/share/nmt/nativeCallStackPrinter.hpp +++ b/src/hotspot/share/nmt/nativeCallStackPrinter.hpp @@ -29,7 +29,7 @@ #include "memory/arena.hpp" #include "nmt/memTag.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" class outputStream; class NativeCallStack; @@ -41,7 +41,7 @@ class NativeCallStackPrinter { // Cache-related data are mutable to be able to use NativeCallStackPrinter as // inline member in classes with const printing methods. mutable Arena _text_storage; - mutable ResourceHashtable _cache; + mutable HashTable _cache; outputStream* const _out; public: NativeCallStackPrinter(outputStream* out); diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index be4a7a474d4..8999acf4d3a 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -37,8 +37,8 @@ #include "utilities/align.hpp" #include "utilities/bytes.hpp" #include "utilities/constantTag.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" // A ConstantPool is an array containing class constants as described in the // class file. @@ -872,7 +872,7 @@ private: private: class SymbolHash: public CHeapObj { - ResourceHashtable _table; + HashTable _table; public: void add_if_absent(const Symbol* sym, u2 value) { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 9266e8ca091..dcec45ff4e2 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1116,7 +1116,7 @@ void InstanceKlass::initialize_super_interfaces(TRAPS) { } } -using InitializationErrorTable = ResourceHashtable; +using InitializationErrorTable = HashTable; static InitializationErrorTable* _initialization_error_table; void InstanceKlass::add_initialization_error(JavaThread* current, Handle exception) { diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index b4fd5fd61ab..baf19773a7b 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -37,7 +37,7 @@ #include "oops/objArrayKlass.hpp" #include "runtime/handles.hpp" #include "runtime/mutexLocker.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" class ciEnv; class ciBaseObject; @@ -173,7 +173,7 @@ public: // A set of TD objects that we collect during the training run. class TrainingDataSet { friend TrainingData; - ResizeableResourceHashtable @@ -229,7 +229,7 @@ public: // A widget to ensure that we visit TD object only once (TD objects can have pointer to // other TD object that are sometimes circular). class Visitor { - ResizeableResourceHashtable _visited; + ResizeableHashTable _visited; public: Visitor(unsigned size) : _visited(size, 0x3fffffff) { } bool is_visited(TrainingData* td) { diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 5a4a6c2667d..cef7aa61219 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -87,8 +87,8 @@ #include "runtime/timer.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" // -------------------- Compile::mach_constant_base_node ----------------------- // Constant table base node singleton. @@ -2786,7 +2786,7 @@ uint Compile::eval_macro_logic_op(uint func, uint in1 , uint in2, uint in3) { return res; } -static uint eval_operand(Node* n, ResourceHashtable& eval_map) { +static uint eval_operand(Node* n, HashTable& eval_map) { assert(n != nullptr, ""); assert(eval_map.contains(n), "absent"); return *(eval_map.get(n)); @@ -2794,7 +2794,7 @@ static uint eval_operand(Node* n, ResourceHashtable& eval_map) { static void eval_operands(Node* n, uint& func1, uint& func2, uint& func3, - ResourceHashtable& eval_map) { + HashTable& eval_map) { assert(is_vector_bitwise_op(n), ""); if (is_vector_unary_bitwise_op(n)) { @@ -2818,7 +2818,7 @@ uint Compile::compute_truth_table(Unique_Node_List& partition, Unique_Node_List& assert(inputs.size() <= 3, "sanity"); ResourceMark rm; uint res = 0; - ResourceHashtable eval_map; + HashTable eval_map; // Populate precomputed functions for inputs. // Each input corresponds to one column of 3 input truth-table. diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 27e397790d4..730f0750159 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1982,7 +1982,7 @@ class DataNodeGraph : public StackObj { DataNodeGraph(const Unique_Node_List& data_nodes, PhaseIdealLoop* phase) : _phase(phase), _data_nodes(data_nodes), - // Use 107 as best guess which is the first resize value in ResizeableResourceHashtable::large_table_sizes. + // Use 107 as best guess which is the first resize value in ResizeableHashTable::large_table_sizes. _orig_to_new(107, MaxNodeLimit) { #ifdef ASSERT diff --git a/src/hotspot/share/opto/mempointer.cpp b/src/hotspot/share/opto/mempointer.cpp index e400e40e4a2..0dadc14a686 100644 --- a/src/hotspot/share/opto/mempointer.cpp +++ b/src/hotspot/share/opto/mempointer.cpp @@ -25,7 +25,7 @@ #include "classfile/vmSymbols.hpp" #include "opto/addnode.hpp" #include "opto/mempointer.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" MemPointerParserCallback MemPointerParserCallback::_empty; diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index dc0ac474c4b..c2b3c4fb0ad 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -222,7 +222,7 @@ typedef Node** DUIterator_Fast; typedef Node** DUIterator_Last; #endif -typedef ResizeableResourceHashtable OrigToNewHashtable; +typedef ResizeableHashTable OrigToNewHashtable; // Node Sentinel #define NodeSentinel (Node*)-1 diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index ecec380fbfe..f2198113d31 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -35,7 +35,7 @@ private: const PackSet& _packset; VTransform& _vtransform; - ResourceHashtable _idx_to_vtnode; + HashTable _idx_to_vtnode; public: SuperWordVTransformBuilder(const PackSet& packset, diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp index d3d0c2cefae..f8aa73bed05 100644 --- a/src/hotspot/share/prims/foreignGlobals.cpp +++ b/src/hotspot/share/prims/foreignGlobals.cpp @@ -26,7 +26,7 @@ #include "memory/resourceArea.hpp" #include "prims/foreignGlobals.inline.hpp" #include "runtime/jniHandles.inline.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" StubLocations::StubLocations() { for (uint32_t i = 0; i < LOCATION_LIMIT; i++) { @@ -201,7 +201,7 @@ class ArgumentShuffle::ComputeMoveOrder: public StackObj { return a.type() == b.type() && a.index_or_offset() == b.index_or_offset(); } - using KillerTable = ResourceHashtable< + using KillerTable = HashTable< VMStorage, MoveOperation*, 32, // doesn't need to be big. don't have that many argument registers (in known ABIs) AnyObj::RESOURCE_AREA, diff --git a/src/hotspot/share/prims/jvmtiTagMapTable.hpp b/src/hotspot/share/prims/jvmtiTagMapTable.hpp index f86b6386a9a..f717552da2b 100644 --- a/src/hotspot/share/prims/jvmtiTagMapTable.hpp +++ b/src/hotspot/share/prims/jvmtiTagMapTable.hpp @@ -28,7 +28,7 @@ #include "gc/shared/collectedHeap.hpp" #include "memory/allocation.hpp" #include "oops/weakHandle.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" class JvmtiEnv; class JvmtiTagMapKeyClosure; @@ -65,14 +65,14 @@ class JvmtiTagMapKey : public CHeapObj { }; typedef -ResizeableResourceHashtable ResizableResourceHT; + JvmtiTagMapKey::equals> ResizableHT; class JvmtiTagMapTable : public CHeapObj { private: - ResizableResourceHT _table; + ResizableHT _table; public: JvmtiTagMapTable(); diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 5eb9601e4c5..3d83959d76a 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -27,8 +27,8 @@ #include "logging/logLevel.hpp" #include "logging/logTag.hpp" -#include "memory/allStatic.hpp" #include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 149ebef4294..beed5df5254 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -80,7 +80,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" #include "utilities/xmlstream.hpp" #ifdef COMPILER1 @@ -2450,7 +2450,7 @@ class ArchivedAdapterTable : public OffsetCompactHashtable< #endif // INCLUDE_CDS // A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries -using AdapterHandlerTable = ResourceHashtable; diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 089a432a8b5..e35c3651f5b 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -30,7 +30,7 @@ #include "runtime/basicLock.hpp" #include "runtime/handles.hpp" #include "runtime/javaThread.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" template class GrowableArray; class LogStream; diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index c8af260f66e..6247b351573 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -39,9 +39,9 @@ #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" #include "utilities/powerOfTwo.hpp" -#include "utilities/resourceHash.hpp" #include "utilities/vmError.hpp" // The '_cnt', '_max' and '_times" fields are enabled via @@ -191,15 +191,15 @@ class ThreadScanHashtable : public CHeapObj { return (unsigned int)(((uint32_t)(uintptr_t)s1) * 2654435761u); } - // ResourceHashtable SIZE is specified at compile time so we + // HashTable SIZE is specified at compile time so we // use 1031 which is the first prime after 1024. - typedef ResourceHashtable PtrTable; PtrTable * _ptrs; public: - // ResourceHashtable is passed to various functions and populated in + // HashTable is passed to various functions and populated in // different places so we allocate it using C_HEAP to make it immune // from any ResourceMarks that happen to be in the code paths. ThreadScanHashtable() : _ptrs(new (mtThread) PtrTable()) {} diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index da833150d74..2cfc84376af 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -291,9 +291,9 @@ class ObjectMonitorsDump : public MonitorClosure, public ObjectMonitorsView { AnyObj::C_HEAP, mtThread, AllocFailStrategy::RETURN_NULL> {}; - // ResourceHashtable SIZE is specified at compile time so we + // HashTable SIZE is specified at compile time so we // use 1031 which is the first prime after 1024. - typedef ResourceHashtable PtrTable; PtrTable* _ptrs; size_t _key_count; @@ -326,7 +326,7 @@ class ObjectMonitorsDump : public MonitorClosure, public ObjectMonitorsView { } public: - // ResourceHashtable is passed to various functions and populated in + // HashTable is passed to various functions and populated in // different places so we allocate it using C_HEAP to make it immune // from any ResourceMarks that happen to be in the code paths. ObjectMonitorsDump() : _ptrs(new (mtThread) PtrTable), _key_count(0), _om_count(0) {} diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 2e299083ac3..051096ae24a 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -831,7 +831,7 @@ public: class DumperClassCacheTable { private: - // ResourceHashtable SIZE is specified at compile time so we + // HashTable SIZE is specified at compile time so we // use 1031 which is the first prime after 1024. static constexpr size_t TABLE_SIZE = 1031; @@ -841,7 +841,7 @@ private: // sized table from overloading. static constexpr int CACHE_TOP = 256; - typedef ResourceHashtable PtrTable; PtrTable* _ptrs; diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 181786cd238..2a179f5814f 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1332,7 +1332,7 @@ typedef const char* ccstr; typedef const char* ccstrlist; // represents string arguments which accumulate //---------------------------------------------------------------------------------------------------- -// Default hash/equals functions used by ResourceHashtable +// Default hash/equals functions used by HashTable template unsigned primitive_hash(const K& k) { unsigned hash = (unsigned)((uintptr_t)k); diff --git a/src/hotspot/share/utilities/resourceHash.hpp b/src/hotspot/share/utilities/hashTable.hpp similarity index 89% rename from src/hotspot/share/utilities/resourceHash.hpp rename to src/hotspot/share/utilities/hashTable.hpp index a99239b21a0..cd85328657a 100644 --- a/src/hotspot/share/utilities/resourceHash.hpp +++ b/src/hotspot/share/utilities/hashTable.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_UTILITIES_RESOURCEHASH_HPP -#define SHARE_UTILITIES_RESOURCEHASH_HPP +#ifndef SHARE_UTILITIES_HASHTABLE_HPP +#define SHARE_UTILITIES_HASHTABLE_HPP #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" @@ -33,20 +33,20 @@ #include template -class ResourceHashtableNode : public AnyObj { +class HashTableNode : public AnyObj { public: unsigned _hash; K _key; V _value; - ResourceHashtableNode* _next; + HashTableNode* _next; - ResourceHashtableNode(unsigned hash, K const& key, V const& value, - ResourceHashtableNode* next = nullptr) : + HashTableNode(unsigned hash, K const& key, V const& value, + HashTableNode* next = nullptr) : _hash(hash), _key(key), _value(value), _next(next) {} // Create a node with a default-constructed value. - ResourceHashtableNode(unsigned hash, K const& key, - ResourceHashtableNode* next = nullptr) : + HashTableNode(unsigned hash, K const& key, + HashTableNode* next = nullptr) : _hash(hash), _key(key), _value(), _next(next) {} }; @@ -58,12 +58,12 @@ template< unsigned (*HASH) (K const&), bool (*EQUALS)(K const&, K const&) > -class ResourceHashtableBase : public STORAGE { +class HashTableBase : public STORAGE { static_assert(ALLOC_TYPE == AnyObj::C_HEAP || std::is_trivially_destructible::value, "Destructor for K is only called with C_HEAP"); static_assert(ALLOC_TYPE == AnyObj::C_HEAP || std::is_trivially_destructible::value, "Destructor for V is only called with C_HEAP"); - using Node = ResourceHashtableNode; + using Node = HashTableNode; private: int _number_of_entries; @@ -94,17 +94,17 @@ class ResourceHashtableBase : public STORAGE { Node const** lookup_node(unsigned hash, K const& key) const { return const_cast( - const_cast(this)->lookup_node(hash, key)); + const_cast(this)->lookup_node(hash, key)); } protected: Node** table() const { return STORAGE::table(); } - ResourceHashtableBase() : STORAGE(), _number_of_entries(0) {} - ResourceHashtableBase(unsigned size) : STORAGE(size), _number_of_entries(0) {} - NONCOPYABLE(ResourceHashtableBase); + HashTableBase() : STORAGE(), _number_of_entries(0) {} + HashTableBase(unsigned size) : STORAGE(size), _number_of_entries(0) {} + NONCOPYABLE(HashTableBase); - ~ResourceHashtableBase() { + ~HashTableBase() { if (ALLOC_TYPE == AnyObj::C_HEAP) { Node* const* bucket = table(); const unsigned sz = table_size(); @@ -343,13 +343,13 @@ class ResourceHashtableBase : public STORAGE { }; template -class FixedResourceHashtableStorage : public AnyObj { - using Node = ResourceHashtableNode; +class FixedHashTableStorage : public AnyObj { + using Node = HashTableNode; Node* _table[TABLE_SIZE]; protected: - FixedResourceHashtableStorage() { memset(_table, 0, sizeof(_table)); } - ~FixedResourceHashtableStorage() = default; + FixedHashTableStorage() { memset(_table, 0, sizeof(_table)); } + ~FixedHashTableStorage() = default; constexpr unsigned table_size() const { return TABLE_SIZE; @@ -368,13 +368,13 @@ template< unsigned (*HASH) (K const&) = primitive_hash, bool (*EQUALS)(K const&, K const&) = primitive_equals > -class ResourceHashtable : public ResourceHashtableBase< - FixedResourceHashtableStorage, +class HashTable : public HashTableBase< + FixedHashTableStorage, K, V, ALLOC_TYPE, MEM_TAG, HASH, EQUALS> { - NONCOPYABLE(ResourceHashtable); + NONCOPYABLE(HashTable); public: - ResourceHashtable() : ResourceHashtableBase, + HashTable() : HashTableBase, K, V, ALLOC_TYPE, MEM_TAG, HASH, EQUALS>() {} }; -#endif // SHARE_UTILITIES_RESOURCEHASH_HPP +#endif // SHARE_UTILITIES_HASHTABLE_HPP diff --git a/src/hotspot/share/utilities/nativeCallStack.hpp b/src/hotspot/share/utilities/nativeCallStack.hpp index 5038fe31aef..32635a72d51 100644 --- a/src/hotspot/share/utilities/nativeCallStack.hpp +++ b/src/hotspot/share/utilities/nativeCallStack.hpp @@ -27,8 +27,8 @@ #include "memory/allocation.hpp" #include "nmt/nmtCommon.hpp" +#include "utilities/hashTable.hpp" #include "utilities/ostream.hpp" -#include "utilities/resourceHash.hpp" /* * This class represents a native call path (does not include Java frame) diff --git a/src/hotspot/share/utilities/objectBitSet.hpp b/src/hotspot/share/utilities/objectBitSet.hpp index 124188cd321..73f1c89dd40 100644 --- a/src/hotspot/share/utilities/objectBitSet.hpp +++ b/src/hotspot/share/utilities/objectBitSet.hpp @@ -29,7 +29,7 @@ #include "oops/oop.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/bitMap.hpp" -#include "utilities/resizeableResourceHash.hpp" +#include "utilities/resizableHashTable.hpp" class MemRegion; @@ -52,7 +52,7 @@ class ObjectBitSet : public CHeapObj { return hash ^ (hash >> 3); } - typedef ResizeableResourceHashtable BitMapFragmentTable; CHeapBitMap* get_fragment_bits(uintptr_t addr); diff --git a/src/hotspot/share/utilities/objectBitSet.inline.hpp b/src/hotspot/share/utilities/objectBitSet.inline.hpp index 482a97bc2d1..e1b4d728b10 100644 --- a/src/hotspot/share/utilities/objectBitSet.inline.hpp +++ b/src/hotspot/share/utilities/objectBitSet.inline.hpp @@ -52,8 +52,8 @@ ObjectBitSet::~ObjectBitSet() { delete current; current = next; } - // destructors for ResourceHashtable base deletes nodes, and - // ResizeableResourceHashtableStorage deletes the table. + // destructors for HashTable base deletes nodes, and + // ResizeableHashTableStorage deletes the table. } template diff --git a/src/hotspot/share/utilities/resizeableResourceHash.hpp b/src/hotspot/share/utilities/resizableHashTable.hpp similarity index 86% rename from src/hotspot/share/utilities/resizeableResourceHash.hpp rename to src/hotspot/share/utilities/resizableHashTable.hpp index b0c992bf1ef..b445ed8a55e 100644 --- a/src/hotspot/share/utilities/resizeableResourceHash.hpp +++ b/src/hotspot/share/utilities/resizableHashTable.hpp @@ -22,28 +22,28 @@ * */ -#ifndef SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP -#define SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP +#ifndef SHARE_UTILITIES_RESIZEABLEHASHTABLE_HPP +#define SHARE_UTILITIES_RESIZEABLEHASHTABLE_HPP -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" template< typename K, typename V, AnyObj::allocation_type ALLOC_TYPE, MemTag MEM_TAG> -class ResizeableResourceHashtableStorage : public AnyObj { - using Node = ResourceHashtableNode; +class ResizeableHashTableStorage : public AnyObj { + using Node = HashTableNode; protected: unsigned _table_size; Node** _table; - ResizeableResourceHashtableStorage(unsigned table_size) { + ResizeableHashTableStorage(unsigned table_size) { _table_size = table_size; _table = alloc_table(table_size); } - ~ResizeableResourceHashtableStorage() { + ~ResizeableHashTableStorage() { if (ALLOC_TYPE == C_HEAP) { FREE_C_HEAP_ARRAY(Node*, _table); } @@ -76,15 +76,15 @@ template< unsigned (*HASH) (K const&) = primitive_hash, bool (*EQUALS)(K const&, K const&) = primitive_equals > -class ResizeableResourceHashtable : public ResourceHashtableBase< - ResizeableResourceHashtableStorage, +class ResizeableHashTable : public HashTableBase< + ResizeableHashTableStorage, K, V, ALLOC_TYPE, MEM_TAG, HASH, EQUALS> { unsigned _max_size; - using BASE = ResourceHashtableBase, + using BASE = HashTableBase, K, V, ALLOC_TYPE, MEM_TAG, HASH, EQUALS>; - using Node = ResourceHashtableNode; - NONCOPYABLE(ResizeableResourceHashtable); + using Node = HashTableNode; + NONCOPYABLE(ResizeableHashTable); // Calculate next "good" hashtable size based on requested count int calculate_resize(bool use_large_table_sizes) const { @@ -111,7 +111,7 @@ class ResizeableResourceHashtable : public ResourceHashtableBase< } public: - ResizeableResourceHashtable(unsigned size, unsigned max_size) + ResizeableHashTable(unsigned size, unsigned max_size) : BASE(size), _max_size(max_size) { assert(size <= 0x3fffffff && max_size <= 0x3fffffff, "avoid overflow in resize"); } @@ -180,4 +180,4 @@ public: #endif // ASSERT }; -#endif // SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP +#endif // SHARE_UTILITIES_RESIZABLEHASHTABLE_HPP diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index ee91ff49ded..8e68be22749 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -27,8 +27,8 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" -#include "utilities/resourceHash.hpp" // #define LOG_PLEASE #include "testutils.hpp" @@ -206,7 +206,7 @@ static void test_attempt_reserve_memory_between_random_distribution(unsigned num // Allocate n times within that hole (with subsequent deletions) and remember unique addresses returned. constexpr unsigned num_tries_per_attach_point = 100; ResourceMark rm; - ResourceHashtable ht; + HashTable ht; const unsigned num_tries = expect_failure ? 3 : (num_possible_attach_points * num_tries_per_attach_point); unsigned num_uniq = 0; // Number of uniq addresses returned diff --git a/test/hotspot/gtest/utilities/test_resourceHash.cpp b/test/hotspot/gtest/utilities/test_hashtable.cpp similarity index 82% rename from test/hotspot/gtest/utilities/test_resourceHash.cpp rename to test/hotspot/gtest/utilities/test_hashtable.cpp index 7f89f6c6b91..4fa4bcfa8fc 100644 --- a/test/hotspot/gtest/utilities/test_resourceHash.cpp +++ b/test/hotspot/gtest/utilities/test_hashtable.cpp @@ -29,9 +29,9 @@ #include "unittest.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/resourceHash.hpp" +#include "utilities/hashTable.hpp" -class CommonResourceHashtableTest : public ::testing::Test { +class CommonHashTableTest : public ::testing::Test { protected: typedef void* K; typedef uintx V; @@ -79,7 +79,7 @@ class CommonResourceHashtableTest : public ::testing::Test { }; -class SmallResourceHashtableTest : public CommonResourceHashtableTest { +class SmallHashTableTest : public CommonHashTableTest { protected: template< @@ -93,7 +93,7 @@ class SmallResourceHashtableTest : public CommonResourceHashtableTest { static void test(V step) { EqualityTestIter et; - ResourceHashtable rh; + HashTable rh; ASSERT_FALSE(rh.contains(as_K(step))); @@ -157,61 +157,61 @@ class SmallResourceHashtableTest : public CommonResourceHashtableTest { }; }; -TEST_VM_F(SmallResourceHashtableTest, default) { +TEST_VM_F(SmallHashTableTest, default) { ResourceMark rm; Runner<>::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, default_shifted) { +TEST_VM_F(SmallHashTableTest, default_shifted) { ResourceMark rm; Runner<>::test(0x10); } -TEST_VM_F(SmallResourceHashtableTest, bad_hash) { +TEST_VM_F(SmallHashTableTest, bad_hash) { ResourceMark rm; Runner::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, bad_hash_shifted) { +TEST_VM_F(SmallHashTableTest, bad_hash_shifted) { ResourceMark rm; Runner::test(0x10); } -TEST_VM_F(SmallResourceHashtableTest, identity_hash) { +TEST_VM_F(SmallHashTableTest, identity_hash) { ResourceMark rm; Runner::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, identity_hash_shifted) { +TEST_VM_F(SmallHashTableTest, identity_hash_shifted) { ResourceMark rm; Runner::test(0x10); } -TEST_VM_F(SmallResourceHashtableTest, primitive_hash_no_rm) { +TEST_VM_F(SmallHashTableTest, primitive_hash_no_rm) { Runner, primitive_equals, 512, AnyObj::C_HEAP>::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, primitive_hash_no_rm_shifted) { +TEST_VM_F(SmallHashTableTest, primitive_hash_no_rm_shifted) { Runner, primitive_equals, 512, AnyObj::C_HEAP>::test(0x10); } -TEST_VM_F(SmallResourceHashtableTest, bad_hash_no_rm) { +TEST_VM_F(SmallHashTableTest, bad_hash_no_rm) { Runner, 512, AnyObj::C_HEAP>::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, bad_hash_no_rm_shifted) { +TEST_VM_F(SmallHashTableTest, bad_hash_no_rm_shifted) { Runner, 512, AnyObj::C_HEAP>::test(0x10); } -TEST_VM_F(SmallResourceHashtableTest, identity_hash_no_rm) { +TEST_VM_F(SmallHashTableTest, identity_hash_no_rm) { Runner, 1, AnyObj::C_HEAP>::test(0x1); } -TEST_VM_F(SmallResourceHashtableTest, identity_hash_no_rm_shifted) { +TEST_VM_F(SmallHashTableTest, identity_hash_no_rm_shifted) { Runner, 1, AnyObj::C_HEAP>::test(0x10); } -class GenericResourceHashtableTest : public CommonResourceHashtableTest { +class GenericHashTableTest : public CommonHashTableTest { protected: template< @@ -225,7 +225,7 @@ class GenericResourceHashtableTest : public CommonResourceHashtableTest { static void test(unsigned num_elements = SIZE) { EqualityTestIter et; - ResourceHashtable rh; + HashTable rh; for (uintptr_t i = 0; i < num_elements; ++i) { ASSERT_TRUE(rh.put(as_K(i), i)); @@ -263,39 +263,39 @@ class GenericResourceHashtableTest : public CommonResourceHashtableTest { }; }; -TEST_VM_F(GenericResourceHashtableTest, default) { +TEST_VM_F(GenericHashTableTest, default) { ResourceMark rm; Runner<>::test(); } -TEST_VM_F(GenericResourceHashtableTest, bad_hash) { +TEST_VM_F(GenericHashTableTest, bad_hash) { ResourceMark rm; Runner::test(); } -TEST_VM_F(GenericResourceHashtableTest, identity_hash) { +TEST_VM_F(GenericHashTableTest, identity_hash) { ResourceMark rm; Runner::test(); } -TEST_VM_F(GenericResourceHashtableTest, primitive_hash_no_rm) { +TEST_VM_F(GenericHashTableTest, primitive_hash_no_rm) { Runner, primitive_equals, 512, AnyObj::C_HEAP>::test(); } -TEST_VM_F(GenericResourceHashtableTest, bad_hash_no_rm) { +TEST_VM_F(GenericHashTableTest, bad_hash_no_rm) { Runner, 512, AnyObj::C_HEAP>::test(); } -TEST_VM_F(GenericResourceHashtableTest, identity_hash_no_rm) { +TEST_VM_F(GenericHashTableTest, identity_hash_no_rm) { Runner, 1, AnyObj::C_HEAP>::test(512); } -// Simple ResourceHashtable whose key is a SymbolHandle and value is an int +// Simple HashTable whose key is a SymbolHandle and value is an int // This test is to show that the SymbolHandle will correctly handle the refcounting // in the table. -class SimpleResourceHashtableDeleteTest : public ::testing::Test { +class SimpleHashTableDeleteTest : public ::testing::Test { public: - ResourceHashtable _simple_test_table; + HashTable _simple_test_table; class SimpleDeleter : public StackObj { public: @@ -305,7 +305,7 @@ class SimpleResourceHashtableDeleteTest : public ::testing::Test { }; }; -TEST_VM_F(SimpleResourceHashtableDeleteTest, simple_remove) { +TEST_VM_F(SimpleHashTableDeleteTest, simple_remove) { TempNewSymbol t = SymbolTable::new_symbol("abcdefg_simple"); Symbol* s = t; int s_orig_count = s->refcount(); @@ -317,7 +317,7 @@ TEST_VM_F(SimpleResourceHashtableDeleteTest, simple_remove) { ASSERT_EQ(s->refcount(), s_orig_count) << "refcount should be same as start"; } -TEST_VM_F(SimpleResourceHashtableDeleteTest, simple_delete) { +TEST_VM_F(SimpleHashTableDeleteTest, simple_delete) { TempNewSymbol t = SymbolTable::new_symbol("abcdefg_simple"); Symbol* s = t; int s_orig_count = s->refcount(); @@ -330,10 +330,10 @@ TEST_VM_F(SimpleResourceHashtableDeleteTest, simple_delete) { ASSERT_EQ(s->refcount(), s_orig_count) << "refcount should be same as start"; } -// More complicated ResourceHashtable with SymbolHandle in the key. Since the *same* Symbol is part +// More complicated HashTable with SymbolHandle in the key. Since the *same* Symbol is part // of the value, it's not necessary to manipulate the refcount of the key, but you must in the value. // Luckily SymbolHandle does this. -class ResourceHashtableDeleteTest : public ::testing::Test { +class HashTableDeleteTest : public ::testing::Test { public: class TestValue : public CHeapObj { SymbolHandle _s; @@ -348,8 +348,8 @@ class ResourceHashtableDeleteTest : public ::testing::Test { // Symbol* s() const { return _s; } // needed for conversion from TempNewSymbol to SymbolHandle member }; - // ResourceHashtable whose value is a *copy* of TestValue. - ResourceHashtable _test_table; + // HashTable whose value is a *copy* of TestValue. + HashTable _test_table; class Deleter : public StackObj { public: @@ -362,8 +362,8 @@ class ResourceHashtableDeleteTest : public ::testing::Test { } }; - // ResourceHashtable whose value is a pointer to TestValue. - ResourceHashtable _ptr_test_table; + // HashTable whose value is a pointer to TestValue. + HashTable _ptr_test_table; class PtrDeleter : public StackObj { public: @@ -378,7 +378,7 @@ class ResourceHashtableDeleteTest : public ::testing::Test { }; -TEST_VM_F(ResourceHashtableDeleteTest, value_remove) { +TEST_VM_F(HashTableDeleteTest, value_remove) { TempNewSymbol s = SymbolTable::new_symbol("abcdefg"); int s_orig_count = s->refcount(); { @@ -396,7 +396,7 @@ TEST_VM_F(ResourceHashtableDeleteTest, value_remove) { ASSERT_EQ(s->refcount(), s_orig_count) << "refcount should be as we started"; } -TEST_VM_F(ResourceHashtableDeleteTest, value_delete) { +TEST_VM_F(HashTableDeleteTest, value_delete) { TempNewSymbol d = SymbolTable::new_symbol("defghijklmnop"); int d_orig_count = d->refcount(); { @@ -412,7 +412,7 @@ TEST_VM_F(ResourceHashtableDeleteTest, value_delete) { ASSERT_EQ(d->refcount(), d_orig_count) << "refcount should be as we started"; } -TEST_VM_F(ResourceHashtableDeleteTest, check_delete_ptr) { +TEST_VM_F(HashTableDeleteTest, check_delete_ptr) { TempNewSymbol s = SymbolTable::new_symbol("abcdefg_ptr"); int s_orig_count = s->refcount(); { @@ -432,7 +432,7 @@ TEST_VM_F(ResourceHashtableDeleteTest, check_delete_ptr) { ASSERT_EQ(s->refcount(), s_orig_count) << "refcount should be as we started"; } -class ResourceHashtablePrintTest : public ::testing::Test { +class HashTablePrintTest : public ::testing::Test { public: class TestValue { int _i; @@ -441,7 +441,7 @@ class ResourceHashtablePrintTest : public ::testing::Test { public: TestValue(int i) : _i(i), _j(i+1), _k(i+2) {} }; - ResourceHashtable _test_table; + HashTable _test_table; class TableDeleter { public: @@ -452,7 +452,7 @@ class ResourceHashtablePrintTest : public ::testing::Test { }; }; -TEST_VM_F(ResourceHashtablePrintTest, print_test) { +TEST_VM_F(HashTablePrintTest, print_test) { for (int i = 0; i < 300; i++) { TestValue* tv = new TestValue(i); _test_table.put(i, tv); // all the entries can be the same. From 9660320041d0ba0f22ebe074a64472557b85a24c Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 13 Aug 2025 20:43:46 +0000 Subject: [PATCH 074/471] 8364781: Re-examine DigitList digits resizing during parsing Reviewed-by: liach, naoto --- src/java.base/share/classes/java/text/DigitList.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 3eeabb7e77e..26238345047 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -42,6 +42,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import jdk.internal.math.FloatingDecimal; +import jdk.internal.util.ArraysSupport; /** * Digit List. Private to DecimalFormat. @@ -153,7 +154,7 @@ final class DigitList implements Cloneable { */ public void append(char digit) { if (count == digits.length) { - char[] data = new char[count + 100]; + char[] data = new char[ArraysSupport.newLength(count, 1, count)]; System.arraycopy(digits, 0, data, 0, count); digits = data; } From 9c266ae83c047025d778da41e413701ac3b50b03 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 13 Aug 2025 20:49:16 +0000 Subject: [PATCH 075/471] 8365229: ARM32: c2i_no_clinit_check_entry assert failed after JDK-8364269 Reviewed-by: kvn, adinn, bulasevich, phh --- src/hotspot/cpu/zero/sharedRuntime_zero.cpp | 6 +++--- src/hotspot/share/code/codeBlob.cpp | 6 ++++-- src/hotspot/share/runtime/sharedRuntime.cpp | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 2c5fb717c40..df162fbfa74 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -56,11 +56,11 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, const BasicType *sig_bt, const VMRegPair *regs, AdapterHandlerEntry* handler) { + // VM expects i2c entry to be always filled. The rest can be unset. handler->set_entry_points(CAST_FROM_FN_PTR(address,zero_null_code_stub), - CAST_FROM_FN_PTR(address,zero_null_code_stub), - CAST_FROM_FN_PTR(address,zero_null_code_stub), + nullptr, + nullptr, nullptr); - return; } nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 5b87e8c5670..9ec5478a071 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -450,8 +450,10 @@ AdapterBlob::AdapterBlob(int size, CodeBuffer* cb, int entry_offset[AdapterBlob: BufferBlob("I2C/C2I adapters", CodeBlobKind::Adapter, cb, size, sizeof(AdapterBlob)) { assert(entry_offset[0] == 0, "sanity check"); for (int i = 1; i < AdapterBlob::ENTRY_COUNT; i++) { - assert(entry_offset[i] > 0 && entry_offset[i] < cb->insts()->size(), - "invalid entry offset 0x%x", entry_offset[i]); + // The entry is within the adapter blob or unset. + assert((entry_offset[i] > 0 && entry_offset[i] < cb->insts()->size()) || + (entry_offset[i] == -1), + "invalid entry offset[%d] = 0x%x", i, entry_offset[i]); } _c2i_offset = entry_offset[1]; _c2i_unverified_offset = entry_offset[2]; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index beed5df5254..5bfddb8a04a 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2778,7 +2778,12 @@ AdapterBlob* AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handle adapter_blob->get_offsets(offsets); address i2c_entry = adapter_blob->content_begin(); assert(offsets[0] == 0, "sanity check"); - handler->set_entry_points(i2c_entry, i2c_entry + offsets[1], i2c_entry + offsets[2], i2c_entry + offsets[3]); + handler->set_entry_points( + i2c_entry, + (offsets[1] != -1) ? (i2c_entry + offsets[1]) : nullptr, + (offsets[2] != -1) ? (i2c_entry + offsets[2]) : nullptr, + (offsets[3] != -1) ? (i2c_entry + offsets[3]) : nullptr + ); } return adapter_blob; } @@ -2842,9 +2847,12 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob, assert(AdapterBlob::ENTRY_COUNT == 4, "sanity"); address i2c_entry = handler->get_i2c_entry(); entry_offset[0] = 0; // i2c_entry offset - entry_offset[1] = handler->get_c2i_entry() - i2c_entry; - entry_offset[2] = handler->get_c2i_unverified_entry() - i2c_entry; - entry_offset[3] = handler->get_c2i_no_clinit_check_entry() - i2c_entry; + entry_offset[1] = (handler->get_c2i_entry() != nullptr) ? + (handler->get_c2i_entry() - i2c_entry) : -1; + entry_offset[2] = (handler->get_c2i_unverified_entry() != nullptr) ? + (handler->get_c2i_unverified_entry() - i2c_entry) : -1; + entry_offset[3] = (handler->get_c2i_no_clinit_check_entry() != nullptr) ? + (handler->get_c2i_no_clinit_check_entry() - i2c_entry) : -1; adapter_blob = AdapterBlob::create(&buffer, entry_offset); if (adapter_blob == nullptr) { From 9dcc502cc83773561707f2afe9aee1f9e2386b9e Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 14 Aug 2025 04:55:02 +0000 Subject: [PATCH 076/471] 8365375: Method SU3.setAcceleratorSelectionForeground assigns to acceleratorForeground Reviewed-by: aivanov, prr, kizune --- .../share/classes/com/sun/java/swing/SwingUtilities3.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java index a17f1f480ed..5e1e149eb9e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -248,7 +248,7 @@ public class SwingUtilities3 { } public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) { - acceleratorForeground = acceleratorSelectionFg; + acceleratorSelectionForeground = acceleratorSelectionFg; } public static void setAcceleratorForeground(Color acceleratorFg) { From c22e01d77648036db4ed640521e82c49f8791ca1 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 14 Aug 2025 07:02:08 +0000 Subject: [PATCH 077/471] 8341342: Elements.getAllModuleElements() does not work properly before JavacTask.analyze() Reviewed-by: vromero, liach --- .../sun/tools/javac/model/JavacElements.java | 1 + test/jdk/tools/sincechecker/SinceChecker.java | 1 - .../elements/TestElementsProgrammatic.java | 74 +++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/processing/model/util/elements/TestElementsProgrammatic.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index 7cf419f3ca8..73219ca38ae 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -128,6 +128,7 @@ public class JavacElements implements Elements { @Override @DefinedBy(Api.LANGUAGE_MODEL) public Set getAllModuleElements() { + ensureEntered("getAllModuleElements"); if (allowModules) return Collections.unmodifiableSet(modules.allModules()); else diff --git a/test/jdk/tools/sincechecker/SinceChecker.java b/test/jdk/tools/sincechecker/SinceChecker.java index a7ec90d53f8..f9a8e3d49dd 100644 --- a/test/jdk/tools/sincechecker/SinceChecker.java +++ b/test/jdk/tools/sincechecker/SinceChecker.java @@ -297,7 +297,6 @@ public class SinceChecker { Collections.singletonList(SimpleJavaFileObject.forSource(URI.create("myfo:/Test.java"), ""))); ct.analyze(); Elements elements = ct.getElements(); - elements.getModuleElement("java.base"); try (EffectiveSourceSinceHelper javadocHelper = EffectiveSourceSinceHelper.create(ct, List.of(root), this)) { processModuleCheck(elements.getModuleElement(moduleName), ct, moduleDirectory, javadocHelper); } catch (Exception e) { diff --git a/test/langtools/tools/javac/processing/model/util/elements/TestElementsProgrammatic.java b/test/langtools/tools/javac/processing/model/util/elements/TestElementsProgrammatic.java new file mode 100644 index 00000000000..dda3faac232 --- /dev/null +++ b/test/langtools/tools/javac/processing/model/util/elements/TestElementsProgrammatic.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8341342 + * @summary Test Elements methods programmatically + * @modules jdk.compiler + * @run junit TestElementsProgrammatic + */ + +import com.sun.source.util.JavacTask; +import java.net.URI; +import java.util.List; +import java.util.function.Consumer; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Programmatically test workings of various methods of Elements. + */ +public class TestElementsProgrammatic { + + private final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler(); + + @ParameterizedTest + @MethodSource + public void automaticallyEnter(Consumer verify) { + //make sure the get{All,}{Module,Package,Type}Element{s,} methods will automatically enter: + JavaFileObject input = + SimpleJavaFileObject.forSource(URI.create("mem://Test.java"), ""); + List inputs = List.of(input); + JavacTask task = (JavacTask) systemCompiler.getTask(null, null, null, null, null, inputs); + verify.accept(task); + } + + private static List> automaticallyEnter() { + return List.of( + task -> assertFalse(task.getElements().getAllModuleElements().isEmpty()), + task -> assertNotNull(task.getElements().getModuleElement("java.base")), + task -> assertNotNull(task.getElements().getPackageElement("java.lang")), + task -> assertFalse(task.getElements().getAllPackageElements("java.lang").isEmpty()), + task -> assertNotNull(task.getElements().getTypeElement("java.lang.Object")), + task -> assertFalse(task.getElements().getAllTypeElements("java.lang.Object").isEmpty()) + ); + } +} From a6be2286421e069a292c749eecd6bdc38a8deaf2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 14 Aug 2025 07:04:40 +0000 Subject: [PATCH 078/471] 8365314: javac fails with an exception for erroneous source Reviewed-by: vromero --- .../com/sun/tools/javac/code/Lint.java | 17 ++++++------ .../javac/recovery/AnnotationRecovery.java | 26 ++++++++++++++++++- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 5a4d09b67ba..6d83f95fce4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -528,14 +528,15 @@ public class Lint { // Given a @SuppressWarnings annotation, extract the recognized suppressions private EnumSet suppressionsFrom(Attribute.Compound suppressWarnings) { EnumSet result = LintCategory.newEmptySet(); - Attribute.Array values = (Attribute.Array)suppressWarnings.member(names.value); - for (Attribute value : values.values) { - Optional.of(value) - .filter(val -> val instanceof Attribute.Constant) - .map(val -> (String) ((Attribute.Constant) val).value) - .flatMap(LintCategory::get) - .filter(lc -> lc.annotationSuppression) - .ifPresent(result::add); + if (suppressWarnings.member(names.value) instanceof Attribute.Array values) { + for (Attribute value : values.values) { + Optional.of(value) + .filter(val -> val instanceof Attribute.Constant) + .map(val -> (String) ((Attribute.Constant) val).value) + .flatMap(LintCategory::get) + .filter(lc -> lc.annotationSuppression) + .ifPresent(result::add); + } } return result; } diff --git a/test/langtools/tools/javac/recovery/AnnotationRecovery.java b/test/langtools/tools/javac/recovery/AnnotationRecovery.java index e5e52b82159..ea94f0f582d 100644 --- a/test/langtools/tools/javac/recovery/AnnotationRecovery.java +++ b/test/langtools/tools/javac/recovery/AnnotationRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8270139 8361445 + * @bug 8270139 8361445 8365314 * @summary Verify error recovery w.r.t. annotations * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -224,4 +224,28 @@ public class AnnotationRecovery extends TestRunner { } } + @Test //JDK-8365314 + public void testSuppressWarningsMissingAttribute() throws Exception { + String code = """ + @SuppressWarnings + public class Test { + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "Test.java:1:1: compiler.err.annotation.missing.default.value: java.lang.SuppressWarnings, value", + "1 error" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } } From 3e3298509f136583b18e5ab8bf75a8b012016f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 14 Aug 2025 07:37:10 +0000 Subject: [PATCH 079/471] 8365317: ZGC: Setting ZYoungGCThreads lower than ZOldGCThreads may result in a crash Reviewed-by: tschatzl, eosterlund --- src/hotspot/share/gc/z/zDirector.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index e46b1c9e167..380a1e48ab4 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -725,8 +725,8 @@ static ZWorkerCounts select_worker_threads(const ZDirectorStats& stats, uint you // Adjust down the old workers so the next minor during major will be less sad old_workers = old_workers_clamped; // Since collecting the old generation depends on the initial young collection - // finishing, we don't want it to have fewer workers than the old generation. - young_workers = MAX2(old_workers, young_workers); + // finishing, we ideally don't want it to have fewer workers than the old generation. + young_workers = clamp(MAX2(old_workers, young_workers), 1u, ZYoungGCThreads); } else if (type == ZWorkerSelectionType::minor_during_old) { // Adjust young and old workers for minor during old to fit within ConcGCThreads young_workers = young_workers_clamped; From e320162815d529bc65cd058b34ec39d60d032ce7 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Thu, 14 Aug 2025 07:39:49 +0000 Subject: [PATCH 080/471] 8365218: [JVMCI] AArch64 CPU features are not computed correctly after 8364128 Reviewed-by: dnsimon --- .../hotspot/HotSpotJVMCIBackendFactory.java | 65 ++----------------- .../AArch64HotSpotJVMCIBackendFactory.java | 2 +- .../AMD64HotSpotJVMCIBackendFactory.java | 16 +++-- .../RISCV64HotSpotJVMCIBackendFactory.java | 2 +- 4 files changed, 20 insertions(+), 65 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java index 319b9b9bc44..e0fc314de5b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java @@ -27,10 +27,10 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.LongFunction; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.runtime.JVMCIBackend; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; public interface HotSpotJVMCIBackendFactory { @@ -48,7 +48,8 @@ public interface HotSpotJVMCIBackendFactory { * @param enumType the class of {@code CPUFeatureType} * @param constants VM constants. Each entry whose key starts with {@code "VM_Version::CPU_"} * specifies a CPU feature and its value is a mask for a bit in {@code features} - * @param features bits specifying CPU features + * @param bitMaskSupplier supplier to get the bit mask for the corresponding VM constant + * @param featuresSupplier supplier to get the bits specifying CPU features * @param renaming maps from VM feature names to enum constant names where the two differ * @throws IllegalArgumentException if any VM CPU feature constant cannot be converted to an * enum value @@ -57,18 +58,19 @@ public interface HotSpotJVMCIBackendFactory { static > EnumSet convertFeatures( Class enumType, Map constants, - long features, + LongFunction bitMaskSupplier, + LongFunction featuresSupplier, Map renaming) { EnumSet outFeatures = EnumSet.noneOf(enumType); List missing = new ArrayList<>(); for (Entry e : constants.entrySet()) { - long bitMask = e.getValue(); + long bitMask = bitMaskSupplier.apply(e.getValue()); String key = e.getKey(); if (key.startsWith("VM_Version::CPU_")) { String name = key.substring("VM_Version::CPU_".length()); try { CPUFeatureType feature = Enum.valueOf(enumType, renaming.getOrDefault(name, name)); - if ((features & bitMask) != 0) { + if ((featuresSupplier.apply(e.getValue()) & bitMask) != 0) { outFeatures.add(feature); } } catch (IllegalArgumentException iae) { @@ -82,57 +84,4 @@ public interface HotSpotJVMCIBackendFactory { return outFeatures; } - /** - * Converts CPU features bit map into enum constants. - * - * @param CPU feature enum type - * @param enumType the class of {@code CPUFeatureType} - * @param constants VM constants. Each entry whose key starts with {@code "VM_Version::CPU_"} - * specifies a CPU feature and its value is a mask for a bit in {@code features} - * @param featuresBitMapAddress pointer to {@code VM_Features::_features_bitmap} field of {@code VM_Version::_features} - * @param featuresBitMapSize size of feature bit map in bytes - * @param renaming maps from VM feature names to enum constant names where the two differ - * @throws IllegalArgumentException if any VM CPU feature constant cannot be converted to an - * enum value - * @return the set of converted values - */ - static > EnumSet convertFeatures( - Class enumType, - Map constants, - long featuresBitMapAddress, - long featuresBitMapSize, - Map renaming) { - EnumSet outFeatures = EnumSet.noneOf(enumType); - List missing = new ArrayList<>(); - - for (Entry e : constants.entrySet()) { - String key = e.getKey(); - long bitIndex = e.getValue(); - if (key.startsWith("VM_Version::CPU_")) { - String name = key.substring("VM_Version::CPU_".length()); - try { - final long featuresElementShiftCount = 6; // log (# of bits per long) - final long featuresElementMask = (1L << featuresElementShiftCount) - 1; - - CPUFeatureType feature = Enum.valueOf(enumType, renaming.getOrDefault(name, name)); - - long featureIndex = bitIndex >>> featuresElementShiftCount; - long featureBitMask = 1L << (bitIndex & featuresElementMask); - assert featureIndex < featuresBitMapSize; - - long featuresElement = UNSAFE.getLong(featuresBitMapAddress + featureIndex * Long.BYTES); - - if ((featuresElement & featureBitMask) != 0) { - outFeatures.add(feature); - } - } catch (IllegalArgumentException iae) { - missing.add(name); - } - } - } - if (!missing.isEmpty()) { - throw new JVMCIError("Missing CPU feature constants: %s", missing); - } - return outFeatures; - } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java index 19c161d6bde..1ee016b73a8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java @@ -49,7 +49,7 @@ public class AArch64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFac private static EnumSet computeFeatures(AArch64HotSpotVMConfig config) { // Configure the feature set using the HotSpot flag settings. Map constants = config.getStore().getConstants(); - return HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, config.vmVersionFeatures, emptyMap()); + return HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, idx -> 1L << idx, _ -> config.vmVersionFeatures, emptyMap()); } private static TargetDescription createTarget(AArch64HotSpotVMConfig config) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java index 040f39e3b8a..cae6d18e71e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java @@ -26,6 +26,8 @@ import static jdk.vm.ci.common.InitTimer.timer; import java.util.EnumSet; import java.util.Map; + +import jdk.internal.misc.Unsafe; import jdk.internal.util.OperatingSystem; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; @@ -50,11 +52,15 @@ public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFacto Map constants = config.getStore().getConstants(); Map renaming = Map.of("3DNOW_PREFETCH", "AMD_3DNOW_PREFETCH"); long featuresBitMapAddress = config.vmVersionFeatures + config.vmFeaturesFeaturesOffset; - EnumSet features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, - constants, - featuresBitMapAddress, - config.vmFeaturesFeaturesSize, - renaming); + EnumSet features = HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, idx -> { + final long featuresElementShiftCount = 6; // log (# of bits per long) + final long featuresElementMask = (1L << featuresElementShiftCount) - 1; + return 1L << (idx & featuresElementMask); + }, idx -> { + final long featuresElementShiftCount = 6; // log (# of bits per long) + long featureIndex = idx >>> featuresElementShiftCount; + return Unsafe.getUnsafe().getLong(featuresBitMapAddress + featureIndex * Long.BYTES); + }, renaming); assert features.contains(AMD64.CPUFeature.SSE) : "minimum config for x64"; assert features.contains(AMD64.CPUFeature.SSE2) : "minimum config for x64"; return features; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotJVMCIBackendFactory.java index c0e31124500..f50fcf1dbbc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotJVMCIBackendFactory.java @@ -49,7 +49,7 @@ public class RISCV64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFac private static EnumSet computeFeatures(RISCV64HotSpotVMConfig config) { // Configure the feature set using the HotSpot flag settings. Map constants = config.getStore().getConstants(); - return HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, config.vmVersionFeatures, emptyMap()); + return HotSpotJVMCIBackendFactory.convertFeatures(CPUFeature.class, constants, mask -> mask, _ -> config.vmVersionFeatures, emptyMap()); } private static TargetDescription createTarget(RISCV64HotSpotVMConfig config) { From 7698c373a684235812c9dc11edd751059f9e8e81 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 14 Aug 2025 10:43:21 +0000 Subject: [PATCH 081/471] 8364556: JFR: Disable SymbolTableStatistics and StringTableStatistics in default.jfc Reviewed-by: mgronlun --- src/jdk.jfr/share/conf/jfr/default.jfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 463639d7f1e..eb3b8626722 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -33,12 +33,12 @@ - true + false 10 s - true + false 10 s From 98f54d90ea56f63c2fc5137af98b57dbc90fe150 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 14 Aug 2025 11:11:47 +0000 Subject: [PATCH 082/471] 8365487: [asan] some oops (mode) related tests fail Reviewed-by: kbarrett, syan --- .../jtreg/runtime/CompressedOops/UseCompressedOops.java | 4 +++- .../TestGCHeapConfigurationEventWith32BitOops.java | 2 ++ .../TestGCHeapConfigurationEventWithZeroBasedOops.java | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java b/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java index 3d118bf73b1..e5e2a23c565 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @modules java.base/jdk.internal.misc * java.management * @build jdk.test.whitebox.WhiteBox + * @comment Asan changes memory layout and we get a different coops mode + * @requires !vm.asan * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UseCompressedOops */ diff --git a/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java index 9ef90afb063..c98f055aa72 100644 --- a/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java +++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWith32BitOops.java @@ -35,6 +35,8 @@ import jdk.test.whitebox.WhiteBox; * @requires vm.gc == "Parallel" | vm.gc == null * @requires os.family == "linux" | os.family == "windows" * @requires sun.arch.data.model == "64" + * @comment Asan changes memory layout and we get a different coops mode + * @requires !vm.asan * @library /test/lib /test/jdk * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff --git a/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java index 62d858eef98..f69d192ca5f 100644 --- a/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java +++ b/test/jdk/jdk/jfr/event/gc/configuration/TestGCHeapConfigurationEventWithZeroBasedOops.java @@ -33,6 +33,8 @@ import jdk.test.lib.jfr.EventVerifier; * @requires vm.gc == "Parallel" | vm.gc == null * @requires os.family == "linux" | os.family == "windows" * @requires sun.arch.data.model == "64" + * @comment Asan changes memory layout and we get a different coops mode + * @requires !vm.asan * @library /test/lib /test/jdk * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:+UseCompressedOops -Xmx4g jdk.jfr.event.gc.configuration.TestGCHeapConfigurationEventWithZeroBasedOops */ From 41520998aa8808452ee384b213b2a77c7bad668d Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Thu, 14 Aug 2025 12:31:20 +0000 Subject: [PATCH 083/471] 8365098: make/RunTests.gmk generates a wrong path to test artifacts on Alpine Reviewed-by: erikj, ihse --- make/RunTests.gmk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 60ae1bd4763..574fd869092 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1243,7 +1243,7 @@ UseSpecialTestHandler = \ # Now process each test to run and setup a proper make rule $(foreach test, $(TESTS_TO_RUN), \ $(eval TEST_ID := $(shell $(ECHO) $(strip $(test)) | \ - $(TR) -cs '[a-z][A-Z][0-9]\n' '[_*1000]')) \ + $(TR) -cs '[a-z][A-Z][0-9]\n' '_')) \ $(eval ALL_TEST_IDS += $(TEST_ID)) \ $(if $(call UseCustomTestHandler, $(test)), \ $(eval $(call SetupRunCustomTest, $(TEST_ID), \ @@ -1323,9 +1323,9 @@ run-test-report: post-run-test TEST TOTAL PASS FAIL ERROR SKIP " " $(foreach test, $(TESTS_TO_RUN), \ $(eval TEST_ID := $(shell $(ECHO) $(strip $(test)) | \ - $(TR) -cs '[a-z][A-Z][0-9]\n' '[_*1000]')) \ + $(TR) -cs '[a-z][A-Z][0-9]\n' '_')) \ $(ECHO) >> $(TEST_LAST_IDS) $(TEST_ID) $(NEWLINE) \ - $(eval NAME_PATTERN := $(shell $(ECHO) $(test) | $(TR) -c '\n' '[_*1000]')) \ + $(eval NAME_PATTERN := $(shell $(ECHO) $(test) | $(TR) -c '\n' '_')) \ $(if $(filter __________________________________________________%, $(NAME_PATTERN)), \ $(eval TEST_NAME := ) \ $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s\n" " " "$(test)" $(NEWLINE) \ From dd113c8df06cc7e1465fb3dfef2e9b2a5a99f1fb Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 14 Aug 2025 14:50:56 +0000 Subject: [PATCH 084/471] 8364628: Serial: Refactor SerialHeap::mem_allocate_work Reviewed-by: phh, kbarrett --- src/hotspot/share/gc/serial/serialHeap.cpp | 51 +++++++------------ src/hotspot/share/gc/serial/serialHeap.hpp | 4 -- .../share/gc/serial/tenuredGeneration.hpp | 2 + .../gc/serial/tenuredGeneration.inline.hpp | 8 +++ 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 48d6a1b74ea..6b9328b8697 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -281,15 +281,6 @@ size_t SerialHeap::max_capacity() const { return _young_gen->max_capacity() + _old_gen->max_capacity(); } -// Return true if any of the following is true: -// . the allocation won't fit into the current young gen heap -// . heap memory is tight -bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const { - size_t young_capacity = _young_gen->capacity_before_gc(); - return (word_size > heap_word_size(young_capacity)) - || _is_heap_almost_full; -} - HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { HeapWord* result = nullptr; if (_old_gen->should_allocate(size, is_tlab)) { @@ -308,32 +299,26 @@ HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; - // Loop until the allocation is satisfied, or unsatisfied after GC. - for (uint try_count = 1; /* return or throw */; try_count += 1) { - // First allocation attempt is lock-free. - DefNewGeneration *young = _young_gen; - if (young->should_allocate(size, is_tlab)) { - result = young->par_allocate(size); + for (uint try_count = 1; /* break */; try_count++) { + if (_young_gen->should_allocate(size, is_tlab)) { + result = _young_gen->par_allocate(size); if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; + break; + } + } + // Try old-gen allocation for non-TLAB. + if (!is_tlab) { + // If it's too large for young-gen or heap is too full. + if (size > heap_word_size(_young_gen->capacity_before_gc()) || _is_heap_almost_full) { + result = _old_gen->par_allocate(size); + if (result != nullptr) { + break; + } } } uint gc_count_before; // Read inside the Heap_lock locked region. { MutexLocker ml(Heap_lock); - log_trace(gc, alloc)("SerialHeap::mem_allocate_work: attempting locked slow path allocation"); - // Note that only large objects get a shot at being - // allocated in later generations. - bool first_only = !should_try_older_generation_allocation(size); - - result = attempt_allocation(size, is_tlab, first_only); - if (result != nullptr) { - assert(is_in_reserved(result), "result not in heap"); - return result; - } - - // Read the gc count while the heap lock is held. gc_count_before = total_collections(); } @@ -341,10 +326,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { VMThread::execute(&op); if (op.gc_succeeded()) { result = op.result(); - - assert(result == nullptr || is_in_reserved(result), - "result not in heap"); - return result; + break; } // Give a warning if we seem to be looping forever. @@ -354,6 +336,9 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { " size=%zu %s", try_count, size, is_tlab ? "(TLAB)" : ""); } } + + assert(result == nullptr || is_in_reserved(result), "postcondition"); + return result; } HeapWord* SerialHeap::attempt_allocation(size_t size, diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index e86eac58515..b89edb33307 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -229,10 +229,6 @@ public: void save_marks(); private: - // Return true if an allocation should be attempted in the older generation - // if it fails in the younger generation. Return false, otherwise. - bool should_try_older_generation_allocation(size_t word_size) const; - // Try to allocate space by expanding the heap. HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 892fc5bb86c..1225005aff4 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -126,6 +126,8 @@ public: // Allocate and returns a block of the requested size, or returns "null". // Assumes the caller has done any necessary locking. inline HeapWord* allocate(size_t word_size); + // Multi-threaded version. + inline HeapWord* par_allocate(size_t word_size); // Expand the old-gen then invoke allocate above. HeapWord* expand_and_allocate(size_t size); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index d88b2566299..1c82566bdf4 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -57,4 +57,12 @@ HeapWord* TenuredGeneration::allocate(size_t word_size) { return res; } +HeapWord* TenuredGeneration::par_allocate(size_t word_size) { + HeapWord* res = _the_space->par_allocate(word_size); + if (res != nullptr) { + _bts->update_for_block(res, res + word_size); + } + return res; +} + #endif // SHARE_GC_SERIAL_TENUREDGENERATION_INLINE_HPP From b0f98df75aee1e94a8c4b3eb8d0b1f4e715011ae Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 14 Aug 2025 15:20:47 +0000 Subject: [PATCH 085/471] 8365416: java.desktop no longer needs preview feature access Reviewed-by: alanb, jpai --- src/java.base/share/classes/module-info.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 43d148a3428..92ed53d2176 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -154,7 +154,6 @@ module java.base { // module declaration be annotated with jdk.internal.javac.ParticipatesInPreview exports jdk.internal.javac to java.compiler, - java.desktop, // for ScopedValue jdk.compiler, jdk.incubator.vector, // participates in preview features jdk.jartool, // participates in preview features From 26ccb3cef17a7a2a4b09af1e1e29b96d54a418aa Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 14 Aug 2025 16:59:05 +0000 Subject: [PATCH 086/471] 8362530: VM crash with -XX:+PrintTieredEvents when collecting AOT profiling Reviewed-by: chagedorn, kvn --- .../share/compiler/compilationPolicy.cpp | 117 ++++++++++-------- .../share/compiler/compilationPolicy.hpp | 5 +- .../runtime/cds/appcds/aotFlags/AOTFlags.java | 10 ++ 3 files changed, 75 insertions(+), 57 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index fd1357398f5..9c49d941bbc 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -404,7 +404,7 @@ double CompilationPolicy::threshold_scale(CompLevel level, int feedback_k) { return 1; } -void CompilationPolicy::print_counters(const char* prefix, Method* m) { +void CompilationPolicy::print_counters_on(outputStream* st, const char* prefix, Method* m) { int invocation_count = m->invocation_count(); int backedge_count = m->backedge_count(); MethodData* mdh = m->method_data(); @@ -416,133 +416,140 @@ void CompilationPolicy::print_counters(const char* prefix, Method* m) { mdo_invocations_start = mdh->invocation_count_start(); mdo_backedges_start = mdh->backedge_count_start(); } - tty->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix, - invocation_count, backedge_count, prefix, - mdo_invocations, mdo_invocations_start, - mdo_backedges, mdo_backedges_start); - tty->print(" %smax levels=%d,%d", prefix, - m->highest_comp_level(), m->highest_osr_comp_level()); + st->print(" %stotal=%d,%d %smdo=%d(%d),%d(%d)", prefix, + invocation_count, backedge_count, prefix, + mdo_invocations, mdo_invocations_start, + mdo_backedges, mdo_backedges_start); + st->print(" %smax levels=%d,%d", prefix, m->highest_comp_level(), m->highest_osr_comp_level()); } -void CompilationPolicy::print_training_data(const char* prefix, Method* method) { +void CompilationPolicy::print_training_data_on(outputStream* st, const char* prefix, Method* method) { methodHandle m(Thread::current(), method); - tty->print(" %smtd: ", prefix); + st->print(" %smtd: ", prefix); MethodTrainingData* mtd = MethodTrainingData::find(m); if (mtd == nullptr) { - tty->print("null"); + st->print("null"); } else { MethodData* md = mtd->final_profile(); - tty->print("mdo="); + st->print("mdo="); if (md == nullptr) { - tty->print("null"); + st->print("null"); } else { int mdo_invocations = md->invocation_count(); int mdo_backedges = md->backedge_count(); int mdo_invocations_start = md->invocation_count_start(); int mdo_backedges_start = md->backedge_count_start(); - tty->print("%d(%d), %d(%d)", mdo_invocations, mdo_invocations_start, mdo_backedges, mdo_backedges_start); + st->print("%d(%d), %d(%d)", mdo_invocations, mdo_invocations_start, mdo_backedges, mdo_backedges_start); } CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); - tty->print(", deps="); + st->print(", deps="); if (ctd == nullptr) { - tty->print("null"); + st->print("null"); } else { - tty->print("%d", ctd->init_deps_left()); + st->print("%d", ctd->init_deps_left()); } } } // Print an event. -void CompilationPolicy::print_event(EventType type, Method* m, Method* im, int bci, CompLevel level) { +void CompilationPolicy::print_event_on(outputStream *st, EventType type, Method* m, Method* im, int bci, CompLevel level) { bool inlinee_event = m != im; - ttyLocker tty_lock; - tty->print("%lf: [", os::elapsedTime()); + st->print("%lf: [", os::elapsedTime()); switch(type) { case CALL: - tty->print("call"); + st->print("call"); break; case LOOP: - tty->print("loop"); + st->print("loop"); break; case COMPILE: - tty->print("compile"); + st->print("compile"); break; case FORCE_COMPILE: - tty->print("force-compile"); + st->print("force-compile"); break; case REMOVE_FROM_QUEUE: - tty->print("remove-from-queue"); + st->print("remove-from-queue"); break; case UPDATE_IN_QUEUE: - tty->print("update-in-queue"); + st->print("update-in-queue"); break; case REPROFILE: - tty->print("reprofile"); + st->print("reprofile"); break; case MAKE_NOT_ENTRANT: - tty->print("make-not-entrant"); + st->print("make-not-entrant"); break; default: - tty->print("unknown"); + st->print("unknown"); } - tty->print(" level=%d ", level); + st->print(" level=%d ", level); ResourceMark rm; char *method_name = m->name_and_sig_as_C_string(); - tty->print("[%s", method_name); + st->print("[%s", method_name); if (inlinee_event) { char *inlinee_name = im->name_and_sig_as_C_string(); - tty->print(" [%s]] ", inlinee_name); + st->print(" [%s]] ", inlinee_name); } - else tty->print("] "); - tty->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile), - CompileBroker::queue_size(CompLevel_full_optimization)); + else st->print("] "); + st->print("@%d queues=%d,%d", bci, CompileBroker::queue_size(CompLevel_full_profile), + CompileBroker::queue_size(CompLevel_full_optimization)); - tty->print(" rate="); - if (m->prev_time() == 0) tty->print("n/a"); - else tty->print("%f", m->rate()); + st->print(" rate="); + if (m->prev_time() == 0) st->print("n/a"); + else st->print("%f", m->rate()); - tty->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback), - threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback)); + st->print(" k=%.2lf,%.2lf", threshold_scale(CompLevel_full_profile, Tier3LoadFeedback), + threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback)); if (type != COMPILE) { - print_counters("", m); + print_counters_on(st, "", m); if (inlinee_event) { - print_counters("inlinee ", im); + print_counters_on(st, "inlinee ", im); } - tty->print(" compilable="); + st->print(" compilable="); bool need_comma = false; if (!m->is_not_compilable(CompLevel_full_profile)) { - tty->print("c1"); + st->print("c1"); need_comma = true; } if (!m->is_not_osr_compilable(CompLevel_full_profile)) { - if (need_comma) tty->print(","); - tty->print("c1-osr"); + if (need_comma) st->print(","); + st->print("c1-osr"); need_comma = true; } if (!m->is_not_compilable(CompLevel_full_optimization)) { - if (need_comma) tty->print(","); - tty->print("c2"); + if (need_comma) st->print(","); + st->print("c2"); need_comma = true; } if (!m->is_not_osr_compilable(CompLevel_full_optimization)) { - if (need_comma) tty->print(","); - tty->print("c2-osr"); + if (need_comma) st->print(","); + st->print("c2-osr"); } - tty->print(" status="); + st->print(" status="); if (m->queued_for_compilation()) { - tty->print("in-queue"); - } else tty->print("idle"); - print_training_data("", m); + st->print("in-queue"); + } else st->print("idle"); + + print_training_data_on(st, "", m); if (inlinee_event) { - print_training_data("inlinee ", im); + print_training_data_on(st, "inlinee ", im); } } - tty->print_cr("]"); + st->print_cr("]"); + +} + +void CompilationPolicy::print_event(EventType type, Method* m, Method* im, int bci, CompLevel level) { + stringStream s; + print_event_on(&s, type, m, im, bci, level); + ResourceMark rm; + tty->print("%s", s.as_string()); } void CompilationPolicy::initialize() { diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index 75374a2f830..f4a7c4c249b 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -287,8 +287,8 @@ class CompilationPolicy : AllStatic { // loop_event checks if a method should be OSR compiled at a different // level. static CompLevel loop_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD); - static void print_counters(const char* prefix, Method* m); - static void print_training_data(const char* prefix, Method* method); + static void print_counters_on(outputStream* st, const char* prefix, Method* m); + static void print_training_data_on(outputStream* st, const char* prefix, Method* method); // Has a method been long around? // We don't remove old methods from the compile queue even if they have // very low activity (see select_task()). @@ -318,6 +318,7 @@ class CompilationPolicy : AllStatic { static void set_c2_count(int x) { _c2_count = x; } enum EventType { CALL, LOOP, COMPILE, FORCE_COMPILE, FORCE_RECOMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; + static void print_event_on(outputStream *st, EventType type, Method* m, Method* im, int bci, CompLevel level); static void print_event(EventType type, Method* m, Method* im, int bci, CompLevel level); // Check if the method can be compiled, change level if necessary static void compile(const methodHandle& mh, int bci, CompLevel level, TRAPS); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java index 0d03313bec2..6db81351e6b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java @@ -257,6 +257,16 @@ public class AOTFlags { out.shouldContain("AOTCache creation is complete: hello.aot"); out.shouldMatch("Picked up JAVA_TOOL_OPTIONS:.* -Dmy.prop=My' 'string' '-Xshare:off' 'here"); out.shouldHaveExitValue(0); + + // Training run with -XX:+PrintTieredEvents (see JDK-8362530). + printTestCase("Training run with -XX:+PrintTieredEvents"); + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=record", + "-XX:+PrintTieredEvents", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, helloClass); + out = CDSTestUtils.executeAndLog(pb, "train-with-tiered-events"); + out.shouldHaveExitValue(0); } static void negativeTests() throws Exception { From ba231052319676ece5105253b58efa4e906feab4 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 14 Aug 2025 17:02:05 +0000 Subject: [PATCH 087/471] 8365048: idea.sh script does not correctly detect/handle git worktrees Reviewed-by: shade, vyazici, erikj, mcimadamore, ihse --- bin/idea.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/idea.sh b/bin/idea.sh index eb37964f396..a184884b61a 100644 --- a/bin/idea.sh +++ b/bin/idea.sh @@ -125,7 +125,8 @@ if [ -d "$TOPLEVEL_DIR/.hg" ] ; then VCS_TYPE="hg4idea" fi -if [ -d "$TOPLEVEL_DIR/.git" ] ; then +# Git worktrees use a '.git' file rather than directory, so test both. +if [ -d "$TOPLEVEL_DIR/.git" -o -f "$TOPLEVEL_DIR/.git" ] ; then VCS_TYPE="Git" fi From dccca0fb7a892d31179b70fa861b8b3cdde54e84 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 14 Aug 2025 19:58:54 +0000 Subject: [PATCH 088/471] 8365572: Shenandoah: Remove unused thread local _paced_time field Reviewed-by: shade --- .../gc/shenandoah/shenandoahThreadLocalData.cpp | 1 - .../gc/shenandoah/shenandoahThreadLocalData.hpp | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp index dd500462d0f..ace5ab5e69a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp @@ -37,7 +37,6 @@ ShenandoahThreadLocalData::ShenandoahThreadLocalData() : _card_table(nullptr), _gclab(nullptr), _gclab_size(0), - _paced_time(0), _plab(nullptr), _plab_desired_size(0), _plab_actual_size(0), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 098e20a72ec..37d935d1f78 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -58,8 +58,6 @@ private: PLAB* _gclab; size_t _gclab_size; - double _paced_time; - // Thread-local allocation buffer only used in generational mode. // Used both by mutator threads and by GC worker threads // for evacuations within the old generation and @@ -237,18 +235,6 @@ public: return data(thread)->_plab_actual_size; } - static void add_paced_time(Thread* thread, double v) { - data(thread)->_paced_time += v; - } - - static double paced_time(Thread* thread) { - return data(thread)->_paced_time; - } - - static void reset_paced_time(Thread* thread) { - data(thread)->_paced_time = 0; - } - // Evacuation OOM handling static bool is_oom_during_evac(Thread* thread) { return data(thread)->_oom_during_evac; From c5cbcac828e1c7aa845cf16e68f6306ae49e050c Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 14 Aug 2025 20:27:08 +0000 Subject: [PATCH 089/471] 8361730: The CodeBuilder.trying(BlockCodeBuilder,CatchBuilder) method generates corrupted bytecode in certain cases Reviewed-by: asotona --- .../share/classes/java/lang/classfile/CodeBuilder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index e640700c2e9..fe82d5d0bf0 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -175,6 +175,11 @@ public sealed interface CodeBuilder * A builder for blocks of code. Its {@link #startLabel()} and {@link * #endLabel()} do not enclose the entire method body, but from the start to * the end of the block. + *

+ * The location where a block of code merges back to its parent block, as + * represented by the {@link #breakLabel()}, is expected to be reachable, + * either from this block or the parent block. The built code may be + * malformed if there is no executable code at that location. * * @since 24 */ From 8c363b3e3e5c1273a5e9b3393ed09a31b0647a21 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 14 Aug 2025 21:41:14 +0000 Subject: [PATCH 090/471] 8364319: Move java.lang.constant.AsTypeMethodHandleDesc to jdk.internal Reviewed-by: redestad --- .../java/lang/constant/ConstantDescs.java | 4 ---- .../java/lang/constant/MethodHandleDesc.java | 3 ++- .../constant/AsTypeMethodHandleDesc.java | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) rename src/java.base/share/classes/{java/lang => jdk/internal}/constant/AsTypeMethodHandleDesc.java (75%) diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java index c976342033f..0ef45ec34bb 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java @@ -44,7 +44,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static java.lang.constant.DirectMethodHandleDesc.*; import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC; /** @@ -338,9 +337,6 @@ public final class ConstantDescs { */ public static final MethodTypeDesc MTD_void = MethodTypeDesc.of(CD_void); - static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE - = MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType", - MethodTypeDesc.of(CD_MethodHandle, CD_MethodType)); /** * Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for * an {@code invokedynamic} callsite, which is a static method whose leading diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java index 6a3541bf5e9..18786481fa6 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import jdk.internal.constant.AsTypeMethodHandleDesc; import jdk.internal.constant.DirectMethodHandleDescImpl; import static java.lang.constant.ConstantDescs.CD_void; diff --git a/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java b/src/java.base/share/classes/jdk/internal/constant/AsTypeMethodHandleDesc.java similarity index 75% rename from src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java rename to src/java.base/share/classes/jdk/internal/constant/AsTypeMethodHandleDesc.java index 32818a9bc00..8b250c0fff8 100644 --- a/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java +++ b/src/java.base/share/classes/jdk/internal/constant/AsTypeMethodHandleDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -22,8 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package java.lang.constant; +package jdk.internal.constant; +import java.lang.constant.ConstantDescs; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -37,15 +42,19 @@ import static java.util.Objects.requireNonNull; * {@link MethodHandle} constant that performs a {@link MethodHandle#asType(MethodType)} * adaptation on another {@link MethodHandle}. */ -final class AsTypeMethodHandleDesc extends DynamicConstantDesc +public final class AsTypeMethodHandleDesc extends DynamicConstantDesc implements MethodHandleDesc { + private static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE + = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.VIRTUAL, CD_MethodHandle, "asType", + MethodTypeDesc.of(CD_MethodHandle, ConstantDescs.CD_MethodType)); + private final MethodHandleDesc underlying; private final MethodTypeDesc type; - AsTypeMethodHandleDesc(MethodHandleDesc underlying, MethodTypeDesc type) { + public AsTypeMethodHandleDesc(MethodHandleDesc underlying, MethodTypeDesc type) { super(BSM_INVOKE, ConstantDescs.DEFAULT_NAME, CD_MethodHandle, - ConstantDescs.MHD_METHODHANDLE_ASTYPE, underlying, type); + MHD_METHODHANDLE_ASTYPE, underlying, type); this.underlying = requireNonNull(underlying); this.type = requireNonNull(type); } From a65f20022080e627da4782b9b643912a9dd69335 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 14 Aug 2025 23:59:34 +0000 Subject: [PATCH 091/471] 8365512: Replace -Xcomp with -Xmixed for AOT assembly phase Reviewed-by: shade --- src/hotspot/share/cds/cdsConfig.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 85c40df2606..51899490a12 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -643,8 +643,17 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla } if (is_dumping_static_archive()) { - if (is_dumping_preimage_static_archive() || is_dumping_final_static_archive()) { - // Don't tweak execution mode + if (is_dumping_preimage_static_archive()) { + // Don't tweak execution mode during AOT training run + } else if (is_dumping_final_static_archive()) { + if (Arguments::mode() == Arguments::_comp) { + // AOT assembly phase submits the non-blocking compilation requests + // for methods collected during training run, then waits for all compilations + // to complete. With -Xcomp, we block for each compilation request, which is + // counter-productive. Switching back to mixed mode improves testing time + // with AOT and -Xcomp. + Arguments::set_mode_flags(Arguments::_mixed); + } } else if (!mode_flag_cmd_line) { // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive. // From 44b19c01acdfff07a4f017466be3f03fae6013c6 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Fri, 15 Aug 2025 02:53:42 +0000 Subject: [PATCH 092/471] 8365532: java/lang/module/ModuleReader/ModuleReaderTest.testImage fails Reviewed-by: alanb --- .../share/classes/jdk/internal/module/SystemModuleFinders.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java index 09ad3dc456d..39f433d4041 100644 --- a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java +++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java @@ -430,6 +430,7 @@ public final class SystemModuleFinders { @Override public Optional find(String name) throws IOException { + Objects.requireNonNull(name); String resourcePath = "/" + module + "/" + name; if (containsResource(resourcePath)) { URI u = JNUA.create("jrt", resourcePath); From 6fb6f3d39b321e2a1c1fa2cef2c19222a6dcf7b9 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 15 Aug 2025 04:25:37 +0000 Subject: [PATCH 093/471] 8361638: java.lang.classfile.CodeBuilder.CatchBuilder should not throw IllegalArgumentException for representable exception handlers Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 28 +++++++++++---- .../classfile/instruction/ExceptionCatch.java | 6 ++-- .../classfile/impl/CatchBuilderImpl.java | 35 ++++++++++--------- .../jdk/classfile/BuilderTryCatchTest.java | 34 ++++++++++++++---- 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index fe82d5d0bf0..c1070bbcc77 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -330,6 +330,11 @@ public sealed interface CodeBuilder /** * A builder to add catch blocks. + *

+ * The order of catch blocks is significant. When an exception is thrown + * by the try block, the first catch block whose exception type is {@linkplain + * Class#isAssignableFrom(Class) the same class as or a superclass of} the + * class of exception thrown is branched to (JVMS {@jvms 2.10}). * * @see #trying * @see ExceptionCatch @@ -348,13 +353,16 @@ public sealed interface CodeBuilder * If the type of exception is {@code null} then the catch block catches * all exceptions. * + * @apiNote + * If the type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionType the type of exception to catch, may be {@code null} * @param catchHandler handler that receives a {@link BlockCodeBuilder} to * generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * an exception of the given type or {@code exceptionType} - * represents a primitive type + * @throws IllegalArgumentException if {@code exceptionType} represents + * a primitive type * @see #catchingMulti * @see #catchingAll */ @@ -372,12 +380,16 @@ public sealed interface CodeBuilder * If list of exception types is empty then the catch block catches all * exceptions. * + * @apiNote + * If every type of exception to catch is already handled by previous + * catch blocks, this block will never be executed. + * * @param exceptionTypes the types of exception to catch * @param catchHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block * @return this builder - * @throws IllegalArgumentException if an existing catch block catches - * one or more exceptions of the given types + * @throws IllegalArgumentException if any exception type represents a + * primitive type * @see #catching * @see #catchingAll */ @@ -392,10 +404,12 @@ public sealed interface CodeBuilder * The caught exception will be on top of the operand stack when the * catch block is entered. * + * @apiNote + * Since this block intercepts all exceptions, all subsequent catch + * blocks will never be executed. + * * @param catchAllHandler handler that receives a {@link BlockCodeBuilder} * to generate the body of the catch block - * @throws IllegalArgumentException if an existing catch block catches - * all exceptions * @see #catching * @see #catchingMulti */ diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java index e924ca718e7..b0e5af2941e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ExceptionCatch.java @@ -39,8 +39,10 @@ import jdk.internal.classfile.impl.AbstractPseudoInstruction; * A pseudo-instruction modeling an entry in the {@code exception_table} array * of a {@link CodeAttribute Code} attribute. Catch (JVMS {@jvms 3.12}) and * finally (JVMS {@jvms 3.14}) blocks in Java source code compile to exception - * table entries. Delivered as a {@link CodeElement} when traversing the - * contents of a {@link CodeModel}. + * table entries. The order of exception table entries is significant: when an + * exception is thrown in a method, execution branches to the first matching + * exception handler if such a handler exists (JVMS {@jvms 2.10}). Delivered as + * a {@link CodeElement} when traversing the contents of a {@link CodeModel}. *

* An exception table entry is composite: * {@snippet lang=text : diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java index d520753326e..89d43135551 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CatchBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -27,8 +27,9 @@ package jdk.internal.classfile.impl; import java.lang.classfile.CodeBuilder; import java.lang.classfile.Label; import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDesc; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -39,14 +40,12 @@ public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder { final CodeBuilder b; final BlockCodeBuilderImpl tryBlock; final Label tryCatchEnd; - final Set catchTypes; BlockCodeBuilderImpl catchBlock; public CatchBuilderImpl(CodeBuilder b, BlockCodeBuilderImpl tryBlock, Label tryCatchEnd) { this.b = b; this.tryBlock = tryBlock; this.tryCatchEnd = tryCatchEnd; - this.catchTypes = new HashSet<>(); } @Override @@ -59,18 +58,24 @@ public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder { Objects.requireNonNull(exceptionTypes); Objects.requireNonNull(catchHandler); + // nullable list of CP entries - null means catching all (0) + List entries = new ArrayList<>(Math.max(1, exceptionTypes.size())); + if (exceptionTypes.isEmpty()) { + entries.add(null); + } else { + for (var exceptionType : exceptionTypes) { + var entry = b.constantPool().classEntry(exceptionType); // throws IAE + entries.add(entry); + } + } + // End validation + if (catchBlock == null) { if (tryBlock.reachable()) { b.branch(Opcode.GOTO, tryCatchEnd); } } - for (var exceptionType : exceptionTypes) { - if (!catchTypes.add(exceptionType)) { - throw new IllegalArgumentException("Existing catch block catches exception of type: " + exceptionType); - } - } - // Finish prior catch block if (catchBlock != null) { catchBlock.end(); @@ -82,13 +87,9 @@ public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder { catchBlock = new BlockCodeBuilderImpl(b, tryCatchEnd); Label tryStart = tryBlock.startLabel(); Label tryEnd = tryBlock.endLabel(); - if (exceptionTypes.isEmpty()) { - catchBlock.exceptionCatchAll(tryStart, tryEnd, catchBlock.startLabel()); - } - else { - for (var exceptionType : exceptionTypes) { - catchBlock.exceptionCatch(tryStart, tryEnd, catchBlock.startLabel(), exceptionType); - } + for (var entry : entries) { + // This accepts null for catching all + catchBlock.exceptionCatch(tryStart, tryEnd, catchBlock.startLabel(), entry); } catchBlock.start(); catchHandler.accept(catchBlock); diff --git a/test/jdk/jdk/classfile/BuilderTryCatchTest.java b/test/jdk/jdk/classfile/BuilderTryCatchTest.java index 3de12559163..0a966e2a655 100644 --- a/test/jdk/jdk/classfile/BuilderTryCatchTest.java +++ b/test/jdk/jdk/classfile/BuilderTryCatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* * @test + * @bug 8361638 * @summary Testing ClassFile builder blocks. * @run junit BuilderTryCatchTest */ @@ -37,6 +38,7 @@ import java.lang.classfile.instruction.ExceptionCatch; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; @@ -47,20 +49,40 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import static java.lang.constant.ConstantDescs.CD_Double; -import static java.lang.constant.ConstantDescs.CD_Integer; -import static java.lang.constant.ConstantDescs.CD_Object; -import static java.lang.constant.ConstantDescs.CD_String; - class BuilderTryCatchTest { static final ClassDesc CD_IOOBE = IndexOutOfBoundsException.class.describeConstable().get(); static final ClassDesc CD_NPE = NullPointerException.class.describeConstable().get(); static final MethodTypeDesc MTD_String = MethodType.methodType(String.class).describeConstable().get(); + @Test + void testExceptionalContracts() throws Throwable { + generateTryCatchMethod(catchBuilder -> { + Consumer handler = tb -> tb.pop().aconst_null().areturn(); + assertThrows(NullPointerException.class, () -> catchBuilder.catching(CD_NPE, null)); + assertThrows(NullPointerException.class, () -> catchBuilder.catchingMulti(null, handler)); + assertThrows(NullPointerException.class, () -> catchBuilder.catchingMulti(List.of(), null)); + assertThrows(NullPointerException.class, () -> catchBuilder.catchingMulti(Collections.singletonList(null), null)); + assertThrows(NullPointerException.class, () -> catchBuilder.catchingAll(null)); + catchBuilder.catchingMulti(List.of(CD_IOOBE, CD_NPE), tb -> { + tb.invokevirtual(CD_Object, "toString", MTD_String); + tb.astore(1); + }); + catchBuilder.catchingAll(tb -> tb.pop().loadConstant("all").areturn()); + assertThrows(IllegalArgumentException.class, () -> catchBuilder.catching(CD_int, handler)); + assertDoesNotThrow(() -> catchBuilder.catching(CD_NPE, handler)); + assertDoesNotThrow(() -> catchBuilder.catching(null, handler)); + assertDoesNotThrow(() -> catchBuilder.catchingMulti(List.of(), handler)); + assertDoesNotThrow(() -> catchBuilder.catchingMulti(List.of(CD_Exception, CD_IOOBE), handler)); + assertThrows(IllegalArgumentException.class, () -> catchBuilder.catchingMulti(List.of(CD_long, CD_Throwable), handler)); + assertDoesNotThrow(() -> catchBuilder.catchingAll(handler)); + }); + } + @Test void testTryCatchCatchAll() throws Throwable { byte[] bytes = generateTryCatchMethod(catchBuilder -> { From e3aeebec1798b9adbb02e11f285951d4275c52e8 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 15 Aug 2025 07:35:52 +0000 Subject: [PATCH 094/471] 8365468: EagerJVMCI should only apply to the CompilerBroker JVMCI runtime Reviewed-by: never --- .../share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 492f20f1b59..c35f216e624 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -186,7 +186,10 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { // Can only do eager initialization of the JVMCI compiler // once the singleton instance is available. if (result.config.getFlag("EagerJVMCI", Boolean.class)) { - result.getCompiler(); + // EagerJVMCI only applies to JVMCI when used by the CompileBroker. + if (result.getCompilerToVM().isCompilerThread()) { + result.getCompiler(); + } } } // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is From fa2eb616482250dff6a3b667798aec37114005a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Fri, 15 Aug 2025 08:55:11 +0000 Subject: [PATCH 095/471] 8365491: VSCode IDE: add basic configuration for the Oracle Java extension Reviewed-by: ihse, jlahoda --- make/ide/vscode/hotspot/template-workspace.jsonc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/ide/vscode/hotspot/template-workspace.jsonc b/make/ide/vscode/hotspot/template-workspace.jsonc index 30533c7ce84..c582c48047d 100644 --- a/make/ide/vscode/hotspot/template-workspace.jsonc +++ b/make/ide/vscode/hotspot/template-workspace.jsonc @@ -12,12 +12,17 @@ ], "extensions": { "recommendations": [ + "oracle.oracle-java", // {{INDEXER_EXTENSIONS}} ] }, "settings": { // {{INDEXER_SETTINGS}} + // Java extension + "jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk", + "jdk.java.onSave.organizeImports": false, // prevents unnecessary changes + // Additional conventions "files.associations": { "*.gmk": "makefile" From 5856dc34c82de9f840be1dc28a9917224971491f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Fri, 15 Aug 2025 09:32:51 +0000 Subject: [PATCH 096/471] 8365199: Use a set instead of a list as the intermediary Klass* storage to reduce typeset processing Reviewed-by: egahlin --- .../checkpoint/objectSampleCheckpoint.cpp | 78 +++---- .../leakprofiler/sampling/objectSample.hpp | 13 +- .../recorder/checkpoint/jfrMetadataEvent.cpp | 5 +- .../recorder/checkpoint/jfrMetadataEvent.hpp | 4 +- .../recorder/checkpoint/types/jfrTypeSet.cpp | 13 +- .../checkpoint/types/jfrTypeSetUtils.cpp | 53 +++-- .../checkpoint/types/jfrTypeSetUtils.hpp | 74 +++---- .../recorder/service/jfrRecorderService.cpp | 7 +- .../share/jfr/support/jfrKlassUnloading.cpp | 15 +- src/hotspot/share/jfr/utilities/jfrSet.hpp | 197 +++++++++++++----- test/jdk/jdk/jfr/event/runtime/TestFlush.java | 2 - 11 files changed, 281 insertions(+), 180 deletions(-) diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index 3d87e86e9bd..300786daf05 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -48,14 +48,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" -const unsigned int initial_size = 431; - -static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { - return new JfrCHeapTraceIdSet(size); -} - -static JfrCHeapTraceIdSet* unloaded_thread_id_set = nullptr; - class ThreadIdExclusiveAccess : public StackObj { private: static Semaphore _mutex_semaphore; @@ -66,19 +58,13 @@ class ThreadIdExclusiveAccess : public StackObj { Semaphore ThreadIdExclusiveAccess::_mutex_semaphore(1); -static bool has_thread_exited(traceid tid) { - assert(tid != 0, "invariant"); - if (unloaded_thread_id_set == nullptr) { - return false; - } - ThreadIdExclusiveAccess lock; - return unloaded_thread_id_set->contains(tid); -} +static const unsigned initial_set_size = 512; +static JfrCHeapTraceIdSet* unloaded_thread_id_set = nullptr; static void add_to_unloaded_thread_set(traceid tid) { ThreadIdExclusiveAccess lock; if (unloaded_thread_id_set == nullptr) { - unloaded_thread_id_set = c_heap_allocate_set(); + unloaded_thread_id_set = new (mtTracing) JfrCHeapTraceIdSet(initial_set_size); } unloaded_thread_id_set->add(tid); } @@ -193,12 +179,6 @@ inline void BlobCache::on_unlink(BlobEntry* entry) const { assert(entry != nullptr, "invariant"); } -static JfrResourceAreaTraceIdSet* id_set = nullptr; - -static void prepare_for_resolution() { - id_set = new JfrResourceAreaTraceIdSet(initial_size); -} - static bool stack_trace_precondition(const ObjectSample* sample) { assert(sample != nullptr, "invariant"); return sample->has_stack_trace_id() && !sample->is_dead(); @@ -213,6 +193,8 @@ static void add_to_leakp_set(const ObjectSample* sample) { JfrTraceId::load_leakp(object->klass()); } +static JfrResourceAreaTraceIdSet* resolution_set = nullptr; + class StackTraceBlobInstaller { private: BlobCache _cache; @@ -220,8 +202,9 @@ class StackTraceBlobInstaller { const JfrStackTrace* resolve(const ObjectSample* sample) const; public: StackTraceBlobInstaller() : _cache(JfrOptionSet::old_object_queue_size()) { - prepare_for_resolution(); + resolution_set = new JfrResourceAreaTraceIdSet(initial_set_size); } + void sample_do(ObjectSample* sample) { if (stack_trace_precondition(sample)) { add_to_leakp_set(sample); @@ -314,8 +297,8 @@ static bool is_klass_unloaded(traceid klass_id) { static bool is_processed(traceid method_id) { assert(method_id != 0, "invariant"); - assert(id_set != nullptr, "invariant"); - return !id_set->add(method_id); + assert(resolution_set != nullptr, "invariant"); + return !resolution_set->add(method_id); } void ObjectSampleCheckpoint::add_to_leakp_set(const InstanceKlass* ik, traceid method_id) { @@ -356,7 +339,7 @@ static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) { assert(sample->has_thread(), "invariant"); - if (sample->is_virtual_thread() || has_thread_exited(sample->thread_id())) { + if (sample->is_virtual_thread() || sample->thread_exited()) { write_blob(sample->thread(), writer); } } @@ -372,13 +355,13 @@ static inline bool should_write(const JfrStackTrace* stacktrace) { class LeakProfilerStackTraceWriter { private: JfrCheckpointWriter& _writer; - int _count; + unsigned _count; public: LeakProfilerStackTraceWriter(JfrCheckpointWriter& writer) : _writer(writer), _count(0) { assert(_stacktrace_id_set != nullptr, "invariant"); } - int count() const { return _count; } + unsigned count() const { return _count; } void operator()(const JfrStackTrace* stacktrace) { if (should_write(stacktrace)) { @@ -394,12 +377,10 @@ void ObjectSampleCheckpoint::write_stacktraces(Thread* thread) { JfrCheckpointWriter writer(thread); writer.write_type(TYPE_STACKTRACE); - const int64_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet - + writer.write_count(_stacktrace_id_set->size()); LeakProfilerStackTraceWriter lpstw(writer); JfrStackTraceRepository::iterate_leakprofiler(lpstw); assert(lpstw.count() == _stacktrace_id_set->size(), "invariant"); - writer.write_count(lpstw.count(), count_offset); } static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) { @@ -422,6 +403,16 @@ static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer) write_type_set_blob(sample, writer); } +static void check_if_thread_exited(const ObjectSample* sample) { + assert(sample != nullptr, "invariant"); + if (sample->thread_exited() || unloaded_thread_id_set == nullptr) { + return; + } + if (unloaded_thread_id_set->contains(sample->thread_id())) { + sample->set_thread_exited(); + } +} + class BlobWriter { private: const ObjectSampler* _sampler; @@ -431,23 +422,36 @@ class BlobWriter { BlobWriter(const ObjectSampler* sampler, JfrCheckpointWriter& writer, jlong last_sweep) : _sampler(sampler), _writer(writer), _last_sweep(last_sweep) {} void sample_do(ObjectSample* sample) { + check_if_thread_exited(sample); if (sample->is_alive_and_older_than(_last_sweep)) { write_blobs(sample, _writer); } } }; +static void delete_unloaded_thread_id_set() { + if (unloaded_thread_id_set != nullptr) { + delete unloaded_thread_id_set; + unloaded_thread_id_set = nullptr; + } +} + static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) { // sample set is predicated on time of last sweep const jlong last_sweep = emit_all ? max_jlong : ObjectSampler::last_sweep(); JfrCheckpointWriter writer(thread, false); BlobWriter cbw(sampler, writer, last_sweep); + ThreadIdExclusiveAccess lock; iterate_samples(cbw, true); + delete_unloaded_thread_id_set(); } -static inline unsigned int set_size() { - const unsigned int queue_size = static_cast(JfrOptionSet::old_object_queue_size()); - return queue_size > initial_size ? queue_size : initial_size; +static inline unsigned stacktrace_id_set_size() { + unsigned queue_size = static_cast(JfrOptionSet::old_object_queue_size()); + if (!is_power_of_2(queue_size)) { + queue_size = next_power_of_2(queue_size); + } + return queue_size > initial_set_size ? queue_size : initial_set_size; } void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) { @@ -456,7 +460,9 @@ void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge assert(thread != nullptr, "invariant"); { ResourceMark rm(thread); - _stacktrace_id_set = new JfrResourceAreaTraceIdSet(set_size()); + const unsigned stacktrace_set_size = stacktrace_id_set_size(); + assert(is_power_of_2(stacktrace_set_size), "invariant"); + _stacktrace_id_set = new JfrResourceAreaTraceIdSet(stacktrace_set_size); write_sample_blobs(sampler, emit_all, thread); if (_stacktrace_id_set->is_nonempty()) { write_stacktraces(thread); diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp index 214de827d03..66ed9145c81 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp @@ -59,6 +59,7 @@ class ObjectSample : public JfrCHeapObj { size_t _heap_used_at_last_gc; int _index; bool _virtual_thread; + mutable bool _thread_exited; void release_references() { _stacktrace.~JfrBlobHandle(); @@ -82,7 +83,8 @@ class ObjectSample : public JfrCHeapObj { _allocated(0), _heap_used_at_last_gc(0), _index(0), - _virtual_thread(false) {} + _virtual_thread(false), + _thread_exited(false) {} ObjectSample* next() const { return _next; @@ -225,6 +227,15 @@ class ObjectSample : public JfrCHeapObj { _virtual_thread = true; } + bool thread_exited() const { + return _thread_exited; + } + + void set_thread_exited() const { + assert(!_thread_exited, "invariant"); + _thread_exited = true; + } + const JfrBlobHandle& type_set() const { return _type_set; } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp index bf27fa59031..20e9c1e6798 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp @@ -64,11 +64,11 @@ static void write_metadata_blob(JfrChunkWriter& chunkwriter, JavaThread* thread) chunkwriter.write_unbuffered(data_address, length); } -void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { +size_t JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { assert(chunkwriter.is_valid(), "invariant"); check_internal_types(); if (last_metadata_id == metadata_id && chunkwriter.has_metadata()) { - return; + return 0; } JavaThread* const jt = JavaThread::current(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); @@ -87,6 +87,7 @@ void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) { chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset); chunkwriter.set_last_metadata_offset(metadata_offset); last_metadata_id = metadata_id; + return 1; } void JfrMetadataEvent::update(jbyteArray metadata) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp index abadbfb0b13..1b5bd45c946 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -36,7 +36,7 @@ class JfrChunkWriter; // class JfrMetadataEvent : AllStatic { public: - static void write(JfrChunkWriter& writer); + static size_t write(JfrChunkWriter& writer); static void update(jbyteArray metadata); }; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 69f002138ec..375ab4d04e9 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -1048,19 +1048,15 @@ class MethodIteratorHost { private: MethodCallback _method_cb; KlassCallback _klass_cb; - KlassUsedPredicate _klass_used_predicate; - MethodUsedPredicate _method_used_predicate; MethodFlagPredicate _method_flag_predicate; public: MethodIteratorHost(JfrCheckpointWriter* writer) : _method_cb(writer, unloading(), false), _klass_cb(writer, unloading(), false), - _klass_used_predicate(current_epoch()), - _method_used_predicate(current_epoch()), _method_flag_predicate(current_epoch()) {} bool operator()(KlassPtr klass) { - if (_method_used_predicate(klass)) { + if (klass->is_instance_klass()) { const InstanceKlass* ik = InstanceKlass::cast(klass); while (ik != nullptr) { const int len = ik->methods()->length(); @@ -1075,7 +1071,7 @@ class MethodIteratorHost { ik = ik->previous_versions(); } } - return _klass_used_predicate(klass) ? _klass_cb(klass) : true; + return _klass_cb(klass); } int count() const { return _method_cb.count(); } @@ -1280,10 +1276,11 @@ static void setup(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer _class_unload = class_unload; _flushpoint = flushpoint; if (_artifacts == nullptr) { - _artifacts = new JfrArtifactSet(class_unload); + _artifacts = new JfrArtifactSet(class_unload, previous_epoch()); } else { - _artifacts->initialize(class_unload); + _artifacts->initialize(class_unload, previous_epoch()); } + assert(current_epoch() || _leakp_writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); assert(!_artifacts->has_klass_entries(), "invariant"); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index d213ecd7d75..c60556927ad 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -29,18 +29,23 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr), - _klass_list(nullptr), - _total_count(0), - _class_unload(class_unload) { - initialize(class_unload); - assert(_klass_list != nullptr, "invariant"); +JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _symbol_table(nullptr), + _klass_set(nullptr), + _klass_loader_set(nullptr), + _klass_loader_leakp_set(nullptr), + _total_count(0), + _class_unload(class_unload) { + initialize(class_unload, previous_epoch); + assert(!previous_epoch || _klass_loader_leakp_set != nullptr, "invariant"); + assert(_klass_loader_set != nullptr, "invariant"); + assert(_klass_set != nullptr, "invariant"); } -static const size_t initial_klass_list_size = 4096; -const int initial_klass_loader_set_size = 64; +static unsigned initial_klass_set_size = 4096; +static unsigned initial_klass_loader_set_size = 64; +static unsigned initial_klass_loader_leakp_set_size = 64; -void JfrArtifactSet::initialize(bool class_unload) { +void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { _class_unload = class_unload; if (_symbol_table == nullptr) { _symbol_table = JfrSymbolTable::create(); @@ -50,9 +55,11 @@ void JfrArtifactSet::initialize(bool class_unload) { _symbol_table->set_class_unload(class_unload); _total_count = 0; // Resource allocations. Keep in this allocation order. - _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size); - _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); - _klass_list = new GrowableArray(initial_klass_list_size); + if (previous_epoch) { + _klass_loader_leakp_set = new JfrKlassSet(initial_klass_loader_leakp_set_size); + } + _klass_loader_set = new JfrKlassSet(initial_klass_loader_set_size); + _klass_set = new JfrKlassSet(initial_klass_set_size); } void JfrArtifactSet::clear() { @@ -93,17 +100,12 @@ traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) } bool JfrArtifactSet::has_klass_entries() const { - return _klass_list->is_nonempty(); + return _klass_set->is_nonempty(); } - -int JfrArtifactSet::entries() const { - return _klass_list->length(); -} - -static inline bool not_in_set(GrowableArray* set, const Klass* k) { +static inline bool not_in_set(JfrArtifactSet::JfrKlassSet* set, const Klass* k) { assert(set != nullptr, "invariant"); assert(k != nullptr, "invariant"); - return !JfrMutablePredicate::test(set, k); + return set->add(k); } bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) { @@ -116,16 +118,21 @@ bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) { void JfrArtifactSet::register_klass(const Klass* k) { assert(k != nullptr, "invariant"); assert(IS_SERIALIZED(k), "invariant"); - assert(_klass_list != nullptr, "invariant"); - _klass_list->append(k); + assert(_klass_set != nullptr, "invariant"); + _klass_set->add(k); } size_t JfrArtifactSet::total_count() const { + assert(_klass_set != nullptr, "invariant"); + initial_klass_set_size = MAX2(initial_klass_set_size, _klass_set->table_size()); + assert(_klass_loader_set != nullptr, "invariant"); + initial_klass_loader_set_size = MAX2(initial_klass_loader_set_size, _klass_loader_set->table_size()); return _total_count; } void JfrArtifactSet::increment_checkpoint_id() { assert(_symbol_table != nullptr, "invariant"); _symbol_table->increment_checkpoint_id(); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); } - diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 657aee9dc53..74200aef1f1 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -28,12 +28,10 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/support/jfrSymbolTable.hpp" #include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" -template -class GrowableArray; - // Composite callback/functor building block template class CompositeFunctor { @@ -135,27 +133,6 @@ class SymbolPredicate { } }; -class KlassUsedPredicate { - bool _current_epoch; - public: - KlassUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} - bool operator()(const Klass* klass) { - return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); - } -}; - -class MethodUsedPredicate { - bool _current_epoch; -public: - MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} - bool operator()(const Klass* klass) { - if (!klass->is_instance_klass()) { - return false; - } - return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); - } -}; - template class MethodFlagPredicate { bool _current_epoch; @@ -203,20 +180,46 @@ class LeakPredicate { * in the respective VM subsystems. */ class JfrArtifactSet : public JfrCHeapObj { + public: + class JfrArtifactSetConfig : public AllStatic { + public: + typedef const Klass* KEY_TYPE; + + constexpr static AnyObj::allocation_type alloc_type() { + return AnyObj::RESOURCE_AREA; + } + + constexpr static MemTag memory_tag() { + return mtInternal; + } + + // Knuth multiplicative hashing. + static uint32_t hash(const KEY_TYPE& k) { + const uint32_t v = static_cast(JfrTraceId::load_raw(k)); + return v * UINT32_C(2654435761); + } + + static bool cmp(const KEY_TYPE& lhs, const KEY_TYPE& rhs) { + return lhs == rhs; + } + }; + + typedef JfrSet JfrKlassSet; + private: JfrSymbolTable* _symbol_table; - GrowableArray* _klass_list; - GrowableArray* _klass_loader_set; - GrowableArray* _klass_loader_leakp_set; + JfrKlassSet* _klass_set; + JfrKlassSet* _klass_loader_set; + JfrKlassSet* _klass_loader_leakp_set; size_t _total_count; bool _class_unload; public: - JfrArtifactSet(bool class_unload); + JfrArtifactSet(bool class_unload, bool previous_epoch); ~JfrArtifactSet(); // caller needs ResourceMark - void initialize(bool class_unload); + void initialize(bool class_unload, bool previous_epoch); void clear(); traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); @@ -231,7 +234,6 @@ class JfrArtifactSet : public JfrCHeapObj { const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; bool has_klass_entries() const; - int entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_cld_klass(const Klass* k, bool leakp); @@ -254,19 +256,17 @@ class JfrArtifactSet : public JfrCHeapObj { template void iterate_klasses(Functor& functor) const { - if (iterate(functor, _klass_list)) { + if (iterate(functor, _klass_set)) { iterate(functor, _klass_loader_set); } } private: template - bool iterate(Functor& functor, GrowableArray* list) const { - assert(list != nullptr, "invariant"); - for (int i = 0; i < list->length(); ++i) { - if (!functor(list->at(i))) { - return false; - } + bool iterate(Functor& functor, JfrKlassSet* set) const { + assert(set != nullptr, "invariant"); + if (set->is_nonempty()) { + set->iterate(functor); } return true; } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index f0170bac460..7784148aee5 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -367,13 +367,14 @@ static u4 flush_typeset(JfrCheckpointManager& checkpoint_manager, JfrChunkWriter class MetadataEvent : public StackObj { private: JfrChunkWriter& _cw; + size_t _elements; public: - MetadataEvent(JfrChunkWriter& cw) : _cw(cw) {} + MetadataEvent(JfrChunkWriter& cw) : _cw(cw), _elements(0) {} bool process() { - JfrMetadataEvent::write(_cw); + _elements = JfrMetadataEvent::write(_cw); return true; } - size_t elements() const { return 1; } + size_t elements() const { return _elements; } }; typedef WriteContent WriteMetadata; diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp index ce5de54ed16..d136eeab53a 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp @@ -30,10 +30,10 @@ #include "runtime/mutexLocker.hpp" #include "utilities/macros.hpp" -static const int initial_size = 1009; +static const int initial_size = 1024; static JfrCHeapTraceIdSet* c_heap_allocate_set(int size = initial_size) { - return new JfrCHeapTraceIdSet(size); + return new (mtTracing) JfrCHeapTraceIdSet(size); } // Track the set of unloaded klasses during a chunk / epoch. @@ -68,18 +68,9 @@ static JfrCHeapTraceIdSet* get_unload_set_previous_epoch() { return get_unload_set(JfrTraceIdEpoch::previous()); } -static bool is_nonempty_set(u1 epoch) { - if (epoch == 0) { - return _unload_set_epoch_0 != nullptr && _unload_set_epoch_0->is_nonempty(); - } - return _unload_set_epoch_1 != nullptr && _unload_set_epoch_1->is_nonempty(); -} - void JfrKlassUnloading::clear() { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (is_nonempty_set(JfrTraceIdEpoch::previous())) { - get_unload_set_previous_epoch()->clear(); - } + get_unload_set_previous_epoch()->clear(); } static void add_to_unloaded_klass_set(traceid klass_id) { diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index 40a5d73f370..b6458d3f9a4 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -25,15 +25,13 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP -#include "jfr/utilities/jfrAllocation.hpp" +#include "memory/allocation.hpp" #include "jfr/utilities/jfrTypes.hpp" -#include "utilities/resizableHashTable.hpp" -template -class ConfigTraceID : public AllStatic { +template +class JfrSetConfig : public AllStatic { public: - typedef AllocPolicy STORAGE; - typedef traceid TYPE; + typedef K KEY_TYPE; constexpr static AnyObj::allocation_type alloc_type() { return AllocType; @@ -44,80 +42,171 @@ class ConfigTraceID : public AllStatic { } // Knuth multiplicative hashing. - static uint32_t hash(const TYPE& id) { - const uint32_t v = static_cast(id); - return v * UINT32_C(2654435761); + static uint32_t hash(const KEY_TYPE& key) { + const uint32_t k = static_cast(key); + return k * UINT32_C(2654435761); } - static bool cmp(const TYPE& lhs, const TYPE& rhs) { + static bool cmp(const KEY_TYPE& lhs, const KEY_TYPE& rhs) { return lhs == rhs; } }; -constexpr static unsigned int MAX_TABLE_SIZE = 0x3fffffff; - template -class JfrSet : public CONFIG::STORAGE { - public: - typedef typename CONFIG::TYPE TYPE; - typedef ResizeableHashTable HashMap; +class JfrSetStorage : public AnyObj { + typedef typename CONFIG::KEY_TYPE K; + protected: + K* _table; + unsigned _table_size; + unsigned _elements; - constexpr static bool is_cheap() { - return CONFIG::alloc_type() == AnyObj::C_HEAP; + static K* alloc_table(unsigned table_size) { + K* table; + if (CONFIG::alloc_type() == C_HEAP) { + table = NEW_C_HEAP_ARRAY(K, table_size, CONFIG::memory_tag()); + } else { + table = NEW_RESOURCE_ARRAY(K, table_size); + } + memset(table, 0, table_size * sizeof(K)); + return table; } - JfrSet(unsigned int initial_size, unsigned int max_size = MAX_TABLE_SIZE) : - _map(is_cheap() ? new (CONFIG::memory_tag()) HashMap(initial_size, max_size) : new HashMap(initial_size, max_size)) {} + JfrSetStorage(unsigned table_size) : + _table(alloc_table(table_size)), + _table_size(table_size), + _elements(0) {} - ~JfrSet() { - if (is_cheap()) { - delete _map; + ~JfrSetStorage() { + if (CONFIG::alloc_type() == C_HEAP) { + FREE_C_HEAP_ARRAY(K, _table); } } - bool add(const TYPE& k) { - bool inserted; - _map->put_if_absent(k, &inserted); - return inserted; + public: + template + void iterate(Functor& functor) { + assert(is_nonempty(), "invariant"); + for (unsigned i = 0; i < _table_size; ++i) { + K k = _table[i]; + if (k != 0) { + functor(k); + } + } } - bool remove(const TYPE& k) { - return _map->remove(k); + unsigned table_size() const { + return _table_size; } - bool contains(const TYPE& k) const { - return _map->contains(k); - } - - bool is_empty() const { - return _map->number_of_entries() == 0; + unsigned size() const { + return _elements; } bool is_nonempty() const { - return !is_empty(); - } - - int size() const { - return _map->number_of_entries(); + return _elements > 0; } void clear() { - if (is_nonempty()) { - _map->unlink(this); - } - assert(is_empty(), "invariant"); + memset(_table, 0, _table_size * sizeof(K)); } - - // Callback for node deletion, used by clear(). - bool do_entry(const TYPE& k, const TYPE& v) { - return true; - } - - private: - HashMap* _map; }; -typedef JfrSet > JfrCHeapTraceIdSet; -typedef JfrSet > JfrResourceAreaTraceIdSet; +template +class JfrSet : public JfrSetStorage { + typedef typename CONFIG::KEY_TYPE K; + static_assert(sizeof(K) > 1, "invalid size of CONFIG::KEY_TYPE"); + private: + static const constexpr unsigned max_initial_size = 1 << 30; + unsigned _table_mask; + unsigned _resize_threshold; // 0.5 load factor + + uint32_t slot_idx(const uint32_t hash) const { + return hash & _table_mask; + } + + void resize() { + assert(this->_elements == _resize_threshold, "invariant"); + K* const old_table = this->_table; + assert(old_table != nullptr, "invariant"); + const unsigned old_table_size = this->table_size(); + guarantee(old_table_size <= max_initial_size, "overflow"); + this->_table_size = old_table_size << 1; + this->_table = JfrSetStorage::alloc_table(this->_table_size); + _table_mask = this->_table_size - 1; + _resize_threshold = old_table_size; + for (unsigned i = 0; i < old_table_size; ++i) { + const K k = old_table[i]; + if (k != 0) { + uint32_t idx = slot_idx(CONFIG::hash(k)); + do { + K v = this->_table[idx]; + if (v == 0) { + this->_table[idx] = k; + break; + } + idx = slot_idx(idx + 1); + } while (true); + } + } + if (CONFIG::alloc_type() == AnyObj::C_HEAP) { + FREE_C_HEAP_ARRAY(K, old_table); + } + assert(_table_mask + 1 == this->_table_size, "invariant"); + assert(_resize_threshold << 1 == this->_table_size, "invariant"); + } + + K* find_slot(K const& k) const { + uint32_t idx = slot_idx(CONFIG::hash(k)); + assert(idx < this->table_size(), "invariant"); + K* result = nullptr; + while (true) { + K v = this->_table[idx]; + if (v == 0) { + result = &this->_table[idx]; + break; + } + if (CONFIG::cmp(v, k)) { + result = reinterpret_cast(p2i(&this->_table[idx]) | 1); + break; + } + idx = slot_idx(idx + 1); + } + assert(result != nullptr, "invariant"); + return result; + } + + public: + JfrSet(unsigned size) : + JfrSetStorage(size), + _table_mask(size - 1), + _resize_threshold(size >> 1) { + assert(size >= 2, "invariant"); + assert(size % 2 == 0, "invariant"); + assert(size <= max_initial_size, "avoid overflow in resize"); + } + + bool contains(K const& k) const { + K* const slot = find_slot(k); + return p2i(slot) & 1; + } + + bool add(K const& k) { + K* const slot = find_slot(k); + if (p2i(slot) & 1) { + // Already exists. + return false; + } + assert(*slot == 0, "invariant"); + *slot = k; + if (++this->_elements == _resize_threshold) { + resize(); + } + assert(this->_elements < _resize_threshold, "invariant"); + return true; + } +}; + +typedef JfrSet > JfrCHeapTraceIdSet; +typedef JfrSet > JfrResourceAreaTraceIdSet; #endif // SHARE_JFR_UTILITIES_JFRSET_HPP diff --git a/test/jdk/jdk/jfr/event/runtime/TestFlush.java b/test/jdk/jdk/jfr/event/runtime/TestFlush.java index 5c450eab05f..fa570406f2a 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestFlush.java +++ b/test/jdk/jdk/jfr/event/runtime/TestFlush.java @@ -143,8 +143,6 @@ public class TestFlush { printFlushEvent(re); Asserts.assertTrue(re.getEventType().getName().contains("Flush"), "invalid Event type"); Asserts.assertGT((long) re.getValue("flushId"), 0L, "Invalid flush ID"); - Asserts.assertGT((long) re.getValue("elements"), 0L, "No elements"); - Asserts.assertGT((long) re.getValue("size"), 0L, "Empty size"); } private static void acknowledgeFlushEvent() { From b6d5f49b8dc2cb7c8e93d7885c2432a28d04e57e Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Fri, 15 Aug 2025 09:41:17 +0000 Subject: [PATCH 097/471] 8365296: Build failure with Clang due to -Wformat warning after JDK-8364611 Reviewed-by: ayang, mbaesken --- .../childSignalDisposition/exePrintSignalDisposition.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c index 8235cdc7410..8f18a32a0f9 100644 --- a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/exePrintSignalDisposition.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. 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 @@ -72,11 +72,7 @@ int main(int argc, char** argv) { } else { printf("%p ", handler); } -#ifdef _AIX printf("%X\n", act.sa_flags); -#else - printf("%X %X\n", act.sa_flags, act.sa_mask); -#endif } return 0; From 059b49b9551ad52f211613a3da2ac0a79deb5ed4 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 15 Aug 2025 10:37:26 +0000 Subject: [PATCH 098/471] 8365244: Some test control variables are undocumented in doc/testing.md Reviewed-by: erikj --- doc/testing.html | 19 +++++++++++++------ doc/testing.md | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/doc/testing.html b/doc/testing.html index b9d1f4ed22f..f75e0da309e 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -72,11 +72,9 @@ id="toc-notes-for-specific-tests">Notes for Specific Tests

  • Non-US locale
  • PKCS11 Tests
  • -
  • ### Testing Ahead-of-time -Optimizations -
      +id="toc-testing-ahead-of-time-optimizations">Testing Ahead-of-time +Optimizations
    • Testing with alternative security providers
    • @@ -435,6 +433,9 @@ the diff between the specified revision and the repository tip.

      The report is stored in build/$BUILD/test-results/jcov-output/diff_coverage_report file.

      +

      AOT_JDK

      +

      See Testing +Ahead-of-time optimizations.

      JTReg keywords

      JOBS

      The test concurrency (-concurrency).

      @@ -556,6 +557,12 @@ each fork. Same as specifying -wi <num>.

      same values as -rff, i.e., text, csv, scsv, json, or latex.

      +

      TEST_JDK

      +

      The path to the JDK that will be used to run the benchmarks.

      +

      Defaults to build/<CONF-NAME>/jdk.

      +

      BENCHMARKS_JAR

      +

      The path to the JAR containing the benchmarks.

      +

      Defaults to test/micro/benchmarks.jar.

      VM_OPTIONS

      Additional VM arguments to provide to forked off VMs. Same as -jvmArgs <args>

      @@ -601,8 +608,8 @@ element of the appropriate @Artifact class. (See JTREG="JAVA_OPTIONS=-Djdk.test.lib.artifacts.nsslib-linux_aarch64=/path/to/NSS-libs"

      For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README.

      -

      ### Testing Ahead-of-time -Optimizations

      +

      Testing Ahead-of-time +Optimizations

      One way to improve test coverage of ahead-of-time (AOT) optimizations in the JDK is to run existing jtreg test cases in a special "AOT_JDK" mode. Example:

      diff --git a/doc/testing.md b/doc/testing.md index bb56c05c295..525b85a8438 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -367,6 +367,10 @@ between the specified revision and the repository tip. The report is stored in `build/$BUILD/test-results/jcov-output/diff_coverage_report` file. +#### AOT_JDK + +See [Testing Ahead-of-time optimizations](#testing-ahead-of-time-optimizations). + ### JTReg keywords #### JOBS @@ -545,6 +549,18 @@ Amount of time to spend in each warmup iteration. Same as specifying `-w Specify to have the test run save a log of the values. Accepts the same values as `-rff`, i.e., `text`, `csv`, `scsv`, `json`, or `latex`. +#### TEST_JDK + +The path to the JDK that will be used to run the benchmarks. + +Defaults to `build//jdk`. + +#### BENCHMARKS_JAR + +The path to the JAR containing the benchmarks. + +Defaults to `test/micro/benchmarks.jar`. + #### VM_OPTIONS Additional VM arguments to provide to forked off VMs. Same as `-jvmArgs ` @@ -612,7 +628,7 @@ For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README. ### Testing Ahead-of-time Optimizations -------------------------------------------------------------------------------- + One way to improve test coverage of ahead-of-time (AOT) optimizations in the JDK is to run existing jtreg test cases in a special "AOT_JDK" mode. Example: From dbae90c950200cb417aebeab65e5fce7a7e5f94f Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 15 Aug 2025 10:45:00 +0000 Subject: [PATCH 099/471] 8364723: Sort share/interpreter includes Reviewed-by: shade, ayang --- src/hotspot/share/interpreter/abstractInterpreter.cpp | 5 ++--- src/hotspot/share/interpreter/bytecodeStream.cpp | 2 +- src/hotspot/share/interpreter/bytecodeTracer.cpp | 4 ++-- src/hotspot/share/interpreter/bytecodeUtils.cpp | 2 +- src/hotspot/share/interpreter/interpreter.cpp | 5 ++--- src/hotspot/share/interpreter/interpreterRuntime.cpp | 2 +- src/hotspot/share/interpreter/templateInterpreter.cpp | 2 +- .../share/interpreter/templateInterpreterGenerator.cpp | 2 +- src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp | 2 +- .../share/interpreter/zero/bytecodeInterpreter.inline.hpp | 3 +-- .../share/interpreter/zero/zeroInterpreterGenerator.hpp | 1 - test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 12 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 0d6ccf3a710..05590add8ff 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -22,23 +22,22 @@ * */ -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "cds/metaspaceShared.hpp" #include "compiler/disassembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeStream.hpp" +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" #include "interpreter/templateTable.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/arrayOop.hpp" #include "oops/constantPool.inline.hpp" #include "oops/cpCache.inline.hpp" -#include "oops/methodData.hpp" #include "oops/method.inline.hpp" +#include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" diff --git a/src/hotspot/share/interpreter/bytecodeStream.cpp b/src/hotspot/share/interpreter/bytecodeStream.cpp index 7454c749828..5a9e32a46b0 100644 --- a/src/hotspot/share/interpreter/bytecodeStream.cpp +++ b/src/hotspot/share/interpreter/bytecodeStream.cpp @@ -22,8 +22,8 @@ * */ -#include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodes.hpp" +#include "interpreter/bytecodeStream.hpp" #include "runtime/handles.inline.hpp" Bytecodes::Code RawBytecodeStream::raw_next_special(Bytecodes::Code code) { diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index 1f912b2b00f..34170108dc4 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -25,14 +25,14 @@ #include "classfile/classPrinter.hpp" #include "classfile/javaClasses.inline.hpp" #include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeTracer.hpp" -#include "interpreter/bytecodes.hpp" #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" #include "oops/constantPool.inline.hpp" -#include "oops/methodData.hpp" #include "oops/method.hpp" +#include "oops/methodData.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index eb4557d6ba0..a5503cc4b88 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -28,8 +28,8 @@ #include "gc/shared/gcLocker.hpp" #include "interpreter/bytecodeUtils.hpp" #include "memory/resourceArea.hpp" -#include "runtime/signature.hpp" #include "runtime/safepointVerifiers.hpp" +#include "runtime/signature.hpp" #include "utilities/events.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/interpreter/interpreter.cpp b/src/hotspot/share/interpreter/interpreter.cpp index 6272deea349..2cc163186e8 100644 --- a/src/hotspot/share/interpreter/interpreter.cpp +++ b/src/hotspot/share/interpreter/interpreter.cpp @@ -22,18 +22,17 @@ * */ -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" #include "interpreter/templateTable.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/arrayOop.hpp" -#include "oops/methodData.hpp" #include "oops/method.hpp" +#include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 8e7e5772ba6..50115f842e2 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -46,8 +46,8 @@ #include "oops/cpCache.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.inline.hpp" -#include "oops/methodData.hpp" #include "oops/method.inline.hpp" +#include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index 0dd82addbfe..44804221dc7 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -22,9 +22,9 @@ * */ +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" #include "interpreter/templateInterpreter.hpp" #include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp index 9a316f3ba46..96f53c517a3 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp @@ -23,9 +23,9 @@ */ #include "compiler/disassembler.hpp" +#include "interpreter/interp_masm.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" #include "interpreter/templateInterpreter.hpp" #include "interpreter/templateInterpreterGenerator.hpp" #include "interpreter/templateTable.hpp" diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 07ec57a6ffe..bfed16f2769 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -29,9 +29,9 @@ #include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "gc/shared/tlab_globals.hpp" #include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/zero/bytecodeInterpreter.inline.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" +#include "interpreter/zero/bytecodeInterpreter.inline.hpp" #include "jvm_io.h" #include "logging/log.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.inline.hpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.inline.hpp index 2a396aec9ad..effee05c2f1 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.inline.hpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.inline.hpp @@ -27,6 +27,7 @@ #include "interpreter/zero/bytecodeInterpreter.hpp" +#include "bytecodeInterpreter_zero.inline.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/macros.hpp" @@ -42,6 +43,4 @@ #define VERIFY_OOP(o) #endif -# include "bytecodeInterpreter_zero.inline.hpp" - #endif // SHARE_INTERPRETER_BYTECODEINTERPRETER_INLINE_HPP diff --git a/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.hpp b/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.hpp index 8c745e51949..f8db4a07e9a 100644 --- a/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.hpp @@ -29,7 +29,6 @@ // of the Zero interpreter generator. # include "entry_zero.hpp" -// # include "interpreter/interp_masm.hpp" class ZeroInterpreterGenerator: public AbstractInterpreterGenerator { diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 072784cda9d..7460a160ee6 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -50,6 +50,7 @@ public class TestIncludesAreSorted { "share/classfile", "share/code", "share/compiler", + "share/interpreter", "share/jvmci", "share/libadt", "share/metaprogramming", From 08db4b99622e488558dd7987c34f1c515fa30426 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 15 Aug 2025 17:56:47 +0000 Subject: [PATCH 100/471] 8365571: GenShen: PLAB promotions may remain disabled for evacuation threads Reviewed-by: kdnilsen, ysr, shade --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 23 ++++--------------- .../share/gc/shenandoah/shenandoahHeap.cpp | 5 ++++ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 81154aff9f0..d4c7ad5df50 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -823,7 +823,6 @@ bool ShenandoahConcurrentGC::has_in_place_promotions(ShenandoahHeap* heap) { return heap->mode()->is_generational() && heap->old_generation()->has_in_place_promotions(); } -template class ShenandoahConcurrentEvacThreadClosure : public ThreadClosure { private: OopClosure* const _oops; @@ -833,13 +832,9 @@ public: void do_thread(Thread* thread) override { JavaThread* const jt = JavaThread::cast(thread); StackWatermarkSet::finish_processing(jt, _oops, StackWatermarkKind::gc); - if (GENERATIONAL) { - ShenandoahThreadLocalData::enable_plab_promotions(thread); - } } }; -template class ShenandoahConcurrentEvacUpdateThreadTask : public WorkerTask { private: ShenandoahJavaThreadsIterator _java_threads; @@ -851,30 +846,20 @@ public: } void work(uint worker_id) override { - if (GENERATIONAL) { - Thread* worker_thread = Thread::current(); - ShenandoahThreadLocalData::enable_plab_promotions(worker_thread); - } - // ShenandoahEvacOOMScope has to be setup by ShenandoahContextEvacuateUpdateRootsClosure. // Otherwise, may deadlock with watermark lock ShenandoahContextEvacuateUpdateRootsClosure oops_cl; - ShenandoahConcurrentEvacThreadClosure thr_cl(&oops_cl); + ShenandoahConcurrentEvacThreadClosure thr_cl(&oops_cl); _java_threads.threads_do(&thr_cl, worker_id); } }; void ShenandoahConcurrentGC::op_thread_roots() { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); + const ShenandoahHeap* const heap = ShenandoahHeap::heap(); assert(heap->is_evacuation_in_progress(), "Checked by caller"); ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_thread_roots); - if (heap->mode()->is_generational()) { - ShenandoahConcurrentEvacUpdateThreadTask task(heap->workers()->active_workers()); - heap->workers()->run_task(&task); - } else { - ShenandoahConcurrentEvacUpdateThreadTask task(heap->workers()->active_workers()); - heap->workers()->run_task(&task); - } + ShenandoahConcurrentEvacUpdateThreadTask task(heap->workers()->active_workers()); + heap->workers()->run_task(&task); } void ShenandoahConcurrentGC::op_weak_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 2baf7e25cba..b90468501f6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1216,6 +1216,11 @@ public: // 1. We need to make the plab memory parsable by remembered-set scanning. // 2. We need to establish a trustworthy UpdateWaterMark value within each old-gen heap region ShenandoahGenerationalHeap::heap()->retire_plab(plab, thread); + + // Re-enable promotions for the next evacuation phase. + ShenandoahThreadLocalData::enable_plab_promotions(thread); + + // Reset the fill size for next evacuation phase. if (_resize && ShenandoahThreadLocalData::plab_size(thread) > 0) { ShenandoahThreadLocalData::set_plab_size(thread, 0); } From 39a365296882b0df49398cd7ac36e801a9aa1c35 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Fri, 15 Aug 2025 18:52:45 +0000 Subject: [PATCH 101/471] 8278874: tighten VerifyStack constraints Co-authored-by: Tom Rodriguez Reviewed-by: mhaessig, never --- src/hotspot/share/classfile/javaClasses.cpp | 5 +- src/hotspot/share/runtime/deoptimization.cpp | 180 ++++++++++--------- src/hotspot/share/runtime/vframeArray.cpp | 117 +++++++----- src/hotspot/share/runtime/vframeArray.hpp | 9 +- 4 files changed, 178 insertions(+), 133 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 5c41ea789b5..20534b93290 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1886,8 +1886,9 @@ JavaThreadStatus java_lang_Thread::get_thread_status(oop java_thread) { // Make sure the caller is operating on behalf of the VM or is // running VM code (state == _thread_in_vm). assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() || - JavaThread::current()->thread_state() == _thread_in_vm, - "Java Thread is not running in vm"); + JavaThread::current()->thread_state() == _thread_in_vm || + JavaThread::current() == java_lang_Thread::thread(java_thread), + "unsafe call to java_lang_Thread::get_thread_status()?"); GET_FIELDHOLDER_FIELD(java_thread, get_thread_status, JavaThreadStatus::NEW /* not initialized */); } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 5f9a80cf100..243903ed233 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -561,7 +561,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread #endif // !PRODUCT GrowableArray* expressions = trap_scope->expressions(); - guarantee(expressions != nullptr && expressions->length() > 0, "must have exception to throw"); + guarantee(expressions != nullptr && expressions->length() == 1, "should have only exception on stack"); + guarantee(exec_mode != Unpack_exception, "rethrow_exception set with Unpack_exception"); ScopeValue* topOfStack = expressions->top(); exceptionObject = StackValue::create_stack_value(&deoptee, &map, topOfStack)->get_obj(); guarantee(exceptionObject() != nullptr, "exception oop can not be null"); @@ -737,6 +738,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread if (exceptionObject() != nullptr) { current->set_exception_oop(exceptionObject()); exec_mode = Unpack_exception; + assert(array->element(0)->rethrow_exception(), "must be"); } #endif @@ -844,6 +846,7 @@ void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_arr } #ifndef PRODUCT +#ifdef ASSERT // Return true if the execution after the provided bytecode continues at the // next bytecode in the code. This is not the case for gotos, returns, and // throws. @@ -868,6 +871,7 @@ static bool falls_through(Bytecodes::Code bc) { } } #endif +#endif // Return BasicType of value being returned JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode)) @@ -932,116 +936,114 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m RegisterMap::ProcessFrames::include, RegisterMap::WalkContinuation::skip); rm.set_include_argument_oops(false); - bool is_top_frame = true; int callee_size_of_parameters = 0; - int callee_max_locals = 0; - for (int i = 0; i < cur_array->frames(); i++) { - vframeArrayElement* el = cur_array->element(i); + for (int frame_idx = 0; frame_idx < cur_array->frames(); frame_idx++) { + bool is_top_frame = (frame_idx == 0); + vframeArrayElement* el = cur_array->element(frame_idx); frame* iframe = el->iframe(); guarantee(iframe->is_interpreted_frame(), "Wrong frame type"); + methodHandle mh(thread, iframe->interpreter_frame_method()); + bool reexecute = el->should_reexecute(); + + int cur_invoke_parameter_size = 0; + int top_frame_expression_stack_adjustment = 0; + int max_bci = mh->code_size(); + BytecodeStream str(mh, iframe->interpreter_frame_bci()); + assert(str.bci() < max_bci, "bci in interpreter frame out of bounds"); + Bytecodes::Code cur_code = str.next(); + + if (!reexecute && !Bytecodes::is_invoke(cur_code)) { + // We can only compute OopMaps for the before state, so we need to roll forward + // to the next bytecode. + assert(is_top_frame, "must be"); + assert(falls_through(cur_code), "must be"); + assert(cur_code != Bytecodes::_illegal, "illegal bytecode"); + assert(str.bci() < max_bci, "bci in interpreter frame out of bounds"); + + // Need to subtract off the size of the result type of + // the bytecode because this is not described in the + // debug info but returned to the interpreter in the TOS + // caching register + BasicType bytecode_result_type = Bytecodes::result_type(cur_code); + if (bytecode_result_type != T_ILLEGAL) { + top_frame_expression_stack_adjustment = type2size[bytecode_result_type]; + } + assert(top_frame_expression_stack_adjustment >= 0, "stack adjustment must be positive"); + + cur_code = str.next(); + // Reflect the fact that we have rolled forward and now need + // top_frame_expression_stack_adjustment + reexecute = true; + } + + assert(cur_code != Bytecodes::_illegal, "illegal bytecode"); + assert(str.bci() < max_bci, "bci in interpreter frame out of bounds"); // Get the oop map for this bci InterpreterOopMap mask; - int cur_invoke_parameter_size = 0; - bool try_next_mask = false; - int next_mask_expression_stack_size = -1; - int top_frame_expression_stack_adjustment = 0; - methodHandle mh(thread, iframe->interpreter_frame_method()); - OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask); - BytecodeStream str(mh, iframe->interpreter_frame_bci()); - int max_bci = mh->code_size(); - // Get to the next bytecode if possible - assert(str.bci() < max_bci, "bci in interpreter frame out of bounds"); + OopMapCache::compute_one_oop_map(mh, str.bci(), &mask); // Check to see if we can grab the number of outgoing arguments // at an uncommon trap for an invoke (where the compiler // generates debug info before the invoke has executed) - Bytecodes::Code cur_code = str.next(); - Bytecodes::Code next_code = Bytecodes::_shouldnotreachhere; if (Bytecodes::is_invoke(cur_code)) { - Bytecode_invoke invoke(mh, iframe->interpreter_frame_bci()); + Bytecode_invoke invoke(mh, str.bci()); cur_invoke_parameter_size = invoke.size_of_parameters(); - if (i != 0 && invoke.has_member_arg()) { + if (!is_top_frame && invoke.has_member_arg()) { callee_size_of_parameters++; } } - if (str.bci() < max_bci) { - next_code = str.next(); - if (next_code >= 0) { - // The interpreter oop map generator reports results before - // the current bytecode has executed except in the case of - // calls. It seems to be hard to tell whether the compiler - // has emitted debug information matching the "state before" - // a given bytecode or the state after, so we try both - if (!Bytecodes::is_invoke(cur_code) && falls_through(cur_code)) { - // Get expression stack size for the next bytecode - InterpreterOopMap next_mask; - OopMapCache::compute_one_oop_map(mh, str.bci(), &next_mask); - next_mask_expression_stack_size = next_mask.expression_stack_size(); - if (Bytecodes::is_invoke(next_code)) { - Bytecode_invoke invoke(mh, str.bci()); - next_mask_expression_stack_size += invoke.size_of_parameters(); - } - // Need to subtract off the size of the result type of - // the bytecode because this is not described in the - // debug info but returned to the interpreter in the TOS - // caching register - BasicType bytecode_result_type = Bytecodes::result_type(cur_code); - if (bytecode_result_type != T_ILLEGAL) { - top_frame_expression_stack_adjustment = type2size[bytecode_result_type]; - } - assert(top_frame_expression_stack_adjustment >= 0, "stack adjustment must be positive"); - try_next_mask = true; - } - } - } // Verify stack depth and oops in frame - // This assertion may be dependent on the platform we're running on and may need modification (tested on x86 and sparc) - if (!( - /* SPARC */ - (iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + callee_size_of_parameters) || - /* x86 */ - (iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + callee_max_locals) || - (try_next_mask && - (iframe->interpreter_frame_expression_stack_size() == (next_mask_expression_stack_size - - top_frame_expression_stack_adjustment))) || - (is_top_frame && (exec_mode == Unpack_exception) && iframe->interpreter_frame_expression_stack_size() == 0) || - (is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute || el->should_reexecute()) && - (iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + cur_invoke_parameter_size)) - )) { - { - // Print out some information that will help us debug the problem - tty->print_cr("Wrong number of expression stack elements during deoptimization"); - tty->print_cr(" Error occurred while verifying frame %d (0..%d, 0 is topmost)", i, cur_array->frames() - 1); - tty->print_cr(" Current code %s", Bytecodes::name(cur_code)); - if (try_next_mask) { - tty->print_cr(" Next code %s", Bytecodes::name(next_code)); - } - tty->print_cr(" Fabricated interpreter frame had %d expression stack elements", - iframe->interpreter_frame_expression_stack_size()); - tty->print_cr(" Interpreter oop map had %d expression stack elements", mask.expression_stack_size()); - tty->print_cr(" try_next_mask = %d", try_next_mask); - tty->print_cr(" next_mask_expression_stack_size = %d", next_mask_expression_stack_size); - tty->print_cr(" callee_size_of_parameters = %d", callee_size_of_parameters); - tty->print_cr(" callee_max_locals = %d", callee_max_locals); - tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment); - tty->print_cr(" exec_mode = %d", exec_mode); - tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size); - tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id()); - tty->print_cr(" Interpreted frames:"); - for (int k = 0; k < cur_array->frames(); k++) { - vframeArrayElement* el = cur_array->element(k); - tty->print_cr(" %s (bci %d)", el->method()->name_and_sig_as_C_string(), el->bci()); - } - cur_array->print_on_2(tty); + auto match = [&]() { + int iframe_expr_ssize = iframe->interpreter_frame_expression_stack_size(); +#if INCLUDE_JVMCI + if (is_top_frame && el->rethrow_exception()) { + return iframe_expr_ssize == 1; } +#endif + // This should only be needed for C1 + if (is_top_frame && exec_mode == Unpack_exception && iframe_expr_ssize == 0) { + return true; + } + if (reexecute) { + int expr_ssize_before = iframe_expr_ssize + top_frame_expression_stack_adjustment; + int oopmap_expr_invoke_ssize = mask.expression_stack_size() + cur_invoke_parameter_size; + return expr_ssize_before == oopmap_expr_invoke_ssize; + } else { + int oopmap_expr_callee_ssize = mask.expression_stack_size() + callee_size_of_parameters; + return iframe_expr_ssize == oopmap_expr_callee_ssize; + } + }; + if (!match()) { + // Print out some information that will help us debug the problem + tty->print_cr("Wrong number of expression stack elements during deoptimization"); + tty->print_cr(" Error occurred while verifying frame %d (0..%d, 0 is topmost)", frame_idx, cur_array->frames() - 1); + tty->print_cr(" Current code %s", Bytecodes::name(cur_code)); + tty->print_cr(" Fabricated interpreter frame had %d expression stack elements", + iframe->interpreter_frame_expression_stack_size()); + tty->print_cr(" Interpreter oop map had %d expression stack elements", mask.expression_stack_size()); + tty->print_cr(" callee_size_of_parameters = %d", callee_size_of_parameters); + tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment); + tty->print_cr(" exec_mode = %d", exec_mode); + tty->print_cr(" original should_reexecute = %s", el->should_reexecute() ? "true" : "false"); + tty->print_cr(" reexecute = %s%s", reexecute ? "true" : "false", + (reexecute != el->should_reexecute()) ? " (changed)" : ""); +#if INCLUDE_JVMCI + tty->print_cr(" rethrow_exception = %s", el->rethrow_exception() ? "true" : "false"); +#endif + tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size); + tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id()); + tty->print_cr(" Interpreted frames:"); + for (int k = 0; k < cur_array->frames(); k++) { + vframeArrayElement* el = cur_array->element(k); + tty->print_cr(" %s (bci %d)", el->method()->name_and_sig_as_C_string(), el->bci()); + } + cur_array->print_on_2(tty); guarantee(false, "wrong number of expression stack elements during deopt"); } VerifyOopClosure verify; iframe->oops_interpreted_do(&verify, &rm, false); callee_size_of_parameters = mh->size_of_parameters(); - callee_max_locals = mh->max_locals(); - is_top_frame = false; } } #endif // !PRODUCT diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index e17961fc424..224bce4513a 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -23,6 +23,7 @@ */ #include "classfile/vmSymbols.hpp" +#include "code/scopeDesc.hpp" #include "code/vmreg.inline.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/bytecode.inline.hpp" @@ -61,7 +62,10 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { _method = vf->method(); _bci = vf->raw_bci(); - _reexecute = vf->should_reexecute(); + _reexecute = vf->should_reexecute(); // initial value, updated in unpack_on_stack +#if INCLUDE_JVMCI + _rethrow = vf->scope()->rethrow_exception(); +#endif #ifdef ASSERT _removed_monitors = false; #endif @@ -171,7 +175,34 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { } } -int unpack_counter = 0; +static int unpack_counter = 0; + +bool vframeArrayElement::should_reexecute(bool is_top_frame, int exec_mode) const { + if (is_top_frame) { + switch (exec_mode) { + case Deoptimization::Unpack_uncommon_trap: + case Deoptimization::Unpack_reexecute: + return true; + case Deoptimization::Unpack_exception: + assert(raw_bci() >= 0, "bad bci %d for Unpack_exception", raw_bci()); + default: + break; + } + } + if (raw_bci() == SynchronizationEntryBCI) { + return true; + } + bool reexec = should_reexecute(); + assert(is_top_frame || reexec == false, "unexepected should_reexecute()"); +#ifdef ASSERT + if (!reexec) { + address bcp = method()->bcp_from(bci()); + Bytecodes::Code code = Bytecodes::code_at(method(), bcp); + assert(!Interpreter::bytecode_should_reexecute(code), "should_reexecute mismatch"); + } +#endif + return reexec; +} void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, int callee_parameters, @@ -189,20 +220,37 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, // C++ interpreter doesn't need a pc since it will figure out what to do when it // begins execution address pc; - bool use_next_mdp = false; // true if we should use the mdp associated with the next bci - // rather than the one associated with bcp - if (raw_bci() == SynchronizationEntryBCI) { + bool reexecute = should_reexecute(is_top_frame, exec_mode); + if (is_top_frame && exec_mode == Deoptimization::Unpack_exception) { + assert(raw_bci() >= 0, "bad bci %d for Unpack_exception", raw_bci()); + bcp = method()->bcp_from(bci()); + // exception is pending + pc = Interpreter::rethrow_exception_entry(); + // [phh] We're going to end up in some handler or other, so it doesn't + // matter what mdp we point to. See exception_handler_for_exception() + // in interpreterRuntime.cpp. + } else if (raw_bci() == SynchronizationEntryBCI) { // We are deoptimizing while hanging in prologue code for synchronized method bcp = method()->bcp_from(0); // first byte code pc = Interpreter::deopt_entry(vtos, 0); // step = 0 since we don't skip current bytecode - } else if (should_reexecute()) { //reexecute this bytecode + assert(reexecute, "must be"); + } else if (reexecute) { //reexecute this bytecode assert(is_top_frame, "reexecute allowed only for the top frame"); bcp = method()->bcp_from(bci()); - pc = Interpreter::deopt_reexecute_entry(method(), bcp); + switch (exec_mode) { + case Deoptimization::Unpack_uncommon_trap: + case Deoptimization::Unpack_reexecute: + // Do not special-case _athrow or _return_register_finalizer + pc = Interpreter::deopt_entry(vtos, 0); + break; + default: + // Yes, special-case _athrow and _return_register_finalizer + pc = Interpreter::deopt_reexecute_entry(method(), bcp); + } } else { bcp = method()->bcp_from(bci()); + assert(!reexecute, "must be"); pc = Interpreter::deopt_continue_after_entry(method(), bcp, callee_parameters, is_top_frame); - use_next_mdp = true; } assert(Bytecodes::is_defined(*bcp), "must be a valid bytecode"); @@ -239,44 +287,32 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, } else { // Reexecute invoke in top frame pc = Interpreter::deopt_entry(vtos, 0); - use_next_mdp = false; +#ifdef ASSERT + Bytecodes::Code code = Bytecodes::code_at(method(), bcp); + assert(Bytecodes::is_invoke(code), "must be"); + assert(!reexecute, "must be"); +#endif + // It would be nice if the VerifyStack logic in unpack_frames() was refactored so + // we could check the stack before and after changing the reexecute mode, but + // it should pass either way because an invoke uses the same stack state for both modes, + // which is: args popped but result not yet pushed. + reexecute = true; popframe_preserved_args_size_in_bytes = in_bytes(thread->popframe_preserved_args_size()); // Note: the PopFrame-related extension of the expression stack size is done in // Deoptimization::fetch_unroll_info_helper popframe_preserved_args_size_in_words = in_words(thread->popframe_preserved_args_size_in_words()); } - } else if (!realloc_failure_exception && JvmtiExport::can_force_early_return() && state != nullptr && - state->is_earlyret_pending()) { - // Force early return from top frame after deoptimization - pc = Interpreter::remove_activation_early_entry(state->earlyret_tos()); - } else { - if (realloc_failure_exception && JvmtiExport::can_force_early_return() && state != nullptr && state->is_earlyret_pending()) { + } else if (JvmtiExport::can_force_early_return() && state != nullptr && state->is_earlyret_pending()) { + if (!realloc_failure_exception) { + // Force early return from top frame after deoptimization + pc = Interpreter::remove_activation_early_entry(state->earlyret_tos()); + } else { state->clr_earlyret_pending(); state->set_earlyret_oop(nullptr); state->clr_earlyret_value(); } - // Possibly override the previous pc computation of the top (youngest) frame - switch (exec_mode) { - case Deoptimization::Unpack_deopt: - // use what we've got - break; - case Deoptimization::Unpack_exception: - // exception is pending - pc = SharedRuntime::raw_exception_handler_for_return_address(thread, pc); - // [phh] We're going to end up in some handler or other, so it doesn't - // matter what mdp we point to. See exception_handler_for_exception() - // in interpreterRuntime.cpp. - break; - case Deoptimization::Unpack_uncommon_trap: - case Deoptimization::Unpack_reexecute: - // redo last byte code - pc = Interpreter::deopt_entry(vtos, 0); - use_next_mdp = false; - break; - default: - ShouldNotReachHere(); - } } + _reexecute = reexecute; } // Setup the interpreter frame @@ -317,17 +353,16 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, assert(src->obj() != nullptr || ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, src->obj())), "should be held, after move_to"); } - if (ProfileInterpreter) { - iframe()->interpreter_frame_set_mdp(nullptr); // clear out the mdp. - } iframe()->interpreter_frame_set_bcp(bcp); if (ProfileInterpreter) { MethodData* mdo = method()->method_data(); - if (mdo != nullptr) { + if (mdo != nullptr && exec_mode != Deoptimization::Unpack_exception) { int bci = iframe()->interpreter_frame_bci(); - if (use_next_mdp) ++bci; + if (!reexecute) ++bci; address mdp = mdo->bci_to_dp(bci); iframe()->interpreter_frame_set_mdp(mdp); + } else { + iframe()->interpreter_frame_set_mdp(nullptr); // clear out the mdp. } } diff --git a/src/hotspot/share/runtime/vframeArray.hpp b/src/hotspot/share/runtime/vframeArray.hpp index b270046252d..d7390bedff4 100644 --- a/src/hotspot/share/runtime/vframeArray.hpp +++ b/src/hotspot/share/runtime/vframeArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -56,6 +56,9 @@ class vframeArrayElement { frame _frame; // the interpreter frame we will unpack into int _bci; // raw bci for this vframe bool _reexecute; // whether we should reexecute this bytecode +#if INCLUDE_JVMCI + bool _rethrow; // from ScopeDesc::rethrow_exception() +#endif Method* _method; // the method for this vframe MonitorChunk* _monitors; // active monitors for this vframe StackValueCollection* _locals; @@ -71,7 +74,11 @@ class vframeArrayElement { int bci(void) const; int raw_bci(void) const { return _bci; } + bool should_reexecute(bool is_top_frame, int exec_mode) const; bool should_reexecute(void) const { return _reexecute; } +#if INCLUDE_JVMCI + bool rethrow_exception(void) const { return _rethrow; } +#endif Method* method(void) const { return _method; } From 6e760b9b746eba3d40ec246f3e194ce9f8c5ae29 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 15 Aug 2025 20:00:01 +0000 Subject: [PATCH 102/471] 8365622: Shenandoah: Fix Shenandoah simple bit map test Reviewed-by: ysr --- .../hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp index 45d6cf47fe0..0d81320befc 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp @@ -443,7 +443,7 @@ public: }; -TEST(BasicShenandoahSimpleBitMapTest, minimum_test) { +TEST_F(ShenandoahSimpleBitMapTest, minimum_test) { bool result = ShenandoahSimpleBitMapTest::run_test(); ASSERT_EQ(result, true); From b69a3849b21b4bb1e21ad276633de45da6200168 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 15 Aug 2025 20:02:43 +0000 Subject: [PATCH 103/471] 8365198: Remove unnecessary mention of finalize in ImageIO reader/writer docs Reviewed-by: bchristi, azvegint --- src/java.desktop/share/classes/javax/imageio/ImageReader.java | 3 +-- src/java.desktop/share/classes/javax/imageio/ImageWriter.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/imageio/ImageReader.java b/src/java.desktop/share/classes/javax/imageio/ImageReader.java index 3488f60b9b7..281e7298354 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageReader.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageReader.java @@ -2501,8 +2501,7 @@ public abstract class ImageReader { /** * Allows any resources held by this object to be released. The - * result of calling any other method (other than - * {@code finalize}) subsequent to a call to this method + * result of calling any other method subsequent to a call to this method * is undefined. * *

      It is important for applications to call this method when they diff --git a/src/java.desktop/share/classes/javax/imageio/ImageWriter.java b/src/java.desktop/share/classes/javax/imageio/ImageWriter.java index a688d9aea91..fd8cc3a753d 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageWriter.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageWriter.java @@ -2000,8 +2000,7 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Allows any resources held by this object to be released. The - * result of calling any other method (other than - * {@code finalize}) subsequent to a call to this method + * result of calling any other method subsequent to a call to this method * is undefined. * *

      It is important for applications to call this method when they From b023fea06216d5196592ff5239dc592aa8e34a02 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 15 Aug 2025 22:12:57 +0000 Subject: [PATCH 104/471] 8365558: Fix stub entry init and blob creation on Zero Reviewed-by: asmehra, kvn --- src/hotspot/cpu/zero/sharedRuntime_zero.cpp | 6 ++-- .../cpu/zero/stubDeclarations_zero.hpp | 4 +-- src/hotspot/share/runtime/sharedRuntime.cpp | 33 +++++++++++++++---- src/hotspot/share/runtime/stubRoutines.cpp | 19 ++++++----- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index df162fbfa74..b2e406c205b 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -56,10 +56,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, const BasicType *sig_bt, const VMRegPair *regs, AdapterHandlerEntry* handler) { - // VM expects i2c entry to be always filled. The rest can be unset. + // foil any attempt to call the i2c, c2i or unverified c2i entries handler->set_entry_points(CAST_FROM_FN_PTR(address,zero_null_code_stub), - nullptr, - nullptr, + CAST_FROM_FN_PTR(address,zero_null_code_stub), + CAST_FROM_FN_PTR(address,zero_null_code_stub), nullptr); } diff --git a/src/hotspot/cpu/zero/stubDeclarations_zero.hpp b/src/hotspot/cpu/zero/stubDeclarations_zero.hpp index 3126cf71460..2357bbb5169 100644 --- a/src/hotspot/cpu/zero/stubDeclarations_zero.hpp +++ b/src/hotspot/cpu/zero/stubDeclarations_zero.hpp @@ -37,7 +37,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(initial, 32) \ + do_arch_blob(initial, 0) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ @@ -58,7 +58,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(final, 32) \ + do_arch_blob(final, 0) \ #endif // CPU_ZERO_STUBDECLARATIONS_HPP diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 5bfddb8a04a..13612496fbd 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2602,19 +2602,24 @@ void AdapterHandlerLibrary::initialize() { BasicType obj_obj_args[] = { T_OBJECT, T_OBJECT }; _obj_obj_arg_handler = create_adapter(obj_obj_arg_blob, 2, obj_obj_args); - assert(no_arg_blob != nullptr && - obj_arg_blob != nullptr && - int_arg_blob != nullptr && - obj_int_arg_blob != nullptr && - obj_obj_arg_blob != nullptr, "Initial adapters must be properly created"); + // we should always get an entry back but we don't have any + // associated blob on Zero + assert(_no_arg_handler != nullptr && + _obj_arg_handler != nullptr && + _int_arg_handler != nullptr && + _obj_int_arg_handler != nullptr && + _obj_obj_arg_handler != nullptr, "Initial adapter handlers must be properly created"); } // Outside of the lock +#ifndef ZERO + // no blobs to register when we are on Zero post_adapter_creation(no_arg_blob, _no_arg_handler); post_adapter_creation(obj_arg_blob, _obj_arg_handler); post_adapter_creation(int_arg_blob, _int_arg_handler); post_adapter_creation(obj_int_arg_blob, _obj_int_arg_handler); post_adapter_creation(obj_obj_arg_blob, _obj_obj_arg_handler); +#endif // ZERO } AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint) { @@ -2709,12 +2714,15 @@ const char* AdapterHandlerEntry::_entry_names[] = { #ifdef ASSERT void AdapterHandlerLibrary::verify_adapter_sharing(int total_args_passed, BasicType* sig_bt, AdapterHandlerEntry* cached_entry) { + // we can only check for the same code if there is any +#ifndef ZERO AdapterBlob* comparison_blob = nullptr; AdapterHandlerEntry* comparison_entry = create_adapter(comparison_blob, total_args_passed, sig_bt, true); assert(comparison_blob == nullptr, "no blob should be created when creating an adapter for comparison"); assert(comparison_entry->compare_code(cached_entry), "code must match"); // Release the one just created AdapterHandlerEntry::deallocate(comparison_entry); +# endif // ZERO } #endif /* ASSERT*/ @@ -2792,8 +2800,13 @@ AdapterBlob* AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handle void AdapterHandlerLibrary::print_adapter_handler_info(outputStream* st, AdapterHandlerEntry* handler, AdapterBlob* adapter_blob) { ttyLocker ttyl; ResourceMark rm; - int insts_size = adapter_blob->code_size(); + int insts_size; + // on Zero the blob may be null handler->print_adapter_on(tty); + if (adapter_blob == nullptr) { + return; + } + insts_size = adapter_blob->code_size(); st->print_cr("i2c argument handler for: %s %s (%d bytes generated)", handler->fingerprint()->as_basic_args_string(), handler->fingerprint()->as_string(), insts_size); @@ -2834,6 +2847,11 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob, sig_bt, regs, handler); +#ifdef ZERO + // On zero there is no code to save and no need to create a blob and + // or relocate the handler. + adapter_blob = nullptr; +#else #ifdef ASSERT if (VerifyAdapterSharing) { handler->save_code(buf->code_begin(), buffer.insts_size()); @@ -2869,12 +2887,15 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob, assert(success || !AOTCodeCache::is_dumping_adapter(), "caching of adapter must be disabled"); } handler->relocate(adapter_blob->content_begin()); +#endif // ZERO + #ifndef PRODUCT // debugging support if (PrintAdapterHandlers || PrintStubCode) { print_adapter_handler_info(tty, handler, adapter_blob); } #endif + return true; } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 86975f7d0a6..82608737be8 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -168,14 +168,6 @@ static BufferBlob* initialize_stubs(BlobId blob_id, const char* assert_msg) { assert(StubInfo::is_stubgen(blob_id), "not a stubgen blob %s", StubInfo::name(blob_id)); ResourceMark rm; - if (code_size == 0) { - LogTarget(Info, stubs) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print_cr("%s\t not generated", buffer_name); - } - return nullptr; - } TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); // Add extra space for large CodeEntryAlignment int size = code_size + CodeEntryAlignment * max_aligned_stubs; @@ -196,9 +188,18 @@ static BufferBlob* initialize_stubs(BlobId blob_id, } CodeBuffer buffer(stubs_code); StubGenerator_generate(&buffer, blob_id); + if (code_size == 0) { + assert(buffer.insts_size() == 0, "should not write into buffer when bob size declared as 0"); + LogTarget(Info, stubs) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("%s\t not generated", buffer_name); + } + return nullptr; + } // When new stubs added we need to make sure there is some space left // to catch situation when we should increase size again. - assert(code_size == 0 || buffer.insts_remaining() > 200, + assert(buffer.insts_remaining() > 200, "increase %s, code_size: %d, used: %d, free: %d", assert_msg, code_size, buffer.total_content_size(), buffer.insts_remaining()); From a70521c62e0841895d71cce2c872bd12f1183e33 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 15 Aug 2025 22:45:01 +0000 Subject: [PATCH 105/471] 8364973: Add JVMTI stress testing mode Reviewed-by: erikj, ihse, sspitsyn --- doc/starting-next-release.html | 5 +- doc/testing.html | 6 + doc/testing.md | 7 + make/RunTests.gmk | 14 +- make/RunTestsPrebuiltSpec.gmk | 16 + .../jtreg/ProblemList-jvmti-stress-agent.txt | 101 ++ .../lib/ir_framework/TestFramework.java | 13 + test/jdk/ProblemList-jvmti-stress-agent.txt | 47 + test/jtreg-ext/requires/VMProps.java | 7 +- .../test/lib/jvmti/libJvmtiStressAgent.cpp | 987 ++++++++++++++++++ 10 files changed, 1196 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt create mode 100644 test/jdk/ProblemList-jvmti-stress-agent.txt create mode 100644 test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp diff --git a/doc/starting-next-release.html b/doc/starting-next-release.html index 421229f9fbc..6cffdf38b0f 100644 --- a/doc/starting-next-release.html +++ b/doc/starting-next-release.html @@ -11,11 +11,8 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - /* The extra [class] is a hack that increases specificity enough to - override a similar rule in reveal.js */ - ul.task-list[class]{list-style: none;} + ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { - font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; diff --git a/doc/testing.html b/doc/testing.html index f75e0da309e..fa774aa312f 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -458,6 +458,12 @@ class, named Virtual, is currently part of the JDK build in the test/jtreg_test_thread_factory/ directory. This class gets compiled during the test image build. The implementation of the Virtual class creates a new virtual thread for executing each test class.

      +

      JVMTI_STRESS_AGENT

      +

      Executes JTReg tests with JVM TI stress agent. The stress agent is +the part of test library and located in +test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp. The +value of this argument is set as JVM TI agent options. This mode uses +ProblemList-jvmti-stress-agent.txt as an additional exclude list.

      TEST_MODE

      The test mode (agentvm or othervm).

      Defaults to agentvm.

      diff --git a/doc/testing.md b/doc/testing.md index 525b85a8438..4cfc36c85f9 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -401,6 +401,13 @@ the `test/jtreg_test_thread_factory/` directory. This class gets compiled during the test image build. The implementation of the Virtual class creates a new virtual thread for executing each test class. +#### JVMTI_STRESS_AGENT + +Executes JTReg tests with JVM TI stress agent. The stress agent is the part of +test library and located in `test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp`. +The value of this argument is set as JVM TI agent options. +This mode uses ProblemList-jvmti-stress-agent.txt as an additional exclude list. + #### TEST_MODE The test mode (`agentvm` or `othervm`). diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 574fd869092..46f9a2e4047 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -204,8 +204,9 @@ $(eval $(call SetTestOpt,AOT_JDK,JTREG)) $(eval $(call ParseKeywordVariable, JTREG, \ SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \ - TEST_MODE ASSERT VERBOSE RETAIN TEST_THREAD_FACTORY MAX_MEM RUN_PROBLEM_LISTS \ - RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT AOT_JDK $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ + TEST_MODE ASSERT VERBOSE RETAIN TEST_THREAD_FACTORY JVMTI_STRESS_AGENT \ + MAX_MEM RUN_PROBLEM_LISTS RETRY_COUNT REPEAT_COUNT MAX_OUTPUT REPORT \ + AOT_JDK $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \ $(CUSTOM_JTREG_STRING_KEYWORDS), \ @@ -876,6 +877,15 @@ define SetupRunJtregTestBody )) endif + ifneq ($$(JTREG_JVMTI_STRESS_AGENT), ) + AGENT := $$(LIBRARY_PREFIX)JvmtiStressAgent$$(SHARED_LIBRARY_SUFFIX)=$$(JTREG_JVMTI_STRESS_AGENT) + $1_JTREG_BASIC_OPTIONS += -javaoption:'-agentpath:$(TEST_IMAGE_DIR)/hotspot/jtreg/native/$$(AGENT)' + $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ + )) + endif + + ifneq ($$(JTREG_LAUNCHER_OPTIONS), ) $1_JTREG_LAUNCHER_OPTIONS += $$(JTREG_LAUNCHER_OPTIONS) endif diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk index 03c877a4277..e9fd901c9e1 100644 --- a/make/RunTestsPrebuiltSpec.gmk +++ b/make/RunTestsPrebuiltSpec.gmk @@ -176,3 +176,19 @@ ULIMIT := ulimit ifeq ($(OPENJDK_BUILD_OS), windows) PATHTOOL := cygpath endif + +# These settings are needed to run testing with jvmti agent +ifeq ($(OPENJDK_BUILD_OS), linux) + LIBRARY_PREFIX := lib + SHARED_LIBRARY_SUFFIX := .so +endif + +ifeq ($(OPENJDK_BUILD_OS), windows) + LIBRARY_PREFIX := + SHARED_LIBRARY_SUFFIX := .dll +endif + +ifeq ($(OPENJDK_BUILD_OS), macosx) + LIBRARY_PREFIX := lib + SHARED_LIBRARY_SUFFIX := .dylib +endif diff --git a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt new file mode 100644 index 00000000000..636d02cb8b0 --- /dev/null +++ b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt @@ -0,0 +1,101 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. 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. +# +# 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. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +############################################################################# +# +# List of quarantined tests failing with jvmti stress agent in any mode. +# +############################################################################# + + +compiler/macronodes/TestTopInMacroElimination.java 8362832 generic-all + +gc/stringdedup/TestStringDeduplicationAgeThreshold.java 8362562 generic-all +gc/stringdedup/TestStringDeduplicationInterned.java 8362562 generic-all +gc/stringdedup/TestStringDeduplicationPrintOptions.java 8362562 generic-all + + +serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java 8362350 generic-all +vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t007/TestDescription.java 8362350 generic-all + +# Incompatbile tests + +# IR +compiler/loopopts/superword/TestDependencyOffsets.java#avx1-v016-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx1-v016-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx1-v032-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx1-v032-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx2-v016-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx2-v016-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx2-v032-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#avx2-v032-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v004-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v004-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v008-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v008-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v016-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#sse4-v016-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vanilla-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v004-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v004-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v008-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v008-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v016-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v016-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v032-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v032-U 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v064-A 0000000 generic-all +compiler/loopopts/superword/TestDependencyOffsets.java#vec-v064-U 0000000 generic-all + +# Requires solo jvmti capabilities + +compiler/jvmci/events/JvmciShutdownEventTest.java 0000000 generic-all + +# jdwp +runtime/6294277/SourceDebugExtension.java 0000000 generic-all + +# heap stats +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorArrayAllSampledTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorEventOnOffTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCParallelTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCSerialTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorGCTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorIllegalArgumentTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorInitialAllocationTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorInterpreterArrayTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorInterpreterObjectTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorMultiArrayTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorNoCapabilityTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorRecursiveTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatObjectCorrectnessTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatSimpleTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadDisabledTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadOnOffTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorTwoAgentsTest.java 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorVMEventsTest.java#id0 0000000 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorVMEventsTest.java#id1 0000000 generic-all diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 6782bd68fed..8e509c66c9a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -36,6 +36,7 @@ import jdk.test.lib.Platform; import jdk.test.lib.Utils; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; import java.io.PrintWriter; import java.io.StringWriter; @@ -349,6 +350,7 @@ public class TestFramework { if (shouldInstallWhiteBox()) { installWhiteBox(); } + checkCompatibleFlags(); checkIRRuleCompilePhasesFormat(); disableIRVerificationIfNotFeasible(); @@ -775,12 +777,23 @@ public class TestFramework { return Arrays.stream(testClass.getDeclaredMethods()).anyMatch(m -> m.getAnnotationsByType(IR.class).length > 0); } + private void checkCompatibleFlags() { + for (String flag : Utils.getTestJavaOpts()) { + if (flag.contains("-agentpath")) { + throw new SkippedException("Can't run test with agent."); + } + } + } + private List anyNonWhitelistedJTregVMAndJavaOptsFlags() { List flags = Arrays.stream(Utils.getTestJavaOpts()) .map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", "")) .collect(Collectors.toList()); List nonWhiteListedFlags = new ArrayList(); for (String flag : flags) { + if (flag.contains("agentpath")) { + throw new SkippedException("Can't run test with -javaagent"); + } // Property flags (prefix -D), -ea and -esa are whitelisted. if (!flag.startsWith("-D") && !flag.startsWith("-e") && JTREG_WHITELIST_FLAGS.stream().noneMatch(flag::contains)) { // Found VM flag that is not whitelisted diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt new file mode 100644 index 00000000000..4a6e80a9402 --- /dev/null +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -0,0 +1,47 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. 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. +# +# 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. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +############################################################################# +# +# List of quarantined tests failing with jvmti stress agent in any mode. +# +############################################################################# + + +sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java 8362658 generic-all +sun/security/ssl/SSLSessionImpl/MultiNSTClient.java 8362658 generic-all +sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java 8362658 generic-all +sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java 8362658 generic-all +sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java 8362658 generic-all +sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java 8362658 generic-all +sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java 8362658 generic-all + + +# List of tests incompatible with jvmti stress agent or requiring more investigation + +com/sun/jdi/EATests.java#id0 0000000 generic-all +com/sun/jdi/ThreadMemoryLeakTest.java 0000000 generic-all + +# weak referenced are not cleared +java/lang/WeakPairMap/Driver.java 0000000 generic-all +java/lang/ref/ReachabilityFenceTest.java 0000000 generic-all diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 5ac0bea3937..74ea525b415 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -422,7 +422,12 @@ public class VMProps implements Callable> { * @return true if CDS is supported by the VM to be tested. */ protected String vmCDS() { - return "" + WB.isCDSIncluded(); + boolean noJvmtiAdded = allFlags() + .filter(s -> s.startsWith("-agentpath")) + .findAny() + .isEmpty(); + + return "" + (noJvmtiAdded && WB.isCDSIncluded()); } /** diff --git a/test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp b/test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp new file mode 100644 index 00000000000..c760edc66d6 --- /dev/null +++ b/test/lib/jdk/test/lib/jvmti/libJvmtiStressAgent.cpp @@ -0,0 +1,987 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmti.h" +#include "jvmti_common.hpp" + +/* +* + * The jtreg tests might be executed with this agent to ensure that corresponding + * JDK functionality is not broken. + * + * IMPORTANT + * The tests that are incompatible with agent should be placed + * into ProblemList-jvmti-stress-agent.txt with 000000 bug. + * + * Test supports 2 modes: + * - standard, where the agent doesn't require debugging capabilities + * - debug, where the agent additionally test debug-related functionality + * The debug mode is incompatible with debugger tests and debug jvmti tests. + * The standard mode should be compatible with all tests except problemlisted. + * + * The JVMTI agent starts jvmti agent tread that enable/disable different + * events and call different jvmti functions concurrently with test execution. + * + * The main requirement is to don't change test behaviour. + * + */ + +#define JVMTI_AGENT_NAME "JvmtiStressAgent" + +/* Global settings and some statistics counters */ +typedef struct { + + /* Verbose logging support */ + jboolean is_verbose; + + /* If debugging functionality could be used. Set from agent args.*/ + jboolean is_debugger_enabled; + + /* Monitor and flags to synchronize agent completion.*/ + jrawMonitorID finished_lock; + volatile jboolean request_agent_thread_stop; + volatile jboolean is_agent_finished; + + /* Some settings configured in gdata_init(). */ + + /* If agent enabled or not. */ + jboolean is_tracing_enabled; + + /* If events testing is enabled. */ + jboolean are_events_enabled; + + /* If interponly and frequent events testing is enabled. */ + jboolean are_frequent_events_enabled; + + /* Should we iterate heap */ + jboolean is_heap_iterate_enabled; + + /* Is Heap sampling enabled */ + jboolean is_heap_sampling_enabled; + + jint heap_sampling_interval; + jint events_interval; + jint frequent_events_interval; + + /* Excluded events */ + jint* events_excluded; + jsize events_excluded_size; + + /* Event statistics */ + + /* The counters are racy intentionally to avoid synchronization. */ + jlong cbBreakpoint; + jlong cbClassFileLoadHook; + jlong cbClassLoad; + jlong cbClassPrepare; + jlong cbCompiledMethodLoad; + jlong cbCompiledMethodUnload; + jlong cbDataDumpRequest; + jlong cbDynamicCodeGenerated; + jlong cbException; + jlong cbExceptionCatch; + jlong cbFieldAccess; + jlong cbFieldModification; + jlong cbFramePop; + jlong cbGarbageCollectionFinish; + jlong cbGarbageCollectionStart; + jlong cbMethodEntry; + jlong cbMethodExit; + jlong cbMonitorContendedEnter; + jlong cbMonitorContendedEntered; + jlong cbMonitorWait; + jlong cbMonitorWaited; + jlong cbNativeMethodBind; + jlong cbObjectFree; + jlong cbResourceExhausted; + jlong cbSampledObjectAlloc; + jlong cbSingleStep; + jlong cbThreadEnd; + jlong cbThreadStart; + jlong cbVirtualThreadEnd; + jlong cbVirtualThreadStart; + jlong cbVMDeath; + jlong cbVMInit; + jlong cbVMObjectAlloc; + + /* Inspector statistics are intentionally racy. */ + jlong inspectedMethods; + jlong inspectedVariables; + + /* File for debug output, agent shouldn't write into stdout. */ + FILE* log_file; +} GlobalData; + +GlobalData *gdata; + +static GlobalData* +gdata_init(jboolean is_debugger_enabled, jboolean is_verbose) { + static GlobalData data; + (void) memset(&data, 0, sizeof (GlobalData)); + + data.is_debugger_enabled = is_debugger_enabled; + data.is_verbose = is_verbose; + + data.request_agent_thread_stop = JNI_FALSE; + data.is_agent_finished = JNI_FALSE; + + /* Set jvmti stress properties */ + data.heap_sampling_interval = 1000; + data.frequent_events_interval = 10; + + data.is_tracing_enabled = JNI_TRUE; + data.are_events_enabled = JNI_TRUE; + data.are_frequent_events_enabled = JNI_TRUE; + // disabled so far + data.is_heap_iterate_enabled = JNI_FALSE; + data.is_heap_sampling_enabled = JNI_FALSE; + + + if (data.is_debugger_enabled) { + data.events_excluded_size = 0; + data.events_excluded = nullptr; + } else { + data.events_excluded_size = 4; + data.events_excluded = new jint[4] { + JVMTI_EVENT_BREAKPOINT, + JVMTI_EVENT_FIELD_ACCESS, + JVMTI_EVENT_FIELD_MODIFICATION, + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, + }; + } + if (data.is_verbose) { + data.log_file = fopen("JvmtiStressAgent.out", "w"); + } + + return &data; +} + +void +gdata_close() { + free(gdata->events_excluded); + if (gdata->is_verbose) { + fclose(gdata->log_file); + } +} + +// Internal buffer length for all messages +#define MESSAGE_LIMIT 16384 + +void +debug(const char* format, ...) { + if (!gdata->is_verbose) { + return; + } + char dest[MESSAGE_LIMIT]; + va_list argptr; + va_start(argptr, format); + vsnprintf(dest, MESSAGE_LIMIT, format, argptr); + va_end(argptr); + // Enable if needed, tests might fail with unexpected output + //printf("%s\n", dest); + fprintf(gdata->log_file, "%s\n", dest); + fflush(gdata->log_file); +} + +/* Some helper functions to start/stop jvmti stress agent thread. */ +void +check_jni_exception(JNIEnv *jni, const char *message) { + jobject exception = jni->ExceptionOccurred(); + if (exception != nullptr) { + jni->ExceptionDescribe(); + fatal(jni, message); + } +} + +jclass +find_class(JNIEnv *jni, const char *name) { + char message[MESSAGE_LIMIT]; + jclass clazz = jni->FindClass(name); + snprintf(message, MESSAGE_LIMIT, "Failed to find class %s.", name); + check_jni_exception(jni, message); + return clazz; +} + +jmethodID +get_method_id(JNIEnv *jni, jclass clazz, const char *name, const char *sig) { + char message[MESSAGE_LIMIT]; + jmethodID method = jni->GetMethodID(clazz, name, sig); + snprintf(message, MESSAGE_LIMIT, "Failed to find method %s.", name); + check_jni_exception(jni, message); + return method; +} + +void +create_agent_thread(jvmtiEnv *jvmti, JNIEnv *jni, const char *name, jvmtiStartFunction func) { + + check_jni_exception(jni, "JNIException before creating Agent Thread."); + jclass clazz = find_class(jni, "java/lang/Thread"); + jmethodID thread_ctor = get_method_id(jni, clazz, "", + "(Ljava/lang/String;)V"); + + jstring name_utf = jni->NewStringUTF(name); + check_jni_exception(jni, "Error creating utf name of thread."); + + jthread thread = jni->NewObject(clazz, thread_ctor, name_utf); + check_jni_exception(jni, "Error during instantiation of Thread object."); + jvmtiError err = jvmti->RunAgentThread( + thread, func, nullptr, JVMTI_THREAD_NORM_PRIORITY); + check_jvmti_status(jni, err, "RunAgentThread"); +} + +/* + * The method blocks execution until agent thread finishes. + * Should be executed during VMDeath to don't run JVMTI functionality + * during dead phase. + */ +void +request_agent_thread_stop_and_wait(jvmtiEnv *jvmti, JNIEnv *jni) { + RawMonitorLocker rml(jvmti, jni, gdata->finished_lock); + gdata->request_agent_thread_stop = JNI_TRUE; + while (!gdata->is_agent_finished) { + rml.wait(1000); + } + debug("Native agent stopped"); +} + +/* + * The method is called by agent thread to ensure that thread correctly exits. + */ +static jboolean +should_stop(jvmtiEnv *jvmti, JNIEnv *jni) { + jboolean should_stop = JNI_FALSE; + RawMonitorLocker rml(jvmti, jni, gdata->finished_lock); + should_stop = gdata->request_agent_thread_stop; + if (should_stop == JNI_TRUE) { + gdata->is_agent_finished = JNI_TRUE; + rml.notify_all(); + } + return should_stop; +} + +/* + * Agent stress functions. The agent is stopped in VMDeath only and should be + * always ready to get JVMTI_ERROR_THREAD_NOT_ALIVE error. + */ + +/* Read stack, frames, method, variables, etc. */ +static void +walk_stack(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + jvmtiError err = JVMTI_ERROR_NONE; + debug("In walk_stack: %p", thread); + + jvmtiFrameInfo frames[5]; + jint count = 0; + err = jvmti->GetStackTrace(thread, 0, 5, frames, &count); + if (err == JVMTI_ERROR_THREAD_NOT_ALIVE || err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_error(err, "GetStackTrace"); + + debug("Stack depth: %d", count); + + for (int frame_index = 0; frame_index < count; frame_index++) { + char *method_name = nullptr; + jint method_modifiers = 0; + err = jvmti->GetMethodName(frames[frame_index].method, &method_name, nullptr, nullptr); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "GetMethodName"); + + err = jvmti->GetMethodModifiers(frames[frame_index].method, &method_modifiers); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "GetMethodModifiers"); + + debug("Inspecting method: %s, %d", method_name, method_modifiers); + deallocate(jvmti, jni, method_name); + + jvmtiLocalVariableEntry* table = nullptr; + jint entry_count = 0; + err = jvmti->GetLocalVariableTable(frames[frame_index].method, &entry_count, &table); + if (err == JVMTI_ERROR_NATIVE_METHOD || err == JVMTI_ERROR_ABSENT_INFORMATION + || err == JVMTI_ERROR_WRONG_PHASE) { + continue; + } + check_jvmti_status(jni, err, "GetLocalVariableTable"); + + gdata->inspectedMethods += 1; + gdata->inspectedVariables += entry_count; + + debug("Variables: "); + for (int cnt = 0; cnt < entry_count; cnt++) { + debug(" %s %d", table[cnt].name, table[cnt].slot); + deallocate(jvmti, jni, table[cnt].name); + deallocate(jvmti, jni, table[cnt].signature); + deallocate(jvmti, jni, table[cnt].generic_signature); + } + deallocate(jvmti, jni, table); + } + debug("---- End of stack inspection %d -----", count); +} + +/* Iterate with walk_stack through all thread. */ +static void JNICALL +walk_all_threads_stacks(jvmtiEnv *jvmti, JNIEnv *jni) { + jint threads_count = 0; + jthread *threads = nullptr; + jvmtiError err = JVMTI_ERROR_NONE; + debug("Inspect: Starting cycle..."); + err = jvmti->GetAllThreads(&threads_count, &threads); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "GetAllThreads"); + for (int t = 0; t < (int)threads_count; t++) { + jvmtiThreadInfo info; + debug("Inspecting thread num %d at addr [%p]",t, threads[t]); + err = jvmti->GetThreadInfo(threads[t], &info); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "GetThreadInfo"); + // Skip agent thread itself and JFR threads to avoid potential deadlocks + if (strstr(info.name, JVMTI_AGENT_NAME) == nullptr + && strstr(info.name, "JFR") == nullptr) { + // The non-intrusive actions are allowed to ensure that results of target + // thread are not affected. + jthread thread = threads[t]; + walk_stack(jvmti, jni, thread); + + // Suspend/resume are solo capabilities and are treated like debugging + if (gdata->is_debugger_enabled) { + debug("Inspect: Trying to suspend thread %s", info.name); + err = jvmti->SuspendThread(thread); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + if (err == JVMTI_ERROR_THREAD_NOT_ALIVE) { + debug("Inspect: thread %s is not alive. Skipping.", info.name); + continue; + } + check_jvmti_status(jni, err, "SuspendThread"); + debug("Inspect: Suspended thread %s", info.name); + + walk_stack(jvmti, jni, thread); + + debug("Inspect: Trying to resume thread %s", info.name); + err = jvmti->ResumeThread(thread); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "ResumeThread"); + debug("Inspect: Resumed thread %s", info.name); + } + + } + deallocate(jvmti, jni, info.name); + jni->DeleteLocalRef(info.thread_group); + jni->DeleteLocalRef(info.context_class_loader); + jni->DeleteLocalRef(threads[t]); + } + deallocate(jvmti, jni, threads); +} + +/* Heap inspection helpers. */ +static jint JNICALL +heap_iteration_callback(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) { + int* count = (int*) user_data; + *count += 1; + return JVMTI_VISIT_OBJECTS; +} + +static jint +get_heap_info(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass) { + jvmtiError err = JVMTI_ERROR_NONE; + int count = 0; + jvmtiHeapCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof (callbacks)); + callbacks.heap_iteration_callback = &heap_iteration_callback; + err = jvmti->IterateThroughHeap(0, klass, &callbacks, &count); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return count; + } + check_jvmti_status(jni, err, "IterateThroughHeap"); + return count; +} + + +/* + * Events testing helper functions. + */ + + +int +is_event_frequent(int event) { + // Should include all interpreter-only events and all frequent events. + return event == JVMTI_EVENT_SINGLE_STEP + || event == JVMTI_EVENT_METHOD_ENTRY + || event == JVMTI_EVENT_METHOD_EXIT + || event == JVMTI_EVENT_FRAME_POP + || event == JVMTI_EVENT_FIELD_ACCESS + || event == JVMTI_EVENT_FIELD_MODIFICATION + || event == JVMTI_EVENT_EXCEPTION_CATCH + || event == JVMTI_EVENT_EXCEPTION + ; +} + +int +is_event_excluded(int event) { + for (int i = 0; i < gdata->events_excluded_size; i++) { + if (event == gdata->events_excluded[i]) { + return JNI_TRUE; + } + } + return JNI_FALSE; +} + +static void +enable_events(jvmtiEnv *jvmti, jboolean update_frequent_events) { + debug("Enabling events\n"); + for(int event = JVMTI_MIN_EVENT_TYPE_VAL; event < JVMTI_MAX_EVENT_TYPE_VAL; event++) { + if (is_event_excluded(event)) { + debug("Event %d excluded.", event); + continue; + } + if (is_event_frequent(event) != update_frequent_events ) { + debug("Event %d is not enabled as frequent/slow.", event); + continue; + } + jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, + static_cast(event), nullptr); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_error(err, "SetEventNotificationMode"); + } + debug("Enabling events done\n"); +} + +static void +enable_frequent_events(jvmtiEnv *jvmti) { + enable_events(jvmti, JNI_TRUE); +} + +static void +enable_common_events(jvmtiEnv *jvmti) { + enable_events(jvmti,JNI_FALSE); +} + + +static void +disable_all_events(jvmtiEnv *jvmti) { + jvmtiError err = JVMTI_ERROR_NONE; + for (int event = JVMTI_MIN_EVENT_TYPE_VAL; event < JVMTI_MAX_EVENT_TYPE_VAL; event++) { + // VM_DEATH is used to stop agent + if (event == JVMTI_EVENT_VM_DEATH) { + continue; + } + err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, static_cast(event), nullptr); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_error(err, "SetEventNotificationMode"); + } +} + +/* + * The JVMTI agent main loop. + */ + +static void JNICALL +stress_agent(jvmtiEnv *jvmti, JNIEnv *jni, void *p) { + jvmtiError err = JVMTI_ERROR_NONE; + debug("Debugger: Thread started."); + while (!should_stop(jvmti, jni)) { + + if (gdata->are_events_enabled) { + enable_common_events(jvmti); + } + + // Iterate through heap and get some statistics + if (gdata->is_heap_iterate_enabled) { + jclass kls = find_class(jni, "java/lang/String"); + jlong obj_count = get_heap_info(jvmti, jni, kls); + debug("Debugger: Heap info: %d", obj_count); + } + + + // requires can_generate_sampled_object_alloc_events + // which is solo capability + if (gdata->is_heap_sampling_enabled) { + err = jvmti->SetHeapSamplingInterval(gdata->heap_sampling_interval); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + check_jvmti_status(jni, err, "SetHeapSamplingInterval"); + } + + if (gdata->is_tracing_enabled) { + walk_all_threads_stacks(jvmti, jni); + } + + sleep_ms(gdata->events_interval); + + err = jvmti->SetHeapSamplingInterval(0); + if (err == JVMTI_ERROR_WRONG_PHASE) { + return; + } + if (gdata->is_heap_sampling_enabled) { + check_jvmti_status(jni, err, "SetHeapSamplingInterval"); + } + + if (gdata->are_frequent_events_enabled) { + enable_frequent_events(jvmti); + sleep_ms(gdata->frequent_events_interval); + } + disable_all_events(jvmti); + sleep_ms(gdata->events_interval); + } + debug("Debugger: Thread finished."); +} + + +/* + * Events section. + * Most of the events just increase counter and print debug info. + * The VMInit/VMDeath are also start and stop jvmti stress agent. + */ + +static void +register_event(jlong *event) { + (*event)++; +} + +static void JNICALL +cbVMInit(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + register_event(&gdata->cbVMInit); + debug("Event cbVMInit\n"); + create_agent_thread(jvmti, jni, JVMTI_AGENT_NAME, &stress_agent); +} + +static void JNICALL +cbVMDeath(jvmtiEnv *jvmti, JNIEnv *jni) { + register_event(&gdata->cbVMDeath); + debug("Event cbVMDeath\n"); + request_agent_thread_stop_and_wait(jvmti, jni); + destroy_raw_monitor(jvmti, jni, gdata->finished_lock); +} + +static void JNICALL +cbThreadStart(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + register_event(&gdata->cbThreadStart); + debug("Event cbThreadStart\n"); +} + +static void JNICALL +cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + register_event(&gdata->cbThreadEnd); + debug("Event cbThreadEnd\n"); +} + +static void JNICALL +cbVirtualThreadStart(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + register_event(&gdata->cbThreadStart); + debug("Event cbThreadStart\n"); +} + +static void JNICALL +cbVirtualThreadEnd(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) { + register_event(&gdata->cbThreadEnd); + debug("Event cbThreadEnd\n"); +} + +static void JNICALL +cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* jni, + jclass class_being_redefined, jobject loader, + const char* name, jobject protection_domain, + jint class_data_len, const unsigned char *class_data, + jint *new_class_data_len, unsigned char **new_class_data) { + /* TODO uncomment for more stress + unsigned char* new_class_data_copy = (unsigned char*) malloc(class_data_len); + memcpy(new_class_data_copy, class_data, class_data_len); + *new_class_data_len = class_data_len; + *new_class_data = new_class_data_copy; + */ + register_event(&gdata->cbClassFileLoadHook); + debug("Event cbClassFileLoadHook\n"); +} + +static void JNICALL +cbClassLoad(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jclass klass) { + register_event(&gdata->cbClassLoad); + debug("Event cbClassLoad\n"); +} + +static void JNICALL +cbClassPrepare(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jclass klass) { + register_event(&gdata->cbClassPrepare); + debug("Event cbClassPrepare\n"); +} + +static void JNICALL +cbDataDumpRequest(jvmtiEnv *jvmti) { + register_event(&gdata->cbDataDumpRequest); + debug("Event cbDataDumpRequest\n"); +} + +static void JNICALL +cbException(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jlocation location, + jobject exception, + jmethodID catch_method, + jlocation catch_location) { + register_event(&gdata->cbException); + debug("Event cbException\n"); +} + +static void JNICALL +cbExceptionCatch(jvmtiEnv *jvmti, JNIEnv *jni, + jthread thread, jmethodID method, jlocation location, + jobject exception) { + register_event(&gdata->cbExceptionCatch); + debug("Event cbExceptionCatch\n"); +} + +static void JNICALL +cbMonitorWait(jvmtiEnv *jvmti, JNIEnv *jni, + jthread thread, jobject object, jlong timeout) { + register_event(&gdata->cbMonitorWait); + debug("Event cbMonitorWait\n"); +} + +static void JNICALL +cbMonitorWaited(jvmtiEnv *jvmti, JNIEnv *jni, + jthread thread, jobject object, jboolean timed_out) { + register_event(&gdata->cbMonitorWaited); + debug("Event cbMonitorWaited\n"); +} + +static void JNICALL +cbMonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *jni, + jthread thread, jobject object) { + register_event(&gdata->cbMonitorContendedEnter); + debug("Event cbMonitorContendedEnter\n"); +} + +static void JNICALL +cbMonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* jni, + jthread thread, jobject object) { + register_event(&gdata->cbMonitorContendedEntered); + debug("Event cbMonitorContendedEntered\n"); +} + +static void JNICALL +cbGarbageCollectionStart(jvmtiEnv *jvmti) { + register_event(&gdata->cbGarbageCollectionStart); + debug("Event cbGarbageCollectionStart\n"); +} + +static void JNICALL +cbGarbageCollectionFinish(jvmtiEnv *jvmti) { + register_event(&gdata->cbGarbageCollectionFinish); + debug("Event cbGarbageCollectionFinish\n"); +} + +static void JNICALL +cbObjectFree(jvmtiEnv *jvmti, jlong tag) { + register_event(&gdata->cbObjectFree); + debug("Event cbObjectFree\n"); +} + +static void JNICALL +cbBreakpoint(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jlocation location) { + register_event(&gdata->cbBreakpoint); + debug("Event cbBreakpoint\n"); +} + +static void JNICALL +cbSingleStep(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jlocation location) { + register_event(&gdata->cbSingleStep); + debug("Event cbSingleStep\n"); +} + +static void JNICALL +cbFieldAccess(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jlocation location, + jclass field_klass, + jobject object, + jfieldID field) { + register_event(&gdata->cbFieldAccess); + debug("Event cbFieldAccess\n"); +} + +static void JNICALL +cbFieldModification(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jlocation location, + jclass field_klass, + jobject object, + jfieldID field, + char signature_type, + jvalue new_value) { + register_event(&gdata->cbFieldModification); + debug("Event cbFieldModification\n"); +} + +static void JNICALL +cbFramePop(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jboolean was_popped_by_exception) { + register_event(&gdata->cbFramePop); + debug("Event cbFramePop\n"); +} + +static void JNICALL +cbMethodEntry(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method) { + register_event(&gdata->cbMethodEntry); + debug("Event cbMethodEntry\n"); +} + +static void JNICALL +cbMethodExit(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + jboolean was_popped_by_exception, + jvalue return_value) { + register_event(&gdata->cbMethodExit); + debug("Event cbMethodExit\n"); +} + +static void JNICALL +cbNativeMethodBind(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jmethodID method, + void* address, + void** new_address_ptr) { + register_event(&gdata->cbNativeMethodBind); + debug("Event cbNativeMethodBind\n"); +} + +static void JNICALL +cbCompiledMethodLoad(jvmtiEnv *jvmti, + jmethodID method, + jint code_size, + const void* code_addr, + jint map_length, + const jvmtiAddrLocationMap* map, + const void* compile_info) { + register_event(&gdata->cbCompiledMethodLoad); + debug("Event cbCompiledMethodLoad\n"); +} + +static void JNICALL +cbCompiledMethodUnload(jvmtiEnv *jvmti, + jmethodID method, + const void* code_addr) { + register_event(&gdata->cbCompiledMethodUnload); + debug("Event cbCompiledMethodUnload\n"); +} + +static void JNICALL +cbDynamicCodeGenerated(jvmtiEnv *jvmti, + const char* name, + const void* address, + jint length) { + register_event(&gdata->cbDynamicCodeGenerated); + debug("Event cbDynamicCodeGenerated\n"); +} + +static void JNICALL +cbResourceExhausted(jvmtiEnv *jvmti, + JNIEnv *jni, + jint flags, + const void* reserved, + const char* description) { + register_event(&gdata->cbResourceExhausted); + debug("Event cbResourceExhausted\n"); +} + +static void JNICALL +cbVMObjectAlloc(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jobject object, + jclass object_klass, + jlong size) { + register_event(&gdata->cbVMObjectAlloc); + debug("Event cbVMObjectAlloc\n"); +} + +static void JNICALL +cbSampledObjectAlloc(jvmtiEnv *jvmti, + JNIEnv *jni, + jthread thread, + jobject object, + jclass object_klass, + jlong size) { + register_event(&gdata->cbSampledObjectAlloc); + debug("Event cbSampledObjectAlloc\n"); +} + + + +static void +set_callbacks(jvmtiEnv *jvmti, jboolean on) { + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiEventCallbacks callbacks; + + (void) memset(&callbacks, 0, sizeof (callbacks)); + if (on == JNI_FALSE) { + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + return; + } + callbacks.Breakpoint = &cbBreakpoint; + callbacks.ClassFileLoadHook = &cbClassFileLoadHook; + callbacks.ClassLoad = &cbClassLoad; + callbacks.ClassPrepare = &cbClassPrepare; + callbacks.CompiledMethodLoad = &cbCompiledMethodLoad; + callbacks.CompiledMethodUnload = &cbCompiledMethodUnload; + callbacks.DataDumpRequest = &cbDataDumpRequest; + callbacks.DynamicCodeGenerated = &cbDynamicCodeGenerated; + callbacks.Exception = &cbException; + callbacks.ExceptionCatch = &cbExceptionCatch; + callbacks.FieldAccess = &cbFieldAccess; + callbacks.FieldModification = &cbFieldModification; + callbacks.FramePop = &cbFramePop; + callbacks.GarbageCollectionFinish = &cbGarbageCollectionFinish; + callbacks.GarbageCollectionStart = &cbGarbageCollectionStart; + callbacks.MethodEntry = &cbMethodEntry; + callbacks.MethodExit = &cbMethodExit; + callbacks.MonitorContendedEnter = &cbMonitorContendedEnter; + callbacks.MonitorContendedEntered = &cbMonitorContendedEntered; + callbacks.MonitorWait = &cbMonitorWait; + callbacks.MonitorWaited = &cbMonitorWaited; + callbacks.NativeMethodBind = &cbNativeMethodBind; + callbacks.ObjectFree = &cbObjectFree; + callbacks.ResourceExhausted = &cbResourceExhausted; + callbacks.SampledObjectAlloc = &cbSampledObjectAlloc; + callbacks.SingleStep = &cbSingleStep; + callbacks.ThreadEnd = &cbThreadEnd; + callbacks.ThreadStart = &cbThreadStart; + callbacks.VirtualThreadEnd = &cbVirtualThreadEnd; + callbacks.VirtualThreadStart = &cbVirtualThreadStart; + callbacks.VMDeath = &cbVMDeath; + callbacks.VMInit = &cbVMInit; + callbacks.VMObjectAlloc = &cbVMObjectAlloc; + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); +} + +static +void get_capabilities(jvmtiEnv *jvmti) { + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof (capabilities)); + err = jvmti->GetPotentialCapabilities(&capabilities); + + if (!gdata->is_debugger_enabled) { + //init_always_solo_capabilities + capabilities.can_suspend = false; + + // onload_solo + capabilities.can_generate_breakpoint_events = false; + capabilities.can_generate_field_access_events = false; + capabilities.can_generate_field_modification_events = false; + } + + capabilities.can_generate_early_vmstart = false; + + check_jvmti_error(err, "GetPotentialCapabilities"); + err = jvmti->AddCapabilities(&capabilities); + check_jvmti_error(err, "AddCapabilities"); +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + jint res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_21); + if (res != JNI_OK) { + return JNI_ERR; + } + + jboolean is_debugger_enabled = JNI_TRUE; + jboolean is_verbose = JNI_FALSE; + + if (options != nullptr) { + char *opts = strdup(options); + char *token = strtok(opts, ","); + + while (token != nullptr) { + if (strncmp(token, "debugger=", 9) == 0) { + if (strcmp(token + 9, "true") == 0) { + is_debugger_enabled = JNI_TRUE; + } else { + is_debugger_enabled = JNI_FALSE; + } + } + if (strncmp(token, "verbose", 7) == 0) { + is_verbose = JNI_TRUE; + } + token = strtok(nullptr, ","); + } + free(opts); + } + gdata = gdata_init(is_debugger_enabled, is_verbose); + get_capabilities(jvmti); + gdata->finished_lock = create_raw_monitor(jvmti, "Finished lock"); + set_callbacks(jvmti, JNI_TRUE); + jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, + JVMTI_EVENT_VM_INIT, nullptr); + check_jvmti_error(err, "SetEventNotificationMode"); + return JNI_OK; +} + +JNIEXPORT void JNICALL +Agent_OnUnload(JavaVM *vm) { + if (!gdata->request_agent_thread_stop) { + printf("Agent_OnUnload happened before requested stop.\n"); + } + gdata_close(); +} From 57210af9bceb582be112564465ab66cebd43a4c0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 16 Aug 2025 04:41:25 +0000 Subject: [PATCH 106/471] 8365555: Cleanup redundancies in jpackage implementation Reviewed-by: almatvee --- .../jpackage/internal/DesktopIntegration.java | 2 +- .../internal/LinuxApplicationLayout.java | 25 +- .../internal/LinuxApplicationLayoutMixin.java | 2 +- .../jpackage/internal/LinuxDebBundler.java | 3 +- .../internal/LinuxPackageBuilder.java | 31 +- .../jpackage/internal/model/LinuxPackage.java | 3 - .../internal/model/LinuxPackageMixin.java | 7 +- .../jdk/jpackage/internal/AppImageSigner.java | 38 +- .../jdk/jpackage/internal/MacAppBundler.java | 4 +- .../internal/MacApplicationBuilder.java | 21 +- .../internal/MacApplicationLayout.java | 29 +- .../internal/MacApplicationLayoutMixin.java | 7 +- .../internal/MacBuildEnvFromParams.java} | 32 +- .../jdk/jpackage/internal/MacBundle.java | 17 +- .../jdk/jpackage/internal/MacDmgBundler.java | 2 +- .../internal/MacDmgPackageBuilder.java | 1 - .../jdk/jpackage/internal/MacFromParams.java | 16 +- .../jpackage/internal/MacPackageBuilder.java | 13 +- .../internal/MacPackagingPipeline.java | 148 ++- .../jdk/jpackage/internal/MacPkgBundler.java | 2 +- .../jpackage/internal/model/MacPackage.java | 27 +- .../jpackage/internal/ApplicationBuilder.java | 27 +- .../internal/ApplicationImageUtils.java | 2 +- .../jdk/jpackage/internal/BuildEnv.java | 82 +- .../jpackage/internal/BuildEnvBuilder.java | 29 +- .../jpackage/internal/BuildEnvFromParams.java | 24 +- .../jdk/jpackage/internal/FromParams.java | 7 +- .../internal/JLinkRuntimeBuilder.java | 2 +- .../jdk/jpackage/internal/PackageBuilder.java | 38 +- .../jpackage/internal/PackagingPipeline.java | 211 ++--- .../internal/model/AppImageLayout.java | 99 +- .../internal/model/ApplicationLayout.java | 40 +- .../jdk/jpackage/internal/model/Package.java | 73 +- .../internal/model/RuntimeBuilder.java | 2 +- .../internal/model/RuntimeLayout.java | 26 +- .../internal/resources/ResourceLocator.java | 4 +- .../jdk/jpackage/internal/util/PathGroup.java | 17 + .../jdk/jpackage/internal/util/PathUtils.java | 11 +- .../internal/WinPackagingPipeline.java | 2 - .../internal/model/WinExePackage.java | 1 + .../jpackage/helpers-test/TEST.properties | 2 +- .../jdk/jpackage/test/JavaAppDescTest.java | 15 +- .../jdk/jpackage/test/JPackageCommand.java | 13 +- test/jdk/tools/jpackage/junit/TEST.properties | 2 + .../internal/LinuxApplicationLayoutTest.java | 57 ++ .../jdk/tools/jpackage/junit/linux/junit.java | 32 + .../internal/MacApplicationLayoutTest.java | 57 ++ .../tools/jpackage/junit/macosx/junit.java | 32 + .../jdk/jpackage/internal/BuildEnvTest.java | 140 +++ .../internal/PackagingPipelineTest.java | 872 ++++++++++++++++++ .../internal/model/AppImageLayoutTest.java | 99 +- .../internal/model/ApplicationLayoutTest.java | 63 +- .../jpackage/internal/util/PathGroupTest.java | 8 + .../jdk/jpackage/test/JUnitAdapter.java | 14 +- .../tools/jpackage/junit/windows/junit.java | 3 +- 55 files changed, 2114 insertions(+), 422 deletions(-) rename src/jdk.jpackage/{share/classes/jdk/jpackage/internal/AppImageDesc.java => macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java} (59%) create mode 100644 test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxApplicationLayoutTest.java create mode 100644 test/jdk/tools/jpackage/junit/linux/junit.java create mode 100644 test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationLayoutTest.java create mode 100644 test/jdk/tools/jpackage/junit/macosx/junit.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/BuildEnvTest.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java rename test/jdk/tools/jpackage/{helpers-test => junit/tools}/jdk/jpackage/test/JUnitAdapter.java (90%) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index dad9917c48f..2d0c78c2474 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -355,7 +355,7 @@ final class DesktopIntegration extends ShellCustomAction { * - installPath(): path where it should be installed by package manager; */ private InstallableFile createDesktopFile(String fileName) { - var srcPath = pkg.asPackageApplicationLayout().orElseThrow().resolveAt(env.appImageDir()).desktopIntegrationDirectory().resolve(fileName); + var srcPath = env.asApplicationLayout().orElseThrow().desktopIntegrationDirectory().resolve(fileName); var installPath = pkg.asInstalledPackageApplicationLayout().orElseThrow().desktopIntegrationDirectory().resolve(fileName); return new InstallableFile(srcPath, installPath); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java index ea87363a9bb..677ee199a84 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayout.java @@ -24,9 +24,10 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; import java.nio.file.Path; +import java.util.function.UnaryOperator; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.util.CompositeProxy; @@ -40,7 +41,25 @@ interface LinuxApplicationLayout extends ApplicationLayout, LinuxApplicationLayo @Override default LinuxApplicationLayout resolveAt(Path root) { - return create(ApplicationLayout.super.resolveAt(root), - resolveNullablePath(root, libAppLauncher())); + return (LinuxApplicationLayout)ApplicationLayout.super.resolveAt(root); + } + + @Override + default LinuxApplicationLayout unresolve() { + return (LinuxApplicationLayout)ApplicationLayout.super.unresolve(); + } + + @Override + default LinuxApplicationLayout resetRootDirectory() { + if (isResolved()) { + return create(ApplicationLayout.super.resetRootDirectory(), libAppLauncher()); + } else { + return this; + } + } + + @Override + default LinuxApplicationLayout map(UnaryOperator mapper) { + return create(ApplicationLayout.super.map(mapper), mapNullablePath(mapper, libAppLauncher())); } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java index a88dbc9e16e..21606153669 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxApplicationLayoutMixin.java @@ -26,7 +26,7 @@ package jdk.jpackage.internal; import java.nio.file.Path; -// Must be publc to allow access from AppImageLayout.toPathGroup() +// Must be public to allow access from AppImageLayout.toPathGroup() public interface LinuxApplicationLayoutMixin { /** diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index 1915fd00c0e..d5b369ba23a 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -351,8 +351,7 @@ public class LinuxDebBundler extends LinuxPackageBundler { data.put("APPLICATION_LICENSE_TEXT", licenseText); data.put("APPLICATION_ARCH", pkg.arch()); data.put("APPLICATION_INSTALLED_SIZE", Long.toString( - AppImageLayout.toPathGroup(pkg.packageLayout().resolveAt( - env.appImageDir())).sizeInBytes() >> 10)); + AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10)); data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( value -> "Homepage: " + value).orElse("")); data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java index 4ed84909958..cc00d7816f5 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBuilder.java @@ -33,7 +33,9 @@ import java.util.regex.Pattern; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxApplication; import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.LinuxPackageMixin; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.StandardPackageType; @@ -52,24 +54,35 @@ final class LinuxPackageBuilder { pkgBuilder.name(pkgBuilder.create().packageName().toLowerCase().replaceAll("[ _]", "-")); } - final var pkg = pkgBuilder.create(); + final var tmpPkg = pkgBuilder.create(); - final var stdPkgType = pkg.asStandardPackageType(); + final var stdPkgType = tmpPkg.asStandardPackageType(); if (stdPkgType.isPresent()) { - validatePackageName(pkg.packageName(), stdPkgType.orElseThrow()); + validatePackageName(tmpPkg.packageName(), stdPkgType.orElseThrow()); } - var reply = create(pkg, pkg.packageLayout()); - if (reply.isInstallDirInUsrTree()) { - reply = create(pkg, usrTreePackageLayout(pkg.relativeInstallDir(), pkg.packageName())); + final AppImageLayout relativeInstalledLayout; + if (create(tmpPkg).isInstallDirInUsrTree()) { + final var usrTreeLayout = usrTreePackageLayout(tmpPkg.relativeInstallDir(), tmpPkg.packageName()); + if (tmpPkg.isRuntimeInstaller()) { + relativeInstalledLayout = RuntimeLayout.create(usrTreeLayout.runtimeDirectory()); + } else { + relativeInstalledLayout = usrTreeLayout; + } + } else { + relativeInstalledLayout = tmpPkg.appImageLayout().resolveAt(tmpPkg.relativeInstallDir()).resetRootDirectory(); } - return reply; + final var app = ApplicationBuilder.overrideAppImageLayout(pkgBuilder.app(), relativeInstalledLayout); + + return create(pkgBuilder + .app(LinuxApplication.create(app)) + .installedPackageLayout(relativeInstalledLayout.resolveAt(Path.of("/")).resetRootDirectory()) + .create()); } - private LinuxPackage create(Package pkg, AppImageLayout pkgLayout) throws ConfigException { + private LinuxPackage create(Package pkg) throws ConfigException { return LinuxPackage.create(pkg, new LinuxPackageMixin.Stub( - pkgLayout, Optional.ofNullable(menuGroupName).orElseGet(DEFAULTS::menuGroupName), Optional.ofNullable(category), Optional.ofNullable(additionalDependencies), diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java index aef1c5eb700..28d47fc46a8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackage.java @@ -36,9 +36,6 @@ public interface LinuxPackage extends Package, LinuxPackageMixin { LinuxApplication app(); - @Override - AppImageLayout packageLayout(); - @Override default String packageFileName() { String packageFileNameTemlate = asStandardPackageType().map(stdType -> { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java index f890aa6ff39..5bcf57194f6 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/model/LinuxPackageMixin.java @@ -31,11 +31,6 @@ import java.util.Optional; */ public interface LinuxPackageMixin { - /** - * Overrides {@link Package#packageLayout()}. - */ - AppImageLayout packageLayout(); - /** * Gets the name of the start menu group where to create shortcuts for * application launchers of this package. @@ -88,7 +83,7 @@ public interface LinuxPackageMixin { /** * Default implementation of {@link LinuxPackageMixin} interface. */ - record Stub(AppImageLayout packageLayout, String menuGroupName, + record Stub(String menuGroupName, Optional category, Optional additionalDependencies, Optional release, String arch) implements LinuxPackageMixin { } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index d7b2431c1d3..7563dfa0ed3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -25,6 +25,8 @@ package jdk.jpackage.internal; import static java.util.stream.Collectors.joining; +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT; import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import java.io.IOException; @@ -44,13 +46,14 @@ import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; +import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ExceptionBox; final class AppImageSigner { - static Consumer createSigner(MacApplication app, CodesignConfig signingCfg) { + static Consumer createSigner(MacApplication app, CodesignConfig signingCfg) { return toConsumer(appImage -> { try { new AppImageSigner(Codesigners.create(signingCfg)).sign(app, appImage); @@ -67,12 +70,12 @@ final class AppImageSigner { private static final class SignFilter implements Predicate { - SignFilter(Application app, Path appImage) { + SignFilter(Application app, MacBundle appImage) { Objects.requireNonNull(appImage); // Don't explicitly sign main launcher. It will be implicitly signed when the bundle is signed. otherExcludePaths = app.asApplicationLayout().map(appLayout -> { - return appLayout.resolveAt(appImage); + return appLayout.resolveAt(appImage.root()); }).map(ApplicationLayout::launchersDirectory).flatMap(launchersDir -> { return app.mainLauncher().map(Launcher::executableNameWithSuffix).map(launchersDir::resolve); }).map(Set::of).orElseGet(Set::of); @@ -98,11 +101,16 @@ final class AppImageSigner { private final Set otherExcludePaths; } - private void sign(MacApplication app, Path appImage) throws CodesignException, IOException { + private void sign(MacApplication app, MacBundle appImage) throws CodesignException, IOException { + if (!appImage.isValid()) { + throw new IllegalArgumentException(); + } + + app = normalizeAppImageLayout(app); final var fileFilter = new SignFilter(app, appImage); - try (var content = Files.walk(appImage)) { + try (var content = Files.walk(appImage.root())) { content.filter(fileFilter).forEach(toConsumer(path -> { final var origPerms = ensureCanWrite(path); try { @@ -118,10 +126,10 @@ final class AppImageSigner { // Sign runtime root directory if present app.asApplicationLayout().map(appLayout -> { - return appLayout.resolveAt(appImage); + return appLayout.resolveAt(appImage.root()); }).map(MacApplicationLayout.class::cast).map(MacApplicationLayout::runtimeRootDirectory).ifPresent(codesigners); - final var frameworkPath = appImage.resolve("Contents/Frameworks"); + final var frameworkPath = appImage.contentsDir().resolve("Frameworks"); if (Files.isDirectory(frameworkPath)) { try (var content = Files.list(frameworkPath)) { content.forEach(toConsumer(path -> { @@ -131,7 +139,7 @@ final class AppImageSigner { } // Sign the app image itself - codesigners.accept(appImage); + codesigners.accept(appImage.root()); } private static Set ensureCanWrite(Path path) { @@ -235,5 +243,19 @@ final class AppImageSigner { } } + private static MacApplication normalizeAppImageLayout(MacApplication app) { + switch (app.imageLayout()) { + case MacApplicationLayout macLayout -> { + return MacApplicationBuilder.overrideAppImageLayout(app, APPLICATION_LAYOUT); + } + case RuntimeLayout macLayout -> { + return MacApplicationBuilder.overrideAppImageLayout(app, RUNTIME_BUNDLE_LAYOUT); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + private final Codesigners codesigners; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index 28d91156059..cce35ece117 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -42,11 +42,11 @@ public class MacAppBundler extends AppImageBundler { final BuildEnv env; if (StandardBundlerParam.hasPredefinedAppImage(params)) { - env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); final var pkg = MacPackagingPipeline.createSignAppImagePackage(app, env); MacPackagingPipeline.build(Optional.of(pkg)).create().execute(env, pkg, output); } else { - env = BuildEnv.withAppImageDir(BuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); + env = BuildEnv.withAppImageDir(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params), output); MacPackagingPipeline.build(Optional.empty()) .excludeDirFromCopying(output.getParent()) .excludeDirFromCopying(OUTPUT_DIR.fetchFrom(params)).create().execute(env, app); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index ca05be519ff..fc1dd97d9ab 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -34,6 +34,7 @@ import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacApplicationMixin; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.AppImageSigningConfig; final class MacApplicationBuilder { @@ -95,12 +96,28 @@ final class MacApplicationBuilder { validateAppVersion(app); - final var mixin = new MacApplicationMixin.Stub(validatedIcon(), validatedBundleName(), - validatedBundleIdentifier(), validatedCategory(), appStore, createSigningConfig()); + final var mixin = new MacApplicationMixin.Stub( + validatedIcon(), + validatedBundleName(), + validatedBundleIdentifier(), + validatedCategory(), + appStore, + createSigningConfig()); return MacApplication.create(app, mixin); } + static MacApplication overrideAppImageLayout(MacApplication app, AppImageLayout appImageLayout) { + final var mixin = new MacApplicationMixin.Stub( + app.icon(), + app.bundleName(), + app.bundleIdentifier(), + app.category(), + app.appStore(), + app.signingConfig()); + return MacApplication.create(ApplicationBuilder.overrideAppImageLayout(app, appImageLayout), mixin); + } + static boolean isValidBundleIdentifier(String id) { for (int i = 0; i < id.length(); i++) { char a = id.charAt(i); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java index 971548ea4f5..7c90134e288 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayout.java @@ -24,9 +24,10 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; import java.nio.file.Path; +import java.util.function.UnaryOperator; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.util.CompositeProxy; @@ -35,12 +36,32 @@ interface MacApplicationLayout extends ApplicationLayout, MacApplicationLayoutMi static MacApplicationLayout create(ApplicationLayout layout, Path runtimeRootDir) { return CompositeProxy.build() .invokeTunnel(CompositeProxyTunnel.INSTANCE) - .create(MacApplicationLayout.class, layout, new MacApplicationLayoutMixin.Stub(runtimeRootDir)); + .create(MacApplicationLayout.class, layout, + new MacApplicationLayoutMixin.Stub(runtimeRootDir)); } @Override default MacApplicationLayout resolveAt(Path root) { - return create(ApplicationLayout.super.resolveAt(root), - resolveNullablePath(root, runtimeRootDirectory())); + return (MacApplicationLayout)ApplicationLayout.super.resolveAt(root); } + + @Override + default MacApplicationLayout unresolve() { + return (MacApplicationLayout)ApplicationLayout.super.unresolve(); + } + + @Override + default MacApplicationLayout resetRootDirectory() { + if (isResolved()) { + return create(ApplicationLayout.super.resetRootDirectory(), runtimeRootDirectory()); + } else { + return this; + } + } + + @Override + default MacApplicationLayout map(UnaryOperator mapper) { + return create(ApplicationLayout.super.map(mapper), mapNullablePath(mapper, runtimeRootDirectory())); + } + } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java index b6342b173dc..0acc853f58b 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationLayoutMixin.java @@ -26,12 +26,15 @@ package jdk.jpackage.internal; import java.nio.file.Path; -// Must be publc to allow access from AppImageLayout.toPathGroup() +// Must be public to allow access from AppImageLayout.toPathGroup() public interface MacApplicationLayoutMixin { /** - * Path to the root Java runtime directory in the application image. + * Returns path to the root Java runtime directory in the application image. + *

      * The root Java runtime directory should have "Contents/Home" subdirectory. + * + * @return the path to the root Java runtime directory in the application image */ Path runtimeRootDirectory(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java similarity index 59% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java rename to src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java index fafcb7777a6..31759c8c529 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageDesc.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBuildEnvFromParams.java @@ -22,35 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal; -import java.nio.file.Path; -import java.util.Objects; -import java.util.Optional; -import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.MacPackage; -record AppImageDesc(AppImageLayout appImageLayout, Path path) { +final class MacBuildEnvFromParams { - AppImageDesc { - Objects.requireNonNull(appImageLayout); - Objects.requireNonNull(path); - } - - AppImageLayout resolvedAppImagelayout() { - return appImageLayout.resolveAt(path); - } - - Optional asResolvedApplicationLayout() { - return asApplicationLayout().map(v -> v.resolveAt(path)); - } - - Optional asApplicationLayout() { - if (appImageLayout instanceof ApplicationLayout layout) { - return Optional.of(layout); - } else { - return Optional.empty(); - } - } + static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam(BuildEnv.class, params -> { + return BuildEnvFromParams.create(params, MacPackagingPipeline.APPLICATION_LAYOUT::resolveAt, MacPackage::guessRuntimeLayout); + }); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java index af07a1145dc..f485653cf80 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundle.java @@ -28,6 +28,7 @@ package jdk.jpackage.internal; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.AppImageLayout; /** @@ -73,7 +74,19 @@ record MacBundle(Path root) { return new MacBundle(dir).isValid(); } - static MacBundle fromAppImageLayout(AppImageLayout layout) { - return new MacBundle(layout.rootDirectory()); + static Optional fromAppImageLayout(AppImageLayout layout) { + final var root = layout.rootDirectory(); + final var bundleSubdir = root.relativize(layout.runtimeDirectory()); + final var contentsDirname = Path.of("Contents"); + var bundleRoot = root; + for (int i = 0; i != bundleSubdir.getNameCount(); i++) { + var nameComponent = bundleSubdir.getName(i); + if (contentsDirname.equals(nameComponent)) { + return Optional.of(new MacBundle(bundleRoot)); + } else { + bundleRoot = bundleRoot.resolve(nameComponent); + } + } + return Optional.empty(); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index 56aacf6e44a..d2c72765d7a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -71,7 +71,7 @@ public class MacDmgBundler extends MacBaseInstallerBundler { Path outputParentDir) throws PackagerException { final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); final var packager = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index d453bb59184..c2b9c25f327 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -53,7 +53,6 @@ final class MacDmgPackageBuilder { } MacDmgPackage create() throws ConfigException { - final var superPkgBuilder = pkgBuilder.pkgBuilder(); final var pkg = pkgBuilder.create(); return MacDmgPackage.create(pkg, new MacDmgPackageMixin.Stub( diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java index 754d09a7156..4be2f9859c8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromParams.java @@ -39,13 +39,12 @@ import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FI import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; -import static jdk.jpackage.internal.model.MacPackage.RUNTIME_PACKAGE_LAYOUT; +import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG; import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG; import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -64,6 +63,7 @@ import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacFileAssociation; import jdk.jpackage.internal.model.MacLauncher; +import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; @@ -75,20 +75,16 @@ final class MacFromParams { private static MacApplication createMacApplication( Map params) throws ConfigException, IOException { - final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(params).map(predefinedRuntimeImage -> { - if (Files.isDirectory(RUNTIME_PACKAGE_LAYOUT.resolveAt(predefinedRuntimeImage).runtimeDirectory())) { - return RUNTIME_PACKAGE_LAYOUT; - } else { - return RuntimeLayout.DEFAULT; - } - }); + final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(params) + .map(MacPackage::guessRuntimeLayout) + .map(RuntimeLayout::unresolve); final var launcherFromParams = new LauncherFromParams(Optional.of(MacFromParams::createMacFa)); final var superAppBuilder = createApplicationBuilder(params, toFunction(launcherParams -> { var launcher = launcherFromParams.create(launcherParams); return MacLauncher.create(launcher); - }), APPLICATION_LAYOUT, predefinedRuntimeLayout); + }), APPLICATION_LAYOUT, RUNTIME_BUNDLE_LAYOUT, predefinedRuntimeLayout); if (hasPredefinedAppImage(params)) { // Set the main launcher start up info. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java index a16194a6260..cf5c6a934f7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackageBuilder.java @@ -24,8 +24,11 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.MacPackagingPipeline.LayoutUtils.packagerLayout; + import java.util.Objects; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacPackage; import jdk.jpackage.internal.model.MacPackageMixin; @@ -45,7 +48,15 @@ final class MacPackageBuilder { } MacPackage create() throws ConfigException { - final var pkg = pkgBuilder.create(); + + final var app = (MacApplication)pkgBuilder.app(); + + var pkg = pkgBuilder.create(); + + pkgBuilder.app(MacApplicationBuilder.overrideAppImageLayout(app, packagerLayout(pkg))) + .installedPackageLayout(pkg.installedPackageLayout()); + + pkg = pkgBuilder.create(); return MacPackage.create(pkg, new MacPackageMixin.Stub(pkg.predefinedAppImage().map(v -> predefinedAppImageSigned))); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java index 556efdd0fd3..a6ed164d9f7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java @@ -39,6 +39,7 @@ import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.io.IOException; import java.io.StringWriter; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -49,10 +50,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.UnaryOperator; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import jdk.jpackage.internal.PackagingPipeline.AppImageBuildEnv; +import jdk.jpackage.internal.PackagingPipeline.AppImageTaskAction; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; @@ -98,21 +101,10 @@ final class MacPackagingPipeline { COPY_SIGN } - static AppImageLayout packagingLayout(Package pkg) { - return pkg.appImageLayout().resolveAt(pkg.relativeInstallDir().getFileName()); - } - static PackagingPipeline.Builder build(Optional pkg) { final var builder = PackagingPipeline.buildStandard() - .appContextMapper(appContext -> { - return new TaskContextProxy(appContext, true, false); - }) - .pkgContextMapper(appContext -> { - final var isRuntimeInstaller = pkg.map(Package::isRuntimeInstaller).orElse(false); - final var withPredefinedAppImage = pkg.flatMap(Package::predefinedAppImage).isPresent(); - return new TaskContextProxy(appContext, false, isRuntimeInstaller || withPredefinedAppImage); - }) - .appImageLayoutForPackaging(MacPackagingPipeline::packagingLayout) + .contextMapper(pkg.map(MacPackagingPipeline::mapPackageTaskContext) + .orElseGet(MacPackagingPipeline::mapAppTaskContext)) .task(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT) .packageAction(MacPackagingPipeline::runPostAppImageUserScript).add() .task(CopyAppImageTaskID.COPY) @@ -156,13 +148,13 @@ final class MacPackagingPipeline { .addDependent(BuildApplicationTaskID.CONTENT).add(); builder.task(MacBuildApplicationTaskID.SIGN) - .appImageAction(MacPackagingPipeline::sign) + .appImageAction(LayoutUtils.withBundleLayout(MacPackagingPipeline::sign)) .addDependencies(builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.BUILD_APPLICATION_IMAGE)) .addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE) .add(); builder.task(MacCopyAppImageTaskID.COPY_SIGN) - .appImageAction(MacPackagingPipeline::sign) + .appImageAction(LayoutUtils.withBundleLayout(MacPackagingPipeline::sign)) .addDependencies(builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.COPY_APP_IMAGE)) .addDependent(PrimaryTaskID.COPY_APP_IMAGE) .add(); @@ -182,7 +174,6 @@ final class MacPackagingPipeline { disabledTasks.add(PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT); builder.task(MacCopyAppImageTaskID.REPLACE_APP_IMAGE_FILE) .applicationAction(createWriteAppImageFileAction()).add(); - builder.appImageLayoutForPackaging(Package::appImageLayout); } else if (p.isRuntimeInstaller()) { builder.task(MacCopyAppImageTaskID.COPY_RUNTIME_JLILIB) @@ -236,23 +227,83 @@ final class MacPackagingPipeline { }).get(); } - private static void copyAppImage(MacPackage pkg, AppImageDesc srcAppImage, - AppImageDesc dstAppImage) throws IOException { + static final class LayoutUtils { + /** + * Returns unresolved app image layout for the specified package for use with + * the signing function defined in {@link MacPackagingPipeline} class and + * {@link MacPkgPackager} and {@link MacDmgPackager} packagers. + *

      + * Paths of the result app image layout will start with the bundle name. E.g.: + * for a package with relative installation directory set to + * {@code "Applications/Acme/MyApp.app"} and the "launchers" directory of an + * application layout set to {@code "Contents/MacOS"}, the result application + * layout object will be such that the value of its "launchers" directory will + * be {@code "MyApp.app/Contents/MacOS"}. The root directory of the result app + * image layout will be an empty path ({@link Path.of("")}), i.e. the app image + * layout will be unresolved. + * + * @param pkg the package + * @return the unresolved app image layout for the specified package suitable + * for the use with macosx packaging pipeline and packagers + */ + static AppImageLayout packagerLayout(Package pkg) { + return pkg.appImageLayout().resolveAt(pkg.relativeInstallDir().getFileName()).resetRootDirectory(); + } + + static AppImageBuildEnv fromPackagerLayout(AppImageBuildEnv cfg) { + + var bundleDirectoryName = cfg.envLayout().runtimeDirectory().getName(0); + var bundleLayout = cfg.envLayout().map(bundleDirectoryName::relativize).resetRootDirectory(); + var bundleRoot = cfg.env().appImageDir().resolve(bundleDirectoryName); + var app = MacApplicationBuilder.overrideAppImageLayout(cfg.app(), bundleLayout); + var env = BuildEnv.withAppImageLayout(cfg.env(), bundleLayout.resolveAt(bundleRoot)); + + return new AppImageBuildEnv<>(env, app); + } + + static AppImageTaskAction withBundleLayout(AppImageTaskAction action) { + return new AppImageTaskAction<>() { + @Override + public void execute(AppImageBuildEnv env) throws IOException, PackagerException { + if (!env.envLayout().runtimeDirectory().getName(0).equals(Path.of("Contents"))) { + env = LayoutUtils.fromPackagerLayout(env); + } + action.execute(env); + } + }; + } + } + + private static void copyAppImage(MacPackage pkg, AppImageLayout srcAppImage, + AppImageLayout dstAppImage) throws IOException { boolean predefinedAppImageSigned = pkg.predefinedAppImageSigned().orElse(false); - var inputRootDirectory = srcAppImage.resolvedAppImagelayout().rootDirectory(); + final Optional srcMacBundle; + if (pkg.isRuntimeInstaller()) { + srcMacBundle = MacBundle.fromAppImageLayout(srcAppImage); + } else { + srcMacBundle = Optional.empty(); + } - if (pkg.isRuntimeInstaller() && MacBundle.isDirectoryMacBundle(inputRootDirectory)) { + srcMacBundle.ifPresentOrElse(inputBundle -> { // Building runtime package from the input runtime bundle. // Copy the input bundle verbatim. - FileUtils.copyRecursive( - inputRootDirectory, - dstAppImage.resolvedAppImagelayout().rootDirectory(), - LinkOption.NOFOLLOW_LINKS); - } else { - PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, !predefinedAppImageSigned); - } + try { + FileUtils.copyRecursive( + inputBundle.root(), + MacBundle.fromAppImageLayout(dstAppImage).orElseThrow().root(), + LinkOption.NOFOLLOW_LINKS); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }, () -> { + try { + PackagingPipeline.copyAppImage(srcAppImage, dstAppImage, !predefinedAppImageSigned); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); } private static void copyJliLib( @@ -272,10 +323,23 @@ final class MacPackagingPipeline { } } - private static void runPostAppImageUserScript(PackageBuildEnv env) throws IOException { - PackagingPipeline.runPostAppImageUserScript(new PackageBuildEnv<>( - BuildEnv.withAppImageDir(env.env(), env.env().appImageDir().resolve(env.envLayout().rootDirectory())), - env.pkg(), env.pkg().appImageLayout(), env.outputDir())); + private static void runPostAppImageUserScript(PackageBuildEnv cfg) throws IOException { + var appCfg = LayoutUtils.fromPackagerLayout( + new AppImageBuildEnv<>(cfg.env(), (MacApplication)cfg.pkg().app())); + + var pkg = cfg.pkg(); pkg = new Package.Stub( + appCfg.app(), + pkg.type(), + pkg.packageName(), + pkg.description(), + pkg.version(), + pkg.aboutURL(), + pkg.licenseFile(), + pkg.predefinedAppImage(), + pkg.installedPackageLayout(), + pkg.relativeInstallDir()); + + PackagingPipeline.runPostAppImageUserScript(new PackageBuildEnv<>(appCfg.env(), pkg, cfg.outputDir())); } private static void writePackageFile(PackageBuildEnv env) throws IOException { @@ -331,7 +395,7 @@ final class MacPackagingPipeline { final var app = env.app(); - final var infoPlistFile = MacBundle.fromAppImageLayout(env.resolvedLayout()).infoPlistFile(); + final var infoPlistFile = MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow().infoPlistFile(); Log.verbose(I18N.format("message.preparing-info-plist", PathUtils.normalizedAbsolutePathString(infoPlistFile))); @@ -384,8 +448,7 @@ final class MacPackagingPipeline { } final Runnable signAction = () -> { - final var appImageDir = env.resolvedLayout().rootDirectory(); - AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(appImageDir); + AppImageSigner.createSigner(app, codesignConfigBuilder.create()).accept(MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow()); }; app.signingConfig().flatMap(AppImageSigningConfig::keychain).map(Keychain::new).ifPresentOrElse(keychain -> { @@ -467,7 +530,7 @@ final class MacPackagingPipeline { private static MacBundle runtimeBundle(AppImageBuildEnv env) { if (env.app().isRuntime()) { - return new MacBundle(env.resolvedLayout().rootDirectory()); + return MacBundle.fromAppImageLayout(env.resolvedLayout()).orElseThrow(); } else { return new MacBundle(((MacApplicationLayout)env.resolvedLayout()).runtimeRootDirectory()); } @@ -498,6 +561,21 @@ final class MacPackagingPipeline { } } + private static UnaryOperator mapAppTaskContext() { + return ctx -> { + return new TaskContextProxy(ctx, true, false); + }; + } + + private static UnaryOperator mapPackageTaskContext(Package pkg) { + return ctx -> { + final var isRuntimeInstaller = pkg.isRuntimeInstaller(); + final var withPredefinedAppImage = pkg.predefinedAppImage().isPresent(); + return new TaskContextProxy(ctx, false, isRuntimeInstaller || withPredefinedAppImage); + }; + } + + private record TaskContextProxy(TaskContext delegate, boolean forApp, boolean copyAppImage) implements TaskContext { @Override diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index f785cc49f67..bc19e7c4a1a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -73,7 +73,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler { Path outputParentDir) throws PackagerException { final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); final var packager = MacPkgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java index 083fc225581..4d38cf4ed70 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java @@ -24,21 +24,14 @@ */ package jdk.jpackage.internal.model; +import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.internal.util.CompositeProxy; public interface MacPackage extends Package, MacPackageMixin { - MacApplication app(); - @Override - default AppImageLayout appImageLayout() { - if (isRuntimeInstaller()) { - return RUNTIME_PACKAGE_LAYOUT; - } else { - return Package.super.appImageLayout(); - } - } + MacApplication app(); default Path installDir() { return Path.of("/").resolve(relativeInstallDir()); @@ -48,5 +41,19 @@ public interface MacPackage extends Package, MacPackageMixin { return CompositeProxy.create(MacPackage.class, pkg, mixin); } - public static final RuntimeLayout RUNTIME_PACKAGE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); + /** + * Guesses layout of a runtime image at the given path. + * + * @param path the path to a runtime image + * @return the runtime image layout resolved at the given path + */ + public static RuntimeLayout guessRuntimeLayout(Path path) { + if (Files.isDirectory(RUNTIME_BUNDLE_LAYOUT.resolveAt(path).runtimeDirectory())) { + return RUNTIME_BUNDLE_LAYOUT.resolveAt(path); + } else { + return RuntimeLayout.DEFAULT.resolveAt(path); + } + } + + public static final RuntimeLayout RUNTIME_BUNDLE_LAYOUT = RuntimeLayout.create(Path.of("Contents/Home")); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 09bf04372ce..141a1b5155f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -153,9 +153,30 @@ final class ApplicationBuilder { } static Launcher overrideLauncherStartupInfo(Launcher launcher, LauncherStartupInfo startupInfo) { - return new Launcher.Stub(launcher.name(), Optional.of(startupInfo), - launcher.fileAssociations(), launcher.isService(), launcher.description(), - launcher.icon(), launcher.defaultIconResourceName(), launcher.extraAppImageFileData()); + return new Launcher.Stub( + launcher.name(), + Optional.of(startupInfo), + launcher.fileAssociations(), + launcher.isService(), + launcher.description(), + launcher.icon(), + launcher.defaultIconResourceName(), + launcher.extraAppImageFileData()); + } + + static Application overrideAppImageLayout(Application app, AppImageLayout appImageLayout) { + return new Application.Stub( + app.name(), + app.description(), + app.version(), + app.vendor(), + app.copyright(), + app.srcDir(), + app.contentDirs(), + Objects.requireNonNull(appImageLayout), + app.runtimeBuilder(), + app.launchers(), + app.extraAppImageFileData()); } record MainLauncherStartupInfo(String qualifiedClassName) implements LauncherStartupInfo { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index e2686c17128..7d3250ff7b9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -84,7 +84,7 @@ final class ApplicationImageUtils { static ApplicationImageTaskAction createWriteRuntimeAction() { return env -> { - env.app().runtimeBuilder().orElseThrow().createRuntime(env.resolvedLayout()); + env.app().runtimeBuilder().orElseThrow().create(env.resolvedLayout()); }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java index 1d2a43bf5d6..527f747b229 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnv.java @@ -27,57 +27,111 @@ package jdk.jpackage.internal; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +/** + * Build environment. + */ interface BuildEnv { + /** + * Returns root directory for intermediate build files. + * + * @return the root directory for intermediate build files + */ Path buildRoot(); + /** + * Returns true if the build should be verbose output. + * + * @return true if the build should be verbose output + */ boolean verbose(); + /** + * Returns the path of the resource directory or an empty {@link Optional} + * instance if none is configured with the build. + * + * @return the path of the resource directory or an empty {@link Optional} + * instance if non is configured with the build + */ Optional resourceDir(); /** - * Returns path to application image directory. + * Returns the path of the app image directory of this build. * - * The return value is supposed to be used as a parameter for - * ApplicationLayout#resolveAt function. + * @return the path of the app image directory of this build */ default Path appImageDir() { - return buildRoot().resolve("image"); + return appImageLayout().rootDirectory(); } + /** + * Returns resolved app image layout of the app image directory. The return + * layout is resolved at {@link #appImageDir()} path. + * + * @return the resolved app image layout of the app image directory + */ + AppImageLayout appImageLayout(); + + default Optional asApplicationLayout() { + if (appImageLayout() instanceof ApplicationLayout layout) { + return Optional.of(layout); + } else { + return Optional.empty(); + } + } + + /** + * Returns a path to a directory for intermediate configuration files. + * @return the path to the directory for intermediate configuration files + */ default Path configDir() { return buildRoot().resolve("config"); } + /** + * Creates an {@link OverridableResource} instance for the given resource name. + * + * @param defaultName the resource name + * @return the {@link OverridableResource} instance wrapping a resource with the + * given name + */ OverridableResource createResource(String defaultName); static BuildEnv withAppImageDir(BuildEnv env, Path appImageDir) { return ((Internal.DefaultBuildEnv)env).copyWithAppImageDir(appImageDir); } - static BuildEnv create(Path buildRoot, Optional resourceDir, boolean verbose, Class resourceLocator) { - return new Internal.DefaultBuildEnv(buildRoot, resourceDir, verbose, resourceLocator, Optional.empty()); + static BuildEnv withAppImageLayout(BuildEnv env, AppImageLayout appImageLayout) { + return ((Internal.DefaultBuildEnv)env).copyWithAppImageLayout(appImageLayout); + } + + static BuildEnv create(Path buildRoot, Optional resourceDir, boolean verbose, + Class resourceLocator, AppImageLayout appImageLayout) { + return new Internal.DefaultBuildEnv(buildRoot, resourceDir, verbose, + resourceLocator, appImageLayout); } static final class Internal { - private static record DefaultBuildEnv(Path buildRoot, Optional resourceDir, - boolean verbose, Class resourceLocator, Optional optAppImageDir) implements BuildEnv { + private record DefaultBuildEnv(Path buildRoot, Optional resourceDir, + boolean verbose, Class resourceLocator, + AppImageLayout appImageLayout) implements BuildEnv { DefaultBuildEnv { Objects.requireNonNull(buildRoot); Objects.requireNonNull(resourceDir); Objects.requireNonNull(resourceLocator); - Objects.requireNonNull(optAppImageDir); + Objects.requireNonNull(appImageLayout); } - DefaultBuildEnv copyWithAppImageDir(Path appImageDir) { - return new DefaultBuildEnv(buildRoot, resourceDir, verbose, resourceLocator, Optional.of(appImageDir)); + DefaultBuildEnv copyWithAppImageDir(Path v) { + return copyWithAppImageLayout(appImageLayout.unresolve().resolveAt(v)); } - @Override - public Path appImageDir() { - return optAppImageDir.orElseGet(BuildEnv.super::appImageDir); + DefaultBuildEnv copyWithAppImageLayout(AppImageLayout v) { + return new DefaultBuildEnv(buildRoot, resourceDir, verbose, resourceLocator, v); } @Override diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java index 9974e407ca7..ba70913eca9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvBuilder.java @@ -29,8 +29,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.resources.ResourceLocator; final class BuildEnvBuilder { @@ -40,8 +42,6 @@ final class BuildEnvBuilder { } BuildEnv create() throws ConfigException { - Objects.requireNonNull(appImageDir); - var exceptionBuilder = I18N.buildConfigException("ERR_BuildRootInvalid", root); if (Files.isDirectory(root)) { try (var rootDirContents = Files.list(root)) { @@ -57,8 +57,8 @@ final class BuildEnvBuilder { throw exceptionBuilder.create(); } - return BuildEnv.withAppImageDir(BuildEnv.create(root, Optional.ofNullable(resourceDir), - verbose, ResourceLocator.class), appImageDir); + return BuildEnv.create(root, Optional.ofNullable(resourceDir), verbose, + ResourceLocator.class, resolvedAppImageLayout()); } BuildEnvBuilder verbose(boolean v) { @@ -76,21 +76,34 @@ final class BuildEnvBuilder { return this; } - BuildEnvBuilder appImageDirFor(Application app) { - appImageDir = defaultAppImageDir(root).resolve(app.appImageDirName()); + BuildEnvBuilder appImageLayout(AppImageLayout v) { + appImageLayout = v; return this; } - BuildEnvBuilder appImageDirForPackage() { - appImageDir = defaultAppImageDir(root); + BuildEnvBuilder appImageDirFor(Application app) { + appImageDir = defaultAppImageDir(root).resolve(app.appImageDirName()); + appImageLayout = app.imageLayout(); return this; } + BuildEnvBuilder appImageDirFor(Package pkg) { + appImageDir = defaultAppImageDir(root); + appImageLayout = pkg.appImageLayout(); + return this; + } + + private AppImageLayout resolvedAppImageLayout() { + Objects.requireNonNull(appImageLayout); + return Optional.ofNullable(appImageDir).map(appImageLayout.unresolve()::resolveAt).orElse(appImageLayout); + } + private static Path defaultAppImageDir(Path root) { return root.resolve("image"); } private Path appImageDir; + private AppImageLayout appImageLayout; private Path resourceDir; private boolean verbose; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java index 24ae249297e..6fb1a342fbf 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BuildEnvFromParams.java @@ -24,18 +24,25 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; +import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE; +import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.StandardBundlerParam.TEMP_ROOT; import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE; +import java.nio.file.Path; import java.util.Map; +import java.util.function.Function; +import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.RuntimeLayout; final class BuildEnvFromParams { - static BuildEnv create(Map params) throws ConfigException { + static BuildEnv create(Map params, + Function predefinedAppImageLayoutProvider, + Function predefinedRuntimeImageLayoutProvider) throws ConfigException { final var builder = new BuildEnvBuilder(TEMP_ROOT.fetchFrom(params)); @@ -47,11 +54,13 @@ final class BuildEnvFromParams { final var pkg = FromParams.getCurrentPackage(params); if (app.isRuntime()) { - PREDEFINED_RUNTIME_IMAGE.copyInto(params, builder::appImageDir); + var layout = predefinedRuntimeImageLayoutProvider.apply(PREDEFINED_RUNTIME_IMAGE.findIn(params).orElseThrow()); + builder.appImageLayout(layout); } else if (StandardBundlerParam.hasPredefinedAppImage(params)) { - PREDEFINED_APP_IMAGE.copyInto(params, builder::appImageDir); + var layout = predefinedAppImageLayoutProvider.apply(PREDEFINED_APP_IMAGE.findIn(params).orElseThrow()); + builder.appImageLayout(layout); } else if (pkg.isPresent()) { - builder.appImageDirForPackage(); + builder.appImageDirFor(pkg.orElseThrow()); } else { builder.appImageDirFor(app); } @@ -59,6 +68,7 @@ final class BuildEnvFromParams { return builder.create(); } - static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam( - BuildEnv.class, BuildEnvFromParams::create); + static final BundlerParamInfo BUILD_ENV = BundlerParamInfo.createBundlerParam(BuildEnv.class, params -> { + return create(params, PLATFORM_APPLICATION_LAYOUT::resolveAt, RuntimeLayout.DEFAULT::resolveAt); + }); } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index d4ea595969a..ec9718c5d24 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -79,12 +79,13 @@ final class FromParams { static ApplicationBuilder createApplicationBuilder(Map params, Function, Launcher> launcherMapper, ApplicationLayout appLayout) throws ConfigException, IOException { - return createApplicationBuilder(params, launcherMapper, appLayout, Optional.of(RuntimeLayout.DEFAULT)); + return createApplicationBuilder(params, launcherMapper, appLayout, RuntimeLayout.DEFAULT, Optional.of(RuntimeLayout.DEFAULT)); } static ApplicationBuilder createApplicationBuilder(Map params, Function, Launcher> launcherMapper, - ApplicationLayout appLayout, Optional predefinedRuntimeLayout) throws ConfigException, IOException { + ApplicationLayout appLayout, RuntimeLayout runtimeLayout, + Optional predefinedRuntimeLayout) throws ConfigException, IOException { final var appBuilder = new ApplicationBuilder(); @@ -104,7 +105,7 @@ final class FromParams { layout -> predefinedRuntimeImage.map(layout::resolveAt)).map(RuntimeLayout::runtimeDirectory); if (isRuntimeInstaller) { - appBuilder.appImageLayout(predefinedRuntimeLayout.orElseThrow()); + appBuilder.appImageLayout(runtimeLayout); } else { appBuilder.appImageLayout(appLayout); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java index c09c1ae4b1f..bd82b34d897 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkRuntimeBuilder.java @@ -61,7 +61,7 @@ final class JLinkRuntimeBuilder implements RuntimeBuilder { } @Override - public void createRuntime(AppImageLayout appImageLayout) throws PackagerException { + public void create(AppImageLayout appImageLayout) throws PackagerException { var args = new ArrayList(); args.add("--output"); args.add(appImageLayout.runtimeDirectory().toString()); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index 221e0dcac07..f93cd0eab14 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -29,6 +29,7 @@ import static jdk.jpackage.internal.I18N.buildConfigException; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.Package; @@ -86,9 +87,19 @@ final class PackageBuilder { Optional.ofNullable(aboutURL), Optional.ofNullable(licenseFile), Optional.ofNullable(predefinedAppImage), + validatedInstalledPackageLayout(relativeInstallDir), relativeInstallDir); } + PackageBuilder app(Application v) { + app = v; + return this; + } + + Application app() { + return app; + } + PackageBuilder name(String v) { name = v; return this; @@ -169,10 +180,34 @@ final class PackageBuilder { } } + PackageBuilder installedPackageLayout(AppImageLayout v) { + installedPackageLayout = v; + return this; + } + + Optional installedPackageLayout() { + return Optional.ofNullable(installedPackageLayout); + } + private String validatedName() { return name().orElseGet(app::name); } + private AppImageLayout validatedInstalledPackageLayout(Path relativeInstallDir) { + return installedPackageLayout().orElseGet(() -> { + var theInstallDir = relativeInstallDir; + if (type instanceof StandardPackageType stdType) { + switch (stdType) { + case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { + theInstallDir = Path.of("/").resolve(theInstallDir); + } + default -> {} + } + } + return app.imageLayout().resolveAt(theInstallDir).resetRootDirectory(); + }); + } + private static Path mapInstallDir(Path installDir, PackageType pkgType) throws ConfigException { var ex = buildConfigException("error.invalid-install-dir", installDir).create(); @@ -235,6 +270,7 @@ final class PackageBuilder { } } + private Application app; private String name; private Path fileName; private String description; @@ -243,7 +279,7 @@ final class PackageBuilder { private Path licenseFile; private Path predefinedAppImage; private Path installDir; + private AppImageLayout installedPackageLayout; private final PackageType type; - private final Application app; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java index 276bed4f31c..64a37878bd8 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagingPipeline.java @@ -26,6 +26,7 @@ package jdk.jpackage.internal; import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.model.AppImageLayout.toPathGroup; import java.io.IOException; import java.nio.file.LinkOption; @@ -38,9 +39,9 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; @@ -62,7 +63,7 @@ final class PackagingPipeline { * @param app the application */ void execute(BuildEnv env, Application app) throws PackagerException { - execute(appContextMapper.apply(createTaskContext(env, app))); + execute(contextMapper.apply(createTaskContext(env, app))); } /** @@ -81,8 +82,7 @@ final class PackagingPipeline { * @param outputDir the output directory for the package file */ void execute(BuildEnv env, Package pkg, Path outputDir) throws PackagerException { - execute((StartupParameters)createPackagingTaskContext(env, pkg, outputDir, - taskConfig, appImageLayoutForPackaging.apply(pkg))); + execute((StartupParameters)createPackagingTaskContext(env, pkg, outputDir, taskConfig)); } /** @@ -92,7 +92,7 @@ final class PackagingPipeline { * @param startupParameters the pipeline startup parameters */ void execute(StartupParameters startupParameters) throws PackagerException { - execute(pkgContextMapper.apply(createTaskContext((PackagingTaskContext)startupParameters))); + execute(contextMapper.apply(createTaskContext((PackagingTaskContext)startupParameters))); } /** @@ -135,21 +135,27 @@ final class PackagingPipeline { void execute(TaskAction taskAction) throws IOException, PackagerException; } - record AppImageBuildEnv(BuildEnv env, T app, U envLayout) { + record AppImageBuildEnv(BuildEnv env, T app) { + @SuppressWarnings("unchecked") + U envLayout() { + return (U)app.imageLayout(); + } + @SuppressWarnings("unchecked") U resolvedLayout() { - return (U)envLayout.resolveAt(env.appImageDir()); + return (U)env.appImageLayout(); } } - record PackageBuildEnv(BuildEnv env, T pkg, U envLayout, Path outputDir) { + record PackageBuildEnv(BuildEnv env, T pkg, Path outputDir) { @SuppressWarnings("unchecked") - U resolvedLayout() { - return (U)envLayout.resolveAt(env.appImageDir()); + U envLayout() { + return (U)pkg.appImageLayout(); } - AppImageBuildEnv appImageBuildEnv() { - return new AppImageBuildEnv<>(env, pkg.app(), envLayout); + @SuppressWarnings("unchecked") + U resolvedLayout() { + return (U)env.appImageLayout(); } } @@ -165,7 +171,7 @@ final class PackagingPipeline { @FunctionalInterface interface CopyAppImageTaskAction extends TaskAction { - void execute(T pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException, PackagerException; + void execute(T pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException, PackagerException; } @FunctionalInterface @@ -195,6 +201,11 @@ final class PackagingPipeline { super(id); } + private TaskBuilder(TaskID id, TaskConfig config) { + this(id); + config.action().ifPresent(this::setAction); + } + private TaskBuilder setAction(TaskAction v) { action = v; return this; @@ -225,6 +236,10 @@ final class PackagingPipeline { return setAction(action); } + boolean hasAction() { + return action != null; + } + @Override public TaskBuilder addDependent(TaskID v) { super.addDependent(v); @@ -283,6 +298,12 @@ final class PackagingPipeline { return new TaskBuilder(id); } + Stream configuredTasks() { + return taskConfig.entrySet().stream().map(e -> { + return new TaskBuilder(e.getKey(), e.getValue()); + }); + } + Builder excludeDirFromCopying(Path path) { Objects.requireNonNull(path); excludeCopyDirs.add(path); @@ -290,23 +311,7 @@ final class PackagingPipeline { } Builder contextMapper(UnaryOperator v) { - appContextMapper(v); - pkgContextMapper(v); - return this; - } - - Builder appContextMapper(UnaryOperator v) { - appContextMapper = v; - return this; - } - - Builder pkgContextMapper(UnaryOperator v) { - pkgContextMapper = v; - return this; - } - - Builder appImageLayoutForPackaging(Function v) { - appImageLayoutForPackaging = v; + contextMapper = v; return this; } @@ -318,27 +323,18 @@ final class PackagingPipeline { } StartupParameters createStartupParameters(BuildEnv env, Package pkg, Path outputDir) { - return createPackagingTaskContext(env, pkg, outputDir, taskConfig, - validatedAppImageLayoutForPackaging().apply(pkg)); - } - - private Function validatedAppImageLayoutForPackaging() { - return Optional.ofNullable(appImageLayoutForPackaging).orElse(Package::packageLayout); + return createPackagingTaskContext(env, pkg, outputDir, taskConfig); } PackagingPipeline create() { return new PackagingPipeline(taskGraphSnapshot(), taskConfig, - Optional.ofNullable(appContextMapper).orElse(UnaryOperator.identity()), - Optional.ofNullable(pkgContextMapper).orElse(UnaryOperator.identity()), - validatedAppImageLayoutForPackaging()); + Optional.ofNullable(contextMapper).orElse(UnaryOperator.identity())); } private final FixedDAG.Builder taskGraphBuilder = FixedDAG.build(); private final List excludeCopyDirs = new ArrayList<>(); private final Map taskConfig = new HashMap<>(); - private UnaryOperator appContextMapper; - private UnaryOperator pkgContextMapper; - private Function appImageLayoutForPackaging; + private UnaryOperator contextMapper; private FixedDAG taskGraphSnapshot; } @@ -404,21 +400,20 @@ final class PackagingPipeline { return builder; } - static void copyAppImage(Package pkg, AppImageDesc srcAppImage, AppImageDesc dstAppImage) throws IOException { + static void copyAppImage(Package pkg, AppImageLayout srcAppImage, AppImageLayout dstAppImage) throws IOException { copyAppImage(srcAppImage, dstAppImage, true); } - static void copyAppImage(AppImageDesc srcAppImage, AppImageDesc dstAppImage, + static void copyAppImage(AppImageLayout srcAppImage, AppImageLayout dstAppImage, boolean removeAppImageFile) throws IOException { - final var srcLayout = srcAppImage.resolvedAppImagelayout(); - final var srcLayoutPathGroup = AppImageLayout.toPathGroup(srcLayout); + final var srcLayoutPathGroup = toPathGroup(srcAppImage); - if (removeAppImageFile && srcLayout instanceof ApplicationLayout appLayout) { + if (removeAppImageFile && srcAppImage instanceof ApplicationLayout appLayout) { // Copy app layout omitting application image info file. srcLayoutPathGroup.ghostPath(AppImageFile.getPathInAppImage(appLayout)); } - srcLayoutPathGroup.copy(AppImageLayout.toPathGroup(dstAppImage.resolvedAppImagelayout()), LinkOption.NOFOLLOW_LINKS); + srcLayoutPathGroup.copy(toPathGroup(dstAppImage), LinkOption.NOFOLLOW_LINKS); } static void runPostAppImageUserScript(PackageBuildEnv env) throws IOException { @@ -432,57 +427,66 @@ final class PackagingPipeline { } private PackagingPipeline(FixedDAG taskGraph, Map taskConfig, - UnaryOperator appContextMapper, UnaryOperator pkgContextMapper, - Function appImageLayoutForPackaging) { + UnaryOperator contextMapper) { this.taskGraph = Objects.requireNonNull(taskGraph); this.taskConfig = Objects.requireNonNull(taskConfig); - this.appContextMapper = Objects.requireNonNull(appContextMapper); - this.pkgContextMapper = Objects.requireNonNull(pkgContextMapper); - this.appImageLayoutForPackaging = Objects.requireNonNull(appImageLayoutForPackaging); + this.contextMapper = Objects.requireNonNull(contextMapper); } private TaskContext createTaskContext(BuildEnv env, Application app) { - return new DefaultTaskContext(taskGraph, env, app, app.asApplicationLayout(), Optional.empty()); + return new DefaultTaskContext(taskGraph, env, app, Optional.empty()); } private TaskContext createTaskContext(PackagingTaskContext packagingContext) { - final var pkgEnv = BuildEnv.withAppImageDir(packagingContext.env.env(), packagingContext.srcAppImage.path()); - return new DefaultTaskContext(taskGraph, pkgEnv, packagingContext.env.pkg.app(), - packagingContext.srcAppImage.asApplicationLayout(), Optional.of(packagingContext)); + return new DefaultTaskContext(taskGraph, packagingContext.env(), + packagingContext.pkg().app(), Optional.of(packagingContext)); } private static PackagingTaskContext createPackagingTaskContext(BuildEnv env, Package pkg, - Path outputDir, Map taskConfig, AppImageLayout appImageLayoutForPackaging) { + Path outputDir, Map taskConfig) { Objects.requireNonNull(env); Objects.requireNonNull(outputDir); Objects.requireNonNull(taskConfig); - Objects.requireNonNull(appImageLayoutForPackaging); + if (pkg.appImageLayout().isResolved()) { + throw new IllegalArgumentException(); + } - final AppImageDesc srcAppImageDesc; - final AppImageDesc dstAppImageDesc; + final AppImageLayout srcLayout; + final AppImageLayout dstLayout; if (pkg.app().runtimeBuilder().isPresent()) { // Runtime builder is present, will build application image. - // appImageDir() should point to a directory where the application image will be created. - srcAppImageDesc = new AppImageDesc(appImageLayoutForPackaging, env.appImageDir()); - dstAppImageDesc = srcAppImageDesc; + srcLayout = pkg.appImageLayout().resolveAt(env.appImageDir()); + dstLayout = srcLayout; } else { - srcAppImageDesc = new AppImageDesc(pkg.app().imageLayout(), - pkg.predefinedAppImage().orElseThrow(UnsupportedOperationException::new)); + srcLayout = pkg.predefinedAppImage().map(predefinedAppImage -> { + // Will create a package from the predefined app image. + if (predefinedAppImage.equals(env.appImageDir())) { + return env.appImageLayout(); + } else { + return pkg.appImageLayout().resolveAt(predefinedAppImage); + } + }).orElseGet(() -> { + // No predefined app image and no runtime builder. + // This should be runtime packaging. + if (pkg.isRuntimeInstaller()) { + return env.appImageLayout(); + } else { + // Can't create app image without runtime builder. + throw new UnsupportedOperationException(); + } + }); if (taskConfig.get(CopyAppImageTaskID.COPY).action().isEmpty()) { - // "copy app image" task action is undefined indicating - // the package will use provided app image as-is. - dstAppImageDesc = srcAppImageDesc; + // "copy app image" task action is empty indicating + // the package will use provided app image in place. + dstLayout = srcLayout; } else { - dstAppImageDesc = new AppImageDesc(appImageLayoutForPackaging, env.buildRoot().resolve("image")); + dstLayout = pkg.appImageLayout().resolveAt(env.buildRoot().resolve("image")); } } - final var pkgEnv = new PackageBuildEnv<>( - BuildEnv.withAppImageDir(env, dstAppImageDesc.path()), pkg, dstAppImageDesc.appImageLayout(), outputDir); - - return new PackagingTaskContext(pkgEnv, srcAppImageDesc); + return new PackagingTaskContext(BuildEnv.withAppImageLayout(env, dstLayout), pkg, outputDir, srcLayout); } private void execute(TaskContext context) throws PackagerException { @@ -500,28 +504,30 @@ final class PackagingPipeline { try { builder.create().call(); + } catch (ExceptionBox ex) { + throw new PackagerException(ex.getCause()); + } catch (RuntimeException ex) { + throw ex; + } catch (PackagerException ex) { + throw ex; } catch (Exception ex) { - if (ex instanceof PackagerException pex) { - throw pex; - } else if (ex instanceof ExceptionBox bex) { - throw new PackagerException(bex.getCause()); - } else { - throw new PackagerException(ex); - } + throw new PackagerException(ex); } } - private record PackagingTaskContext(PackageBuildEnv env, - AppImageDesc srcAppImage) implements TaskContext, StartupParameters { + private record PackagingTaskContext(BuildEnv env, Package pkg, Path outputDir, + AppImageLayout srcAppImage) implements TaskContext, StartupParameters { PackagingTaskContext { Objects.requireNonNull(env); + Objects.requireNonNull(pkg); + Objects.requireNonNull(outputDir); Objects.requireNonNull(srcAppImage); } @Override public BuildEnv packagingEnv() { - return env.env; + return env; } @Override @@ -538,28 +544,31 @@ final class PackagingPipeline { @Override public void execute(TaskAction taskAction) throws IOException, PackagerException { if (taskAction instanceof PackageTaskAction) { - ((PackageTaskAction)taskAction).execute(env); + ((PackageTaskAction)taskAction).execute(pkgBuildEnv()); } else if (taskAction instanceof CopyAppImageTaskAction) { - ((CopyAppImageTaskAction)taskAction).execute(env.pkg(), - srcAppImage, new AppImageDesc(env.envLayout(), env.env().appImageDir())); + ((CopyAppImageTaskAction)taskAction).execute(pkg(), + srcAppImage, env.appImageLayout()); } else { throw new IllegalArgumentException(); } } AppImageBuildEnv appImageBuildEnv() { - return env.appImageBuildEnv(); + return new AppImageBuildEnv<>(env, pkg.app()); + } + + PackageBuildEnv pkgBuildEnv() { + return new PackageBuildEnv<>(env, pkg, outputDir); } } private record DefaultTaskContext(FixedDAG taskGraph, BuildEnv env, Application app, - Optional appLayout, Optional pkg) implements TaskContext { + Optional pkg) implements TaskContext { DefaultTaskContext { Objects.requireNonNull(taskGraph); Objects.requireNonNull(env); Objects.requireNonNull(app); - Objects.requireNonNull(appLayout); Objects.requireNonNull(pkg); } @@ -571,11 +580,11 @@ final class PackagingPipeline { if (pkg.isPresent() && !pkg.orElseThrow().test(taskID)) { return false; - } else if (pkg.isEmpty() && isPackageTask) { - // Building application image, skip packaging tasks. + } else if (pkg.isEmpty() && (isPackageTask || isCopyAppImageTask)) { + // Building application image, skip packaging and copying app image tasks. return false; - } else if (app.runtimeBuilder().isEmpty() && isBuildApplicationImageTask && !isCopyAppImageTask) { - // Runtime builder is not present, skip building application image tasks. + } else if (pkg.isPresent() && app.runtimeBuilder().isEmpty() && isBuildApplicationImageTask && !isCopyAppImageTask) { + // Building a package, runtime builder is not present, skip building application image tasks. return false; } else if (app.runtimeBuilder().isPresent() && isCopyAppImageTask && !isBuildApplicationImageTask) { // Runtime builder is present, skip copying app image tasks. @@ -596,7 +605,7 @@ final class PackagingPipeline { } else if (taskAction instanceof NoArgTaskAction noArgAction) { noArgAction.execute(); } else { - pkg.orElseThrow().execute(taskAction); + pkg.orElseThrow(UnsupportedOperationException::new).execute(taskAction); } } @@ -612,7 +621,7 @@ final class PackagingPipeline { @SuppressWarnings("unchecked") private AppImageBuildEnv appBuildEnv() { - return new AppImageBuildEnv<>(env, app, (T)appLayout.orElseThrow()); + return new AppImageBuildEnv<>(env, app); } } @@ -622,11 +631,7 @@ final class PackagingPipeline { Objects.requireNonNull(config); return () -> { if (config.action.isPresent() && context.test(id)) { - try { - context.execute(config.action.orElseThrow()); - } catch (ExceptionBox ex) { - throw ExceptionBox.rethrowUnchecked(ex); - } + context.execute(config.action.orElseThrow()); } return null; }; @@ -634,7 +639,5 @@ final class PackagingPipeline { private final FixedDAG taskGraph; private final Map taskConfig; - private final Function appImageLayoutForPackaging; - private final UnaryOperator appContextMapper; - private final UnaryOperator pkgContextMapper; + private final UnaryOperator contextMapper; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index 1cd0e0f6c2e..a64946c06d0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -25,15 +25,18 @@ package jdk.jpackage.internal.model; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + import java.lang.reflect.Modifier; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.util.PathGroup; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; /** @@ -41,9 +44,14 @@ import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; * * App image layout is a collection of files and directories with specific roles * (executables, configuration files, etc.) sharing the same root directory. - * - * The layout is "unresolved" if the root directory is an empty string and - * "resolved" otherwise. + *

      + * The layout is "unresolved" if the root directory is an empty path + * ({@code Path.of("")}) and "resolved" otherwise. + *

      + * The return value of the {@link #runtimeDirectory()} method call is always a + * path starting with the path returned by the {@link #rootDirectory()} method + * call. Public methods without parameters and with the return type {@link Path} + * in the derived interfaces must comply to this constrain. */ public interface AppImageLayout { @@ -56,29 +64,94 @@ public interface AppImageLayout { Path runtimeDirectory(); /** - * Root directory of this app image. + * Root directory of this app image layout. * It should normally be equal to Path.of("") for unresolved layout. * - * @return the root directory of this app image + * @return the root directory of this app image layout */ Path rootDirectory(); /** - * Creates a copy of this app image resolved at the given root directory. + * Returns a copy of this app image layout with the root directory set to an empty + * path ({@code Path.of("")}) or this instance if its root directory is already + * an empty path. + * + * @return an app image layout with the root directory set to an empty path + */ + AppImageLayout resetRootDirectory(); + + /** + * Returns true if the root directory of this app image layout is + * not an empty path, i.e, if it is not equal to Path.of(""). + * + * @return true if the root directory of this app image layout is + * not an empty path + */ + default boolean isResolved() { + return !rootDirectory().equals(Path.of("")); + } + + /** + * Creates a copy of this app image layout resolved at the given root directory. * * @param root path to a directory at which to resolve the layout - * @return a copy of this app image resolved at the given root directory + * @return a copy of this app image layout resolved at the given root directory */ - AppImageLayout resolveAt(Path root); + default AppImageLayout resolveAt(Path root) { + return map(root::resolve); + } + + /** + * Returns a copy of this app image layout resolved such that its root directory + * is set to an empty path ({@code Path.of("")}) or this instance if its root + * directory is already an empty path. + * + * @return an app image layout resolved at {@code Path.of("")} path + */ + default AppImageLayout unresolve() { + if (isResolved()) { + final var root = rootDirectory(); + return map(root::relativize); + } else { + return this; + } + } + + /** + * Returns a copy of this app image layout with the specified mapper applied to + * every path. + * + * @param mapper the mapper to use with every path in this app image layout. + * @return the copy of this app image layout with the specified mapper applied + * to every path + */ + AppImageLayout map(UnaryOperator mapper); /** * Default implementation of {@link AppImageLayout} interface. - */ + */ record Stub(Path rootDirectory, Path runtimeDirectory) implements AppImageLayout { + public Stub { + Objects.requireNonNull(rootDirectory); + } + + public Stub(Path runtimeDirectory) { + this(Path.of(""), runtimeDirectory); + } + @Override - public AppImageLayout resolveAt(Path base) { - return new Stub(resolveNullablePath(base, rootDirectory), resolveNullablePath(base, runtimeDirectory)); + public AppImageLayout resetRootDirectory() { + if (isResolved()) { + return new Stub(runtimeDirectory); + } else { + return this; + } + } + + @Override + public AppImageLayout map(UnaryOperator mapper) { + return new Stub(mapNullablePath(mapper, rootDirectory), mapNullablePath(mapper, runtimeDirectory)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index b8b2eda4437..013d2fc78cd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -24,10 +24,11 @@ */ package jdk.jpackage.internal.model; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; import java.nio.file.Path; import java.util.Objects; +import java.util.function.UnaryOperator; import jdk.jpackage.internal.util.CompositeProxy; /** @@ -42,7 +43,26 @@ public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixi @Override default ApplicationLayout resolveAt(Path root) { - return buildFrom(this).resolveAt(root).create(); + return (ApplicationLayout)AppImageLayout.super.resolveAt(root); + } + + @Override + default ApplicationLayout unresolve() { + return (ApplicationLayout)AppImageLayout.super.unresolve(); + } + + @Override + default ApplicationLayout resetRootDirectory() { + if (isResolved()) { + return buildFrom(this).rootDirectory("").create(); + } else { + return this; + } + } + + @Override + default ApplicationLayout map(UnaryOperator mapper) { + return buildFrom(this).mutate(mapper).create(); } /** @@ -113,14 +133,14 @@ public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixi return this; } - public Builder resolveAt(Path base) { - rootDirectory(resolveNullablePath(base, rootDirectory)); - launchersDirectory(resolveNullablePath(base, launchersDirectory)); - appDirectory(resolveNullablePath(base, appDirectory)); - runtimeDirectory(resolveNullablePath(base, runtimeDirectory)); - appModsDirectory(resolveNullablePath(base, appModsDirectory)); - desktopIntegrationDirectory(resolveNullablePath(base, desktopIntegrationDirectory)); - contentDirectory(resolveNullablePath(base, contentDirectory)); + public Builder mutate(UnaryOperator mapper) { + rootDirectory(mapNullablePath(mapper, rootDirectory)); + launchersDirectory(mapNullablePath(mapper, launchersDirectory)); + appDirectory(mapNullablePath(mapper, appDirectory)); + runtimeDirectory(mapNullablePath(mapper, runtimeDirectory)); + appModsDirectory(mapNullablePath(mapper, appModsDirectory)); + desktopIntegrationDirectory(mapNullablePath(mapper, desktopIntegrationDirectory)); + contentDirectory(mapNullablePath(mapper, contentDirectory)); return this; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 6d2fdaf0bbb..33c707b776f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -30,19 +30,11 @@ import java.util.Optional; /** * Native application package. * - * The interface specifies the source app image layout with two transformations: - * package app image layout and installed app image layout. + * The interface specifies the source app image and the installed app image layouts. *

      * Use {@link #appImageLayout()} or {@link #asApplicationLayout()} to get the * unresolved source app image layout. *

      - * Package app image layout is the source app image layout resolved at the - * relative installation directory of the package. Additionally, to resolve the - * source layout, some packages may transform the source layout. - *

      - * Use {@link #packageLayout()} or {@link #asPackageApplicationLayout()} to get - * the package app image layout. - *

      * Installed app image layout is the layout of the installed app image. *

      * Use {@link #installedPackageLayout()} or @@ -55,25 +47,21 @@ import java.util.Optional; * * * Source app image layout - * Package app image layout * Installed app image layout * * * Windows * bin/foo.exe app/foo.jar * Duke/bin/foo.exe Duke/app/foo.jar - * Duke/bin/foo.exe Duke/app/foo.jar * * * Linux * bin/foo lib/app/foo.jar - * opt/duke/bin/foo opt/duke/lib/app/foo.jar * /opt/duke/bin/foo /opt/duke/lib/app/foo.jar * * * OSX * Contents/MacOS/foo Contents/app/foo.jar - * Applications/Duke.app/Contents/MacOS/foo Applications/Duke.app/Contents/app/foo.jar * /Applications/Duke.app/Contents/MacOS/foo /Applications/Duke.app/Contents/app/foo.jar * * @@ -169,7 +157,6 @@ public interface Package extends BundleSpec { * * @return the unresolved app image layout of the application of this package * - * @see #packageLayout * @see #installedPackageLayout */ default AppImageLayout appImageLayout() { @@ -193,68 +180,14 @@ public interface Package extends BundleSpec { return app().asApplicationLayout(); } - /** - * Gets the layout of the installed app image of the application resolved at the - * relative installation directory of this package. - * - * @return the layout of the installed app image of the application resolved at - * the relative installation directory of this package - * - * @see #relativeInstallDir - * @see #appImageLayout - * @see #installedPackageLayout - */ - default AppImageLayout packageLayout() { - return appImageLayout().resolveAt(relativeInstallDir()); - } - - /** - * Returns the layout of the installed app image of the application resolved at - * the relative installation directory of this package as - * {@link ApplicationLayout} type or an empty {@link Optional} instance if the - * layout object is of incompatible type. - *

      - * Returns an empty {@link Optional} instance if {@link #isRuntimeInstaller()} - * returns true. - * - * @return the layout of the installed app image of the application resolved at - * the relative installation directory of this package as - * {@link ApplicationLayout} type - * - * @see #packageLayout - */ - default Optional asPackageApplicationLayout() { - if (packageLayout() instanceof ApplicationLayout layout) { - return Optional.of(layout); - } else { - return Optional.empty(); - } - } - /** * Gets the layout of the installed app image of this package. * * @return the layout of the installed app image of this package * * @see #appImageLayout - * @see #packageLayout */ - default AppImageLayout installedPackageLayout() { - return asStandardPackageType().map(stdType -> { - switch (stdType) { - case LINUX_DEB, LINUX_RPM, MAC_DMG, MAC_PKG -> { - return packageLayout().resolveAt(Path.of("/")); - } - case WIN_EXE, WIN_MSI -> { - return packageLayout(); - } - default -> { - // Should never get here - throw new IllegalStateException(); - } - } - }).orElseThrow(UnsupportedOperationException::new); - } + AppImageLayout installedPackageLayout(); /** * Returns the layout of the installed app image of this package as @@ -334,6 +267,6 @@ public interface Package extends BundleSpec { */ record Stub(Application app, PackageType type, String packageName, String description, String version, Optional aboutURL, Optional licenseFile, Optional predefinedAppImage, - Path relativeInstallDir) implements Package { + AppImageLayout installedPackageLayout, Path relativeInstallDir) implements Package { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java index bce3b417b7c..c989bcc8915 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeBuilder.java @@ -43,7 +43,7 @@ public interface RuntimeBuilder { * @param appImageLayout the app image where to create Java runtime. * @throws PackagerException if packaging error occurs */ - void createRuntime(AppImageLayout appImageLayout) throws PackagerException; + void create(AppImageLayout appImageLayout) throws PackagerException; /** * Gets the default set of paths where to find Java modules. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java index 733fc7a74c3..d995774af8f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/RuntimeLayout.java @@ -24,9 +24,10 @@ */ package jdk.jpackage.internal.model; -import static jdk.jpackage.internal.util.PathUtils.resolveNullablePath; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; import java.nio.file.Path; +import java.util.function.UnaryOperator; import jdk.jpackage.internal.util.CompositeProxy; /** @@ -39,8 +40,27 @@ public interface RuntimeLayout extends AppImageLayout { @Override default RuntimeLayout resolveAt(Path root) { - return create(new AppImageLayout.Stub(resolveNullablePath(root, rootDirectory()), - resolveNullablePath(root, runtimeDirectory()))); + return (RuntimeLayout)AppImageLayout.super.resolveAt(root); + } + + @Override + default RuntimeLayout resetRootDirectory() { + if (isResolved()) { + return create(runtimeDirectory()); + } else { + return this; + } + } + + @Override + default RuntimeLayout unresolve() { + return (RuntimeLayout)AppImageLayout.super.unresolve(); + } + + @Override + default RuntimeLayout map(UnaryOperator mapper) { + return create(new RuntimeLayout.Stub(mapNullablePath(mapper, rootDirectory()), + mapNullablePath(mapper, runtimeDirectory()))); } /** diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/ResourceLocator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/ResourceLocator.java index dfb5da7f829..93d317b0128 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/ResourceLocator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/ResourceLocator.java @@ -32,7 +32,7 @@ package jdk.jpackage.internal.resources; * to call getResourceAsStream() to get those resources. */ -public class ResourceLocator { - public ResourceLocator() { +public final class ResourceLocator { + private ResourceLocator() { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java index 08a91175c1e..55144826efb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathGroup.java @@ -470,5 +470,22 @@ public final class PathGroup { } } + @Override + public int hashCode() { + return Objects.hash(entries); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PathGroup other = (PathGroup) obj; + return Objects.equals(entries, other.entries); + } + private final Map entries; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index 31019832b73..a8944a67ae0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -25,7 +25,9 @@ package jdk.jpackage.internal.util; import java.nio.file.Path; +import java.util.Objects; import java.util.Optional; +import java.util.function.UnaryOperator; public final class PathUtils { @@ -47,8 +49,13 @@ public final class PathUtils { return parent != null ? parent.resolve(filename) : Path.of(filename); } - public static Path resolveNullablePath(Path base, Path path) { - return Optional.ofNullable(path).map(base::resolve).orElse(null); + public static Path mapNullablePath(UnaryOperator mapper, Path path) { + Objects.requireNonNull(mapper); + if (path != null) { + return mapper.apply(path); + } else { + return null; + } } public static Path normalizedAbsolutePath(Path path) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java index be529bdc19e..2fa7dd895c3 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinPackagingPipeline.java @@ -34,7 +34,6 @@ import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.ApplicationLayout; -import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinLauncher; @@ -47,7 +46,6 @@ final class WinPackagingPipeline { static PackagingPipeline.Builder build() { return PackagingPipeline.buildStandard() - .appImageLayoutForPackaging(Package::appImageLayout) .task(CopyAppImageTaskID.COPY).noaction().add() .task(WinAppImageTaskID.REBRAND_LAUNCHERS) .addDependency(BuildApplicationTaskID.LAUNCHERS) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java index 6244090b71f..f7715c5ac3d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/model/WinExePackage.java @@ -46,6 +46,7 @@ public interface WinExePackage extends Package, WinExePackageMixin { pkg.aboutURL(), pkg.licenseFile(), pkg.predefinedAppImage(), + pkg.installedPackageLayout(), pkg.relativeInstallDir()); } } diff --git a/test/jdk/tools/jpackage/helpers-test/TEST.properties b/test/jdk/tools/jpackage/helpers-test/TEST.properties index 1830ea05443..ff5e0eef9de 100644 --- a/test/jdk/tools/jpackage/helpers-test/TEST.properties +++ b/test/jdk/tools/jpackage/helpers-test/TEST.properties @@ -1,6 +1,6 @@ JUnit.dirs = . -lib.dirs = /test/jdk/tools/jpackage/helpers /test/jdk/tools/jpackage/helpers-test +lib.dirs = /test/jdk/tools/jpackage/helpers /test/jdk/tools/jpackage/junit/tools modules=jdk.jpackage/jdk.jpackage.internal:+open \ jdk.jpackage/jdk.jpackage.internal.util:+open \ diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java index 50f1992f796..08d0ba76d1c 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java @@ -42,11 +42,10 @@ public class JavaAppDescTest extends JUnitAdapter { @Parameter({"Foo", "Foo.class"}) @Parameter({"com.bar.A", "com/bar/A.class"}) @Parameter({"module/com.bar.A", "com/bar/A.class"}) - public static void testClassFilePath(String... args) { - var appDesc = args[0]; - var expectedClassFilePath = Path.of(args[1]); - TKit.assertEquals(expectedClassFilePath.toString(), JavaAppDesc.parse( - appDesc).classFilePath().toString(), null); + public static void testClassFilePath(String appDesc, String expectedClassFile) { + var expectedClassFilePath = Path.of(expectedClassFile); + TKit.assertEquals(expectedClassFilePath.toString(), + JavaAppDesc.parse(appDesc).classFilePath().toString(), null); } public static List input() { @@ -55,6 +54,12 @@ public class JavaAppDescTest extends JUnitAdapter { createTestCase("foo.jar*", "foo.jar*hello.jar:Hello"), createTestCase("Bye", "hello.jar:Bye"), createTestCase("bye.jar:", "bye.jar:Hello"), + createTestCase("bye.jar:!", appDesc -> { + return appDesc + .setBundleFileName("bye.jar") + .setClassName("Hello") + .setWithMainClass(true); + }), createTestCase("duke.jar:com.other/com.other.foo.bar.Buz!@3.7", appDesc -> { return appDesc .setBundleFileName("duke.jar") diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 3a89ba28d26..3a423fd71ca 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1174,10 +1174,15 @@ public class JPackageCommand extends CommandArguments { "Check for unexpected value of property in app image file"); } - TKit.assertStringListEquals( - addLauncherNames().stream().sorted().toList(), - aif.addLaunchers().keySet().stream().sorted().toList(), - "Check additional launcher names"); + // Don't compare the add launchers configured on the command line with the + // add launchers listed in the `.jpackage.xml` file if the latter comes from + // a predefined app image. + if (!hasArgument("--app-image")) { + TKit.assertStringListEquals( + addLauncherNames().stream().sorted().toList(), + aif.addLaunchers().keySet().stream().sorted().toList(), + "Check additional launcher names"); + } } } diff --git a/test/jdk/tools/jpackage/junit/TEST.properties b/test/jdk/tools/jpackage/junit/TEST.properties index 34d66c3b8d7..c540eb76869 100644 --- a/test/jdk/tools/jpackage/junit/TEST.properties +++ b/test/jdk/tools/jpackage/junit/TEST.properties @@ -1,5 +1,7 @@ JUnit.dirs = share +lib.dirs = /test/jdk/tools/jpackage/helpers /test/jdk/tools/jpackage/junit/tools + modules=jdk.jpackage/jdk.jpackage.internal:+open \ jdk.jpackage/jdk.jpackage.internal.model:+open \ jdk.jpackage/jdk.jpackage.internal.pipeline:+open \ diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxApplicationLayoutTest.java new file mode 100644 index 00000000000..0bb0fe5b73e --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxApplicationLayoutTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.nio.file.Path; +import jdk.jpackage.internal.model.AppImageLayoutTest; +import jdk.jpackage.internal.model.ApplicationLayoutTest; +import org.junit.jupiter.api.Test; + +public class LinuxApplicationLayoutTest { + + @Test + public void testResolveAt() { + AppImageLayoutTest.testResolveAt(createLayout()); + } + + @Test + public void testResolveAtRepeat() { + AppImageLayoutTest.testResolveAtRepeat(createLayout()); + } + + @Test + public void testUnresolve() { + AppImageLayoutTest.testUnresolve(createLayout()); + } + + @Test + public void testEmptyRootDirectory() { + AppImageLayoutTest.testEmptyRootDirectory(createLayout()); + } + + public static LinuxApplicationLayout createLayout() { + return LinuxApplicationLayout.create(ApplicationLayoutTest.createLayout(), + Path.of("libapplauncher.so")); + } +} diff --git a/test/jdk/tools/jpackage/junit/linux/junit.java b/test/jdk/tools/jpackage/junit/linux/junit.java new file mode 100644 index 00000000000..214812e951e --- /dev/null +++ b/test/jdk/tools/jpackage/junit/linux/junit.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @summary Test LinuxApplicationLayout + * @requires (os.family == "linux") + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/LinuxApplicationLayoutTest.java + * ../../share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java + * ../../share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.LinuxApplicationLayoutTest + */ diff --git a/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationLayoutTest.java new file mode 100644 index 00000000000..7ee3b41b7f2 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationLayoutTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import java.nio.file.Path; +import jdk.jpackage.internal.model.AppImageLayoutTest; +import jdk.jpackage.internal.model.ApplicationLayoutTest; +import org.junit.jupiter.api.Test; + +public class MacApplicationLayoutTest { + + @Test + public void testResolveAt() { + AppImageLayoutTest.testResolveAt(createLayout()); + } + + @Test + public void testResolveAtRepeat() { + AppImageLayoutTest.testResolveAtRepeat(createLayout()); + } + + @Test + public void testUnresolve() { + AppImageLayoutTest.testUnresolve(createLayout()); + } + + @Test + public void testEmptyRootDirectory() { + AppImageLayoutTest.testEmptyRootDirectory(createLayout()); + } + + public static MacApplicationLayout createLayout() { + return MacApplicationLayout.create(ApplicationLayoutTest.createLayout(), + Path.of("Contents/runtime")); + } +} diff --git a/test/jdk/tools/jpackage/junit/macosx/junit.java b/test/jdk/tools/jpackage/junit/macosx/junit.java new file mode 100644 index 00000000000..1549aaa6cd7 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/macosx/junit.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @summary Test MacApplicationLayoutTest + * @requires (os.family == "mac") + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/MacApplicationLayoutTest.java + * ../../share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java + * ../../share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.MacApplicationLayoutTest + */ diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/BuildEnvTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/BuildEnvTest.java new file mode 100644 index 00000000000..c71ef307f0e --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/BuildEnvTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.model.AppImageLayout.toPathGroup; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.file.Path; +import java.util.Optional; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.RuntimeLayout; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + + +public class BuildEnvTest { + + @ParameterizedTest + @ValueSource(strings = {"", "image"}) + public void testUnresolvedAppImageLayout(Path appImageDir) { + final var rootDir = Path.of(""); + + final var env = BuildEnv.create(rootDir, Optional.empty(), true, + BuildEnvTest.class, RuntimeLayout.DEFAULT.resolveAt(appImageDir).resetRootDirectory()); + + assertEquals(env.appImageDir(), env.appImageLayout().rootDirectory()); + + assertEquals(Path.of(""), env.appImageDir()); + assertEquals(toPathGroup(RuntimeLayout.DEFAULT.resolveAt(appImageDir)), toPathGroup(env.appImageLayout())); + assertEquals(rootDir, env.buildRoot()); + assertEquals(rootDir.resolve("config"), env.configDir()); + assertEquals(Optional.empty(), env.resourceDir()); + assertTrue(env.verbose()); + } + + @Test + public void testResolvedAppImageLayout() { + final var rootDir = Path.of("/oof"); + final var appImageDir = Path.of("/foo/bar"); + + final var layout = RuntimeLayout.DEFAULT.resolveAt(appImageDir); + final var env = BuildEnv.create(rootDir, Optional.empty(), true, BuildEnvTest.class, layout); + + assertSame(layout, env.appImageLayout()); + assertEquals(env.appImageDir(), env.appImageLayout().rootDirectory()); + + assertEquals(Path.of("/foo/bar"), env.appImageDir()); + assertEquals(toPathGroup(RuntimeLayout.DEFAULT.resolveAt(appImageDir)), toPathGroup(env.appImageLayout())); + assertEquals(rootDir, env.buildRoot()); + assertEquals(rootDir.resolve("config"), env.configDir()); + assertEquals(Optional.empty(), env.resourceDir()); + assertTrue(env.verbose()); + } + + @ParameterizedTest + @ValueSource(strings = {"", "/foo/bar"}) + public void test_withAppImageDir(Path appImageDir) { + final var rootDir = Path.of("/oof"); + + final var layout = RuntimeLayout.DEFAULT; + final var env = BuildEnv.withAppImageDir(BuildEnv.create(rootDir, + Optional.empty(), false, BuildEnvTest.class, layout), appImageDir); + + assertNotSame(layout, env.appImageLayout()); + assertEquals(env.appImageDir(), env.appImageLayout().rootDirectory()); + + assertEquals(appImageDir, env.appImageDir()); + assertEquals(toPathGroup(RuntimeLayout.DEFAULT.resolveAt(appImageDir)), toPathGroup(env.appImageLayout())); + assertEquals(rootDir, env.buildRoot()); + assertEquals(rootDir.resolve("config"), env.configDir()); + assertEquals(Optional.empty(), env.resourceDir()); + assertFalse(env.verbose()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void test_withAppImageLayout(boolean resolved) { + final var rootDir = Path.of("/oof"); + + final var appImageDir = Path.of("/foo/bar"); + + final AppImageLayout layout; + if (resolved) { + layout = RuntimeLayout.DEFAULT.resolveAt(appImageDir); + } else { + layout = RuntimeLayout.DEFAULT.resolveAt(appImageDir).resetRootDirectory(); + } + + final var env = BuildEnv.withAppImageLayout(BuildEnv.create(rootDir, + Optional.empty(), false, BuildEnvTest.class, RuntimeLayout.DEFAULT), layout); + + assertSame(layout, env.appImageLayout()); + assertEquals(env.appImageDir(), env.appImageLayout().rootDirectory()); + + assertEquals(toPathGroup(RuntimeLayout.DEFAULT.resolveAt(appImageDir)), toPathGroup(env.appImageLayout())); + assertEquals(rootDir, env.buildRoot()); + assertEquals(rootDir.resolve("config"), env.configDir()); + assertEquals(Optional.empty(), env.resourceDir()); + assertFalse(env.verbose()); + } + + @Test + public void test_asApplicationLayout() { + final var rootDir = Path.of("r"); + + assertTrue(BuildEnv.create(rootDir, Optional.empty(), false, + BuildEnvTest.class, RuntimeLayout.DEFAULT).asApplicationLayout().isEmpty()); + + var layout = ApplicationLayout.build().setAll("foo").create(); + assertSame(layout, BuildEnv.create(rootDir, Optional.empty(), false, + BuildEnvTest.class, layout).asApplicationLayout().orElseThrow()); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java new file mode 100644 index 00000000000..24c1d62c34f --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import jdk.jpackage.internal.PackagingPipeline.BuildApplicationTaskID; +import jdk.jpackage.internal.PackagingPipeline.CopyAppImageTaskID; +import jdk.jpackage.internal.PackagingPipeline.NoArgTaskAction; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskAction; +import jdk.jpackage.internal.PackagingPipeline.TaskContext; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.Application; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Package; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.RuntimeBuilder; +import jdk.jpackage.internal.model.RuntimeLayout; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; + + +public class PackagingPipelineTest { + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testBuildApplication(boolean withRuntimeBuilder, @TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final var app = createApp(TEST_LAYOUT_1, withRuntimeBuilder ? Optional.of(TestRuntimeBuilder.INSTANCE) : Optional.empty()); + final var env = buildEnv(workDir.resolve("build")).appImageDirFor(app).create(); + + // Build application image in `env.appImageDir()` directory. + final var builder = buildPipeline(); + if (app.runtimeBuilder().isEmpty()) { + builder.task(BuildApplicationTaskID.RUNTIME).noaction().add(); + } + + builder.create().execute(env, app); + + assertEquals(app.appImageDirName(), env.appImageDir().getFileName()); + + var executedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(env, app); + })); + + List expectedActions = new ArrayList<>(); + if (app.runtimeBuilder().isPresent()) { + expectedActions.add(BuildApplicationTaskID.RUNTIME); + } + expectedActions.addAll(List.of(BuildApplicationTaskID.LAUNCHERS, BuildApplicationTaskID.CONTENT)); + + assertEquals(expectedActions, executedTaskActions); + + final ExpectedAppImage expectedAppImage; + if (withRuntimeBuilder) { + expectedAppImage = ExpectedAppImage.build().dir("") + .file("launchers/my-launcher", TestLauncher.CONTENT) + .file("runtime/my-runtime", TestRuntimeBuilder.CONTENT); + } else { + expectedAppImage = ExpectedAppImage.build().dir("") + .file("launchers/my-launcher", TestLauncher.CONTENT); + } + + assertEquals(expectedAppImage, ExpectedAppImage.load(env.appImageDir())); + } + + @Test + void testCopyApplication(@TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final var srcApp = createApp(TEST_LAYOUT_1, TestRuntimeBuilder.INSTANCE); + + final var srcEnv = buildEnv(workDir.resolve("build")).appImageDirFor(srcApp).create(); + + // Build application image in `srcEnv.appImageDir()` directory. + buildPipeline().create().execute(srcEnv, srcApp); + + final var dstApp = createApp(TEST_LAYOUT_2, TestRuntimeBuilder.INSTANCE); + + final var dstEnv = buildEnv(workDir.resolve("build-2")) + .appImageLayout(dstApp.imageLayout().resolveAt(workDir.resolve("a/b/c"))) + .create(); + + // Copy application image from `srcEnv.appImageDir()` into `dstEnv.appImageDir()` + // with layout transformation. + // This test exercises flexibility of the packaging pipeline. + final var builder = buildPipeline() + .task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).applicationAction(cfg -> { + assertSame(dstApp, cfg.app()); + assertEquals(dstEnv.appImageDir(), cfg.env().appImageLayout().rootDirectory()); + assertFalse(Files.exists(dstEnv.appImageDir())); + PackagingPipeline.copyAppImage(srcEnv.appImageLayout(), cfg.env().appImageLayout(), false); + }).add(); + + // Disable the default "build application image" actions of the tasks which + // are the dependencies of `PrimaryTaskID.BUILD_APPLICATION_IMAGE` task as + // their output will be overwritten in the custom action of this task. + builder.taskGraphSnapshot().getAllTailsOf(PrimaryTaskID.BUILD_APPLICATION_IMAGE).forEach(taskId -> { + builder.task(taskId).noaction().add(); + }); + + builder.create().execute(dstEnv, dstApp); + + AppImageLayout.toPathGroup(dstEnv.appImageLayout()).paths().forEach(path -> { + assertTrue(Files.exists(path)); + }); + + assertEquals(Path.of("c"), dstEnv.appImageDir().getFileName()); + + var executedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(dstEnv, dstApp); + })); + + assertEquals(List.of(PrimaryTaskID.BUILD_APPLICATION_IMAGE), executedTaskActions); + + final ExpectedAppImage expectedAppImage = ExpectedAppImage.build().dir("") + .file("q/launchers/my-launcher", TestLauncher.CONTENT) + .file("qqq/runtime/my-runtime", TestRuntimeBuilder.CONTENT); + + assertEquals(expectedAppImage, ExpectedAppImage.load(dstEnv.appImageDir())); + } + + @Test + void testCreatePackage(@TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final var outputDir = workDir.resolve("bundles"); + final var pkg = buildPackage(createApp(TEST_LAYOUT_1_WITH_INSTALL_DIR, TestRuntimeBuilder.INSTANCE)).create(); + final var env = buildEnv(workDir.resolve("build")).appImageDirFor(pkg).create(); + + final var builder = buildPipeline(); + + // Will create an app image in `env.appImageDir()` directory with `pkg.appImageLayout()` layout. + // Will convert the created app image into a package. + builder.create().execute(env, pkg, outputDir); + + final var expected = createTestPackageFileContents(env.appImageLayout()); + final var actual = Files.readString(outputDir.resolve(pkg.packageFileNameWithSuffix())); + + assertEquals(expected, actual); + System.out.println(String.format("testCreatePackage:\n---\n%s\n---", actual)); + + var executedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(env, pkg, outputDir); + })); + + assertEquals(List.of( + BuildApplicationTaskID.RUNTIME, + BuildApplicationTaskID.LAUNCHERS, + BuildApplicationTaskID.CONTENT, + PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT, + PrimaryTaskID.PACKAGE + ), executedTaskActions); + + final var expectedAppImage = ExpectedAppImage.build().dir("") + .file(TEST_INSTALL_DIR.resolve("launchers/my-launcher"), TestLauncher.CONTENT) + .file(TEST_INSTALL_DIR.resolve("runtime/my-runtime"), TestRuntimeBuilder.CONTENT); + + assertEquals(expectedAppImage, ExpectedAppImage.load(env.appImageDir())); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testCreateRuntimeInstaller(boolean transformLayout, @TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final AppImageLayout srcLayout; + if (transformLayout) { + // Create an application layout such that the runtime directory doesn't + // have a common parent with other directories otherwise the runtime directory + // will be skipped when copying the app image layout as path groups because + // the destination app image layout is of type RuntimeLayout and have only + // the runtime directory. + srcLayout = ApplicationLayout.build() + .launchersDirectory("launchers") + .appDirectory("lib") + .runtimeDirectory("runtime") + .appModsDirectory("lib") + .contentDirectory("lib") + .desktopIntegrationDirectory("lib") + .create(); + } else { + srcLayout = RuntimeLayout.DEFAULT; + } + + // Create a runtime image in `env.appImageDir()` directory. + final var env = buildEnv(workDir.resolve("build")) + .appImageLayout(srcLayout) + .appImageDir(workDir.resolve("rt")) + .create(); + TestRuntimeBuilder.INSTANCE.create(env.appImageLayout()); + + final var pipeline = buildPackage(createApp( + RuntimeLayout.DEFAULT.resolveAt(TEST_INSTALL_DIR).resetRootDirectory())).create(); + + final var expectedAppImage = ExpectedAppImage.build().dir("") + .file(TEST_INSTALL_DIR.resolve("my-runtime"), TestRuntimeBuilder.CONTENT); + + createAndVerifyPackage(buildPipeline(), pipeline, env, workDir.resolve("bundles"), + String.format("testCreateRuntimeInstaller(%s)", transformLayout), expectedAppImage, + CopyAppImageTaskID.COPY, + PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT, + PrimaryTaskID.PACKAGE); + } + + private enum ExternalAppImageMode { + + // Copy predefined app image from `BuildEnv.appImageDir()`. + // Layout of the predefined app image is `BuildEnv.appImageLayout()` and + // its unresolved variant equals to `Package.appImageLayout()`. + COPY_FROM_BUILD_ENV, + + // Copy predefined app image from some directory. + // Layout of the predefined app image is `Package.appImageLayout()`. + COPY, + + // Copy predefined app image from `BuildEnv.appImageDir()`. + // Layout of the predefined app image is `BuildEnv.appImageLayout()` and + // its unresolved variant is NOT equal to `Package.appImageLayout()`. + TRANSFORM_FROM_BUILD_ENV, + ; + + static final Set FROM_BUILD_ENV = Set.of( + COPY_FROM_BUILD_ENV, TRANSFORM_FROM_BUILD_ENV); + } + + @ParameterizedTest + @EnumSource(ExternalAppImageMode.class) + void testCreatePackageFromExternalAppImage(ExternalAppImageMode mode, @TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final ApplicationLayout appLayout; + final ExpectedAppImage expectedAppImage; + if (ExternalAppImageMode.TRANSFORM_FROM_BUILD_ENV == mode) { + appLayout = TEST_LAYOUT_2_WITH_INSTALL_DIR; + expectedAppImage = ExpectedAppImage.build().dir("") + .file(TEST_INSTALL_DIR.resolve("q/launchers/my-launcher"), TestLauncher.CONTENT) + .file(TEST_INSTALL_DIR.resolve("qqq/runtime/my-runtime"), TestRuntimeBuilder.CONTENT); + } else { + appLayout = TEST_LAYOUT_1_WITH_INSTALL_DIR; + expectedAppImage = ExpectedAppImage.build().dir("") + .file(TEST_INSTALL_DIR.resolve("launchers/my-launcher"), TestLauncher.CONTENT) + .file(TEST_INSTALL_DIR.resolve("runtime/my-runtime"), TestRuntimeBuilder.CONTENT); + } + + final BuildEnv env; + final Path predefinedAppImage; + if (ExternalAppImageMode.FROM_BUILD_ENV.contains(mode)) { + // External app image is stored in the build env app image directory. + env = setupBuildEnvForExternalAppImage(workDir); + predefinedAppImage = env.appImageDir(); + } else { + // External app image is stored outside of the build env app image directory + // and should have the same layout as the app's app image layout. + env = buildEnv(workDir.resolve("build")) + .appImageDir(workDir) + // Always need some app image layout. + .appImageLayout(new AppImageLayout.Stub(Path.of(""))) + .create(); + final var externalAppImageLayout = appLayout.resolveAt(workDir.resolve("app-image")); + TestRuntimeBuilder.INSTANCE.create(externalAppImageLayout); + TestLauncher.INSTANCE.create(externalAppImageLayout); + predefinedAppImage = externalAppImageLayout.rootDirectory(); + } + + final var pkg = buildPackage(createApp(appLayout)) + .predefinedAppImage(predefinedAppImage) + .create(); + + createAndVerifyPackage(buildPipeline(), pkg, env, workDir.resolve("bundles"), + String.format("testCreatePackageFromExternalAppImage(%s)", mode), expectedAppImage, + CopyAppImageTaskID.COPY, + PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT, + PrimaryTaskID.PACKAGE); + } + + @ParameterizedTest + @EnumSource(names={"COPY", "COPY_FROM_BUILD_ENV"}) + void testCreatePackageFromExternalAppImageNoCopyAction(ExternalAppImageMode mode, @TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final ApplicationLayout appLayout = TEST_LAYOUT_1_WITH_INSTALL_DIR; + + final BuildEnv env; + final ApplicationLayout predefinedAppImageLayout; + if (ExternalAppImageMode.FROM_BUILD_ENV.contains(mode)) { + // External app image is stored in the build env app image directory. + env = setupBuildEnvForExternalAppImage(workDir); + predefinedAppImageLayout = env.asApplicationLayout().orElseThrow(); + } else { + // External app image is stored outside of the build env app image directory + // and should have the same layout as the app's app image layout. + env = buildEnv(workDir.resolve("build")) + .appImageDir(workDir) + // Always need some app image layout. + .appImageLayout(new AppImageLayout.Stub(Path.of(""))) + .create(); + predefinedAppImageLayout = appLayout.resolveAt(workDir.resolve("app-image")); + TestRuntimeBuilder.INSTANCE.create(predefinedAppImageLayout); + TestLauncher.INSTANCE.create(predefinedAppImageLayout); + } + + final var pkg = buildPackage(createApp(appLayout)) + .predefinedAppImage(predefinedAppImageLayout.rootDirectory()) + .create(); + + final var outputDir = workDir.resolve("bundles"); + + final var builder = buildPipeline().configuredTasks().filter(task -> { + return CopyAppImageTaskID.COPY.equals(task.task()); + }).findFirst().orElseThrow().noaction().add(); + + final var startupParameters = builder.createStartupParameters(env, pkg, outputDir); + + builder.create().execute(startupParameters); + + final var expected = createTestPackageFileContents(predefinedAppImageLayout); + final var actual = Files.readString(outputDir.resolve(pkg.packageFileNameWithSuffix())); + assertEquals(expected, actual); + System.out.println(String.format("%s:\n---\n%s\n---", + String.format("testCreatePackageFromExternalAppImage(%s)", mode), actual)); + + final ExpectedAppImage expectedAppImage = ExpectedAppImage.build().dir("") + .file(predefinedAppImageLayout.unresolve().launchersDirectory().resolve("my-launcher"), TestLauncher.CONTENT) + .file(predefinedAppImageLayout.unresolve().runtimeDirectory().resolve("my-runtime"), TestRuntimeBuilder.CONTENT); + assertEquals(expectedAppImage, ExpectedAppImage.load(pkg.predefinedAppImage().orElseThrow())); + + var actualExecutedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(startupParameters); + })); + assertEquals(List.of( + PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT, + PrimaryTaskID.PACKAGE), actualExecutedTaskActions); + } + + @Test + void testCreatePackageFromExternalAppImageWithoutExternalAppImageError(@TempDir Path workDir) throws ConfigException, PackagerException, IOException { + + final var env = setupBuildEnvForExternalAppImage(workDir); + final var pkg = buildPackage(createApp(TEST_LAYOUT_1_WITH_INSTALL_DIR)).create(); + final var pipeline = buildPipeline().create(); + + assertThrowsExactly(UnsupportedOperationException.class, () -> pipeline.execute(env, pkg, workDir)); + } + + @Test + void testExceptionRethrow_RuntimeException() throws ConfigException, PackagerException, IOException { + + final var expectedException = new RuntimeException("foo"); + final var ex = testExceptionRethrow(expectedException, expectedException.getClass(), () -> { + throw expectedException; + }); + assertSame(expectedException, ex); + } + + @Test + void testExceptionRethrow_PackagerException() throws ConfigException, PackagerException, IOException { + + final var expectedException = new PackagerException("param.vendor.default"); + final var ex = testExceptionRethrow(expectedException, expectedException.getClass(), () -> { + throw expectedException; + }); + assertSame(expectedException, ex); + } + + @Test + void testExceptionRethrow_Exception() throws ConfigException, PackagerException, IOException { + + final var expectedException = new Exception("foo"); + final var ex = testExceptionRethrow(expectedException, PackagerException.class, () -> { + rethrowUnchecked(expectedException); + }); + assertSame(expectedException, ex.getCause()); + } + + @Test + void testAppImageAction() throws PackagerException, IOException { + + final var app = createApp(TEST_LAYOUT_1); + final var env = dummyBuildEnv(); + + final var executed = new boolean[1]; + + PackagingPipeline.build() + // The pipleline must have at least two tasks, add a dummy. + .task(new TaskID() {}).addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add() + .task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).appImageAction(ctx -> { + assertSame(app, ctx.app()); + assertSame(env, ctx.env()); + executed[0] = true; + }).add().create().execute(env, app); + + assertTrue(executed[0]); + } + + @Test + void testAppImageActionWithPackage() throws PackagerException, IOException { + + final var pkg = buildPackage(createApp(TEST_LAYOUT_1, TestRuntimeBuilder.INSTANCE)).create(); + final var env = dummyBuildEnv(); + + final var executed = new boolean[1]; + + final var builder = PackagingPipeline.build() + // The pipleline must have at least two tasks, add a dummy. + .task(new TaskID() {}).addDependent(PrimaryTaskID.PACKAGE).add(); + + final var startupParameters = builder.createStartupParameters(env, pkg, Path.of("")); + + builder.task(PrimaryTaskID.PACKAGE).appImageAction(ctx -> { + assertSame(pkg.app(), ctx.app()); + assertSame(startupParameters.packagingEnv(), ctx.env()); + executed[0] = true; + }).add().create().execute(startupParameters); + + assertTrue(executed[0]); + } + + @Test + void testPackageActionWithApplication() throws PackagerException, IOException { + + final var app = createApp(TEST_LAYOUT_1); + final var env = dummyBuildEnv(); + + final var pipeline = PackagingPipeline.build() + // The pipleline must have at least two tasks, add a dummy. + .task(new TaskID() {}).addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add() + .task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).packageAction(ctx -> { + throw new AssertionError(); + }).add().create(); + + // If the pipeline is building an application, it can not execute actions that take a package as an argument. + assertThrowsExactly(UnsupportedOperationException.class, () -> pipeline.execute(env, app)); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testContextMapper(boolean allowAll) throws PackagerException, IOException { + + var builder = PackagingPipeline.buildStandard().contextMapper(ctx -> { + return new TaskContext() { + @Override + public boolean test(TaskID task) { + return allowAll; + } + + @Override + public void execute(TaskAction taskAction) throws IOException, PackagerException { + if (!allowAll) { + throw new AssertionError(); + } + ctx.execute(taskAction); + } + }; + }); + + var actualExecutedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(dummyBuildEnv(), createApp(TEST_LAYOUT_1)); + })); + + List expectedExecutedTaskActions; + + if (allowAll) { + expectedExecutedTaskActions = List.of( + BuildApplicationTaskID.RUNTIME, + BuildApplicationTaskID.LAUNCHERS, + BuildApplicationTaskID.CONTENT, + BuildApplicationTaskID.APP_IMAGE_FILE, + CopyAppImageTaskID.COPY, + PackageTaskID.RUN_POST_IMAGE_USER_SCRIPT); + } else { + expectedExecutedTaskActions = List.of(); + } + + assertEquals(expectedExecutedTaskActions, actualExecutedTaskActions); + } + + public static List dryRun(PackagingPipeline.Builder builder, + Consumer callback) { + + List executedTaskActions = new ArrayList<>(); + builder.configuredTasks().filter(PackagingPipeline.Builder.TaskBuilder::hasAction).forEach(taskBuilder -> { + var taskId = taskBuilder.task(); + taskBuilder.action(() -> { + executedTaskActions.add(taskId); + }).add(); + }); + + callback.accept(builder); + + return executedTaskActions; + } + + private static Exception testExceptionRethrow(Exception expectedException, + Class expectedCatchExceptionType, + NoArgTaskAction throwAction) throws PackagerException, IOException { + + final var app = createApp(TEST_LAYOUT_1); + final var env = dummyBuildEnv(); + + var pipeline = PackagingPipeline.build() + // The pipleline must have at least two tasks, add a dummy. + .task(new TaskID() {}).addDependent(PrimaryTaskID.BUILD_APPLICATION_IMAGE).add() + .task(PrimaryTaskID.BUILD_APPLICATION_IMAGE).action(throwAction).add().create(); + + return assertThrowsExactly(expectedCatchExceptionType, () -> pipeline.execute(env, app)); + } + + private static BuildEnv setupBuildEnvForExternalAppImage(Path workDir) throws ConfigException { + // Create an app image in `env.appImageDir()` directory. + final var env = buildEnv(workDir.resolve("build")) + .appImageLayout(TEST_LAYOUT_1.resolveAt(Path.of("a/b/c")).resetRootDirectory()) + .appImageDir(workDir.resolve("app-image")) + .create(); + TestRuntimeBuilder.INSTANCE.create(env.appImageLayout()); + TestLauncher.INSTANCE.create((ApplicationLayout)env.appImageLayout()); + + return env; + } + + private static void createAndVerifyPackage(PackagingPipeline.Builder builder, Package pkg, + BuildEnv env, Path outputDir, String logMsgHeader, ExpectedAppImage expectedAppImage, + TaskID... expectedExecutedTaskActions) throws PackagerException, IOException { + Objects.requireNonNull(logMsgHeader); + + final var startupParameters = builder.createStartupParameters(env, pkg, outputDir); + + assertNotSameAppImageDirs(env, startupParameters.packagingEnv()); + + // Will create an app image in `startupParameters.packagingEnv().appImageDir()` directory + // with `pkg.appImageLayout()` layout using an app image (runtime image) from `env.appImageDir()` as input. + // Will convert the created app image into a package. + // Will not overwrite the contents of `env.appImageDir()` directory. + builder.create().execute(startupParameters); + + final var packagingAppImageDir = startupParameters.packagingEnv().appImageDir(); + + final var expected = createTestPackageFileContents(pkg.appImageLayout().resolveAt(packagingAppImageDir)); + + final var actual = Files.readString(outputDir.resolve(pkg.packageFileNameWithSuffix())); + + assertEquals(expected, actual); + System.out.println(String.format("%s:\n---\n%s\n---", logMsgHeader, actual)); + + assertEquals(expectedAppImage, ExpectedAppImage.load(packagingAppImageDir)); + + var actualExecutedTaskActions = dryRun(builder, toConsumer(_ -> { + builder.create().execute(startupParameters); + })); + + assertEquals(List.of(expectedExecutedTaskActions), actualExecutedTaskActions); + } + + private static Application createApp(AppImageLayout appImageLayout) { + return createApp(appImageLayout, Optional.empty()); + } + + private static Application createApp(AppImageLayout appImageLayout, RuntimeBuilder runtimeBuilder) { + return createApp(appImageLayout, Optional.of(runtimeBuilder)); + } + + private static Application createApp(AppImageLayout appImageLayout, Optional runtimeBuilder) { + Objects.requireNonNull(appImageLayout); + Objects.requireNonNull(runtimeBuilder); + if (appImageLayout.isResolved()) { + throw new IllegalArgumentException(); + } + + return new Application.Stub( + "foo", + "My app", + "1.0", + "Acme", + "copyright", + Optional.empty(), + List.of(), + appImageLayout, + runtimeBuilder, + List.of(), + Map.of()); + } + + + private static final class PackageBuilder { + PackageBuilder(Application app) { + this.app = Objects.requireNonNull(app); + } + + Package create() { + return new Package.Stub( + app, + new PackageType() {}, + "the-package", + "My package", + "1.0", + Optional.empty(), + Optional.empty(), + Optional.ofNullable(predefinedAppImage), + null, + TEST_INSTALL_DIR); + } + + PackageBuilder predefinedAppImage(Path v) { + predefinedAppImage = v; + return this; + } + + private Path predefinedAppImage; + private final Application app; + } + + + private static PackageBuilder buildPackage(Application app) { + return new PackageBuilder(app); + } + + private static BuildEnvBuilder buildEnv(Path rootDir) { + return new BuildEnvBuilder(rootDir); + } + + private static BuildEnv dummyBuildEnv() { + return BuildEnv.create(Path.of("foo"), Optional.empty(), false, PackagingPipeline.class, RuntimeLayout.DEFAULT); + } + + private static PackagingPipeline.Builder buildPipeline() { + return PackagingPipeline.buildStandard() + // Disable building the app image file (.jpackage.xml) as we don't have launchers in the test app. + .task(BuildApplicationTaskID.APP_IMAGE_FILE).noaction().add() + .task(BuildApplicationTaskID.LAUNCHERS).applicationAction(cfg -> { + TestLauncher.INSTANCE.create(cfg.resolvedLayout()); + }).add() + .task(PrimaryTaskID.PACKAGE).packageAction(cfg -> { + var str = createTestPackageFileContents(cfg.resolvedLayout()); + var packageFile = cfg.outputDir().resolve(cfg.pkg().packageFileNameWithSuffix()); + Files.createDirectories(packageFile.getParent()); + Files.writeString(packageFile, str); + }).add(); + } + + private static String createTestPackageFileContents(AppImageLayout pkgLayout) throws IOException { + return ExpectedAppImage.load(pkgLayout.rootDirectory()).toString(); + } + + private static void assertNotSameAppImageDirs(BuildEnv a, BuildEnv b) { + assertNotEquals(a.appImageDir(), b.appImageDir()); + assertEquals(a.buildRoot(), b.buildRoot()); + assertEquals(a.configDir(), b.configDir()); + assertEquals(a.resourceDir(), b.resourceDir()); + } + + + private static final class TestRuntimeBuilder implements RuntimeBuilder { + @Override + public void create(AppImageLayout appImageLayout) { + assertTrue(appImageLayout.isResolved()); + try { + Files.createDirectories(appImageLayout.runtimeDirectory()); + Files.writeString(runtimeFile(appImageLayout), CONTENT); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static Path runtimeFile(AppImageLayout appImageLayout) { + return appImageLayout.runtimeDirectory().resolve("my-runtime"); + } + + static final String CONTENT = "this is the runtime"; + + static final TestRuntimeBuilder INSTANCE = new TestRuntimeBuilder(); + } + + + private static final class TestLauncher { + public void create(ApplicationLayout appLayout) { + assertTrue(appLayout.isResolved()); + try { + Files.createDirectories(appLayout.launchersDirectory()); + Files.writeString(launcherFile(appLayout), CONTENT); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static Path launcherFile(ApplicationLayout appLayout) { + return appLayout.launchersDirectory().resolve("my-launcher"); + } + + static final String CONTENT = "this is the launcher"; + + static final TestLauncher INSTANCE = new TestLauncher(); + } + + + private static final class ExpectedAppImage { + + static ExpectedAppImage build() { + return new ExpectedAppImage(new HashSet<>()); + } + + static ExpectedAppImage load(Path appImageRoot) throws IOException { + try (var walk = Files.walk(appImageRoot)) { + return new ExpectedAppImage(walk.sorted().map(path -> { + var relativePath = appImageRoot.relativize(path); + if (Files.isDirectory(path)) { + return new Directory(relativePath); + } else { + return new File(relativePath, toSupplier(() -> Files.readString(path)).get()); + } + }).collect(Collectors.toSet())); + } + } + + ExpectedAppImage file(Path path, String content) { + return add(new File(path, content)); + } + + ExpectedAppImage file(String path, String content) { + return file(Path.of(path), content); + } + + ExpectedAppImage dir(Path path) { + return add(new Directory(path)); + } + + ExpectedAppImage dir(String path) { + return dir(Path.of(path)); + } + + @Override + public String toString() { + return items.stream().map(AppImageItem::toString).sorted().collect(Collectors.joining("\n")); + } + + @Override + public int hashCode() { + return Objects.hash(items); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + ExpectedAppImage other = (ExpectedAppImage) obj; + return Objects.equals(items, other.items); + } + + private ExpectedAppImage(Set items) { + this.items = Objects.requireNonNull(items); + } + + private ExpectedAppImage add(AppImageItem v) { + var path = v.path(); + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + + items.add(v); + while (path.getNameCount() > 1) { + items.add(new Directory(path = path.getParent())); + } + return this; + } + + private interface AppImageItem { + Path path(); + } + + private record File(Path path, String content) implements AppImageItem { + + File { + Objects.requireNonNull(path); + Objects.requireNonNull(content); + } + + @Override + public String toString() { + return String.format("%s[%s]", path, content); + } + } + + private record Directory(Path path) implements AppImageItem { + + Directory { + Objects.requireNonNull(path); + } + + @Override + public String toString() { + return path.toString(); + } + } + + private final Set items; + } + + + private static final ApplicationLayout TEST_LAYOUT_1 = ApplicationLayout.build() + .launchersDirectory("launchers") + .appDirectory("") + .runtimeDirectory("runtime") + .appModsDirectory("") + .contentDirectory("") + .desktopIntegrationDirectory("") + .create(); + + private static final ApplicationLayout TEST_LAYOUT_2 = ApplicationLayout.build() + .launchersDirectory("q/launchers") + .appDirectory("") + .runtimeDirectory("qqq/runtime") + .appModsDirectory("") + .contentDirectory("") + .desktopIntegrationDirectory("") + .create(); + + private static final Path TEST_INSTALL_DIR = Path.of("Acme/My app"); + + private static final ApplicationLayout TEST_LAYOUT_1_WITH_INSTALL_DIR = + TEST_LAYOUT_1.resolveAt(TEST_INSTALL_DIR).resetRootDirectory(); + + private static final ApplicationLayout TEST_LAYOUT_2_WITH_INSTALL_DIR = + TEST_LAYOUT_2.resolveAt(TEST_INSTALL_DIR).resetRootDirectory(); +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java index 1c863b653b1..5948d74079e 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java @@ -23,12 +23,14 @@ package jdk.jpackage.internal.model; +import static jdk.jpackage.internal.model.AppImageLayout.toPathGroup; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; import java.nio.file.Path; import java.util.List; import java.util.Set; +import jdk.jpackage.internal.util.PathGroup; import org.junit.jupiter.api.Test; @@ -48,7 +50,7 @@ public class AppImageLayoutTest { public void testPathGroup() { final var layout = new AppImageLayout.Stub(Path.of("root"), Path.of("runtime")); - final var pathGroup = AppImageLayout.toPathGroup(layout); + final var pathGroup = toPathGroup(layout); assertEquals(Set.of("runtimeDirectory"), pathGroup.keys()); assertEquals(List.of(layout.runtimeDirectory()), pathGroup.paths()); @@ -56,15 +58,88 @@ public class AppImageLayoutTest { @Test public void testResolveAt() { - final var dir = Path.of("foo/bar"); - - final var layout = new AppImageLayout.Stub(Path.of(""), Path.of("runtime")); - - final var resolvedLayout = layout.resolveAt(dir); - - assertNotSame(layout, resolvedLayout); - - assertEquals(dir.resolve(layout.rootDirectory()), resolvedLayout.rootDirectory()); - assertEquals(dir.resolve(layout.runtimeDirectory()), resolvedLayout.runtimeDirectory()); + testResolveAt(new AppImageLayout.Stub(Path.of("foo"))); } + + @Test + public void testResolveAtRepeat() { + testResolveAtRepeat(new AppImageLayout.Stub(Path.of("foo"))); + } + + @Test + public void testUnresolve() { + testUnresolve(new AppImageLayout.Stub(Path.of("runtime"))); + } + + @Test + public void testEmptyRootDirectory() { + testEmptyRootDirectory(new AppImageLayout.Stub(Path.of("rt"))); + } + + public static void testResolveAt(AppImageLayout testee) { + + var dir = Path.of("foo/bar"); + + assertLayout(testee.resolveAt(dir), true, testee, dir); + } + + public static void testResolveAtRepeat(AppImageLayout testee) { + + var resolvedLayout = testee.resolveAt(Path.of("b/c")).resolveAt(Path.of("a")); + + assertLayout(resolvedLayout, true, testee, Path.of("a/b/c")); + } + + public static void testUnresolve(AppImageLayout testee) { + if (testee.isResolved()) { + throw new IllegalArgumentException(); + } + + var resolvedLayout = testee.resolveAt(Path.of("foo/bar")); + var layout = resolvedLayout.unresolve(); + + assertLayout(layout, false, testee, Path.of("")); + + resolvedLayout = testee.resolveAt(Path.of("").toAbsolutePath()); + layout = resolvedLayout.unresolve(); + + assertLayout(layout, false, testee, Path.of("")); + + assertSame(testee, testee.unresolve()); + } + + public static void testEmptyRootDirectory(AppImageLayout testee) { + if (testee.isResolved()) { + throw new IllegalArgumentException(); + } + + assertEmptyRootDirectory(testee); + + final var resolved = testee.resolveAt(Path.of("t")); + + assertEmptyRootDirectory(resolved); + } + + private static void assertEmptyRootDirectory(AppImageLayout testee) { + if (testee.isResolved()) { + var newLayout = testee.resetRootDirectory(); + assertLayout(newLayout, false, Path.of(""), toPathGroup(testee)); + } else { + assertSame(testee, testee.resetRootDirectory()); + } + } + + private static void assertLayout(AppImageLayout actual, boolean expectedResolved, + AppImageLayout base, Path baseResolveAt) { + assertLayout(actual, expectedResolved, baseResolveAt.resolve(base.rootDirectory()), + toPathGroup(base).resolveAt(baseResolveAt)); + } + + private static void assertLayout(AppImageLayout actual, boolean expectedResolved, + Path expectedRootDir, PathGroup expectedPaths) { + assertEquals(expectedResolved, actual.isResolved()); + assertEquals(expectedRootDir, actual.rootDirectory()); + assertEquals(expectedPaths, toPathGroup(actual)); + } + } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java index 089a363e0e4..063b11ec589 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -23,20 +23,51 @@ package jdk.jpackage.internal.model; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; public class ApplicationLayoutTest { - public void test(boolean move, Path tempDir) throws IOException { + @Test + public void testMove(@TempDir Path tempDir) throws IOException { + test(true, tempDir); + } + + @Test + public void testCopy(@TempDir Path tempDir) throws IOException { + test(false, tempDir); + } + + @Test + public void testResolveAt() { + AppImageLayoutTest.testResolveAt(createLayout()); + } + + @Test + public void testResolveAtRepeat() { + AppImageLayoutTest.testResolveAtRepeat(createLayout()); + } + + @Test + public void testUnresolve() { + AppImageLayoutTest.testUnresolve(createLayout()); + } + + @Test + public void testEmptyRootDirectory() { + AppImageLayoutTest.testEmptyRootDirectory(createLayout()); + } + + private static void test(boolean move, Path tempDir) throws IOException { final var srcAppImageRoot = tempDir.resolve("src"); Files.createDirectories(srcAppImageRoot); @@ -55,14 +86,7 @@ public class ApplicationLayoutTest { Files.createDirectories(path); } - final var layout = ApplicationLayout.build() - .launchersDirectory("bin") - .appDirectory("lib/app") - .runtimeDirectory("runtime") - .appModsDirectory("mods") - .contentDirectory("content") - .desktopIntegrationDirectory("lib/apps") - .create(); + final var layout = createLayout(); final var dstAppImageRoot = tempDir.resolve("dst"); Files.createDirectories(dstAppImageRoot); @@ -100,13 +124,14 @@ public class ApplicationLayoutTest { } } - @Test - public void testMove(@TempDir Path tempDir) throws IOException { - test(true, tempDir); - } - - @Test - public void testCopy(@TempDir Path tempDir) throws IOException { - test(false, tempDir); + public static ApplicationLayout createLayout() { + return ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("runtime") + .appModsDirectory("mods") + .contentDirectory("content") + .desktopIntegrationDirectory("lib/apps") + .create(); } } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index 579cf5f083c..c5b5e271960 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -65,6 +65,14 @@ public class PathGroupTest { assertThrowsExactly(NullPointerException.class, () -> new PathGroup(Map.of()).getPath(null)); } + @Test + public void equals() { + assertEquals(new PathGroup(Map.of()), new PathGroup(Map.of())); + assertEquals(new PathGroup(Map.of("foo", Path.of("bar"))), new PathGroup(Map.of("foo", Path.of("bar")))); + assertNotEquals(new PathGroup(Map.of("foo", Path.of("bar"))), new PathGroup(Map.of("foo", Path.of("rab")))); + assertNotEquals(new PathGroup(Map.of("foo", Path.of("bar"))), new PathGroup(Map.of("Foo", Path.of("bar")))); + } + @Test public void testEmptyPathGroup() { PathGroup pg = new PathGroup(Map.of()); diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java similarity index 90% rename from test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java rename to test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java index b7c50285797..5a605b1642d 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitAdapter.java @@ -40,10 +40,12 @@ import org.junit.jupiter.api.TestFactory; public class JUnitAdapter { - static { - if (System.getProperty("test.src") == null) { - // Was called by somebody else but not by jtreg - System.setProperty("test.src", Path.of("@@openJdkDir@@/test/jdk/tools/jpackage").toString()); + public static class TestSrcInitializer { + static { + if (System.getProperty("test.src") == null) { + // Was called by somebody else but not by jtreg + System.setProperty("test.src", Path.of("@@openJdkDir@@/test/jdk/tools/jpackage").toString()); + } } } @@ -84,5 +86,9 @@ public class JUnitAdapter { } } + static { + new TestSrcInitializer(); + } + private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); } diff --git a/test/jdk/tools/jpackage/junit/windows/junit.java b/test/jdk/tools/jpackage/junit/windows/junit.java index 38b5cd5ca0c..d27a282f0dc 100644 --- a/test/jdk/tools/jpackage/junit/windows/junit.java +++ b/test/jdk/tools/jpackage/junit/windows/junit.java @@ -24,6 +24,7 @@ /* @test * @summary Test function reading OS version from PE file * @requires (os.family == "windows") - * @compile/module=jdk.jpackage jdk/jpackage/internal/ExecutableOSVersionTest.java + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/ExecutableOSVersionTest.java * @run junit jdk.jpackage/jdk.jpackage.internal.ExecutableOSVersionTest */ From bd65d483df4742bb7ce79b613f10f70a45117f84 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 17 Aug 2025 12:56:42 +0000 Subject: [PATCH 107/471] 8365245: Move size reducing operations to GrowableArrayWithAllocator Reviewed-by: jsjolen, stefank --- src/hotspot/share/utilities/growableArray.hpp | 131 +++++++++--------- test/hotspot/gtest/gc/z/test_zArray.cpp | 4 +- 2 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 759b9451490..53403ca5cf1 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -93,12 +93,6 @@ public: bool is_empty() const { return _len == 0; } bool is_nonempty() const { return _len != 0; } bool is_full() const { return _len == _capacity; } - - void clear() { _len = 0; } - void trunc_to(int length) { - assert(length <= _len,"cannot increase length"); - _len = length; - } }; template class GrowableArrayIterator; @@ -189,11 +183,6 @@ public: return GrowableArrayIterator(this, length()); } - E pop() { - assert(_len > 0, "empty list"); - return _data[--_len]; - } - void at_put(int i, const E& elem) { assert(0 <= i && i < _len, "illegal index %d for length %d", i, _len); _data[i] = elem; @@ -247,59 +236,6 @@ public: return -1; } - // Order preserving remove operations. - - void remove(const E& elem) { - // Assuming that element does exist. - bool removed = remove_if_existing(elem); - if (removed) return; - ShouldNotReachHere(); - } - - bool remove_if_existing(const E& elem) { - // Returns TRUE if elem is removed. - for (int i = 0; i < _len; i++) { - if (_data[i] == elem) { - remove_at(i); - return true; - } - } - return false; - } - - void remove_at(int index) { - assert(0 <= index && index < _len, "illegal index %d for length %d", index, _len); - for (int j = index + 1; j < _len; j++) { - _data[j-1] = _data[j]; - } - _len--; - } - - // Remove all elements up to the index (exclusive). The order is preserved. - void remove_till(int idx) { - remove_range(0, idx); - } - - // Remove all elements in the range [start - end). The order is preserved. - void remove_range(int start, int end) { - assert(0 <= start, "illegal start index %d", start); - assert(start < end && end <= _len, "erase called with invalid range (%d, %d) for length %d", start, end, _len); - - for (int i = start, j = end; j < length(); i++, j++) { - at_put(i, at(j)); - } - trunc_to(length() - (end - start)); - } - - // The order is changed. - void delete_at(int index) { - assert(0 <= index && index < _len, "illegal index %d for length %d", index, _len); - if (index < --_len) { - // Replace removed element with last one. - _data[index] = _data[_len]; - } - } - void sort(int f(E*, E*)) { if (_data == nullptr) return; qsort(_data, length(), sizeof(E), (_sort_Fn)f); @@ -427,6 +363,11 @@ public: void push(const E& elem) { append(elem); } + E pop() { + assert(this->_len > 0, "empty list"); + return this->_data[--this->_len]; + } + E& at_grow(int i, const E& fill = E()) { assert(0 <= i, "negative index %d", i); if (i >= this->_len) { @@ -514,9 +455,71 @@ public: // Ensure capacity is at least new_capacity. void reserve(int new_capacity); + void trunc_to(int length) { + assert(length <= this->_len,"cannot increase length"); + this->_len = length; + } + + // Order preserving remove operations. + + void remove_at(int index) { + assert(0 <= index && index < this->_len, + "illegal index %d for length %d", index, this->_len); + for (int j = index + 1; j < this->_len; j++) { + this->_data[j-1] = this->_data[j]; + } + this->_len--; + } + + void remove(const E& elem) { + // Assuming that element does exist. + bool removed = this->remove_if_existing(elem); + if (removed) return; + ShouldNotReachHere(); + } + + bool remove_if_existing(const E& elem) { + // Returns TRUE if elem is removed. + for (int i = 0; i < this->_len; i++) { + if (this->_data[i] == elem) { + this->remove_at(i); + return true; + } + } + return false; + } + + // Remove all elements up to the index (exclusive). The order is preserved. + void remove_till(int idx) { + remove_range(0, idx); + } + + // Remove all elements in the range [start - end). The order is preserved. + void remove_range(int start, int end) { + assert(0 <= start, "illegal start index %d", start); + assert(start < end && end <= this->_len, + "erase called with invalid range (%d, %d) for length %d", + start, end, this->_len); + + for (int i = start, j = end; j < this->length(); i++, j++) { + this->at_put(i, this->at(j)); + } + this->_len -= (end - start); + } + + // Replaces the designated element with the last element and shrinks by 1. + void delete_at(int index) { + assert(0 <= index && index < this->_len, "illegal index %d for length %d", index, this->_len); + if (index < --this->_len) { + // Replace removed element with last one. + this->_data[index] = this->_data[this->_len]; + } + } + // Reduce capacity to length. void shrink_to_fit(); + void clear() { this->_len = 0; } void clear_and_deallocate(); }; diff --git a/test/hotspot/gtest/gc/z/test_zArray.cpp b/test/hotspot/gtest/gc/z/test_zArray.cpp index acc7688cb10..79d4b29b1f5 100644 --- a/test/hotspot/gtest/gc/z/test_zArray.cpp +++ b/test/hotspot/gtest/gc/z/test_zArray.cpp @@ -127,9 +127,11 @@ TEST_F(ZArrayTest, slice) { const auto check_reversed = [](ZArraySlice original, ZArraySlice reversed) { ASSERT_EQ(original.length(), reversed.length()); + int ri = reversed.length(); for (int e : original) { - ASSERT_EQ(e, reversed.pop()); + ASSERT_EQ(e, reversed.at(--ri)); } + ASSERT_EQ(ri, 0); }; ZArraySlice a_reversed = reverse(a, reverse); From f364fcab792ed5a14e5c2779fa85ecc9d6915ae3 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 18 Aug 2025 05:32:03 +0000 Subject: [PATCH 108/471] 8359119: Change Charset to use StableValue Reviewed-by: alanb, rriggs --- .../classes/java/nio/charset/Charset.java | 116 +++++++++--------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/java.base/share/classes/java/nio/charset/Charset.java b/src/java.base/share/classes/java/nio/charset/Charset.java index b36e11cdc36..1eb3c9c2094 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/src/java.base/share/classes/java/nio/charset/Charset.java @@ -37,13 +37,16 @@ import java.nio.charset.spi.CharsetProvider; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.ServiceLoader; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.function.Supplier; /** @@ -381,17 +384,7 @@ public abstract class Charset }; } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object tryBeginLookup() { - return ThreadTrackHolder.TRACKER.tryBegin(); - } - - private static void endLookup(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } + private static final ScopedValue IN_LOOKUP = ScopedValue.newInstance(); private static Charset lookupViaProviders(final String charsetName) { @@ -406,48 +399,54 @@ public abstract class Charset if (!VM.isBooted()) return null; - Object key = tryBeginLookup(); - if (key == null) { + if (IN_LOOKUP.isBound()) { // Avoid recursive provider lookups return null; } try { - for (Iterator i = providers(); i.hasNext();) { - CharsetProvider cp = i.next(); - Charset cs = cp.charsetForName(charsetName); - if (cs != null) - return cs; - } - return null; - } finally { - endLookup(key); + return ScopedValue.where(IN_LOOKUP, true).call( + new ScopedValue.CallableOp() { + @Override + public Charset call() { + for (Iterator i = providers(); i.hasNext(); ) { + CharsetProvider cp = i.next(); + Charset cs = cp.charsetForName(charsetName); + if (cs != null) + return cs; + } + return null; + } + } + ); + } catch (Exception t) { + // Should not happen + throw new RuntimeException(t); } + } /* The extended set of charsets */ - private static class ExtendedProviderHolder { - static final CharsetProvider[] extendedProviders = extendedProviders(); - // returns ExtendedProvider, if installed - private static CharsetProvider[] extendedProviders() { - CharsetProvider[] cps = new CharsetProvider[1]; - int n = 0; - ServiceLoader sl = + private static final Supplier> EXTENDED_PROVIDERS = StableValue.supplier( + new Supplier<>() { public List get() { return extendedProviders0(); }}); + + private static List extendedProviders0() { + CharsetProvider[] cps = new CharsetProvider[1]; + int n = 0; + final ServiceLoader sl = ServiceLoader.loadInstalled(CharsetProvider.class); - for (CharsetProvider cp : sl) { - if (n + 1 > cps.length) { - cps = Arrays.copyOf(cps, cps.length << 1); - } - cps[n++] = cp; + for (CharsetProvider cp : sl) { + if (n + 1 > cps.length) { + cps = Arrays.copyOf(cps, cps.length << 1); } - return n == cps.length ? cps : Arrays.copyOf(cps, n); + cps[n++] = cp; } + return List.of(n == cps.length ? cps : Arrays.copyOf(cps, n)); } private static Charset lookupExtendedCharset(String charsetName) { if (!VM.isBooted()) // see lookupViaProviders() return null; - CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders; - for (CharsetProvider cp : ecps) { + for (CharsetProvider cp : EXTENDED_PROVIDERS.get()) { Charset cs = cp.charsetForName(charsetName); if (cs != null) return cs; @@ -608,8 +607,7 @@ public abstract class Charset new TreeMap<>( String.CASE_INSENSITIVE_ORDER); put(standardProvider.charsets(), m); - CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders; - for (CharsetProvider ecp :ecps) { + for (CharsetProvider ecp : EXTENDED_PROVIDERS.get()) { put(ecp.charsets(), m); } for (Iterator i = providers(); i.hasNext();) { @@ -619,7 +617,16 @@ public abstract class Charset return Collections.unmodifiableSortedMap(m); } - private @Stable static Charset defaultCharset; + private static final Supplier defaultCharset = StableValue.supplier( + new Supplier<>() { public Charset get() { return defaultCharset0(); }}); + + private static Charset defaultCharset0() { + // do not look for providers other than the standard one + final Charset cs = standardProvider.charsetForName(StaticProperty.fileEncoding()); + return (cs == null) + ? sun.nio.cs.UTF_8.INSTANCE + : cs; + } /** * Returns the default charset of this Java virtual machine. @@ -640,25 +647,19 @@ public abstract class Charset * @since 1.5 */ public static Charset defaultCharset() { - if (defaultCharset == null) { - synchronized (Charset.class) { - // do not look for providers other than the standard one - Charset cs = standardProvider.charsetForName(StaticProperty.fileEncoding()); - if (cs != null) - defaultCharset = cs; - else - defaultCharset = sun.nio.cs.UTF_8.INSTANCE; - } - } - return defaultCharset; + return defaultCharset.get(); } /* -- Instance fields and methods -- */ - private final String name; // tickles a bug in oldjavac - private final String[] aliases; // tickles a bug in oldjavac - private Set aliasSet; + @Stable + private final String name; + @Stable + private final String[] aliases; + @Stable + private final Supplier> aliasSet = StableValue.supplier( + new Supplier<>() { public Set get() { return Set.of(aliases); }}); /** * Initializes a new charset with the given canonical name and alias @@ -710,12 +711,7 @@ public abstract class Charset * @return An immutable set of this charset's aliases */ public final Set aliases() { - Set set = this.aliasSet; - if (set == null) { - set = Set.of(aliases); - this.aliasSet = set; - } - return set; + return aliasSet.get(); } /** From e7ca8c7d55fa959cb43d49d63128420b05b7cc92 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Mon, 18 Aug 2025 07:08:19 +0000 Subject: [PATCH 109/471] 8365436: ImageReaderTest fails when jmods directory not present Reviewed-by: sgehwolf, alanb --- test/jdk/jdk/internal/jimage/ImageReaderTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/jdk/jdk/internal/jimage/ImageReaderTest.java b/test/jdk/jdk/internal/jimage/ImageReaderTest.java index 6bdf0cf479a..8db9a3768d4 100644 --- a/test/jdk/jdk/internal/jimage/ImageReaderTest.java +++ b/test/jdk/jdk/internal/jimage/ImageReaderTest.java @@ -25,11 +25,12 @@ import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReader.Node; import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.util.JarBuilder; +import jdk.tools.jlink.internal.LinkableRuntimeImage; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import org.opentest4j.TestSkippedException; import tests.Helper; import tests.JImageGenerator; @@ -54,6 +55,7 @@ import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; * @test * @summary Tests for ImageReader. * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal * jdk.jlink/jdk.tools.jimage * @library /test/jdk/tools/lib * /test/lib @@ -214,15 +216,15 @@ public class ImageReaderTest { /// Returns the helper for building JAR and jimage files. private static Helper getHelper() { + Helper helper; try { - Helper helper = Helper.newHelper(); - if (helper == null) { - throw new TestSkippedException("Cannot create test helper (exploded image?)"); - } - return helper; + boolean isLinkableRuntime = LinkableRuntimeImage.isLinkableRuntime(); + helper = Helper.newHelper(isLinkableRuntime); } catch (IOException e) { throw new RuntimeException(e); } + Assumptions.assumeTrue(helper != null, "Cannot create test helper, skipping test!"); + return helper; } /// Loads and performs actions on classes stored in a given `ImageReader`. From 166ea12d73c7a40a1a26dc586e3db9d9430c068f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 18 Aug 2025 07:14:09 +0000 Subject: [PATCH 110/471] 8365543: UnixNativeDispatcher.init should lookup open64at and stat64at on AIX Co-authored-by: Joachim Kern Reviewed-by: jkern, stuefe, goetz, alanb --- .../unix/native/libnio/fs/UnixNativeDispatcher.c | 15 +++++++-------- .../java/nio/file/DirectoryStream/SecureDS.java | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index fbf996886ae..5f81241b7dd 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -343,22 +343,21 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) /* system calls that might not be available at run time */ -#if defined(_ALLBSD_SOURCE) - my_openat_func = (openat_func*) openat; - my_fstatat_func = (fstatat_func*) fstatat; -#else - // Make sure we link to the 64-bit version of the functions - my_openat_func = (openat_func*) dlsym(RTLD_DEFAULT, "openat64"); - my_fstatat_func = (fstatat_func*) dlsym(RTLD_DEFAULT, "fstatat64"); -#endif my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); #if defined(_AIX) // Make sure we link to the 64-bit version of the function + my_openat_func = (openat_func*) dlsym(RTLD_DEFAULT, "open64at"); + my_fstatat_func = (fstatat_func*) dlsym(RTLD_DEFAULT, "stat64at"); my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64"); #elif defined(_ALLBSD_SOURCE) + my_openat_func = (openat_func*) openat; + my_fstatat_func = (fstatat_func*) fstatat; my_fdopendir_func = (fdopendir_func*) fdopendir; #else + // Make sure we link to the 64-bit version of the functions + my_openat_func = (openat_func*) dlsym(RTLD_DEFAULT, "openat64"); + my_fstatat_func = (fstatat_func*) dlsym(RTLD_DEFAULT, "fstatat64"); my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); #endif diff --git a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java index 6199596b30c..d5d4b1904ea 100644 --- a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java @@ -24,7 +24,7 @@ /* @test * @bug 4313887 6838333 8343020 8357425 * @summary Unit test for java.nio.file.SecureDirectoryStream - * @requires (os.family == "linux" | os.family == "mac") + * @requires (os.family == "linux" | os.family == "mac" | os.family == "aix") * @library .. /test/lib * @build jdk.test.lib.Platform * @run main SecureDS From 190e113031bc6ece781fdf0d9f3c853ce324f170 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Mon, 18 Aug 2025 08:11:19 +0000 Subject: [PATCH 111/471] 8364263: HttpClient: Improve encapsulation of ProxyServer Reviewed-by: dfuchs, jpai --- test/jdk/java/net/httpclient/ProxyServer.java | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/test/jdk/java/net/httpclient/ProxyServer.java b/test/jdk/java/net/httpclient/ProxyServer.java index 747a20772d1..9ec84fe428f 100644 --- a/test/jdk/java/net/httpclient/ProxyServer.java +++ b/test/jdk/java/net/httpclient/ProxyServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -40,7 +40,7 @@ import static java.util.stream.Collectors.toList; * Two threads are created per client connection. So, it's not * intended for large numbers of parallel connections. */ -public class ProxyServer extends Thread implements Closeable { +public final class ProxyServer implements Closeable { // could use the test library here - Platform.isWindows(), // but it would force all tests that use ProxyServer to @@ -97,9 +97,7 @@ public class ProxyServer extends Thread implements Closeable { this(port, debug, null); } - public ProxyServer(Integer port, - Boolean debug, - Credentials credentials) + private ProxyServer(Integer port, Boolean debug, Credentials credentials) throws IOException { this.debug = debug; @@ -108,15 +106,8 @@ public class ProxyServer extends Thread implements Closeable { listener.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), port)); this.port = ((InetSocketAddress)listener.getLocalAddress()).getPort(); this.credentials = credentials; - setName("ProxyListener"); - setDaemon(true); - connections = new CopyOnWriteArrayList(); - start(); - } - - public ProxyServer(String s) { - credentials = null; connections = new CopyOnWriteArrayList(); + Thread.ofPlatform().name("ProxyListener").daemon().start(this::run); } /** @@ -148,7 +139,7 @@ public class ProxyServer extends Thread implements Closeable { volatile boolean done; - public void run() { + private void run() { int id = 0; try { while (!done) { @@ -656,10 +647,11 @@ public class ProxyServer extends Thread implements Closeable { int port = Integer.parseInt(args[0]); boolean debug = args.length > 1 && args[1].equals("-debug"); System.out.println("Debugging : " + debug); - ProxyServer ps = new ProxyServer(port, debug); - System.out.println("Proxy server listening on port " + ps.getPort()); - while (true) { - Thread.sleep(5000); + try (ProxyServer ps = new ProxyServer(port, debug)) { + System.out.println("Proxy server listening on port " + ps.getPort()); + while (true) { + Thread.sleep(5000); + } } } } From ca753ebad6681a76d18800d23898b7d6af83f567 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 18 Aug 2025 08:12:20 +0000 Subject: [PATCH 112/471] 8365165: Zap C-heap memory at delete/free Reviewed-by: kvn, kbarrett --- src/hotspot/share/nmt/mallocTracker.cpp | 6 ++++++ src/hotspot/share/runtime/globals.hpp | 3 +++ src/hotspot/share/runtime/os.cpp | 6 +++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index 6a2da5f79cd..d919f3ce873 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -207,6 +207,12 @@ void* MallocTracker::record_free_block(void* memblock) { deaccount(header->free_info()); + if (ZapCHeap) { + // To do this zapping, we need to know the block size. + // This is why we have to do it here, and not in os::free. + memset(memblock, freeBlockPad, header->size()); + } + header->mark_block_as_dead(); return (void*)header; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 24dda9ac6d8..ee3c37b471b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -483,6 +483,9 @@ const int ObjectAlignmentInBytes = 8; develop(bool, ZapFillerObjects, trueInDebug, \ "Zap filler objects") \ \ + develop(bool, ZapCHeap, trueInDebug, \ + "Zap allocated/freed C heap space") \ + \ develop(bool, ZapTLAB, trueInDebug, \ "Zap allocated TLABs") \ develop(bool, TestingAsyncLoggingDeathTest, false, \ diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index db2256d70cb..04a363a7aab 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -666,8 +666,8 @@ void* os::malloc(size_t size, MemTag mem_tag, const NativeCallStack& stack) { if (CDSConfig::is_dumping_static_archive()) { // Need to deterministically fill all the alignment gaps in C++ structures. ::memset(inner_ptr, 0, size); - } else { - DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);) + } else if (ZapCHeap) { + ::memset(inner_ptr, uninitBlockPad, size); } DEBUG_ONLY(break_if_ptr_caught(inner_ptr);) return inner_ptr; @@ -740,7 +740,7 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS #ifdef ASSERT assert(old_size == free_info.size, "Sanity"); - if (old_size < size) { + if (ZapCHeap && old_size < size) { // We also zap the newly extended region. ::memset((char*)new_inner_ptr + old_size, uninitBlockPad, size - old_size); } From 2b756ab1e8cfacc5cf5d9c6dfdf1d1c9a6ecf4b1 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Mon, 18 Aug 2025 08:16:32 +0000 Subject: [PATCH 113/471] 8358781: C2 fails with assert "bad profile data type" when TypeProfileCasts is disabled Reviewed-by: mhaessig, kvn, dfenacci --- src/hotspot/share/opto/graphKit.cpp | 18 ++++--- .../compiler/arguments/TestProfileCasts.java | 49 +++++++++++++++++++ 2 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/arguments/TestProfileCasts.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 902968ef4d4..d65239ab0f8 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2309,16 +2309,18 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) { if (!data->as_BitData()->null_seen()) { ptr_kind = ProfileNeverNull; } else { - assert(data->is_ReceiverTypeData(), "bad profile data type"); - ciReceiverTypeData* call = (ciReceiverTypeData*)data->as_ReceiverTypeData(); - uint i = 0; - for (; i < call->row_limit(); i++) { - ciKlass* receiver = call->receiver(i); - if (receiver != nullptr) { - break; + if (TypeProfileCasts) { + assert(data->is_ReceiverTypeData(), "bad profile data type"); + ciReceiverTypeData* call = (ciReceiverTypeData*)data->as_ReceiverTypeData(); + uint i = 0; + for (; i < call->row_limit(); i++) { + ciKlass* receiver = call->receiver(i); + if (receiver != nullptr) { + break; + } } + ptr_kind = (i == call->row_limit()) ? ProfileAlwaysNull : ProfileMaybeNull; } - ptr_kind = (i == call->row_limit()) ? ProfileAlwaysNull : ProfileMaybeNull; } } } diff --git a/test/hotspot/jtreg/compiler/arguments/TestProfileCasts.java b/test/hotspot/jtreg/compiler/arguments/TestProfileCasts.java new file mode 100644 index 00000000000..1a6bcf37919 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestProfileCasts.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8358781 + * @summary Regression test for -XX:-TypeProfileCasts crash + * @requires vm.debug + * @run main/othervm -XX:-TypeProfileCasts -XX:CompileThresholdScaling=0.01 + * compiler.arguments.TestProfileCasts + */ +package compiler.arguments; + +public class TestProfileCasts { + static class Foo { + } + + private static void test(Object o) { + if (o instanceof Foo) { + } + } + + public static void main(String[] args) { + for (int i = 0; i < 100; i++) { + test(new Foo()); + test(null); + } + } +} \ No newline at end of file From 6e91ccd1c3926094a9b6d8f9177d895aba3424a1 Mon Sep 17 00:00:00 2001 From: Pasam Soujanya Date: Mon, 18 Aug 2025 09:37:58 +0000 Subject: [PATCH 114/471] =?UTF-8?q?8365305:=20The=20ARIA=20role=20?= =?UTF-8?q?=E2=80=98contentinfo=E2=80=99=20is=20not=20valid=20for=20the=20?= =?UTF-8?q?element=20

      ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: hannesw --- .../jdk/javadoc/internal/html/HtmlTree.java | 3 +- .../TestHtmlLandmarkRegions.java | 6 ++-- .../testHtmlVersion/TestHtmlVersion.java | 34 +++++++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java index 2d81a2914e6..f53a71a6999 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java @@ -586,8 +586,7 @@ public class HtmlTree extends Content { * @return the element */ public static HtmlTree FOOTER() { - return new HtmlTree(HtmlTag.FOOTER) - .setRole(HtmlAttr.Role.CONTENTINFO); + return new HtmlTree(HtmlTag.FOOTER); } /** diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java b/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java index a65e474a251..784efa9767d 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlLandmarkRegions/TestHtmlLandmarkRegions.java @@ -83,7 +83,7 @@ public class TestHtmlLandmarkRegions extends JavadocTester {

      Document Title

      """, """ -
      """, +
      """, """ bottom text""" ); @@ -113,7 +113,7 @@ public class TestHtmlLandmarkRegions extends JavadocTester {

      Document Title

      """, """ -
      """, +
      """, """ bottom text"""); } @@ -150,7 +150,7 @@ public class TestHtmlLandmarkRegions extends JavadocTester { """
      A sample doc file""", """ -
      """, +
      """, """ bottom text""" ); diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java index 15c85765d68..e9d7f7a795d 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java @@ -85,7 +85,7 @@ public class TestHtmlVersion extends JavadocTester {
    *

    - * If both "nu" and "rg" are specified, the decimal digits from the "nu" - * extension supersedes the implicit one from the "rg" extension. + * For both "nu" and "cu", if they are specified in addition to "rg", the respective + * values from the "nu" and "cu" extension supersede the implicit ones from the "rg" extension. * Although Unicode extensions * defines various keys and values, actual locale-sensitive service implementations * in a Java Runtime Environment might not support any particular Unicode locale From ec7361e082eff3859d9f0dd732f39ae9abd5089a Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Mon, 18 Aug 2025 23:07:57 +0000 Subject: [PATCH 123/471] 8365660: test/jdk/sun/security/pkcs11/KeyAgreement/ tests skipped without SkipExceprion Reviewed-by: rhalade --- .../pkcs11/KeyAgreement/SupportedDHKeys.java | 7 ++-- .../security/pkcs11/KeyAgreement/TestDH.java | 6 ++-- .../pkcs11/KeyAgreement/TestInterop.java | 6 ++-- .../pkcs11/KeyAgreement/TestShort.java | 35 ++++--------------- .../KeyAgreement/UnsupportedDHKeys.java | 7 ++-- 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java b/test/jdk/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java index c4f8e189937..d044934fb59 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/SupportedDHKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @run main/othervm SupportedDHKeys */ +import jtreg.SkippedException; + import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -62,8 +64,7 @@ public class SupportedDHKeys extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyPairGenerator", "DiffieHellman") == null) { - System.out.println("No support of DH KeyPairGenerator, skipping"); - return; + throw new SkippedException("No support of DH KeyPairGenerator, skipping"); } for (SupportedKeySize keySize : SupportedKeySize.values()) { diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java b/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java index 560459c2b09..1140ba75e12 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/TestDH.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -38,14 +38,14 @@ import java.util.Arrays; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestDH extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyAgreement", "DH") == null) { - System.out.println("DH not supported, skipping"); - return; + throw new SkippedException("DH not supported, skipping"); } String kpgAlgorithm = "DH"; KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java b/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java index 810814ebd5d..da15c41132a 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/TestInterop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -40,6 +40,7 @@ import javax.crypto.spec.DHPrivateKeySpec; import javax.crypto.spec.DHPublicKeySpec; import jdk.test.lib.security.DiffieHellmanGroup; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestInterop extends PKCS11Test { @@ -76,8 +77,7 @@ public class TestInterop extends PKCS11Test { @Override public void main(Provider prov) throws Exception { if (prov.getService("KeyAgreement", "DH") == null) { - System.out.println("DH not supported, skipping"); - return; + throw new SkippedException("DH not supported, skipping"); } try { System.out.println("testing generateSecret()"); diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/TestShort.java b/test/jdk/sun/security/pkcs11/KeyAgreement/TestShort.java index 27e6bcbc8a3..d0e03c21f36 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/TestShort.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/TestShort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -31,6 +31,8 @@ * @run main/othervm TestShort */ +import jtreg.SkippedException; + import java.math.BigInteger; import java.security.KeyFactory; import java.security.PrivateKey; @@ -90,12 +92,10 @@ public class TestShort extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyAgreement", "DH") == null) { - System.out.println("DH not supported, skipping"); - return; + throw new SkippedException("DH not supported, skipping"); } + try { - DHPublicKeySpec publicSpec; - DHPrivateKeySpec privateSpec; KeyFactory kf = KeyFactory.getInstance("DH", provider); KeyAgreement ka = KeyAgreement.getInstance("DH", provider); @@ -106,7 +106,7 @@ public class TestShort extends PKCS11Test { ka.init(pr1); ka.doPhase(pu2, true); byte[] n2 = ka.generateSecret(); - if (Arrays.equals(s2, n2) == false) { + if (!Arrays.equals(s2, n2)) { throw new Exception("mismatch 2"); } System.out.println("short ok"); @@ -114,7 +114,7 @@ public class TestShort extends PKCS11Test { ka.init(pr1); ka.doPhase(pu3, true); byte[] n3 = ka.generateSecret(); - if (Arrays.equals(s3, n3) == false) { + if (!Arrays.equals(s3, n3)) { throw new Exception("mismatch 3"); } System.out.println("normal ok"); @@ -123,27 +123,6 @@ public class TestShort extends PKCS11Test { ex.printStackTrace(); throw ex; } - -/* - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", provider); - kpg.initialize(512); -// KeyPair kp1 = kpg.generateKeyPair(); -// System.out.println(kp1.getPublic()); -// System.out.println(kp1.getPrivate()); - while (true) { - KeyAgreement ka = KeyAgreement.getInstance("DH", provider); - ka.init(pr1); - KeyPair kp2 = kpg.generateKeyPair(); - ka.doPhase(kp2.getPublic(), true); - byte[] sec = ka.generateSecret(); - if (sec.length == 64) { - System.out.println(kp2.getPrivate()); - System.out.println(kp2.getPublic()); - System.out.println(toString(sec)); - break; - } - } -/**/ } public static void main(String[] args) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java b/test/jdk/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java index b2a2c29e8af..1cd224c2362 100644 --- a/test/jdk/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java +++ b/test/jdk/sun/security/pkcs11/KeyAgreement/UnsupportedDHKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @run main/othervm UnsupportedDHKeys */ +import jtreg.SkippedException; + import java.security.InvalidParameterException; import java.security.KeyPairGenerator; import java.security.Provider; @@ -59,8 +61,7 @@ public class UnsupportedDHKeys extends PKCS11Test { @Override public void main(Provider provider) throws Exception { if (provider.getService("KeyPairGenerator", "DiffieHellman") == null) { - System.out.println("No supported of DH KeyPairGenerator, skipping"); - return; + throw new SkippedException("DH (DiffieHellman) is not supported in KeyPairGenerator, skipping"); } for (UnsupportedKeySize keySize : UnsupportedKeySize.values()) { From e04a31037588217a246a8dca6ce9a83a031c343d Mon Sep 17 00:00:00 2001 From: Shawn M Emery Date: Mon, 18 Aug 2025 23:54:06 +0000 Subject: [PATCH 124/471] 8364806: Test sun/security/krb5/config/IncludeRandom.java times out on Windows Reviewed-by: mbaesken --- test/jdk/sun/security/krb5/config/IncludeRandom.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/security/krb5/config/IncludeRandom.java b/test/jdk/sun/security/krb5/config/IncludeRandom.java index 11f93f17830..fe05917fd4c 100644 --- a/test/jdk/sun/security/krb5/config/IncludeRandom.java +++ b/test/jdk/sun/security/krb5/config/IncludeRandom.java @@ -53,7 +53,7 @@ public class IncludeRandom { public static void main(String[] args) throws Exception { System.setProperty("java.security.krb5.conf", "f"); - for (var i = 0; i < 10_000; i++) { + for (var i = 0; i < 1000; i++) { test(); } } From f2f7a490c091734ae1aa6cd402a117acbc1c699e Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Tue, 19 Aug 2025 04:40:45 +0000 Subject: [PATCH 125/471] 8365071: ARM32: JFR intrinsic jvm_commit triggers C2 regalloc assert Reviewed-by: mgronlun --- src/hotspot/share/opto/library_call.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6c5efaafc21..ab1b75ae7e6 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3275,7 +3275,7 @@ bool LibraryCallKit::inline_native_jvm_commit() { lease_compare_io->init_req(_true_path, i_o()); lease_compare_io->init_req(_false_path, input_io_state); - lease_result_value->init_req(_true_path, null()); // if the lease was returned, return 0. + lease_result_value->init_req(_true_path, _gvn.longcon(0)); // if the lease was returned, return 0L. lease_result_value->init_req(_false_path, arg); // if not lease, return new updated position. RegionNode* result_rgn = new RegionNode(PATH_LIMIT); From 655dc516c22ac84fccee6b1fdc607c492465be6b Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 19 Aug 2025 05:06:50 +0000 Subject: [PATCH 126/471] 8361842: Move input validation checks to Java for java.lang.StringCoding intrinsics Reviewed-by: rriggs, liach, dfenacci, thartmann, redestad, jrose --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 12 +- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 12 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 66 ++++++----- src/hotspot/share/classfile/vmIntrinsics.hpp | 6 +- src/hotspot/share/opto/c2_globals.hpp | 3 + src/hotspot/share/opto/library_call.cpp | 57 +++++++--- src/hotspot/share/opto/library_call.hpp | 3 +- .../share/classes/java/lang/String.java | 2 +- .../share/classes/java/lang/StringCoding.java | 93 ++++++++++++++-- .../share/classes/java/lang/System.java | 5 +- .../jdk/internal/access/JavaLangAccess.java | 19 ++-- .../share/classes/sun/nio/cs/CESU_8.java | 4 +- .../share/classes/sun/nio/cs/DoubleByte.java | 4 +- .../share/classes/sun/nio/cs/ISO_8859_1.java | 40 +++---- .../share/classes/sun/nio/cs/SingleByte.java | 2 +- .../share/classes/sun/nio/cs/US_ASCII.java | 2 +- .../share/classes/sun/nio/cs/UTF_8.java | 2 +- .../sun/nio/cs/ext/EUC_JP.java.template | 2 +- .../intrinsics/TestVerifyIntrinsicChecks.java | 104 ++++++++++++++++++ .../intrinsics/string/TestCountPositives.java | 30 ++++- .../string/TestEncodeIntrinsics.java | 22 +++- .../intrinsics/string/TestHasNegatives.java | 25 ++++- .../patches/java.base/java/lang/Helper.java | 5 + 23 files changed, 413 insertions(+), 107 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index e51b3c530de..fb307c8831a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -6421,10 +6421,14 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value) // Intrinsic for // -// - sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray -// return the number of characters copied. -// - java/lang/StringUTF16.compress -// return index of non-latin1 character if copy fails, otherwise 'len'. +// - sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// Encodes char[] to byte[] in ISO-8859-1 +// +// - java.lang.StringCoding#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// Encodes byte[] (containing UTF-16) to byte[] in ISO-8859-1 +// +// - java.lang.StringCoding#encodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len) +// Encodes char[] to byte[] in ASCII // // This version always returns the number of characters copied, and does not // clobber the 'len' register. A successful copy will complete with the post- diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index aac2c98fc86..e91af885d78 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2593,10 +2593,14 @@ void C2_MacroAssembler::char_array_compress_v(Register src, Register dst, Regist // Intrinsic for // -// - sun/nio/cs/ISO_8859_1$Encoder.implEncodeISOArray -// return the number of characters copied. -// - java/lang/StringUTF16.compress -// return index of non-latin1 character if copy fails, otherwise 'len'. +// - sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// Encodes char[] to byte[] in ISO-8859-1 +// +// - java.lang.StringCoding#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// Encodes byte[] (containing UTF-16) to byte[] in ISO-8859-1 +// +// - java.lang.StringCoding#encodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len) +// Encodes char[] to byte[] in ASCII // // This version always returns the number of characters copied. A successful // copy will complete with the post-condition: 'res' == 'len', while an diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 2d1005b8438..0b41d594194 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -6027,32 +6027,46 @@ void MacroAssembler::evpbroadcast(BasicType type, XMMRegister dst, Register src, } } -// encode char[] to byte[] in ISO_8859_1 or ASCII - //@IntrinsicCandidate - //private static int implEncodeISOArray(byte[] sa, int sp, - //byte[] da, int dp, int len) { - // int i = 0; - // for (; i < len; i++) { - // char c = StringUTF16.getChar(sa, sp++); - // if (c > '\u00FF') - // break; - // da[dp++] = (byte)c; - // } - // return i; - //} - // - //@IntrinsicCandidate - //private static int implEncodeAsciiArray(char[] sa, int sp, - // byte[] da, int dp, int len) { - // int i = 0; - // for (; i < len; i++) { - // char c = sa[sp++]; - // if (c >= '\u0080') - // break; - // da[dp++] = (byte)c; - // } - // return i; - //} +// Encode given char[]/byte[] to byte[] in ISO_8859_1 or ASCII +// +// @IntrinsicCandidate +// int sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0( +// char[] sa, int sp, byte[] da, int dp, int len) { +// int i = 0; +// for (; i < len; i++) { +// char c = sa[sp++]; +// if (c > '\u00FF') +// break; +// da[dp++] = (byte) c; +// } +// return i; +// } +// +// @IntrinsicCandidate +// int java.lang.StringCoding.encodeISOArray0( +// byte[] sa, int sp, byte[] da, int dp, int len) { +// int i = 0; +// for (; i < len; i++) { +// char c = StringUTF16.getChar(sa, sp++); +// if (c > '\u00FF') +// break; +// da[dp++] = (byte) c; +// } +// return i; +// } +// +// @IntrinsicCandidate +// int java.lang.StringCoding.encodeAsciiArray0( +// char[] sa, int sp, byte[] da, int dp, int len) { +// int i = 0; +// for (; i < len; i++) { +// char c = sa[sp++]; +// if (c >= '\u0080') +// break; +// da[dp++] = (byte) c; +// } +// return i; +// } void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, XMMRegister tmp1Reg, XMMRegister tmp2Reg, XMMRegister tmp3Reg, XMMRegister tmp4Reg, diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 3d110c5706b..c9c5c925f86 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -415,18 +415,18 @@ class methodHandle; \ do_class(java_lang_StringCoding, "java/lang/StringCoding") \ do_intrinsic(_countPositives, java_lang_StringCoding, countPositives_name, countPositives_signature, F_S) \ - do_name( countPositives_name, "countPositives") \ + do_name( countPositives_name, "countPositives0") \ do_signature(countPositives_signature, "([BII)I") \ \ do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \ do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \ - do_name( encodeISOArray_name, "implEncodeISOArray") \ + do_name( encodeISOArray_name, "encodeISOArray0") \ do_signature(encodeISOArray_signature, "([CI[BII)I") \ \ do_intrinsic(_encodeByteISOArray, java_lang_StringCoding, encodeISOArray_name, indexOfI_signature, F_S) \ \ do_intrinsic(_encodeAsciiArray, java_lang_StringCoding, encodeAsciiArray_name, encodeISOArray_signature, F_S) \ - do_name( encodeAsciiArray_name, "implEncodeAsciiArray") \ + do_name( encodeAsciiArray_name, "encodeAsciiArray0") \ \ do_class(java_math_BigInteger, "java/math/BigInteger") \ do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_S) \ diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 540b6600a0f..3a2d4cbdf96 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -666,6 +666,9 @@ product(bool, PrintIntrinsics, false, DIAGNOSTIC, \ "prints attempted and successful inlining of intrinsics") \ \ + develop(bool, VerifyIntrinsicChecks, false, \ + "Verify in intrinsic that Java level checks work as expected") \ + \ develop(bool, StressReflectiveCode, false, \ "Use inexact types at allocations, etc., to test reflection") \ \ diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index ab1b75ae7e6..da04d6b01ac 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -939,7 +939,11 @@ inline Node* LibraryCallKit::generate_limit_guard(Node* offset, } // Emit range checks for the given String.value byte array -void LibraryCallKit::generate_string_range_check(Node* array, Node* offset, Node* count, bool char_count) { +void LibraryCallKit::generate_string_range_check(Node* array, + Node* offset, + Node* count, + bool char_count, + bool halt_on_oob) { if (stopped()) { return; // already stopped } @@ -957,10 +961,17 @@ void LibraryCallKit::generate_string_range_check(Node* array, Node* offset, Node generate_limit_guard(offset, count, load_array_length(array), bailout); if (bailout->req() > 1) { - PreserveJVMState pjvms(this); - set_control(_gvn.transform(bailout)); - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_maybe_recompile); + if (halt_on_oob) { + bailout = _gvn.transform(bailout)->as_Region(); + Node* frame = _gvn.transform(new ParmNode(C->start(), TypeFunc::FramePtr)); + Node* halt = _gvn.transform(new HaltNode(bailout, frame, "unexpected guard failure in intrinsic")); + C->root()->add_req(halt); + } else { + PreserveJVMState pjvms(this); + set_control(_gvn.transform(bailout)); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_maybe_recompile); + } } } @@ -1118,6 +1129,7 @@ bool LibraryCallKit::inline_array_equals(StrIntrinsicNode::ArgEnc ae) { //------------------------------inline_countPositives------------------------------ +// int java.lang.StringCoding#countPositives0(byte[] ba, int off, int len) bool LibraryCallKit::inline_countPositives() { if (too_many_traps(Deoptimization::Reason_intrinsic)) { return false; @@ -1129,13 +1141,14 @@ bool LibraryCallKit::inline_countPositives() { Node* offset = argument(1); Node* len = argument(2); - ba = must_be_not_null(ba, true); - - // Range checks - generate_string_range_check(ba, offset, len, false); - if (stopped()) { - return true; + if (VerifyIntrinsicChecks) { + ba = must_be_not_null(ba, true); + generate_string_range_check(ba, offset, len, false, true); + if (stopped()) { + return true; + } } + Node* ba_start = array_element_address(ba, offset, T_BYTE); Node* result = new CountPositivesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len); set_result(_gvn.transform(result)); @@ -6128,6 +6141,9 @@ CallStaticJavaNode* LibraryCallKit::get_uncommon_trap_from_success_proj(Node* no } //-------------inline_encodeISOArray----------------------------------- +// int sun.nio.cs.ISO_8859_1.Encoder#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// int java.lang.StringCoding#encodeISOArray0(byte[] sa, int sp, byte[] da, int dp, int len) +// int java.lang.StringCoding#encodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len) // encode char[] to byte[] in ISO_8859_1 or ASCII bool LibraryCallKit::inline_encodeISOArray(bool ascii) { assert(callee()->signature()->size() == 5, "encodeISOArray has 5 parameters"); @@ -6138,8 +6154,14 @@ bool LibraryCallKit::inline_encodeISOArray(bool ascii) { Node *dst_offset = argument(3); Node *length = argument(4); - src = must_be_not_null(src, true); - dst = must_be_not_null(dst, true); + // Cast source & target arrays to not-null + if (VerifyIntrinsicChecks) { + src = must_be_not_null(src, true); + dst = must_be_not_null(dst, true); + if (stopped()) { + return true; + } + } const TypeAryPtr* src_type = src->Value(&_gvn)->isa_aryptr(); const TypeAryPtr* dst_type = dst->Value(&_gvn)->isa_aryptr(); @@ -6156,6 +6178,15 @@ bool LibraryCallKit::inline_encodeISOArray(bool ascii) { return false; } + // Check source & target bounds + if (VerifyIntrinsicChecks) { + generate_string_range_check(src, src_offset, length, src_elem == T_BYTE, true); + generate_string_range_check(dst, dst_offset, length, false, true); + if (stopped()) { + return true; + } + } + Node* src_start = array_element_address(src, src_offset, T_CHAR); Node* dst_start = array_element_address(dst, dst_offset, dst_elem); // 'src_start' points to src array + scaled offset diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index fbc6007d4e1..fbac1363dae 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -163,7 +163,8 @@ class LibraryCallKit : public GraphKit { Node* array_length, RegionNode* region); void generate_string_range_check(Node* array, Node* offset, - Node* length, bool char_count); + Node* length, bool char_count, + bool halt_on_oob = false); Node* current_thread_helper(Node* &tls_output, ByteSize handle_offset, bool is_immutable); Node* generate_current_thread(Node* &tls_output); diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index eac8a1355b7..01c26538642 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1019,7 +1019,7 @@ public final class String int sp = 0; int sl = len; while (sp < sl) { - int ret = StringCoding.implEncodeISOArray(val, sp, dst, dp, len); + int ret = StringCoding.encodeISOArray(val, sp, dst, dp, len); sp = sp + ret; dp = dp + ret; if (ret != len) { diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index c02af28c37d..545f216b755 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,8 +26,11 @@ package java.lang; +import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; +import java.util.function.BiFunction; + /** * Utility class for string encoding and decoding. */ @@ -38,7 +41,7 @@ class StringCoding { /** * Count the number of leading non-zero ascii chars in the range. */ - public static int countNonZeroAscii(String s) { + static int countNonZeroAscii(String s) { byte[] value = s.value(); if (s.isLatin1()) { return countNonZeroAsciiLatin1(value, 0, value.length); @@ -50,7 +53,7 @@ class StringCoding { /** * Count the number of non-zero ascii chars in the range. */ - public static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { + private static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { int limit = off + len; for (int i = off; i < limit; i++) { if (ba[i] <= 0) { @@ -63,7 +66,7 @@ class StringCoding { /** * Count the number of leading non-zero ascii chars in the range. */ - public static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { + private static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { int limit = off + strlen; for (int i = off; i < limit; i++) { char c = StringUTF16.charAt(ba, i); @@ -74,7 +77,7 @@ class StringCoding { return strlen; } - public static boolean hasNegatives(byte[] ba, int off, int len) { + static boolean hasNegatives(byte[] ba, int off, int len) { return countPositives(ba, off, len) != len; } @@ -85,9 +88,24 @@ class StringCoding { * bytes in the range. If there are negative bytes, the implementation must return * a value that is less than or equal to the index of the first negative byte * in the range. + * + * @param ba a byte array + * @param off the index of the first byte to start reading from + * @param len the total number of bytes to read + * @throws NullPointerException if {@code ba} is null + * @throws ArrayIndexOutOfBoundsException if the provided sub-range is + * {@linkplain Preconditions#checkFromIndexSize(int, int, int, BiFunction) out of bounds} */ + static int countPositives(byte[] ba, int off, int len) { + Preconditions.checkFromIndexSize( + off, len, + ba.length, // Implicit null check on `ba` + Preconditions.AIOOBE_FORMATTER); + return countPositives0(ba, off, len); + } + @IntrinsicCandidate - public static int countPositives(byte[] ba, int off, int len) { + private static int countPositives0(byte[] ba, int off, int len) { int limit = off + len; for (int i = off; i < limit; i++) { if (ba[i] < 0) { @@ -97,9 +115,37 @@ class StringCoding { return len; } + /** + * Encodes as many ISO-8859-1 codepoints as possible from the source byte + * array containing characters encoded in UTF-16, into the destination byte + * array, assuming that the encoding is ISO-8859-1 compatible. + * + * @param sa the source byte array containing characters encoded in UTF-16 + * @param sp the index of the character (not byte!) from the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the maximum number of characters (not bytes!) to be encoded + * @return the total number of characters (not bytes!) successfully encoded + * @throws NullPointerException if any of the provided arrays is null + */ + static int encodeISOArray(byte[] sa, int sp, + byte[] da, int dp, int len) { + // This method should tolerate invalid arguments, matching the lenient behavior of the VM intrinsic. + // Hence, using operator expressions instead of `Preconditions`, which throw on failure. + int sl; + if ((sp | dp | len) < 0 || + // Halving the length of `sa` to obtain the number of characters: + sp >= (sl = sa.length >>> 1) || // Implicit null check on `sa` + dp >= da.length) { // Implicit null check on `da` + return 0; + } + int minLen = Math.min(len, Math.min(sl - sp, da.length - dp)); + return encodeISOArray0(sa, sp, da, dp, minLen); + } + @IntrinsicCandidate - public static int implEncodeISOArray(byte[] sa, int sp, - byte[] da, int dp, int len) { + private static int encodeISOArray0(byte[] sa, int sp, + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = StringUTF16.getChar(sa, sp++); @@ -110,10 +156,35 @@ class StringCoding { return i; } + /** + * Encodes as many ASCII codepoints as possible from the source + * character array into the destination byte array, assuming that + * the encoding is ASCII compatible. + * + * @param sa the source character array + * @param sp the index of the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the maximum number of characters to be encoded + * @return the total number of characters successfully encoded + * @throws NullPointerException if any of the provided arrays is null + */ + static int encodeAsciiArray(char[] sa, int sp, + byte[] da, int dp, int len) { + // This method should tolerate invalid arguments, matching the lenient behavior of the VM intrinsic. + // Hence, using operator expressions instead of `Preconditions`, which throw on failure. + if ((sp | dp | len) < 0 || + sp >= sa.length || // Implicit null check on `sa` + dp >= da.length) { // Implicit null check on `da` + return 0; + } + int minLen = Math.min(len, Math.min(sa.length - sp, da.length - dp)); + return encodeAsciiArray0(sa, sp, da, dp, minLen); + } + @IntrinsicCandidate - public static int implEncodeAsciiArray(char[] sa, int sp, - byte[] da, int dp, int len) - { + static int encodeAsciiArray0(char[] sa, int sp, + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = sa[sp++]; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 1d62d698896..cc90ca0d235 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -55,7 +55,6 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.ScheduledExecutorService; import java.util.function.Supplier; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -2156,8 +2155,8 @@ public final class System { return String.decodeASCII(src, srcOff, dst, dstOff, len); } - public int uncheckedEncodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len) { - return StringCoding.implEncodeAsciiArray(src, srcOff, dst, dstOff, len); + public int encodeASCII(char[] sa, int sp, byte[] da, int dp, int len) { + return StringCoding.encodeAsciiArray(sa, sp, da, dp, len); } public InputStream initialSystemIn() { diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index efa36b5b2d8..5ceeff99002 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,6 +45,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; +import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -422,15 +423,19 @@ public interface JavaLangAccess { PrintStream initialSystemErr(); /** - * Encodes as many ASCII codepoints as possible from the source array into - * the destination byte array, assuming that the encoding is ASCII - * compatible. - *

    - * WARNING: This method does not perform any bound checks. + * Encodes as many ASCII codepoints as possible from the source + * character array into the destination byte array, assuming that + * the encoding is ASCII compatible. * - * @return the number of bytes successfully encoded, or 0 if none + * @param sa the source character array + * @param sp the index of the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the total number of characters to be encoded + * @return the total number of characters successfully encoded + * @throws NullPointerException if any of the provided arrays is null */ - int uncheckedEncodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len); + int encodeASCII(char[] sa, int sp, byte[] da, int dp, int len); /** * Set the cause of Throwable diff --git a/src/java.base/share/classes/sun/nio/cs/CESU_8.java b/src/java.base/share/classes/sun/nio/cs/CESU_8.java index a9a25e151ad..9b907bcbc65 100644 --- a/src/java.base/share/classes/sun/nio/cs/CESU_8.java +++ b/src/java.base/share/classes/sun/nio/cs/CESU_8.java @@ -446,7 +446,7 @@ class CESU_8 extends Unicode int dl = dst.arrayOffset() + dst.limit(); // Handle ASCII-only prefix - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; @@ -551,7 +551,7 @@ class CESU_8 extends Unicode int dp = 0; // Handle ASCII-only prefix - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(len, da.length)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(len, da.length)); sp += n; dp += n; diff --git a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java index 4738f51515b..165e1e21c0f 100644 --- a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java @@ -600,7 +600,7 @@ public class DoubleByte { try { if (isASCIICompatible) { - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); sp += n; dp += n; } @@ -686,7 +686,7 @@ public class DoubleByte { int dp = 0; int sl = sp + len; if (isASCIICompatible) { - int n = JLA.uncheckedEncodeASCII(src, sp, dst, dp, len); + int n = JLA.encodeASCII(src, sp, dst, dp, len); sp += n; dp += n; } diff --git a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java index 39215bfa93d..ff5970e92a8 100644 --- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java @@ -35,7 +35,6 @@ import java.util.Objects; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; public class ISO_8859_1 @@ -142,20 +141,34 @@ public class ISO_8859_1 private final Surrogate.Parser sgp = new Surrogate.Parser(); - // Method possible replaced with a compiler intrinsic. + /** + * Encodes as many ISO-8859-1 codepoints as possible from the source + * character array into the destination byte array, assuming that + * the encoding is ISO-8859-1 compatible. + * + * @param sa the source character array + * @param sp the index of the source array to start reading from + * @param da the target byte array + * @param dp the index of the target array to start writing to + * @param len the maximum number of characters to be encoded + * @return the total number of characters successfully encoded + * @throws NullPointerException if any of the provided arrays is null + */ private static int encodeISOArray(char[] sa, int sp, byte[] da, int dp, int len) { - if (len <= 0) { + // This method should tolerate invalid arguments, matching the lenient behavior of the VM intrinsic. + // Hence, using operator expressions instead of `Preconditions`, which throw on failure. + if ((sp | dp | len) < 0 || + sp >= sa.length || // Implicit null check on `sa` + dp >= da.length) { // Implicit null check on `da` return 0; } - encodeISOArrayCheck(sa, sp, da, dp, len); - return implEncodeISOArray(sa, sp, da, dp, len); + int minLen = Math.min(len, Math.min(sa.length - sp, da.length - dp)); + return encodeISOArray0(sa, sp, da, dp, minLen); } @IntrinsicCandidate - private static int implEncodeISOArray(char[] sa, int sp, - byte[] da, int dp, int len) - { + private static int encodeISOArray0(char[] sa, int sp, byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = sa[sp++]; @@ -166,17 +179,6 @@ public class ISO_8859_1 return i; } - private static void encodeISOArrayCheck(char[] sa, int sp, - byte[] da, int dp, int len) { - Objects.requireNonNull(sa); - Objects.requireNonNull(da); - Preconditions.checkIndex(sp, sa.length, Preconditions.AIOOBE_FORMATTER); - Preconditions.checkIndex(dp, da.length, Preconditions.AIOOBE_FORMATTER); - - Preconditions.checkIndex(sp + len - 1, sa.length, Preconditions.AIOOBE_FORMATTER); - Preconditions.checkIndex(dp + len - 1, da.length, Preconditions.AIOOBE_FORMATTER); - } - private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { diff --git a/src/java.base/share/classes/sun/nio/cs/SingleByte.java b/src/java.base/share/classes/sun/nio/cs/SingleByte.java index d802cc85aa8..8efa6b295ff 100644 --- a/src/java.base/share/classes/sun/nio/cs/SingleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/SingleByte.java @@ -217,7 +217,7 @@ public class SingleByte int len = Math.min(dl - dp, sl - sp); if (isASCIICompatible) { - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, len); + int n = JLA.encodeASCII(sa, sp, da, dp, len); sp += n; dp += n; len -= n; diff --git a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java index bb84ab1bd4b..3886978d209 100644 --- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java +++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java @@ -159,7 +159,7 @@ public class US_ASCII assert (dp <= dl); dp = (dp <= dl ? dp : dl); - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; diff --git a/src/java.base/share/classes/sun/nio/cs/UTF_8.java b/src/java.base/share/classes/sun/nio/cs/UTF_8.java index 54e479f838a..d2d6d7e485d 100644 --- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java +++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java @@ -452,7 +452,7 @@ public final class UTF_8 extends Unicode { int dl = dst.arrayOffset() + dst.limit(); // Handle ASCII-only prefix - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; diff --git a/src/jdk.charsets/share/classes/sun/nio/cs/ext/EUC_JP.java.template b/src/jdk.charsets/share/classes/sun/nio/cs/ext/EUC_JP.java.template index 4fc0b2796ee..f3d03a9e9c7 100644 --- a/src/jdk.charsets/share/classes/sun/nio/cs/ext/EUC_JP.java.template +++ b/src/jdk.charsets/share/classes/sun/nio/cs/ext/EUC_JP.java.template @@ -309,7 +309,7 @@ public class EUC_JP try { if (enc0201.isASCIICompatible()) { - int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); sp += n; dp += n; } diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java new file mode 100644 index 00000000000..392ca35e2fd --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8361842 + * @summary Verify the effectiveness of the `VerifyIntrinsicChecks` VM flag + * through (bypassing `StringCoding::encodeAsciiArray`, and) feeding + * invalid input to an intrinsified `StringCoding::encodeAsciiArray0` + * (note the `0` suffix!). + * @library /compiler/patches + * @library /test/lib + * @build java.base/java.lang.Helper + * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a + * development flag + * @requires vm.debug == true & vm.flavor == "server" & !vm.graal.enabled + * @run main/othervm compiler.intrinsics.TestVerifyIntrinsicChecks verify + */ + +package compiler.intrinsics; + +import java.lang.Helper; +import java.time.Instant; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public final class TestVerifyIntrinsicChecks { + + public static void main(String[] args) throws Exception { + switch (args[0]) { + case "verify" -> { + log("Starting JVM in a separate process to verify the crash"); + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( + "-Xcomp", + "-XX:-TieredCompilation", + "-XX:CompileCommand=inline,java.lang.StringCoding::encodeAsciiArray0", + "-XX:+VerifyIntrinsicChecks", + "--patch-module", "java.base=%s/java.base".formatted(System.getProperty("test.patch.path")), + "compiler.intrinsics.TestVerifyIntrinsicChecks", + "crash"); + outputAnalyzer.shouldContain("unexpected null in intrinsic"); + outputAnalyzer.shouldNotHaveExitValue(0); + } + case "crash" -> { + log("Triggering the crash"); + warmUpIntrinsicMethod(); + violateIntrinsicMethodContract(); + } + default -> throw new IllegalArgumentException(); + } + } + + private static void warmUpIntrinsicMethod() { + log("Warming up the intrinsic method"); + char[] sa = createAsciiChars(8192); + byte[] sp = new byte[4096]; + for (int i = 0; i < 1_000; i++) { + Helper.StringCodingEncodeAsciiArray0(sa, i, sp, 0, sp.length - i); + } + } + + private static char[] createAsciiChars(int length) { + char[] buffer = new char[length]; + for (int i = 0; i < length; i++) { + buffer[i] = (char) (i % '\u0080'); + } + return buffer; + } + + private static void violateIntrinsicMethodContract() { + log("Violating the intrinsic method contract (sa=null)"); + Helper.StringCodingEncodeAsciiArray0(null, 1, null, 1, 1); + } + + private synchronized static void log(String format, Object... args) { + Object[] extendedArgs = new Object[2 + args.length]; + extendedArgs[0] = Instant.now(); + extendedArgs[1] = Thread.currentThread().getName(); + System.arraycopy(args, 0, extendedArgs, extendedArgs.length - args.length, args.length); + String extendedFormat = "%%s [%%s] %s%%n".formatted(format); + System.out.printf(extendedFormat, extendedArgs); + } + +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java index 76ef4766159..1c20a49d281 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -32,6 +32,7 @@ * @build java.base/java.lang.Helper * @run main compiler.intrinsics.string.TestCountPositives */ + /* * @test * @bug 8281146 8318509 @@ -46,17 +47,38 @@ * @run main/othervm/timeout=1200 -XX:UseAVX=3 compiler.intrinsics.string.TestCountPositives * @run main/othervm/timeout=1200 -XX:UseAVX=3 -XX:+UnlockDiagnosticVMOptions -XX:AVX3Threshold=0 compiler.intrinsics.string.TestCountPositives */ -/** - * This test was derived from compiler.intrinsics.string.TestHasNegatives + +/* + * @test + * @bug 8281146 + * @summary Verify `StringCoding::countPositives` intrinsic Java wrapper checks + * by enabling the ones in the VM intrinsic using + * `-XX:+VerifyIntrinsicChecks` + * @comment This does not check out-of-range conditions. The + * `-XX:+VerifyIntrinsicChecks` version of this test simply ensures + * that the VM intrinsic will produce no spurious errors. + * @key randomness + * @library /compiler/patches + * @library /test/lib + * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a + * development flag + * @requires vm.debug == true + * @build java.base/java.lang.Helper + * @run main/othervm + * -XX:+VerifyIntrinsicChecks + * compiler.intrinsics.string.TestCountPositives */ + package compiler.intrinsics.string; import java.lang.Helper; import java.util.Random; -import java.util.stream.IntStream; import jdk.test.lib.Utils; +/** + * This test was derived from {@link TestHasNegatives}. + */ public class TestCountPositives { private static byte[] bytes = new byte[4096 + 32]; diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java index 38a516e7521..bb343b246ff 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -31,6 +31,26 @@ * @run main/othervm/timeout=1200 --add-opens=java.base/sun.nio.cs=ALL-UNNAMED -Xbatch -Xmx256m compiler.intrinsics.string.TestEncodeIntrinsics */ +/* + * @test + * @bug 6896617 8274242 + * @summary Verify `sun.nio.cs.ISO_8859_1.Encoder::encodeISOArray` intrinsic + * Java wrapper checks by enabling the ones in the VM intrinsic using + * `-XX:+VerifyIntrinsicChecks` + * @comment This does not check out-of-range conditions. The + * `-XX:+VerifyIntrinsicChecks` version of this test simply ensures + * that the VM intrinsic will produce no spurious errors. + * @key randomness + * @library /test/lib + * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a + * development flag + * @requires vm.debug == true + * @run main/othervm/timeout=1200 + * -XX:+VerifyIntrinsicChecks + * --add-opens=java.base/sun.nio.cs=ALL-UNNAMED -Xbatch -Xmx256m + * compiler.intrinsics.string.TestEncodeIntrinsics + */ + package compiler.intrinsics.string; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java index 6edf2dc2e56..a15f6aade2e 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -31,6 +31,7 @@ * @build java.base/java.lang.Helper * @run main compiler.intrinsics.string.TestHasNegatives */ + /* * @test * @bug 8054307 8318509 @@ -46,11 +47,31 @@ * @run main/othervm/timeout=1200 -XX:UseAVX=3 -XX:+UnlockDiagnosticVMOptions -XX:AVX3Threshold=0 compiler.intrinsics.string.TestHasNegatives */ +/* + * @test + * @bug 8054307 + * @summary Verify `StringCoding::hasNegatives` intrinsic Java wrapper checks + * by enabling the ones in the VM intrinsic using + * `-XX:+VerifyIntrinsicChecks` + * @comment This does not check out-of-range conditions. The + * `-XX:+VerifyIntrinsicChecks` version of this test simply ensures + * that the VM intrinsic will produce no spurious errors. + * @key randomness + * @library /compiler/patches + * @library /test/lib + * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a + * development flag + * @requires vm.debug == true + * @build java.base/java.lang.Helper + * @run main/othervm + * -XX:+VerifyIntrinsicChecks + * compiler.intrinsics.string.TestHasNegatives + */ + package compiler.intrinsics.string; import java.lang.Helper; import java.util.Random; -import java.util.stream.IntStream; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index e6c8b68fc6f..3985ad8ea90 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -39,6 +39,11 @@ public class Helper { return StringCoding.countPositives(ba, off, len); } + @jdk.internal.vm.annotation.ForceInline + public static int StringCodingEncodeAsciiArray0(char[] sa, int sp, byte[] da, int dp, int len) { + return StringCoding.encodeAsciiArray0(sa, sp, da, dp, len); + } + @jdk.internal.vm.annotation.ForceInline public static byte[] compressByte(byte[] src, int srcOff, int dstSize, int dstOff, int len) { byte[] dst = new byte[dstSize]; From 4c80780f6a3fef688d932bdad04e98eb1bd16563 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 19 Aug 2025 06:33:12 +0000 Subject: [PATCH 127/471] 8359380: Rework deferral profile logic after JDK-8346465 Reviewed-by: prr --- .../classes/java/awt/color/ICC_Profile.java | 63 ++++----- .../java/awt/color/ICC_ProfileGray.java | 8 +- .../java/awt/color/ICC_ProfileRGB.java | 10 +- ...erralInfo.java => BuiltinProfileInfo.java} | 16 +-- .../sun/java2d/cmm/lcms/LCMSTransform.java | 4 +- .../awt/color/CheckDefaultProperties.java | 38 ++--- .../BuiltInProfileCheck.java | 2 +- .../GetProfileDataAfterTransform.java | 131 ++++++++++++++++++ 8 files changed, 196 insertions(+), 76 deletions(-) rename src/java.desktop/share/classes/sun/java2d/cmm/{ProfileDeferralInfo.java => BuiltinProfileInfo.java} (74%) create mode 100644 test/jdk/java/awt/color/ICC_Profile/GetProfileDataAfterTransform.java diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index 3793b138a96..8bf09195627 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -51,11 +51,11 @@ import java.util.Objects; import java.util.StringTokenizer; import sun.awt.AWTAccessor; +import sun.java2d.cmm.BuiltinProfileInfo; import sun.java2d.cmm.CMSManager; import sun.java2d.cmm.PCMM; import sun.java2d.cmm.Profile; import sun.java2d.cmm.ProfileDataVerifier; -import sun.java2d.cmm.ProfileDeferralInfo; import static sun.java2d.cmm.ProfileDataVerifier.HEADER_SIZE; @@ -102,20 +102,11 @@ public sealed class ICC_Profile implements Serializable private transient volatile Profile cmmProfile; /** - * Stores some information about {@code ICC_Profile} without causing a - * deferred profile to be loaded. Note that we can defer the loading of - * standard profiles only. If this field is null, then {@link #cmmProfile} - * should be used to access profile information. + * Stores information about a built-in profile without triggering profile + * loading. If this field is null, {@link #cmmProfile} should be used to + * access profile data. If not null, the profile is considered immutable. */ - private transient volatile ProfileDeferralInfo deferralInfo; - - - /** - * Set to {@code true} for {@code BuiltInProfile}, {@code false} otherwise. - * This flag is used in {@link #setData(int, byte[])} to prevent modifying - * built-in profiles. - */ - private final transient boolean builtIn; + private transient final BuiltinProfileInfo builtInInfo; /** * The lazy registry of singleton profile objects for specific built-in @@ -124,22 +115,22 @@ public sealed class ICC_Profile implements Serializable */ private interface BuiltInProfile { /* - * ProfileDeferralInfo is used for built-in profile creation only, + * BuiltinProfileInfo is used for built-in profile creation only, * and all built-in profiles should be constructed using it. */ - ICC_Profile SRGB = new ICC_ProfileRGB(new ProfileDeferralInfo( + ICC_Profile SRGB = new ICC_ProfileRGB(new BuiltinProfileInfo( "sRGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY)); - ICC_Profile LRGB = new ICC_ProfileRGB(new ProfileDeferralInfo( + ICC_Profile LRGB = new ICC_ProfileRGB(new BuiltinProfileInfo( "LINEAR_RGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY)); - ICC_Profile XYZ = new ICC_Profile(new ProfileDeferralInfo( + ICC_Profile XYZ = new ICC_Profile(new BuiltinProfileInfo( "CIEXYZ.pf", ColorSpace.TYPE_XYZ, 3, CLASS_ABSTRACT)); - ICC_Profile PYCC = new ICC_Profile(new ProfileDeferralInfo( + ICC_Profile PYCC = new ICC_Profile(new BuiltinProfileInfo( "PYCC.pf", ColorSpace.TYPE_3CLR, 3, CLASS_COLORSPACECONVERSION)); - ICC_Profile GRAY = new ICC_ProfileGray(new ProfileDeferralInfo( + ICC_Profile GRAY = new ICC_ProfileGray(new BuiltinProfileInfo( "GRAY.pf", ColorSpace.TYPE_GRAY, 1, CLASS_DISPLAY)); } @@ -771,7 +762,7 @@ public sealed class ICC_Profile implements Serializable */ ICC_Profile(Profile p) { cmmProfile = p; - builtIn = false; + builtInInfo = null; } /** @@ -779,12 +770,11 @@ public sealed class ICC_Profile implements Serializable * The ID will be 0 until the profile is loaded. * *

    - * Note: {@code ProfileDeferralInfo} is used for built-in profile + * Note: {@code BuiltinProfileInfo} is used for built-in profile * creation only, and all built-in profiles should be constructed using it. */ - ICC_Profile(ProfileDeferralInfo pdi) { - deferralInfo = pdi; - builtIn = true; + ICC_Profile(BuiltinProfileInfo bpi) { + builtInInfo = bpi; } /** @@ -934,7 +924,7 @@ public sealed class ICC_Profile implements Serializable if (cmmProfile != null) { return cmmProfile; } - var is = getStandardProfileInputStream(deferralInfo.filename); + var is = getStandardProfileInputStream(builtInInfo.filename); if (is == null) { return null; } @@ -942,8 +932,6 @@ public sealed class ICC_Profile implements Serializable byte[] data = getProfileDataFromStream(is); if (data != null) { p = cmmProfile = CMSManager.getModule().loadProfile(data); - // from now we cannot use the deferred value, drop it - deferralInfo = null; } } catch (CMMException | IOException ignore) { } @@ -975,9 +963,8 @@ public sealed class ICC_Profile implements Serializable * @return one of the predefined profile class constants */ public int getProfileClass() { - ProfileDeferralInfo info = deferralInfo; - if (info != null) { - return info.profileClass; + if (builtInInfo != null) { + return builtInInfo.profileClass; } byte[] theHeader = getData(cmmProfile(), icSigHead); return getProfileClass(theHeader); @@ -1012,9 +999,8 @@ public sealed class ICC_Profile implements Serializable * {@code ColorSpace} class */ public int getColorSpaceType() { - ProfileDeferralInfo info = deferralInfo; - if (info != null) { - return info.colorSpaceType; + if (builtInInfo != null) { + return builtInInfo.colorSpaceType; } byte[] theHeader = getData(cmmProfile(), icSigHead); return getColorSpaceType(theHeader); @@ -1160,8 +1146,8 @@ public sealed class ICC_Profile implements Serializable * @see ColorSpace */ public void setData(int tagSignature, byte[] tagData) { - if (builtIn) { - throw new IllegalArgumentException("Built-in profile cannot be modified"); + if (builtInInfo != null) { + throw new IllegalArgumentException("Can't modify built-in profile"); } if (tagSignature == ICC_Profile.icSigHead) { @@ -1205,9 +1191,8 @@ public sealed class ICC_Profile implements Serializable * @throws ProfileDataException if color space is in the profile is invalid */ public int getNumComponents() { - ProfileDeferralInfo info = deferralInfo; - if (info != null) { - return info.numComponents; + if (builtInInfo != null) { + return builtInInfo.numComponents; } byte[] theHeader = getData(cmmProfile(), icSigHead); int theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace); diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java index 523668d37ec..f8de7d1581d 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java @@ -37,8 +37,8 @@ package java.awt.color; import java.io.Serial; +import sun.java2d.cmm.BuiltinProfileInfo; import sun.java2d.cmm.Profile; -import sun.java2d.cmm.ProfileDeferralInfo; /** * The {@code ICC_ProfileGray} class is a subclass of the {@code ICC_Profile} @@ -87,10 +87,10 @@ public final class ICC_ProfileGray extends ICC_Profile { /** * Constructs a new {@code ICC_ProfileGray} from a - * {@code ProfileDeferralInfo} object. + * {@code BuiltinProfileInfo} object. */ - ICC_ProfileGray(ProfileDeferralInfo pdi) { - super(pdi); + ICC_ProfileGray(BuiltinProfileInfo bpi) { + super(bpi); } /** diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java index d46852380f3..1c7fab265ac 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java @@ -37,8 +37,8 @@ package java.awt.color; import java.io.Serial; +import sun.java2d.cmm.BuiltinProfileInfo; import sun.java2d.cmm.Profile; -import sun.java2d.cmm.ProfileDeferralInfo; /** * The {@code ICC_ProfileRGB} class is a subclass of the {@code ICC_Profile} @@ -122,12 +122,10 @@ public final class ICC_ProfileRGB extends ICC_Profile { /** * Constructs a new {@code ICC_ProfileRGB} from a - * {@code ProfileDeferralInfo} object. - * - * @param pdi + * {@code BuiltinProfileInfo} object. */ - ICC_ProfileRGB(ProfileDeferralInfo pdi) { - super(pdi); + ICC_ProfileRGB(BuiltinProfileInfo bpi) { + super(bpi); } /** diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralInfo.java b/src/java.desktop/share/classes/sun/java2d/cmm/BuiltinProfileInfo.java similarity index 74% rename from src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralInfo.java rename to src/java.desktop/share/classes/sun/java2d/cmm/BuiltinProfileInfo.java index 522ffa21453..f9f96235d3a 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralInfo.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/BuiltinProfileInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -26,15 +26,15 @@ package sun.java2d.cmm; /** - * A class to pass information about a profile to be loaded from a file to the - * static getInstance(int cspace) method of ICC_Profile. Loading of the profile - * data and initialization of the CMM is to be deferred as long as possible. + * Stores information about a built-in profile used by + * ICC_Profile.getInstance(int cspace) to defer the loading of profile data and + * CMM initialization. Since built-in profiles are immutable, this information + * is always valid. */ -public final class ProfileDeferralInfo { +public final class BuiltinProfileInfo { /** - * Need to have this info for ICC_ColorSpace without causing a deferred - * profile to be loaded. + * Used by ICC_ColorSpace without triggering built-in profile loading. */ public final int colorSpaceType, numComponents, profileClass; @@ -43,7 +43,7 @@ public final class ProfileDeferralInfo { */ public final String filename; - public ProfileDeferralInfo(String fn, int type, int ncomp, int pclass) { + public BuiltinProfileInfo(String fn, int type, int ncomp, int pclass) { filename = fn; colorSpaceType = type; numComponents = ncomp; diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 59f023a9aa2..881a6556ace 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -82,7 +82,7 @@ final class LCMSTransform implements ColorTransform { lcmsProfiles = new LCMSProfile[profiles.length]; for (int i = 0; i < profiles.length; i++) { lcmsProfiles[i] = LCMS.getLcmsProfile(acc.cmmProfile(profiles[i])); - profiles[i].getNumComponents(); // force header initialization + profiles[i].getMajorVersion(); // force header initialization } this.renderingIntent = (renderingIntent == ColorTransform.Any) ? ICC_Profile.icPerceptual : renderingIntent; diff --git a/test/jdk/java/awt/color/CheckDefaultProperties.java b/test/jdk/java/awt/color/CheckDefaultProperties.java index 583c46da7e1..fd44a7e669b 100644 --- a/test/jdk/java/awt/color/CheckDefaultProperties.java +++ b/test/jdk/java/awt/color/CheckDefaultProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -34,8 +34,9 @@ import static java.awt.color.ICC_Profile.CLASS_DISPLAY; /** * @test - * @bug 8256321 - * @summary Verifies profile properties are the same before/after activation + * @bug 8256321 8359380 + * @summary Verifies built-in profile properties are the same before and after + * activation and in copies of built-in profiles */ public final class CheckDefaultProperties { @@ -46,21 +47,26 @@ public final class CheckDefaultProperties { ICC_Profile lrgb = ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB); ICC_Profile pycc = ICC_Profile.getInstance(ColorSpace.CS_PYCC); - // check default values, before profile activation - test(srgb, TYPE_RGB, 3, CLASS_DISPLAY); - test(gray, TYPE_GRAY, 1, CLASS_DISPLAY); - test(xyz, TYPE_XYZ, 3, CLASS_ABSTRACT); - test(lrgb, TYPE_RGB, 3, CLASS_DISPLAY); - test(pycc, TYPE_3CLR, 3, CLASS_COLORSPACECONVERSION); + // checks default values before built-in profiles are activated + test(srgb, gray, xyz, lrgb, pycc); - // activate profiles - srgb.getData(); - gray.getData(); - xyz.getData(); - lrgb.getData(); - pycc.getData(); + // activates built-in profiles and creates copies + ICC_Profile srgbCopy = ICC_Profile.getInstance(srgb.getData()); + ICC_Profile grayCopy = ICC_Profile.getInstance(gray.getData()); + ICC_Profile xyzCopy = ICC_Profile.getInstance(xyz.getData()); + ICC_Profile lrgbCopy = ICC_Profile.getInstance(lrgb.getData()); + ICC_Profile pyccCopy = ICC_Profile.getInstance(pycc.getData()); - // check default values, after profile activation + // checks default values after profile activation + test(srgb, gray, xyz, lrgb, pycc); + + // checks default values in copies of the built-in profiles + test(srgbCopy, grayCopy, xyzCopy, lrgbCopy, pyccCopy); + } + + private static void test(ICC_Profile srgb, ICC_Profile gray, + ICC_Profile xyz, ICC_Profile lrgb, + ICC_Profile pycc) { test(srgb, TYPE_RGB, 3, CLASS_DISPLAY); test(gray, TYPE_GRAY, 1, CLASS_DISPLAY); test(xyz, TYPE_XYZ, 3, CLASS_ABSTRACT); diff --git a/test/jdk/java/awt/color/ICC_Profile/BuiltInProfileCheck/BuiltInProfileCheck.java b/test/jdk/java/awt/color/ICC_Profile/BuiltInProfileCheck/BuiltInProfileCheck.java index 8f00ab10747..6cc10c47550 100644 --- a/test/jdk/java/awt/color/ICC_Profile/BuiltInProfileCheck/BuiltInProfileCheck.java +++ b/test/jdk/java/awt/color/ICC_Profile/BuiltInProfileCheck/BuiltInProfileCheck.java @@ -39,7 +39,7 @@ import java.util.Map; public class BuiltInProfileCheck { private static final int HEADER_TAG = ICC_Profile.icSigHead; private static final int INDEX = ICC_Profile.icHdrDeviceClass; - private static final String EXCEPTION_MSG = "Built-in profile cannot be modified"; + private static final String EXCEPTION_MSG = "Can't modify built-in profile"; /** * {@link #prepareTestProfile(String, boolean, int)} * stores the profile to test in testProfile. diff --git a/test/jdk/java/awt/color/ICC_Profile/GetProfileDataAfterTransform.java b/test/jdk/java/awt/color/ICC_Profile/GetProfileDataAfterTransform.java new file mode 100644 index 00000000000..e6a436ba81e --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/GetProfileDataAfterTransform.java @@ -0,0 +1,131 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorConvertOp; +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/** + * @test + * @bug 8272860 8359380 + * @summary Verifies that ICC_Profile methods work correctly after a + * ColorConvertOp transformation + * @library /test/lib + */ +public final class GetProfileDataAfterTransform { + + private static final int[] CSS = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, + ColorSpace.CS_LINEAR_RGB, ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + /** + * The main process records expected get*() values before conversion and + * passes them to a subprocess, which verifies it after the transform. + * + * @param args If empty, the main process runs all color space pairs and + * spawns subprocesses. If not empty, args[0] and args[1] are source + * and target color space constants, followed by expected profile + * values to validate in the subprocess. + */ + public static void main(String[] args) throws Exception { + if (args.length == 0) { + for (int csFrom : CSS) { + for (int csTo : CSS) { + var from = (ICC_ColorSpace) ColorSpace.getInstance(csFrom); + var to = (ICC_ColorSpace) ColorSpace.getInstance(csTo); + + ICC_Profile profileFrom = from.getProfile(); + ICC_Profile profileTo = to.getProfile(); + + List cmd = new ArrayList<>(); + cmd.add(GetProfileDataAfterTransform.class.getSimpleName()); + + cmd.add(String.valueOf(csFrom)); + cmd.add(String.valueOf(csTo)); + + for (ICC_Profile p : List.of(profileFrom, profileTo)) { + cmd.add(String.valueOf(p.getPCSType())); + cmd.add(String.valueOf(p.getProfileClass())); + cmd.add(String.valueOf(p.getMinorVersion())); + cmd.add(String.valueOf(p.getMajorVersion())); + cmd.add(String.valueOf(p.getColorSpaceType())); + cmd.add(String.valueOf(p.getNumComponents())); + } + + OutputAnalyzer output = ProcessTools.executeTestJava(cmd); + output.shouldHaveExitValue(0).stdoutShouldBeEmpty() + .stderrShouldBeEmpty(); + } + } + } else { + int csFrom = Integer.parseInt(args[0]); + int csTo = Integer.parseInt(args[1]); + var from = (ICC_ColorSpace) ColorSpace.getInstance(csFrom); + var to = (ICC_ColorSpace) ColorSpace.getInstance(csTo); + + BufferedImageOp op = new ColorConvertOp(from, to, null); + // Note from.getProfile() and to.getProfile() are not loaded yet! + op.filter(new BufferedImage(10, 10, TYPE_INT_RGB), + new BufferedImage(10, 10, TYPE_INT_RGB)); + + test(from.getProfile(), args, 2); + test(to.getProfile(), args, 8); + } + } + + private static void test(ICC_Profile profile, String[] args, int offset) { + // Uncomment when JDK-8272860 is fixed + // if (profile.getData() == null) { + // throw new RuntimeException("Profile data is null"); + // } + if (profile.getPCSType() != Integer.parseInt(args[offset++])) { + throw new RuntimeException("Wrong PCStype"); + } + if (profile.getProfileClass() != Integer.parseInt(args[offset++])) { + throw new RuntimeException("Wrong ProfileClass"); + } + if (profile.getMinorVersion() != Integer.parseInt(args[offset++])) { + throw new RuntimeException("Wrong MinorVersion"); + } + if (profile.getMajorVersion() != Integer.parseInt(args[offset++])) { + throw new RuntimeException("Wrong MajorVersion"); + } + if (profile.getColorSpaceType() != Integer.parseInt(args[offset++])) { + throw new RuntimeException("Wrong ColorSpaceType"); + } + if (profile.getNumComponents() != Integer.parseInt(args[offset])) { + throw new RuntimeException("Wrong NumComponents"); + } + } +} From 626bea80abf1660757a12462ebc8313ef6d41f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Tue, 19 Aug 2025 06:37:52 +0000 Subject: [PATCH 128/471] 8356176: C2 MemorySegment: missing RCE with byteSize() in Loop Exit Check inside the for Expression Co-authored-by: Quan Anh Mai Co-authored-by: Emanuel Peter Co-authored-by: Christian Hagedorn Co-authored-by: Tobias Hartmann Reviewed-by: epeter, qamai --- src/hotspot/share/opto/loopnode.hpp | 58 ++++++++++++++ src/hotspot/share/opto/loopopts.cpp | 20 +++-- .../InvariantCodeMotionReassociateAddSub.java | 10 +-- .../loopopts/superword/TestMemorySegment.java | 36 +++------ ...estMemorySegmentByteSizeLongLoopLimit.java | 76 +++++++++++++++++++ .../superword/TestMemorySegmentField.java | 69 +++++++++++++++++ .../runner/ArrayIndexFillTest.java | 10 +-- 7 files changed, 238 insertions(+), 41 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentByteSizeLongLoopLimit.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentField.java diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 730f0750159..8863f37699a 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1630,6 +1630,64 @@ public: // same block. Split thru the Region. void do_split_if(Node *iff, RegionNode** new_false_region = nullptr, RegionNode** new_true_region = nullptr); +private: + // Class to keep track of wins in split_thru_phi. + class SplitThruPhiWins { + private: + // Region containing the phi we are splitting through. + const Node* _region; + + // Sum of all wins regardless of where they happen. This applies to Loops phis as well as non-loop phis. + int _total_wins; + + // For Loops, wins have different impact depending on if they happen on loop entry or on the backedge. + // Number of wins on a loop entry edge if the split is through a loop head, + // otherwise 0. Entry edge wins only pay dividends once on loop entry. + int _loop_entry_wins; + // Number of wins on a loop back-edge, which pay dividends on every iteration. + int _loop_back_wins; + + public: + SplitThruPhiWins(const Node* region) : + _region(region), + _total_wins(0), + _loop_entry_wins(0), + _loop_back_wins(0) {}; + + void reset() {_total_wins = 0; _loop_entry_wins = 0; _loop_back_wins = 0;} + void add_win(int ctrl_index) { + if (_region->is_Loop() && ctrl_index == LoopNode::EntryControl) { + _loop_entry_wins++; + } else if (_region->is_Loop() && ctrl_index == LoopNode::LoopBackControl) { + _loop_back_wins++; + } + _total_wins++; + } + // Is this split profitable with respect to the policy? + bool profitable(int policy) const { + assert(_region->is_Loop() || (_loop_entry_wins == 0 && _loop_back_wins == 0), "wins on loop edges without a loop"); + assert(!_region->is_Loop() || _total_wins == _loop_entry_wins + _loop_back_wins, "missed some win"); + // In general this means that the split has to have more wins than specified + // in the policy. However, for loops we need to take into account where the + // wins happen. We need to be careful when splitting, because splitting nodes + // related to the iv through the phi can sufficiently rearrange the loop + // structure to prevent RCE and thus vectorization. Thus, we only deem splitting + // profitable if the win of a split is not on the entry edge, as such wins + // only pay off once and have a high chance of messing up the loop structure. + return (_loop_entry_wins == 0 && _total_wins > policy) || + // If there are wins on the entry edge but the backadge also has sufficient wins, + // there is sufficient profitability to spilt regardless of the risk of messing + // up the loop structure. + _loop_back_wins > policy || + // If the policy is less than 0, a split is always profitable, i.e. we always + // split. This is needed when we split a node and then must also split a + // dependant node, i.e. spliting a Bool node after splitting a Cmp node. + policy < 0; + } + }; + +public: + // Conversion of fill/copy patterns into intrinsic versions bool do_intrinsify_fill(); bool intrinsify_fill(IdealLoopTree* lpt); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index e2696336238..a09eef0bb81 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -41,6 +41,7 @@ #include "opto/subtypenode.hpp" #include "opto/superword.hpp" #include "opto/vectornode.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" //============================================================================= @@ -66,7 +67,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { return nullptr; } - int wins = 0; + SplitThruPhiWins wins(region); assert(!n->is_CFG(), ""); assert(region->is_Region(), ""); @@ -119,7 +120,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { } if (singleton) { - wins++; + wins.add_win(i); x = makecon(t); } else { // We now call Identity to try to simplify the cloned node. @@ -134,7 +135,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { x->raise_bottom_type(t); Node* y = x->Identity(&_igvn); if (y != x) { - wins++; + wins.add_win(i); x = y; } else { y = _igvn.hash_find(x); @@ -142,7 +143,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { y = similar_subtype_check(x, region->in(i)); } if (y) { - wins++; + wins.add_win(i); x = y; } else { // Else x is a new node we are keeping @@ -165,12 +166,12 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { n->is_Load() && can_move_to_inner_loop(n, region->as_Loop(), x)) { // it is not a win if 'x' moved from an outer to an inner loop // this edge case can only happen for Load nodes - wins = 0; + wins.reset(); break; } } // Too few wins? - if (wins <= policy) { + if (!wins.profitable(policy)) { _igvn.remove_dead_node(phi); return nullptr; } @@ -227,6 +228,13 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { } } +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Split %d %s through %d Phi in %d %s", + n->_idx, n->Name(), phi->_idx, region->_idx, region->Name()); + } +#endif // !PRODUCT + return phi; } diff --git a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java index 4e8daf3d163..11f37c1f7e7 100644 --- a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java +++ b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java @@ -345,7 +345,7 @@ public class InvariantCodeMotionReassociateAddSub { @Test @Arguments(setup = "setup") - @IR(counts = {IRNode.ADD_I, "3"}) + @IR(counts = {IRNode.ADD_I, "2"}) @IR(counts = {IRNode.SUB_I, "1"}) public int addSubInt(int inv1, int inv2, int size) { int result = -1; @@ -381,7 +381,7 @@ public class InvariantCodeMotionReassociateAddSub { @Test @Arguments(setup = "setup") - @IR(counts = {IRNode.ADD_I, "3"}) + @IR(counts = {IRNode.ADD_I, "2"}) @IR(counts = {IRNode.SUB_I, "1"}) public int addSubInt2(int inv1, int inv2, int size) { int result = -1; @@ -417,7 +417,7 @@ public class InvariantCodeMotionReassociateAddSub { @Test @Arguments(setup = "setup") - @IR(counts = {IRNode.ADD_I, "3"}) + @IR(counts = {IRNode.ADD_I, "2"}) @IR(counts = {IRNode.SUB_I, "1"}) public int addSubInt3(int inv1, int inv2, int size) { int result = -1; @@ -453,7 +453,7 @@ public class InvariantCodeMotionReassociateAddSub { @Test @Arguments(setup = "setup") - @IR(counts = {IRNode.ADD_I, "2"}) + @IR(counts = {IRNode.ADD_I, "1"}) @IR(counts = {IRNode.SUB_I, "2"}) public int subSubInt(int inv1, int inv2, int size) { int result = -1; @@ -489,7 +489,7 @@ public class InvariantCodeMotionReassociateAddSub { @Test @Arguments(setup = "setup") - @IR(counts = {IRNode.ADD_I, "2"}) + @IR(counts = {IRNode.ADD_I, "1"}) @IR(counts = {IRNode.SUB_I, "2"}) public int subSubInt2(int inv1, int inv2, int size) { int result = -1; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java index 7ecc14e8980..502fad5be96 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java @@ -706,9 +706,11 @@ class TestMemorySegmentImpl { } @Test - // FAILS: invariants are sorted differently, because of differently inserted Cast. - // See: JDK-8331659 - // Interestingly, it now vectorizes for native, but not for arrays. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) static Object[] testLongLoop_longIndex_intInvar_byte(MemorySegment a, int invar) { for (long i = 0; i < a.byteSize(); i++) { long adr1 = (long)(i) + (long)(invar); @@ -720,9 +722,11 @@ class TestMemorySegmentImpl { } @Test - // FAILS: invariants are sorted differently, because of differently inserted Cast. - // See: JDK-8331659 - // Interestingly, it now vectorizes for native, but not for arrays. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) static Object[] testLongLoop_longIndex_longInvar_byte(MemorySegment a, long invar) { for (long i = 0; i < a.byteSize(); i++) { long adr1 = (long)(i) + (long)(invar); @@ -798,20 +802,12 @@ class TestMemorySegmentImpl { } @Test - @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", - IRNode.ADD_VI, "= 0", - IRNode.STORE_VECTOR, "= 0"}, - applyIfAnd = { "ShortRunningLongLoop", "false", "AlignVector", "false" }, - applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.ADD_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = { "ShortRunningLongLoop", "true", "AlignVector", "false" }, + applyIf = { "AlignVector", "false" }, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // FAILS: invariants are sorted differently, because of differently inserted Cast. - // See: JDK-8331659 static Object[] testLongLoop_longIndex_intInvar_int(MemorySegment a, int invar) { for (long i = 0; i < a.byteSize()/4; i++) { long adr1 = 4L * (long)(i) + 4L * (long)(invar); @@ -823,20 +819,12 @@ class TestMemorySegmentImpl { } @Test - @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", - IRNode.ADD_VI, "= 0", - IRNode.STORE_VECTOR, "= 0"}, - applyIfAnd = { "ShortRunningLongLoop", "false", "AlignVector", "false" }, - applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.ADD_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = { "ShortRunningLongLoop", "true", "AlignVector", "false" }, + applyIf = { "AlignVector", "false" }, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // FAILS: invariants are sorted differently, because of differently inserted Cast. - // See: JDK-8331659 static Object[] testLongLoop_longIndex_longInvar_int(MemorySegment a, long invar) { for (long i = 0; i < a.byteSize()/4; i++) { long adr1 = 4L * (long)(i) + 4L * (long)(invar); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentByteSizeLongLoopLimit.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentByteSizeLongLoopLimit.java new file mode 100644 index 00000000000..4a449d94ca9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentByteSizeLongLoopLimit.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Scenario; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; + +/* + * @test + * @bug 8356176 + * @summary Test vectorization of loops over MemorySegment with unaligned access + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentByteSizeLongLoopLimit + */ + + +public class TestMemorySegmentByteSizeLongLoopLimit { + public static int SIZE = 10_000; + + public static int[] a = new int[SIZE]; + public static long[] b = new long[SIZE]; + + public static MemorySegment msA = MemorySegment.ofArray(a); + public static MemorySegment msB = MemorySegment.ofArray(b); + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + public static void test() { + for (long i = 0; i < msA.byteSize() / 8L; i++) { + int v = msA.get(ValueLayout.JAVA_INT_UNALIGNED, i * 4L); + msB.set(ValueLayout.JAVA_LONG_UNALIGNED, i * 8L, v + 1); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentField.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentField.java new file mode 100644 index 00000000000..6f83b93d055 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentField.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; + +import java.util.Random; +import java.lang.foreign.*; + +/* + * @test + * @bug 8356176 + * @summary Test vectorization of loops over MemorySegment stored in field + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentField + */ + +public class TestMemorySegmentField { + static int SIZE = 10_000; + static MemorySegment MS = Arena.ofAuto().allocate(SIZE * 4); + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + static int zeroInvarI = 0; + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + public static void testFields() { + int invar = zeroInvarI; + for (long i = 0; i < MS.byteSize(); i++) { + long adr = (long)(i) + (long)(invar); + byte v = MS.get(ValueLayout.JAVA_BYTE, adr); + MS.set(ValueLayout.JAVA_BYTE, adr, (byte)(v + 1)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java index 16334103614..8d0ba2be589 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayIndexFillTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -106,7 +106,7 @@ public class ArrayIndexFillTest extends VectorizationTestRunner { @Test @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.POPULATE_INDEX, "=0"}) - // The ConvI2L can be split through the AddI, creating a mix of + // The ConvI2L can be pushed through the AddI, creating a mix of // ConvI2L(AddI) and AddL(ConvI2L) cases, which do not vectorize. // See: JDK-8332878 public long[] fillLongArray() { @@ -132,8 +132,7 @@ public class ArrayIndexFillTest extends VectorizationTestRunner { @Test @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"}, - counts = {IRNode.POPULATE_INDEX, "=0"}) - // See: JDK-8332878 + counts = {IRNode.POPULATE_INDEX, ">0"}) public float[] fillFloatArray() { float[] res = new float[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -155,8 +154,7 @@ public class ArrayIndexFillTest extends VectorizationTestRunner { @Test @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"}, - counts = {IRNode.POPULATE_INDEX, "=0"}) - // See: JDK-8332878 + counts = {IRNode.POPULATE_INDEX, ">0"}) public double[] fillDoubleArray() { double[] res = new double[SIZE]; for (int i = 0; i < SIZE; i++) { From 812434c42072ce4cfc91117a3187df7930500a86 Mon Sep 17 00:00:00 2001 From: Manjunath Matti Date: Tue, 19 Aug 2025 07:57:00 +0000 Subject: [PATCH 129/471] 8359114: [s390x] Add z17 detection code Reviewed-by: amitkumar, aph --- src/hotspot/cpu/s390/vm_version_s390.cpp | 20 ++++++++++++++------ src/hotspot/cpu/s390/vm_version_s390.hpp | 10 +++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 8261fbd083a..ed925aa23b4 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -68,12 +68,13 @@ unsigned int VM_Version::_Icache_lineSize = DEFAULT // z14: 2017-09 // z15: 2019-09 // z16: 2022-05 +// z17: 2025-04 -static const char* z_gen[] = {" ", "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "G9", "G10" }; -static const char* z_machine[] = {" ", "2064", "2084", "2094", "2097", "2817", "2827", "2964", "3906", "8561", "3931" }; -static const char* z_name[] = {" ", "z900", "z990", "z9 EC", "z10 EC", "z196 EC", "ec12", "z13", "z14", "z15", "z16" }; -static const char* z_WDFM[] = {" ", "2006-06-30", "2008-06-30", "2010-06-30", "2012-06-30", "2014-06-30", "2016-12-31", "2019-06-30", "2021-06-30", "2024-12-31", "tbd" }; -static const char* z_EOS[] = {" ", "2014-12-31", "2014-12-31", "2017-10-31", "2019-12-31", "2021-12-31", "2023-12-31", "2024-12-31", "tbd", "tbd", "tbd" }; +static const char* z_gen[] = {" ", "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "G9", "G10", "G11" }; +static const char* z_machine[] = {" ", "2064", "2084", "2094", "2097", "2817", "2827", "2964", "3906", "8561", "3931", "9175" }; +static const char* z_name[] = {" ", "z900", "z990", "z9 EC", "z10 EC", "z196 EC", "ec12", "z13", "z14", "z15", "z16", "z17" }; +static const char* z_WDFM[] = {" ", "2006-06-30", "2008-06-30", "2010-06-30", "2012-06-30", "2014-06-30", "2016-12-31", "2019-06-30", "2021-06-30", "2024-12-31", "tbd", "tbd" }; +static const char* z_EOS[] = {" ", "2014-12-31", "2014-12-31", "2017-10-31", "2019-12-31", "2021-12-31", "2023-12-31", "2024-12-31", "tbd", "tbd", "tbd", "tbd" }; static const char* z_features[] = {" ", "system-z, g1-z900, ldisp", "system-z, g2-z990, ldisp_fast", @@ -85,7 +86,9 @@ static const char* z_features[] = {" ", "system-z, g8-z14, ldisp_fast, extimm, pcrel_load/store, cmpb, cond_load/store, interlocked_update, txm, vectorinstr, instrext2, venh1", "system-z, g9-z15, ldisp_fast, extimm, pcrel_load/store, cmpb, cond_load/store, interlocked_update, txm, vectorinstr, instrext2, venh1, instrext3, venh2", "system-z, g10-z16, ldisp_fast, extimm, pcrel_load/store, cmpb, cond_load/store, interlocked_update, txm, vectorinstr, instrext2, venh1, instrext3, venh2," - "bear_enh, sort_enh, nnpa_assist, storage_key_removal, vpack_decimal_enh" + "bear_enh, sort_enh, nnpa_assist, storage_key_removal, vpack_decimal_enh", + "system-z, g11-z17, ldisp_fast, extimm, pcrel_load/store, cmpb, cond_load/store, interlocked_update, txm, vectorinstr, instrext2, venh1, instrext3, venh2," + "bear_enh, sort_enh, nnpa_assist, storage_key_removal, vpack_decimal_enh, concurrent_function" }; void VM_Version::initialize() { @@ -339,6 +342,11 @@ int VM_Version::get_model_index() { // is the index of the oldest detected model. int ambiguity = 0; int model_ix = 0; + if (is_z17()) { + model_ix = 11; + ambiguity++; + } + if (is_z16()) { model_ix = 10; ambiguity++; diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 6c6eb76bf7b..04005ff2cf9 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -100,7 +100,7 @@ class VM_Version: public Abstract_VM_Version { #define CryptoExtension4Mask 0x0004000000000000UL // z196 (aka message-security assist extension 4, for KMF, KMCTR, KMO) #define DFPPackedConversionMask 0x0000800000000000UL // z13 // ---------------------------------------------- -// --- FeatureBitString Bits 128..192 (DW[2]) --- +// --- FeatureBitString Bits 128..191 (DW[2]) --- // ---------------------------------------------- // 11111111111111111 // 23344455666778889 @@ -118,9 +118,10 @@ class VM_Version: public Abstract_VM_Version { #define NNPAssistFacilityMask 0x0000000004000000UL // z16, Neural-network-processing-assist facility, Bit: 165 // ---------------------------------------------- -// --- FeatureBitString Bits 193..200 (DW[3]) --- +// --- FeatureBitString Bits 192..255 (DW[3]) --- // ---------------------------------------------- #define BEAREnhFacilityMask 0x4000000000000000UL // z16, BEAR-enhancement facility, Bit: 193 +#define ConcurrentFunFacilityMask 0x0040000000000000UL // z17, Concurrent-functions facility, Bit: 201 enum { _max_cache_levels = 8, // As limited by ECAG instruction. @@ -189,7 +190,8 @@ class VM_Version: public Abstract_VM_Version { static bool is_z13() { return has_CryptoExt5() && !has_MiscInstrExt2(); } static bool is_z14() { return has_MiscInstrExt2() && !has_MiscInstrExt3(); } static bool is_z15() { return has_MiscInstrExt3() && !has_BEAR_Enh_Facility(); } - static bool is_z16() { return has_BEAR_Enh_Facility(); } + static bool is_z16() { return has_BEAR_Enh_Facility() && !has_Concurrent_Fun_Facility(); } + static bool is_z17() { return has_Concurrent_Fun_Facility();} // Need to use nested class with unscoped enum. // C++11 declaration "enum class Cipher { ... } is not supported. @@ -497,6 +499,7 @@ class VM_Version: public Abstract_VM_Version { static bool has_BEAR_Enh_Facility() { return (_features[3] & BEAREnhFacilityMask) == BEAREnhFacilityMask; } static bool has_NNP_Assist_Facility() { return (_features[2] & NNPAssistFacilityMask) == NNPAssistFacilityMask; } + static bool has_Concurrent_Fun_Facility() { return (_features[3] & ConcurrentFunFacilityMask) == ConcurrentFunFacilityMask; } // Crypto features query functions. static bool has_Crypto_AES_GCM128() { return has_Crypto() && test_feature_bit(&_cipher_features_KMA[0], Cipher::_AES128, Cipher::_featureBits); } @@ -573,6 +576,7 @@ class VM_Version: public Abstract_VM_Version { static void set_has_VectorPackedDecimalEnh() { _features[2] |= VectorPackedDecimalEnhMask; } static void set_has_BEAR_Enh_Facility() { _features[3] |= BEAREnhFacilityMask;} static void set_has_NNP_Assist_Facility() { _features[2] |= NNPAssistFacilityMask;} + static void set_has_Concurrent_Fun_Facility() { _features[3] |= ConcurrentFunFacilityMask;} static void reset_has_VectorFacility() { _features[2] &= ~VectorFacilityMask; } From 999761d0f6d37c9cd6ec482620800b694c5fb9ad Mon Sep 17 00:00:00 2001 From: Fei Gao Date: Tue, 19 Aug 2025 08:22:40 +0000 Subject: [PATCH 130/471] 8365312: GCC 12 cannot compile SVE on aarch64 with auto-var-init pattern Reviewed-by: kbarrett, ihse, erikj --- make/autoconf/flags-cflags.m4 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 056334e99c4..1e12b04219f 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -954,6 +954,17 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], [ AC_MSG_RESULT([yes]) $2SVE_CFLAGS="-march=armv8-a+sve" + # Switching the initialization mode with gcc from 'pattern' to 'zero' + # avoids the use of unsupported `__builtin_clear_padding` for variable + # length aggregates + if test "x$DEBUG_LEVEL" != xrelease && test "x$TOOLCHAIN_TYPE" = xgcc ; then + INIT_ZERO_FLAG="-ftrivial-auto-var-init=zero" + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_ZERO_FLAG], + IF_TRUE: [ + $2SVE_CFLAGS="${$2SVE_CFLAGS} $INIT_ZERO_FLAG" + ] + ) + fi ], [ AC_MSG_RESULT([no]) From 0b2d0817f14895102600744670e4a6d4764b0259 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 19 Aug 2025 14:45:37 +0000 Subject: [PATCH 131/471] 8365636: JFR: Minor cleanup Reviewed-by: shade --- .../classes/jdk/jfr/AnnotationElement.java | 2 +- .../share/classes/jdk/jfr/Configuration.java | 4 +-- .../share/classes/jdk/jfr/Enabled.java | 4 +-- .../share/classes/jdk/jfr/EventType.java | 6 ++--- .../jdk/jfr/FlightRecorderListener.java | 4 +-- .../share/classes/jdk/jfr/Recording.java | 12 ++++----- .../classes/jdk/jfr/consumer/EventStream.java | 2 +- .../jdk/jfr/consumer/MetadataEvent.java | 4 +-- .../jdk/jfr/consumer/RecordedMethod.java | 6 ++--- .../jdk/jfr/consumer/RecordedObject.java | 2 +- .../jdk/jfr/consumer/RecordingFile.java | 2 +- .../jdk/jfr/consumer/RecordingStream.java | 4 +-- .../jdk/jfr/consumer/package-info.java | 4 +-- .../jdk/jfr/internal/EventControl.java | 2 +- .../classes/jdk/jfr/internal/LongMap.java | 2 +- .../jdk/jfr/internal/PlatformEventType.java | 1 - .../jdk/jfr/internal/PrivateAccess.java | 1 - .../internal/management/ChunkFilename.java | 1 - .../jdk/jfr/internal/periodic/FlushTask.java | 1 - .../jdk/jfr/internal/query/Histogram.java | 8 +++--- .../jdk/jfr/internal/query/QueryParser.java | 1 - .../internal/settings/CPUThrottleSetting.java | 6 +---- .../jfr/internal/settings/MethodSetting.java | 2 +- .../jdk/jfr/internal/settings/Throttler.java | 2 -- .../jdk/jfr/internal/tool/Filters.java | 4 +-- .../jdk/jfr/internal/tool/Metadata.java | 4 +-- .../classes/jdk/jfr/internal/tool/Print.java | 4 +-- .../classes/jdk/jfr/internal/tool/Scrub.java | 2 +- .../jfr/internal/tracing/PlatformTracer.java | 21 +++++++-------- .../jdk/jfr/internal/util/TimespanRate.java | 4 +-- .../share/classes/jdk/jfr/package-info.java | 4 +-- .../jdk/management/jfr/EventTypeInfo.java | 4 +-- .../management/jfr/FlightRecorderMXBean.java | 27 ++++++++++--------- .../management/jfr/SettingDescriptorInfo.java | 4 +-- 34 files changed, 73 insertions(+), 88 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java b/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java index 046709fa92e..155e9098d91 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/AnnotationElement.java @@ -69,7 +69,7 @@ public final class AnnotationElement { } StringJoiner values = new StringJoiner(",", "[", "]"); for (Object object : objects) { - descriptors.add(String.valueOf(object)); + values.add(String.valueOf(object)); } throw new IllegalArgumentException("Annotation " + descriptors + " for " + type.getName() + " doesn't match number of values " + values); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java b/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java index 097f069c895..a423af114a9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Configuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -67,7 +67,7 @@ public final class Configuration { } /** - * Returns the settings that specifies how a recording is configured. + * Returns the settings that specify how a recording is configured. *

    * Modifying the returned {@code Map} object doesn't change the * configuration. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Enabled.java b/src/jdk.jfr/share/classes/jdk/jfr/Enabled.java index 328826356a1..3f3270d7fc0 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Enabled.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Enabled.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ public @interface Enabled { /** * Returns {@code true} if by default the event should be enabled, {@code false} otherwise. * - * @return {@code true} if by default the event should be enabled by default, {@code false} otherwise + * @return {@code true} if by default the event should be enabled, {@code false} otherwise */ boolean value() default true; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventType.java b/src/jdk.jfr/share/classes/jdk/jfr/EventType.java index d9b4e50fca8..0f2057a7981 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -125,7 +125,7 @@ public final class EventType { */ public String getLabel() { if (label == UNKNOWN) { - label = platformEventType.getLabel();; + label = platformEventType.getLabel(); } return label; } @@ -226,7 +226,7 @@ public final class EventType { } /** - * Returns the list of human-readable names that makes up the categories for + * Returns the list of human-readable names that make up the categories for * this event type (for example, {@code "Java Application"}, {@code "Statistics"}). * * @return an immutable list of category names, or a list with the name diff --git a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java index 55798f89de4..e3a172ca3fd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/FlightRecorderListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -36,7 +36,7 @@ public interface FlightRecorderListener { /** * Receives notification when Flight Recorder is initialized. *

    - * This method is also be invoked when a listener is added to an already + * This method is also invoked when a listener is added to an already * initialized Flight Recorder. *

    * This method allows clients to implement their own initialization mechanism diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java index 333645f1731..089a5ed37d8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Recording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Recording.java @@ -44,7 +44,7 @@ import jdk.jfr.internal.WriteablePath; /** * Provides means to configure, start, stop and dump recording data to disk. *

    - * The following example shows how configure, start, stop and dump recording data to disk. + * The following example shows how to configure, start, stop and dump recording data to disk. * * {@snippet class="Snippets" region="RecordingOverview"} * @@ -138,7 +138,7 @@ public final class Recording implements Closeable { * The newly created recording is in the {@link RecordingState#NEW} state. To * start the recording, invoke the {@link Recording#start()} method. * - * @param configuration configuration that contains the settings to be use, not + * @param configuration configuration that contains the settings to be used, not * {@code null} * * @throws IllegalStateException if Flight Recorder can't be created (for @@ -339,7 +339,7 @@ public final class Recording implements Closeable { *

    * Clones are useful for dumping data without stopping the recording. After * a clone is created, the amount of data to copy is constrained - * with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)}method. + * with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)} method. * * @param stop {@code true} if the newly created copy should be stopped * immediately, {@code false} otherwise @@ -615,9 +615,9 @@ public final class Recording implements Closeable { /** * Disables event with the specified name. *

    - * If multiple events with same name (for example, the same class is loaded + * If multiple events with the same name (for example, the same class is loaded * in different class loaders), then all events that match the - * name is disabled. To disable a specific class, use the + * name are disabled. To disable a specific class, use the * {@link #disable(Class)} method or a {@code String} representation of the event * type ID. * @@ -653,7 +653,7 @@ public final class Recording implements Closeable { /** * Disables event. * - * @param eventClass the event to enable, not {@code null} + * @param eventClass the event to disable, not {@code null} * * @throws IllegalArgumentException if {@code eventClass} is an abstract * class or not a subclass of {@link Event} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java index ac325f19f22..d7de775ea3c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java @@ -295,7 +295,7 @@ public interface EventStream extends AutoCloseable { void setReuse(boolean reuse); /** - * Specifies that events arrives in chronological order, sorted by the time + * Specifies that events arrive in chronological order, sorted by the time * they were committed to the stream. * * @param ordered if event objects arrive in chronological order to diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/MetadataEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/MetadataEvent.java index 153d4f343f7..df1e1edc236 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/MetadataEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/MetadataEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -82,7 +82,7 @@ public final class MetadataEvent { * The delta will be from the last metadata event. If no metadata event has been * emitted earlier, the list will be empty. * - * @return an immutable list of added event types, not {@code null} + * @return an immutable list of removed event types, not {@code null} */ public final List getRemovedEventTypes() { if (removed == null) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java index 6c8f23aa02a..7f0dbbf7318 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ public final class RecordedMethod extends RecordedObject { } /** - * Returns the class this method belongs to, if it belong to a Java frame. + * Returns the class this method belongs to, if it belongs to a Java frame. *

    * To ensure this is a Java frame, use the {@link RecordedFrame#isJavaFrame()} * method. @@ -99,7 +99,7 @@ public final class RecordedMethod extends RecordedObject { /** * Returns whether this method is hidden (for example, wrapper code in a lambda - * expressions). + * expression). * * @return {@code true} if method is hidden, {@code false} otherwise */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index 8d4a69a92d7..a229709ecaa 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -183,7 +183,7 @@ public sealed class RecordedObject return defaultValue; } T object = getValue(name); - if (object == null || object.getClass().isAssignableFrom(clazz)) { + if (object == null || object.getClass() == clazz) { return object; } else { return defaultValue; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java index a3880da33fa..2e839e93068 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java @@ -51,7 +51,7 @@ import jdk.jfr.internal.consumer.filter.ChunkWriter.RemovedEvents; /** * A recording file. *

    - * The following example shows how read and print all events in a recording file. + * The following example shows how to read and print all events in a recording file. * * {@snippet class="Snippets" region="RecordingFileOverview"} * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java index 3d6c8de3015..5ec794bdf7c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java @@ -232,8 +232,8 @@ public final class RecordingStream implements AutoCloseable, EventStream { * that is older than the specified length of time is removed by the Java * Virtual Machine (JVM). *

    - * If neither maximum limit or the maximum age is set, the size of the - * recording may grow indefinitely if events are on + * If neither the maximum limit nor the maximum age is set, the size of the + * recording may grow indefinitely if events are not consumed. * * @param maxAge the length of time that data is kept, or {@code null} if * infinite diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java index 81f7977deba..56f47b4e483 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -36,7 +36,7 @@ * Typically this is expressed as {@code "not null"}. If a {@code null} * parameter is used where it is not allowed, a * {@code java.lang.NullPointerException} is thrown. If a {@code null} - * parameters is passed to a method that throws other exceptions, such as + * parameter is passed to a method that throws other exceptions, such as * {@code java.io.IOException}, the {@code java.lang.NullPointerException} takes * precedence, unless the Javadoc for the method explicitly states how * {@code null} is handled, i.e. by throwing {@code java.lang.IllegalArgumentException}. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index 7a8d490d6e5..621c879f712 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -97,7 +97,7 @@ public final class EventControl { } if (eventType.hasThrottle()) { addControl(Throttle.NAME, defineThrottle(eventType)); - eventType.setThrottler(new Throttler(eventType)); + eventType.setThrottler(new Throttler()); } if (eventType.hasLevel()) { addControl(Level.NAME, defineLevel(eventType)); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java index dfb549b5778..3f02e71acdd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java @@ -273,7 +273,7 @@ public final class LongMap { for (int i = 0; i < keys.length; i++) { T o = objects[i]; if (o != null) { - list.add(o); + list.add(o == NULL_OBJECT ? null : o); } } return list; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java index dfe87509e14..c4f0a8e9a0e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java @@ -30,7 +30,6 @@ import java.util.List; import java.util.Objects; import jdk.jfr.SettingDescriptor; -import jdk.jfr.events.ActiveSettingEvent; import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.TimespanRate; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java index 95dbd0986dc..fe5d5aea327 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java @@ -32,7 +32,6 @@ import jdk.jfr.AnnotationElement; import jdk.jfr.Configuration; import jdk.jfr.EventSettings; import jdk.jfr.EventType; -import jdk.jfr.FlightRecorderPermission; import jdk.jfr.Recording; import jdk.jfr.SettingDescriptor; import jdk.jfr.ValueDescriptor; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java index 0d8290b206e..47e8de74037 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ChunkFilename.java @@ -24,7 +24,6 @@ */ package jdk.jfr.internal.management; -import java.nio.file.Paths; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/FlushTask.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/FlushTask.java index 739f32bf634..bed92a2f283 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/FlushTask.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/FlushTask.java @@ -25,7 +25,6 @@ package jdk.jfr.internal.periodic; import jdk.jfr.internal.JVM; -import jdk.jfr.internal.MetadataRepository; import jdk.jfr.internal.PlatformRecorder; import jdk.jfr.internal.PrivateAccess; import jdk.jfr.internal.util.Utils; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Histogram.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Histogram.java index 0eca381cca4..d3d596dc4b9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Histogram.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Histogram.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -50,7 +50,7 @@ final class Histogram { private static final class LookupKey { private Object keys; - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked"}) public void add(Object o) { // One key, fast path if (keys == null) { @@ -58,8 +58,8 @@ final class Histogram { return; } // Three or more keys - if (keys instanceof Set set) { - set.add(o); + if (keys instanceof Set set) { + ((Set) set).add(o); return; } // Two keys diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryParser.java index 51cb2cb03e7..3c7d1e58b35 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryParser.java @@ -28,7 +28,6 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.function.BiConsumer; import java.util.function.Consumer; import jdk.jfr.internal.query.Configuration.Truncate; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java index 997f4a84949..944827f6d6f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Datadog, Inc. All rights reserved. * Copyright (c) 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,9 +27,6 @@ package jdk.jfr.internal.settings; -import static jdk.jfr.internal.util.TimespanUnit.SECONDS; -import static jdk.jfr.internal.util.TimespanUnit.MILLISECONDS; - import java.util.Objects; import java.util.Set; @@ -41,7 +38,6 @@ import jdk.jfr.Name; import jdk.jfr.internal.PlatformEventType; import jdk.jfr.internal.Type; import jdk.jfr.internal.util.TimespanRate; -import jdk.jfr.internal.util.Utils; @MetadataDefinition @Label("CPUThrottleSetting") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/MethodSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/MethodSetting.java index 0f2751b6ac7..b369172d7b6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/MethodSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/MethodSetting.java @@ -42,7 +42,7 @@ import jdk.jfr.internal.tracing.PlatformTracer; @Name(Type.SETTINGS_PREFIX + "Filter") public final class MethodSetting extends FilterSetting { private final Modification modification; - private volatile static boolean initialized; + private static volatile boolean initialized; public MethodSetting(PlatformEventType eventType, Modification modification, String defaultValue) { super(eventType, defaultValue); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java index df8f5a58700..e5093de781b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java @@ -55,8 +55,6 @@ public final class Throttler { private boolean disabled; private boolean update = true; - public Throttler(PlatformEventType t) { - } // Not synchronized in fast path, but uses volatile reads. public boolean sample(long ticks) { if (disabled) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java index e63fd34f8b8..ed983467dc6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Filters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -91,7 +91,7 @@ public class Filters { return !types.stream().anyMatch(f); } - public static Predicate matchAny(List> filters) { + public static Predicate matchAll(List> filters) { if (filters.isEmpty()) { return t -> true; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java index e456b14362f..2d6f55dd4b3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -203,7 +203,7 @@ final class Metadata extends Command { try (PrintWriter pw = new PrintWriter(System.out, false, UTF_8)) { MetadataWriter metadataWriter = new MetadataWriter(pw, showIds); if (!filters.isEmpty()) { - filter = Filters.matchAny(filters); + filter = Filters.matchAll(filters); } List types = findTypes(file); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java index 79dd04c379f..0bc6ceeb18f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -164,7 +164,7 @@ final class Print extends Command { } eventWriter.setStackDepth(stackDepth); if (!eventFilters.isEmpty()) { - eventWriter.setEventFilter(Filters.matchAny(eventFilters)); + eventWriter.setEventFilter(Filters.matchAll(eventFilters)); } try { eventWriter.print(file); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java index 8a02ded1125..6043e841b50 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Scrub.java @@ -214,7 +214,7 @@ final class Scrub extends Command { } optionCount = options.size(); } - return Filters.matchAny(filters); + return Filters.matchAll(filters); } private void ensureUsableOutput(Path input, Path output) throws UserSyntaxException, UserDataException { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/PlatformTracer.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/PlatformTracer.java index 2d40e496dc1..a77123b30f3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/PlatformTracer.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/PlatformTracer.java @@ -35,7 +35,6 @@ import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; import jdk.jfr.internal.MetadataRepository; import jdk.jfr.internal.SecuritySupport; -import jdk.jfr.internal.Type; import jdk.jfr.internal.util.Bytecode; import jdk.jfr.tracing.MethodTracer; @@ -264,18 +263,16 @@ public final class PlatformTracer { // provided a user has specified a non-empty filter for the MethodTrace or // MethodTiming event. public static void initialize() { - try { - Logger.log(LogTag.JFR_METHODTRACE, LogLevel.DEBUG, "Method tracer initialization started."); - Thread current = Thread.currentThread(); - JVM.exclude(current); - long methodId = 16384126; - long classId = methodId >> 16; - ClassLoader cl = null; - String className = " java/lang/String"; - Module m = String.class.getModule(); - var is = ClassLoader.getSystemClassLoader().getResourceAsStream("java/lang/String.class"); + Logger.log(LogTag.JFR_METHODTRACE, LogLevel.DEBUG, "Method tracer initialization started."); + Thread current = Thread.currentThread(); + JVM.exclude(current); + long methodId = 16384126; + long classId = methodId >> 16; + ClassLoader cl = null; + String className = "java/lang/String"; + Module m = String.class.getModule(); + try (var is = ClassLoader.getSystemClassLoader().getResourceAsStream("java/lang/String.class")) { byte[] oldBytecode = is.readAllBytes(); - is.close(); long[] ids = { methodId }; String[] names = { "" }; String[] signatures = { "()V" }; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanRate.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanRate.java index c35432d5d6b..e4606059822 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanRate.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanRate.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2025 SAP SE. All rights reserved. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -25,8 +25,6 @@ */ package jdk.jfr.internal.util; -import jdk.jfr.internal.settings.CPUThrottleSetting; - /** * A rate or fixed period, see {@link jdk.jfr.internal.Rate} */ diff --git a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java index 54866ec508f..812525e0ff4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java @@ -33,7 +33,7 @@ * running application up to the failure or crash. *

    * To define a Flight Recorder event, extend {@link jdk.jfr.Event} and add - * fields that matches the data types of the payload. Metadata about fields, + * fields that match the data types of the payload. Metadata about fields, * such as labels, descriptions and units, can be added by using the annotations * available in the {@code jdk.jfr} package, or by using a user-defined * annotation that has the {@link jdk.jfr.MetadataDefinition} annotation. @@ -232,7 +232,7 @@ * Typically this is expressed as {@code "not null"}. If a {@code null} * parameter is used where it is not allowed, a * {@code java.lang.NullPointerException} is thrown. If a {@code null} - * parameters is passed to a method that throws other exceptions, such as + * parameters are passed to a method that throws other exceptions, such as * {@code java.io.IOException}, the {@code java.lang.NullPointerException} takes * precedence, unless the Javadoc for the method explicitly states how * {@code null} is handled, i.e. by throwing diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java index 15739829ee4..9be2ad90f62 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/EventTypeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -163,7 +163,7 @@ public final class EventTypeInfo { /** * Returns a short sentence or two describing the event type associated with * this {@code EventTypeInfo}, for example - * {@code "Garbage collection performed by the JVM""}. + * {@code "Garbage collection performed by the JVM"}. * * @return the description, or {@code null} if no description exists * diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java index a0648a0b1a6..9f61cc3f358 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,6 +27,7 @@ package jdk.management.jfr; import java.io.IOException; import java.lang.management.PlatformManagedObject; +import java.nio.file.Paths; import java.time.Instant; import java.util.List; import java.util.Map; @@ -47,7 +48,7 @@ import jdk.jfr.Recording; * Specify how long a recording should last, and where and when data * should be dumped. *

  • Settings
    - * Specify which events should be enabled and what kind information each + * Specify which events should be enabled and what kind of information each * event should capture.
  • *
  • Configurations
    * Predefined sets of settings, typically derived from a settings file, @@ -59,7 +60,7 @@ import jdk.jfr.Recording; * *

    Recording options

    *

    - * The following table shows the options names to use with {@link #setRecordingOptions(long, Map)} + * The following table shows the option names to use with {@link #setRecordingOptions(long, Map)} * and {@link #getRecordingOptions(long)}. * * @@ -67,7 +68,7 @@ import jdk.jfr.Recording; * * * - * + * * * * @@ -107,7 +108,7 @@ import jdk.jfr.Recording; * * * - * * @@ -131,8 +132,8 @@ import jdk.jfr.Recording; * - * + * * * @@ -145,7 +146,7 @@ import jdk.jfr.Recording; * {@code "false"} * * - * + * * * * * - * + * * * * @@ -337,7 +338,7 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { * * + * To be able to read from a running recording the value must be set to * * @@ -355,7 +356,7 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { * * @return a unique ID for the stream. * - * @throws IllegalArgumentException if a recording with the iD doesn't + * @throws IllegalArgumentException if a recording with the ID doesn't * exist, or if {@code options} contains invalid values * * @throws IOException if the recording is closed, an I/O error occurs, or @@ -425,7 +426,7 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { * is a textual representation of the settings value (for example, * {@code "60 s"}). * - * @param recordingId the ID of the recordings to get settings for + * @param recordingId the ID of the recording to get settings for * * @return a map that describes the recording settings, not {@code null} * @@ -522,7 +523,7 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { void setRecordingOptions(long recordingId, Map options) throws IllegalArgumentException; /** - * Returns the list of the available recordings, not necessarily running. + * Returns the list of available recordings, not necessarily running. *

    * MBeanServer access:
    * The mapped type of {@code RecordingInfo} is {@code CompositeData} with diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java index 6c13dd24a64..bece634dcca 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/SettingDescriptorInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -108,7 +108,7 @@ public final class SettingDescriptorInfo { /** * Returns the description of the setting associated this * {@code SettingDescriptorInfo} (for example, - * {@code "The duration an event must exceed to be be recorded"}). + * {@code "The duration an event must exceed to be recorded"}). * * @return the description of this setting, not null */ From 4ed268ff9aa6059221d76291c031b0fd29e20b95 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 19 Aug 2025 15:05:25 +0000 Subject: [PATCH 132/471] 8362304: Fix JDWP spec w.r.t. OPAQUE_FRAME and INVALID_SLOT errors Reviewed-by: sspitsyn, alanb, amenkov --- src/java.se/share/data/jdwp/jdwp.spec | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index 5206a0c6ae9..11e3160ec97 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -2148,12 +2148,8 @@ JDWP "Java(tm) Debug Wire Protocol" "the thread is not alive.") (Error INVALID_OBJECT "Thread or value is not a known ID.") (Error THREAD_NOT_SUSPENDED) - (Error OPAQUE_FRAME "Attempted to return early from a frame " - "corresponding to a native method, " - "the thread is a suspended virtual thread and the target " - "VM is unable to force its current frame to return, " - "or the implementation is unable to provide this " - "functionality on this frame.") + (Error OPAQUE_FRAME "Unable to force the current frame to return " + "(e.g. the current frame is executing a native method).") (Error NO_MORE_FRAMES) (Error NOT_IMPLEMENTED) (Error TYPE_MISMATCH "Value is not an appropriate type for the " @@ -2625,6 +2621,8 @@ JDWP "Java(tm) Debug Wire Protocol" (Error INVALID_OBJECT) (Error INVALID_FRAMEID) (Error INVALID_SLOT) + (Error OPAQUE_FRAME "Unable to get the value of local variables in the frame " + "(e.g. the frame is executing a native method).") (Error VM_DEAD) ) ) @@ -2662,9 +2660,9 @@ JDWP "Java(tm) Debug Wire Protocol" (Error INVALID_THREAD) (Error INVALID_OBJECT) (Error INVALID_FRAMEID) - (Error OPAQUE_FRAME "The thread is a suspended virtual thread and the target VM " - "does not support setting the value of local " - "variables in the frame.") + (Error INVALID_SLOT) + (Error OPAQUE_FRAME "Unable to set the value of local variables in the frame " + "(e.g. the frame is executing a native method).") (Error VM_DEAD) ) ) @@ -2713,10 +2711,9 @@ JDWP "Java(tm) Debug Wire Protocol" (Error INVALID_FRAMEID) (Error THREAD_NOT_SUSPENDED) (Error NO_MORE_FRAMES) - (Error OPAQUE_FRAME "If one or more of the frames to pop is a native " - "method or its caller is a native method, or the " - "thread is a suspended virtual thread and the implementation " - "was unable to pop the frames.") + (Error OPAQUE_FRAME "Unable to pop one or more of the frames " + "(e.g. one or more of the frames to pop is a native " + "method or its caller is a native method).") (Error NOT_IMPLEMENTED) (Error VM_DEAD) ) From 0755477c9a06cc773f307c7119efb97df797d23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 19 Aug 2025 16:01:12 +0000 Subject: [PATCH 133/471] 8342705: Add dark mode for docs Reviewed-by: liach --- .../doclets/formats/html/HtmlDoclet.java | 2 + .../doclets/formats/html/HtmlIds.java | 5 + .../doclets/formats/html/Navigation.java | 41 ++- .../doclets/formats/html/resources/glass.svg | 6 +- .../formats/html/resources/highlight.css | 185 ++++++++++ .../doclets/formats/html/resources/moon.svg | 15 + .../formats/html/resources/script.js.template | 52 ++- .../html/resources/standard.properties | 4 + .../formats/html/resources/stylesheet.css | 336 ++++++++++++++++-- .../doclets/formats/html/resources/sun.svg | 22 ++ .../doclets/formats/html/resources/x.svg | 6 +- .../doclets/toolkit/util/DocPaths.java | 6 + .../jdk/javadoc/internal/html/HtmlAttr.java | 1 + .../CheckStylesheetClasses.java | 3 + .../testNavigation/TestModuleNavigation.java | 26 +- .../doclet/testNavigation/TestNavigation.java | 34 ++ .../doclet/testSpecTag/TestSpecTag.java | 15 +- .../doclet/testStylesheet/TestStylesheet.java | 3 +- .../jdk/javadoc/tool/api/basic/APITest.java | 2 + 19 files changed, 697 insertions(+), 67 deletions(-) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index 47b2322226e..d00d7b1becf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -327,6 +327,8 @@ public class HtmlDoclet extends AbstractDoclet { copyResource(DocPaths.RIGHT_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.RIGHT_SVG), true); copyResource(DocPaths.CLIPBOARD_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.CLIPBOARD_SVG), true); copyResource(DocPaths.LINK_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.LINK_SVG), true); + copyResource(DocPaths.MOON_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.MOON_SVG), true); + copyResource(DocPaths.SUN_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.SUN_SVG), true); if (options.createIndex()) { copyResource(DocPaths.SEARCH_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_JS), true); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 42d93c41e11..c257e1e153c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -114,6 +114,11 @@ public class HtmlIds { static final HtmlId SEARCH_INPUT = HtmlId.of("search-input"); static final HtmlId SERVICES = HtmlId.of("services-summary"); static final HtmlId SKIP_NAVBAR_TOP = HtmlId.of("skip-navbar-top"); + static final HtmlId THEME_BUTTON = HtmlId.of("theme-button"); + static final HtmlId THEME_DARK = HtmlId.of("theme-dark"); + static final HtmlId THEME_LIGHT = HtmlId.of("theme-light"); + static final HtmlId THEME_OS = HtmlId.of("theme-os"); + static final HtmlId THEME_PANEL = HtmlId.of("theme-panel"); static final HtmlId UNNAMED_PACKAGE_ANCHOR = HtmlId.of("unnamed-package"); private static final String FIELDS_INHERITANCE = "fields-inherited-from-class-"; private static final String METHODS_INHERITANCE = "methods-inherited-from-class-"; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 61af26259af..1938a4838f5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -137,6 +137,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case MODULE: addOverviewLink(target); @@ -148,6 +149,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case PACKAGE: addOverviewLink(target); @@ -166,6 +168,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case CLASS: addOverviewLink(target); @@ -184,6 +187,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case USE: addOverviewLink(target); @@ -208,6 +212,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case TREE: addOverviewLink(target); @@ -226,6 +231,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case DEPRECATED: case INDEX: @@ -268,6 +274,7 @@ public class Navigation { } else { addHelpLink(target); } + addThemeSwitcher(target); break; case ALL_CLASSES: case ALL_PACKAGES: @@ -285,6 +292,7 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; case DOC_FILE: addOverviewLink(target); @@ -311,16 +319,13 @@ public class Navigation { addIndexLink(target); addSearchLink(target); addHelpLink(target); + addThemeSwitcher(target); break; default: break; } } - private void addContentToList(List listContents, Content source) { - listContents.add(HtmlTree.LI(source)); - } - private void addItemToList(Content list, Content item) { list.add(HtmlTree.LI(item)); } @@ -492,6 +497,17 @@ public class Navigation { } } + private void addThemeSwitcher(Content target) { + var selectTheme = contents.getContent("doclet.theme.select_theme"); + target.add(HtmlTree.LI(HtmlTree.BUTTON(HtmlIds.THEME_BUTTON) + .add(HtmlTree.IMG(pathToRoot.resolve(DocPaths.RESOURCE_FILES).resolve(DocPaths.SUN_SVG), + selectTheme.toString()).addStyle(HtmlIds.THEME_LIGHT.name())) + .add(HtmlTree.IMG(pathToRoot.resolve(DocPaths.RESOURCE_FILES).resolve(DocPaths.MOON_SVG), + selectTheme.toString()).addStyle(HtmlIds.THEME_DARK.name())) + .put(HtmlAttr.ARIA_LABEL, selectTheme.toString()) + .put(HtmlAttr.TITLE, selectTheme.toString()))); + } + private void addSearch(Content target) { var resources = configuration.getDocResources(); var inputText = HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlIds.SEARCH_INPUT) @@ -545,6 +561,7 @@ public class Navigation { navContent.add(aboutDiv); navigationBar.add(HtmlTree.DIV(HtmlStyles.topNav, navContent).setId(HtmlIds.NAVBAR_TOP)); + var subNavContent = HtmlTree.DIV(HtmlStyles.navContent); List subNavLinks = new ArrayList<>(); switch (documentedPage) { @@ -557,6 +574,22 @@ public class Navigation { breadcrumbNav.addAll(subNavLinks, HtmlTree::LI); subNavContent.addUnchecked(breadcrumbNav); + var selectTheme = contents.getContent("doclet.theme.select_theme"); + subNavContent.add(HtmlTree.DIV(HtmlIds.THEME_PANEL) + .add(HtmlTree.DIV(selectTheme)) + .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.THEME_LIGHT.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_LIGHT) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_LIGHT.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.light")))) + .add(HtmlTree.LABEL(HtmlIds.THEME_DARK.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_DARK) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_DARK.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.dark")))) + .add(HtmlTree.LABEL(HtmlIds.THEME_OS.name(), Text.EMPTY) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_OS) + .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_OS.name())) + .add(HtmlTree.SPAN(contents.getContent("doclet.theme.system")))))); + if (options.createIndex() && documentedPage != PageMode.SEARCH) { addSearch(subNavContent); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg index ff7df85e8f6..c979c9f3d83 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/glass.svg @@ -8,6 +8,6 @@ --> - - - \ No newline at end of file + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css index 145c1c7f5d2..77c32543049 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css @@ -65,3 +65,188 @@ /* ignored */ } +body.theme-dark { + .hljs-title.function_, + .hljs-template-variable { + color: #66bcce; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color:#9d9d9d; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #88aece; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #c59bc1; + } + .hljs-attribute { + color: #c59bc1; + } + .hljs-regexp, + .hljs-number { + color: #cfe374; + } + .hljs-link { + color: #b5bd68; + } + .hljs-string { + color: #b5bd68; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } +} + +@media (prefers-color-scheme: dark) { + .hljs-title.function_, + .hljs-template-variable { + color: #66bcce; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color:#9d9d9d; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #88aece; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #c59bc1; + } + .hljs-attribute { + color: #c59bc1; + } + .hljs-regexp, + .hljs-number { + color: #cfe374; + } + .hljs-link { + color: #b5bd68; + } + .hljs-string { + color: #b5bd68; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } + + body.theme-light { + .hljs-title.function_, + .hljs-template-variable { + color: #00738F; + } + .hljs-code, + .hljs-comment, + .hljs-quote { + color: #6e6e71; + font-style: italic; + } + .hljs-meta { + color: #836F00; + } + .hljs-symbol, + .hljs-template-tag, + .hljs-keyword, + .hljs-literal, + .hljs-name, + .hljs-built_in, + .hljs-char.escape_ { + color: #0C40C2; + } + .hljs-variable, + .hljs-property, + .hljs-attr, + .hljs-section { + color: #841191; + } + .hljs-attribute { + color: #164ad9; + } + .hljs-regexp, + .hljs-number { + color: #104BEB; + } + .hljs-link { + color: #47688a; + } + .hljs-string { + color: #008313; + } + .hljs-doctag { + text-decoration: underline; + } + .hljs-emphasis { + font-style: italic; + } + .hljs-strong { + font-weight: bold; + } + .hljs-subst, + .hljs-title, + .hljs-params, + .hljs-bullet, + .hljs-formula, + .hljs-tag, + .hljs-type { + /* ignored */ + } + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg new file mode 100644 index 00000000000..856a8ffeeec --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/moon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index d3b59f4f40b..a32c44b8043 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -328,11 +328,7 @@ document.addEventListener("readystatechange", (e) => { }); document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); - // Make sure current element is visible in breadcrumb navigation on small displays const subnav = document.querySelector("ol.sub-nav-list"); - if (subnav && subnav.lastElementChild) { - subnav.lastElementChild.scrollIntoView({ behavior: "instant", inline: "start", block: "nearest" }); - } const keymap = new Map(); const searchInput = document.getElementById("search-input") || document.getElementById("page-search-input"); @@ -351,6 +347,49 @@ document.addEventListener("DOMContentLoaded", function(e) { const mainnav = navbar.querySelector("ul.nav-list"); const toggleButton = document.querySelector("button#navbar-toggle-button"); const tocMenu = sidebar ? sidebar.cloneNode(true) : null; + const themeButton = document.querySelector("button#theme-button"); + const themePanel = document.querySelector("div#theme-panel"); + var themePanelVisible = false; + themeButton.addEventListener("click", e => { + if (!themePanelVisible) { + let {x, y} = themeButton.getBoundingClientRect(); + themePanel.style.display = "block"; + if (window.innerHeight - 85 < y) { + themePanel.style.top = ""; + themePanel.style.bottom = "4px"; + } else { + themePanel.style.top = y + (expanded ? 0 : 36) + "px"; + themePanel.style.bottom = ""; + } + themePanel.style.left = x + (expanded ? 36 : 0) + "px"; + themeButton.setAttribute("aria-expanded", "true"); + themePanelVisible = true; + e.stopPropagation(); + } + }); + function closeThemePanel(e) { + if (themePanelVisible && (!e || !themePanel.contains(e.target))) { + themePanel.style.removeProperty("display"); + themeButton.setAttribute("aria-expanded", "false"); + themePanelVisible = false; + } + } + themePanel.querySelectorAll("input").forEach(input => { + input.removeAttribute("disabled"); + input.addEventListener("change", e => { + setTheme(e.target.value); + }) + }); + const THEMES = ["theme-light", "theme-dark", "theme-os"]; + function setTheme(theme) { + THEMES.forEach(t => { + if (t !== theme) document.body.classList.remove(t); + }); + document.body.classList.add(theme); + localStorage.setItem("theme", theme); + document.getElementById(theme).checked = true; + } + setTheme(localStorage.getItem("theme") || THEMES[0]); makeFilterWidget(sidebar, updateToc); if (tocMenu) { navbar.appendChild(tocMenu); @@ -362,6 +401,7 @@ document.addEventListener("DOMContentLoaded", function(e) { return; } if (!isInput(e.target) && keymap.has(e.key)) { + closeThemePanel(); var elem = keymap.get(e.key); if (elem === filterInput && !elem.offsetParent) { elem = getVisibleFilterInput(true); @@ -370,6 +410,7 @@ document.addEventListener("DOMContentLoaded", function(e) { elem.select(); e.preventDefault(); } else if (e.key === "Escape") { + closeThemePanel(); if (expanded) { collapse(); e.preventDefault(); @@ -389,6 +430,7 @@ document.addEventListener("DOMContentLoaded", function(e) { var windowWidth; var bodyHeight; function collapse() { + closeThemePanel(); if (expanded) { mainnav.removeAttribute("style"); if (tocMenu) { @@ -403,6 +445,7 @@ document.addEventListener("DOMContentLoaded", function(e) { } } function expand() { + closeThemePanel(); expanded = true; mainnav.style.display = "block"; mainnav.style.removeProperty("height"); @@ -457,6 +500,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); } document.querySelector("main").addEventListener("click", collapse); + document.querySelector("body").addEventListener("click", closeThemePanel); document.querySelectorAll("h1, h2, h3, h4, h5, h6") .forEach((hdr, idx) => { // Create anchor links for headers with an associated id attribute diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index f49174f6dcd..2281a469c1c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -193,6 +193,10 @@ doclet.Window_Help_title=API Help doclet.references={0} references doclet.Window_Search_title=Search doclet.search.main_heading=Search +doclet.theme.select_theme=Select Theme +doclet.theme.light=Light +doclet.theme.dark=Dark +doclet.theme.system=System Setting # label for link/button element to show the information below doclet.search.show_more=Additional resources diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index f7994c7f7ed..587121ad582 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -28,13 +28,35 @@ /* Line height for continuous text blocks */ --block-line-height: 1.5; --code-line-height: 1.6; + /* Navigation bar and content area dimensions */ + --top-nav-height: 44px; + --sub-nav-height: 36px; + --nav-height: calc(var(--top-nav-height) + var(--sub-nav-height)); + --max-content-width: 1500px; + --content-margin: 0 auto; + /* Inline SVG icons for dark theme */ + --right-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); + --glass-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); + --x-svg-dark: url('data:image/svg+xml; utf8, \ + \ + \ + '); +} +body { /* Text colors for body and block elements */ --body-text-color: #181818; --block-text-color: #181818; /* Background colors for various elements */ --body-background-color: #ffffff; --section-background-color: var(--body-background-color); - --detail-background-color: #ffffff; + --detail-background-color: var(--body-background-color); --code-background-color: #f5f5f5; --mark-background-color: #f7f7f7; --detail-block-color: #f4f4f4; @@ -76,9 +98,10 @@ /* Search input colors */ --search-input-background-color: #ffffff; --search-input-text-color: #000000; - --search-input-placeholder-color: #909090; + --search-input-placeholder-color: #757575; /* Highlight color for active search tag target */ - --search-tag-highlight-color: #ffff66; + --search-tag-background-color: #ffff66; + --search-tag-text-color: var(--block-text-color); /* Copy button colors and filters */ --button-border-color: #b0b8c8; --button-active-filter: brightness(96%); @@ -86,12 +109,158 @@ /* Colors for invalid tag notifications */ --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - /* Navigation bar dimensions */ - --top-nav-height: 44px; - --sub-nav-height: 36px; - --nav-height: calc(var(--top-nav-height) + var(--sub-nav-height)); - --max-content-width: 1500px; - --content-margin: 0 auto; +} + +body.theme-dark { + --body-text-color: #e8e8e8; + --block-text-color: #e8e8e8; + --body-background-color: #222528; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #303940; + --mark-background-color: #313131; + --detail-block-color: #f4f4f4; + --navbar-background-color: #395A6F; + --navbar-text-color: #ffffff; + --subnav-background-color: #3d454d; + --subnav-link-color: #d8dcdf; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #38444d; + --even-row-color: #222528; + --odd-row-color: #2d3135; + --title-color: #fff; + --link-color: #94badb; + --link-color-active: #ffb45b; + --toc-background-color: #31363c; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #3f4146; + --snippet-background-color: #2d363c; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #444444; + --table-border-color: #717171; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #303030; + --search-input-text-color: #d0d0d0; + --search-input-placeholder-color: #979797; + --search-tag-background-color: #c6c61e; + --search-tag-text-color: #282828; + --button-border-color: #909090; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: invert(100%) brightness(160%); + } +} + +/* + * Dark theme + */ +@media (prefers-color-scheme: dark) { + body { + --body-text-color: #e8e8e8; + --block-text-color: #e8e8e8; + --body-background-color: #222528; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #303940; + --mark-background-color: #313131; + --detail-block-color: #f4f4f4; + --navbar-background-color: #395A6F; + --navbar-text-color: #ffffff; + --subnav-background-color: #3d454d; + --subnav-link-color: #d8dcdf; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #38444d; + --even-row-color: #222528; + --odd-row-color: #2d3135; + --title-color: #fff; + --link-color: #94badb; + --link-color-active: #ffb45b; + --toc-background-color: #31363c; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #3f4146; + --snippet-background-color: #2d363c; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #444444; + --table-border-color: #717171; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #303030; + --search-input-text-color: #d0d0d0; + --search-input-placeholder-color: #979797; + --search-tag-background-color: #c6c61e; + --search-tag-text-color: #282828; + --button-border-color: #909090; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: invert(100%) brightness(160%); + } + } + + body.theme-light { + --body-text-color: #282828; + --block-text-color: #282828; + --body-background-color: #ffffff; + --section-background-color: var(--body-background-color); + --detail-background-color: var(--body-background-color); + --code-background-color: #f5f5f5; + --mark-background-color: #f7f7f7; + --detail-block-color: #f4f4f4; + --navbar-background-color: #4D7A97; + --navbar-text-color: #ffffff; + --subnav-background-color: #dee3e9; + --subnav-link-color: #47688a; + --member-heading-background-color: var(--subnav-background-color); + --selected-background-color: #f8981d; + --selected-text-color: #253441; + --selected-link-color: #4a698a; + --table-header-color: #ebeff4; + --even-row-color: #ffffff; + --odd-row-color: #f0f0f2; + --title-color: #2c4557; + --link-color: #437291; + --link-color-active: #bb7a2a; + --toc-background-color: #f8f8f8; + --toc-highlight-color: var(--subnav-background-color); + --toc-hover-color: #e9ecf0; + --snippet-background-color: #f2f2f4; + --snippet-text-color: var(--block-text-color); + --snippet-highlight-color: #f7c590; + --pre-background-color: var(--snippet-background-color); + --pre-text-color: var(--snippet-text-color); + --border-color: #e6e6e6; + --table-border-color: #000000; + --tab-border-radius: 2px 2px 0 0; + --search-input-background-color: #ffffff; + --search-input-text-color: #000000; + --search-input-placeholder-color: #757575; + --search-tag-background-color: #ffff66; + --search-tag-text-color: var(--block-text-color); + --button-border-color: #b0b8c8; + --button-active-filter: brightness(96%); + --button-focus-filter: brightness(104%); + --invalid-tag-background-color: #ffe6e6; + --invalid-tag-text-color: #000000; + div.main-grid img { + filter: none; + } + } } /* * Styles for individual HTML elements. @@ -186,7 +355,7 @@ hr { */ .about-language { flex: 0 0 auto; - padding:0 20px; + padding:0 20px 0 10px; margin:0; font-size:0.915em; max-width: 50%; @@ -215,6 +384,7 @@ hr { height: 100%; max-width: var(--max-content-width); margin: var(--content-margin); + position: relative; } .top-nav { background-color:var(--navbar-background-color); @@ -236,6 +406,68 @@ hr { button#navbar-toggle-button { display:none; } +button#theme-button { + position: relative; + top: -9.5px; + width: 32px; + height: 32px; + padding: 6px; + margin-left: -6px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 6px; + cursor: pointer; +} +button#theme-button:hover, +button#theme-button:focus-visible { + border: 1px solid var(--button-border-color); +} +button#theme-button img { + display: none; + width: 18px; +} +body.theme-light button#theme-button img.theme-light { + display: inline; +} +body.theme-dark button#theme-button img.theme-dark { + display: inline; +} +@media (prefers-color-scheme: dark) { + body.theme-os button#theme-button img.theme-dark { + display: inline; + } +} +@media (prefers-color-scheme: light) { + body.theme-os button#theme-button img.theme-light { + display: inline; + } +} +div#theme-panel { + display: none; + position: fixed; + z-index: 8; + background-color: var(--toc-background-color); + color: var(--body-text-color); + padding: 4px; + white-space: nowrap; + border: 1px solid var(--border-color); + border-radius: 4px; + box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); +} +div#theme-panel div:first-child { + font-weight: bold; + font-size: 16px; +} +div#theme-panel div { + padding: 8px; +} +div#theme-panel label { + margin-right: 8px; + cursor: pointer; +} +div#theme-panel input { + margin-right: 4px; +} ul.nav-list { display:inline-flex; margin:0; @@ -252,28 +484,25 @@ ul.nav-list li { div.sub-nav { background-color:var(--subnav-background-color); width:100%; - overflow:hidden; font-size:var(--nav-font-size); - height: var(--sub-nav-height); + min-height: var(--sub-nav-height); } ol.sub-nav-list { flex: 1 1 90%; - line-height: 1.8; - display: inline-flex; + line-height: 1.7; overflow: auto; - scroll-snap-type: x mandatory; - scroll-padding-left: 13px; - scrollbar-width: none; padding-left:6px; - white-space: nowrap; - margin:0; + margin: 4px 0; + min-height: 28px; } ol.sub-nav-list::-webkit-scrollbar { display: none; } ol.sub-nav-list li { list-style:none; - scroll-snap-align: start; + display: inline-block; + padding: 2px 0; + margin-right: -4px; } ol.sub-nav-list li:not(:first-child) { background: url("right.svg") no-repeat 3px; @@ -281,6 +510,17 @@ ol.sub-nav-list li:not(:first-child) { padding-left: 17px; list-style: none; } +body.theme-dark ol.sub-nav-list li:not(:first-child) { + background-image: var(--right-svg-dark); +} +@media (prefers-color-scheme: dark) { + ol.sub-nav-list li:not(:first-child) { + background-image: var(--right-svg-dark); + } + body.theme-light ol.sub-nav-list li:not(:first-child) { + background-image: url("right.svg"); + } +} ol.sub-nav-list a { padding: 3px; } @@ -290,7 +530,8 @@ ol.sub-nav-list a.current-selection { } .sub-nav .nav-list-search { flex: 1 1 10%; - margin: 0 15px; + margin: 4.5px 15px auto 5px; + padding: 1px 0; position:relative; white-space: nowrap; } @@ -362,7 +603,7 @@ body.class-declaration-page section.detail > h3:target { } body.class-declaration-page section.detail:target > h3 > a.anchor-link > img, body.class-declaration-page section.detail > h3:target > a.anchor-link > img { - filter: invert(100%) sepia(4%) saturate(98%) hue-rotate(212deg) brightness(160%) contrast(160%); + filter: invert(100%) brightness(160%); } h1 > sup { font-size: small; @@ -1015,7 +1256,7 @@ li.ui-static-link a, li.ui-static-link a:visited { .ui-autocomplete .search-result-desc { font-size: var(--nav-font-size); padding: 2px 4px; - color: #404040; + color: var(--block-text-color); overflow: hidden; text-overflow: ellipsis; } @@ -1023,7 +1264,7 @@ li.ui-static-link a, li.ui-static-link a:visited { font-weight:bold; } .ui-menu .ui-state-active .search-result-desc { - color: #383838; + color: var(--selected-text-color); } .ui-menu .ui-menu-item-wrapper { padding: 3px 4px; @@ -1042,6 +1283,17 @@ input[type="text"] { font-size: var(--nav-font-size); height: 19px; } +body.theme-dark input[type="text"] { + background-image: var(--glass-svg-dark); +} +@media (prefers-color-scheme: dark) { + input[type="text"] { + background-image: var(--glass-svg-dark); + } + body.theme-light input[type="text"] { + background-image: url('glass.svg'); + } +} input#page-search-input { width: calc(180px + 10vw); margin: 10px 0; @@ -1069,6 +1321,21 @@ input#reset-search, input.reset-filter, input#page-search-reset { font-size:0; visibility:hidden; } +body.theme-dark input#reset-search, +body.theme-dark input.reset-filter, +body.theme-dark input#page-search-reset { + background-image: var(--x-svg-dark); +} +@media (prefers-color-scheme: dark) { + input#reset-search, input.reset-filter, input#page-search-reset { + background-image: var(--x-svg-dark); + } + body.theme-light input#reset-search, + body.theme-light input.reset-filter, + body.theme-light input#page-search-reset { + background-image: url('x.svg'); + } +} input#reset-search { position:absolute; right:5px; @@ -1101,6 +1368,7 @@ select#search-modules { } kbd { background-color: #eeeeee; + color: #282828; border: 1px solid #b0b0b0; border-radius: 3px; padding: 0 4px; @@ -1109,11 +1377,13 @@ kbd { font-weight: bold; } .search-tag-result:target { - background-color:var(--search-tag-highlight-color); + background-color:var(--search-tag-background-color); + color:var(--search-tag-text-color); } dd > span:target, h1 > span:target { - background-color: var(--search-tag-highlight-color); + background-color: var(--search-tag-background-color); + color:var(--search-tag-text-color); } section.class-description dd > span:target, section.class-description h1 > span:target { @@ -1160,6 +1430,7 @@ div#result-container { #result-container div.result-table > a.search-result-link:focus-visible, #result-container div.result-table > a.search-result-link.selected { background-color: var(--selected-background-color); + color: var(--selected-text-color); outline: none; } #result-container div.result-table > a.search-result-link .search-result-label { @@ -1168,7 +1439,6 @@ div#result-container { } #result-container div.result-table > a.search-result-link .search-result-desc { font-size: var(--nav-font-size); - color: #404040; overflow: hidden; text-overflow: ellipsis; } @@ -1502,17 +1772,6 @@ table.striped > tbody > tr > th { .top-nav nav.toc ol.toc-list li { font-size: 1.04em; } - nav.toc a:link, nav.toc a:visited { - text-decoration:none; - color:var(--link-color); - } - nav.toc a[href]:hover, nav.toc a[href]:focus { - text-decoration:none; - color:var(--link-color-active); - } - :root { - scroll-behavior: auto; - } header { max-height: 100vh; overflow-y: visible; @@ -1603,7 +1862,6 @@ table.striped > tbody > tr > th { } @media screen and (max-width: 800px) { .about-language { - padding: 0 16px; max-width: 90%; } ul.nav-list li { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg new file mode 100644 index 00000000000..e8fa03499ac --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/sun.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg index 1efb4109241..34a942ffff1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/x.svg @@ -8,6 +8,6 @@ --> - - - \ No newline at end of file + + + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java index 21f12673619..7bc4da60419 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java @@ -115,6 +115,12 @@ public class DocPaths { /** The name of the right pointing angle icon. */ public static final DocPath RIGHT_SVG = DocPath.create("right.svg"); + /** The name of the moon icon for the dark theme. */ + public static final DocPath MOON_SVG = DocPath.create("moon.svg"); + + /** The name of the sun icon for the light theme. */ + public static final DocPath SUN_SVG = DocPath.create("sun.svg"); + /** The name of the syntax highlighting style sheet. */ public static final DocPath HIGHLIGHT_CSS = DocPath.create("highlight.css"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java index 10aa7c0c57b..2ef3ae9db2a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java @@ -203,6 +203,7 @@ public enum HtmlAttr { public enum InputType { CHECKBOX, + RADIO, RESET, TEXT; diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index ee1fa538a57..ba846c293a2 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -143,6 +143,9 @@ public class CheckStylesheetClasses { "search-result-desc", "search-result-label", "search-result-link", "selected", "sort-asc", "sort-desc", "two-column-search-results", "visible"); + // used for themes + removeAll(styleSheetNames, "theme-dark", "theme-light", "theme-os"); + // very JDK specific styleSheetNames.remove("module-graph"); styleSheetNames.remove("sealed-graph"); diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java index 2614b352b71..b4f28b36f3f 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8196027 8196202 8320458 + * @bug 8196027 8196202 8320458 8342705 * @summary test navigation links * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -87,6 +87,9 @@ public class TestModuleNavigation extends JavadocTester {

  • Index
  • Search
  • Help
  • +
  • """); checkOutput("overview-tree.html", true, @@ -98,6 +101,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("deprecated-list.html", true, @@ -109,6 +115,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("index-all.html", true, @@ -120,6 +129,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Search
  • Help
  • +
  • """); checkOutput("search.html", true, @@ -131,6 +143,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Help
  • +
  • """); checkOutput("help-doc.html", true, @@ -142,6 +157,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Search
  • +
  • """); checkOutput("m/p1/package-summary.html", true, @@ -154,6 +172,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("m/p1/A.html", true, @@ -166,6 +187,9 @@ public class TestModuleNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); } diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java index f7cbb78fbeb..5be754a3163 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java @@ -25,6 +25,7 @@ * @test * @bug 7025314 8023700 7198273 8025633 8026567 8081854 8196027 8182765 * 8196200 8196202 8223378 8258659 8261976 8320458 8329537 8350638 + * 8342705 * @summary Make sure the Next/Prev Class links iterate through all types. * Make sure the navagation is 2 columns, not 3. * @library /tools/lib ../../lib @@ -70,6 +71,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/package-summary.html", true, @@ -81,6 +85,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/A.html", true, @@ -92,6 +99,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/C.html", true, @@ -103,6 +113,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/E.html", true, @@ -114,6 +127,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/I.html", true, @@ -339,6 +355,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/A.html", true, @@ -350,6 +369,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/C.html", true, @@ -361,6 +383,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/E.html", true, @@ -372,6 +397,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """); checkOutput("pkg/I.html", true, @@ -411,6 +439,9 @@ public class TestNavigation extends JavadocTester {
  • Index
  • Search
  • Help
  • +
  • """, """
    - + - + diff --git a/doc/building.md b/doc/building.md index 32c6ae46540..047255d1848 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1258,11 +1258,11 @@ toolchain and a sysroot environment which can easily be used together with the following command: ``` -bash configure --with-devkit= --openjdk-target=ppc64-linux-gnu && make +bash configure --with-devkit= --openjdk-target=ppc64le-linux-gnu && make ``` -will configure and build the JDK for Linux/ppc64 assuming that `` -points to a Linux/x86_64 to Linux/ppc64 devkit. +will configure and build the JDK for Linux/ppc64le assuming that `` +points to a Linux/x86_64 to Linux/ppc64le devkit. Devkits can be created from the `make/devkit` directory by executing: @@ -1281,8 +1281,8 @@ at least the following targets are known to work: | x86_64-linux-gnu | | aarch64-linux-gnu | | arm-linux-gnueabihf | -| ppc64-linux-gnu | | ppc64le-linux-gnu | +| riscv64-linux-gnu | | s390x-linux-gnu | `BASE_OS` must be one of `OL` for Oracle Enterprise Linux or `Fedora`. If the diff --git a/make/devkit/Makefile b/make/devkit/Makefile index 5ffa5265aa3..d2167bf33fa 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -39,7 +39,7 @@ # # make TARGETS="aarch64-linux-gnu" BASE_OS=Fedora # or -# make TARGETS="arm-linux-gnueabihf ppc64-linux-gnu" BASE_OS=Fedora BASE_OS_VERSION=17 +# make TARGETS="arm-linux-gnueabihf ppc64le-linux-gnu" BASE_OS=Fedora BASE_OS_VERSION=17 # # to build several devkits for a specific OS version at once. # You can find the final results under ../../build/devkit/result/-to- @@ -50,7 +50,7 @@ # makefile again for cross compilation. Ex: # # PATH=$PWD/../../build/devkit/result/x86_64-linux-gnu-to-x86_64-linux-gnu/bin:$PATH \ -# make TARGETS="arm-linux-gnueabihf,ppc64-linux-gnu" BASE_OS=Fedora +# make TARGETS="arm-linux-gnueabihf ppc64le-linux-gnu" BASE_OS=Fedora # # This is the makefile which iterates over all host and target platforms. # diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 1b9240df49c..f27d47b822c 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -69,15 +69,26 @@ else ifeq ($(BASE_OS), Fedora) ifeq ($(BASE_OS_VERSION), ) BASE_OS_VERSION := $(DEFAULT_OS_VERSION) endif + ifeq ($(filter aarch64 armhfp ppc64le riscv64 s390x x86_64, $(ARCH)), ) + $(error Only "aarch64 armhfp ppc64le riscv64 s390x x86_64" architectures are supported for Fedora, but "$(ARCH)" was requested) + endif ifeq ($(ARCH), riscv64) + ifeq ($(filter 38 39 40 41, $(BASE_OS_VERSION)), ) + $(error Only Fedora 38-41 are supported for "$(ARCH)", but Fedora $(BASE_OS_VERSION) was requested) + endif BASE_URL := http://fedora.riscv.rocks/repos-dist/f$(BASE_OS_VERSION)/latest/$(ARCH)/Packages/ else - LATEST_ARCHIVED_OS_VERSION := 35 - ifeq ($(filter x86_64 armhfp, $(ARCH)), ) + LATEST_ARCHIVED_OS_VERSION := 36 + ifeq ($(filter aarch64 armhfp x86_64, $(ARCH)), ) FEDORA_TYPE := fedora-secondary else FEDORA_TYPE := fedora/linux endif + ifeq ($(ARCH), armhfp) + ifneq ($(BASE_OS_VERSION), 36) + $(error Fedora 36 is the last release supporting "armhfp", but $(BASE_OS) was requested) + endif + endif NOT_ARCHIVED := $(shell [ $(BASE_OS_VERSION) -gt $(LATEST_ARCHIVED_OS_VERSION) ] && echo true) ifeq ($(NOT_ARCHIVED),true) BASE_URL := https://dl.fedoraproject.org/pub/$(FEDORA_TYPE)/releases/$(BASE_OS_VERSION)/Everything/$(ARCH)/os/Packages/ @@ -464,7 +475,7 @@ ifeq ($(ARCH), armhfp) $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --with-float=hard endif -ifneq ($(filter riscv64 ppc64 ppc64le s390x, $(ARCH)), ) +ifneq ($(filter riscv64 ppc64le s390x, $(ARCH)), ) # We only support 64-bit on these platforms anyway CONFIG += --disable-multilib endif From e912977a6687917ed45520c4d8558ebe630e3f52 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Wed, 20 Aug 2025 13:40:13 +0000 Subject: [PATCH 154/471] 8353444: NMT: rename 'category' to 'MemTag' in malloc tracker Reviewed-by: jsjolen --- src/hotspot/share/nmt/mallocLimit.cpp | 37 +++++++++---------- src/hotspot/share/nmt/mallocLimit.hpp | 8 ++-- .../share/nmt/mallocTracker.inline.hpp | 4 +- .../gtest/nmt/test_nmt_malloclimit.cpp | 6 +-- test/hotspot/gtest/nmt/test_nmt_totals.cpp | 4 +- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/nmt/mallocLimit.cpp b/src/hotspot/share/nmt/mallocLimit.cpp index ed479725cf9..2bce2e459e0 100644 --- a/src/hotspot/share/nmt/mallocLimit.cpp +++ b/src/hotspot/share/nmt/mallocLimit.cpp @@ -61,7 +61,7 @@ public: // Check if string at position matches a malloclimit_mode_t. // Advance position on match. - bool match_mode_flag(MallocLimitMode* out) { + bool match_mode(MallocLimitMode* out) { if (eof()) { return false; } @@ -77,9 +77,9 @@ public: return false; } - // Check if string at position matches a category name. + // Check if string at position matches a MemTag name. // Advances position on match. - bool match_category(MemTag* out) { + bool match_mem_tag(MemTag* out) { if (eof()) { return false; } @@ -130,9 +130,9 @@ void MallocLimitSet::set_global_limit(size_t s, MallocLimitMode flag) { _glob.sz = s; _glob.mode = flag; } -void MallocLimitSet::set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode flag) { +void MallocLimitSet::set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode mode) { const int i = NMTUtil::tag_to_index(mem_tag); - _cat[i].sz = s; _cat[i].mode = flag; + _mtag[i].sz = s; _mtag[i].mode = mode; } void MallocLimitSet::reset() { @@ -144,16 +144,15 @@ void MallocLimitSet::reset() { } void MallocLimitSet::print_on(outputStream* st) const { - static const char* flagnames[] = { MODE_FATAL, MODE_OOM }; if (_glob.sz > 0) { st->print_cr("MallocLimit: total limit: " PROPERFMT " (%s)", PROPERFMTARGS(_glob.sz), mode_to_name(_glob.mode)); } else { for (int i = 0; i < mt_number_of_tags; i++) { - if (_cat[i].sz > 0) { + if (_mtag[i].sz > 0) { st->print_cr("MallocLimit: category \"%s\" limit: " PROPERFMT " (%s)", NMTUtil::tag_to_enum_name(NMTUtil::index_to_tag(i)), - PROPERFMTARGS(_cat[i].sz), mode_to_name(_cat[i].mode)); + PROPERFMTARGS(_mtag[i].sz), mode_to_name(_mtag[i].mode)); } } } @@ -164,10 +163,10 @@ bool MallocLimitSet::parse_malloclimit_option(const char* v, const char** err) { #define BAIL_UNLESS(condition, errormessage) if (!(condition)) { *err = errormessage; return false; } // Global form: - // MallocLimit=[:flag] + // MallocLimit=[:mode] - // Category-specific form: - // MallocLimit=:[:flag][,:[:flag]...] + // MemTag-specific form: + // MallocLimit=:[:mode][,:[:mode]...] reset(); @@ -177,29 +176,29 @@ bool MallocLimitSet::parse_malloclimit_option(const char* v, const char** err) { // Global form? if (sst.match_size(&_glob.sz)) { - // Match optional mode flag (e.g. 1g:oom) + // Match optional mode (e.g. 1g:oom) if (!sst.eof()) { BAIL_UNLESS(sst.match_char(':'), "Expected colon"); - BAIL_UNLESS(sst.match_mode_flag(&_glob.mode), "Expected flag"); + BAIL_UNLESS(sst.match_mode(&_glob.mode), "Expected mode"); } } - // Category-specific form? + // MemTag-specific form? else { while (!sst.eof()) { MemTag mem_tag; - // Match category, followed by : - BAIL_UNLESS(sst.match_category(&mem_tag), "Expected category name"); + // Match MemTag, followed by : + BAIL_UNLESS(sst.match_mem_tag(&mem_tag), "Expected category name"); BAIL_UNLESS(sst.match_char(':'), "Expected colon following category"); - malloclimit* const modified_limit = &_cat[NMTUtil::tag_to_index(mem_tag)]; + malloclimit* const modified_limit = &_mtag[NMTUtil::tag_to_index(mem_tag)]; // Match size BAIL_UNLESS(sst.match_size(&modified_limit->sz), "Expected size"); - // Match optional flag + // Match optional mode if (!sst.eof() && sst.match_char(':')) { - BAIL_UNLESS(sst.match_mode_flag(&modified_limit->mode), "Expected flag"); + BAIL_UNLESS(sst.match_mode(&modified_limit->mode), "Expected mode"); } // More to come? diff --git a/src/hotspot/share/nmt/mallocLimit.hpp b/src/hotspot/share/nmt/mallocLimit.hpp index ec6799b41a3..d41eaabea46 100644 --- a/src/hotspot/share/nmt/mallocLimit.hpp +++ b/src/hotspot/share/nmt/mallocLimit.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 SAP SE. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -46,7 +46,7 @@ class outputStream; class MallocLimitSet { malloclimit _glob; // global limit - malloclimit _cat[mt_number_of_tags]; // per-category limit + malloclimit _mtag[mt_number_of_tags]; // per-memtag limit public: MallocLimitSet(); @@ -57,7 +57,7 @@ public: void set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode mode); const malloclimit* global_limit() const { return &_glob; } - const malloclimit* category_limit(MemTag mem_tag) const { return &_cat[(int)mem_tag]; } + const malloclimit* mem_tag_limit(MemTag mem_tag) const { return &_mtag[(int)mem_tag]; } void print_on(outputStream* st) const; }; @@ -69,7 +69,7 @@ class MallocLimitHandler : public AllStatic { public: static const malloclimit* global_limit() { return _limits.global_limit(); } - static const malloclimit* category_limit(MemTag mem_tag) { return _limits.category_limit(mem_tag); } + static const malloclimit* mem_tag_limit(MemTag mem_tag) { return _limits.mem_tag_limit(mem_tag); } static void initialize(const char* options); static void print_on(outputStream* st); diff --git a/src/hotspot/share/nmt/mallocTracker.inline.hpp b/src/hotspot/share/nmt/mallocTracker.inline.hpp index b2aec345eff..51a7f28cf99 100644 --- a/src/hotspot/share/nmt/mallocTracker.inline.hpp +++ b/src/hotspot/share/nmt/mallocTracker.inline.hpp @@ -49,8 +49,8 @@ inline bool MallocMemorySummary::check_exceeds_limit(size_t s, MemTag mem_tag) { return total_limit_reached(s, so_far, l); } } else { - // Category Limit? - l = MallocLimitHandler::category_limit(mem_tag); + // MemTag Limit? + l = MallocLimitHandler::mem_tag_limit(mem_tag); if (l->sz > 0) { const MallocMemory* mm = as_snapshot()->by_tag(mem_tag); size_t so_far = mm->malloc_size() + mm->arena_size(); diff --git a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp index 83d4bd6235b..da357285148 100644 --- a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp @@ -42,8 +42,8 @@ static bool compare_limits(const malloclimit* a, const malloclimit* b) { static bool compare_sets(const MallocLimitSet* a, const MallocLimitSet* b) { if (compare_limits(a->global_limit(), b->global_limit())) { for (int i = 0; i < mt_number_of_tags; i++) { - if (!compare_limits(a->category_limit(NMTUtil::index_to_tag(i)), - b->category_limit(NMTUtil::index_to_tag(i)))) { + if (!compare_limits(a->mem_tag_limit(NMTUtil::index_to_tag(i)), + b->mem_tag_limit(NMTUtil::index_to_tag(i)))) { return false; } } @@ -92,7 +92,7 @@ TEST(NMT, MallocLimitPerCategory) { test("metaspace:1m,compiler:2m:oom,thread:3m:oom,threadstack:4m:oom,class:5m,classshared:6m", expected); } -TEST(NMT, MallocLimitCategoryEnumNames) { +TEST(NMT, MallocLimitMemTagEnumNames) { MallocLimitSet expected; stringStream option; for (int i = 0; i < mt_number_of_tags; i++) { diff --git a/test/hotspot/gtest/nmt/test_nmt_totals.cpp b/test/hotspot/gtest/nmt/test_nmt_totals.cpp index 61c591fa0bb..690751ede54 100644 --- a/test/hotspot/gtest/nmt/test_nmt_totals.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_totals.cpp @@ -88,8 +88,8 @@ TEST_VM(NMTNumbers, totals) { void* p[NUM_ALLOCS]; for (int i = 0; i < NUM_ALLOCS; i ++) { // spread over categories - int category = i % (mt_number_of_tags - 1); - p[i] = NEW_C_HEAP_ARRAY(char, ALLOC_SIZE, (MemTag)category); + int mtag = i % (mt_number_of_tags - 1); + p[i] = NEW_C_HEAP_ARRAY(char, ALLOC_SIZE, (MemTag)mtag); } const totals_t t2 = get_totals(); From ebf5ae8435e27e4315e43237b1167a1e99150393 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 20 Aug 2025 14:49:16 +0000 Subject: [PATCH 155/471] 8359222: [asan] jvmti/vthread/ToggleNotifyJvmtiTest/ToggleNotifyJvmtiTest triggers stack-buffer-overflow error Reviewed-by: dholmes, fbredberg, coleenp --- .../continuationFreezeThaw_aarch64.inline.hpp | 16 +++++++--- .../arm/continuationFreezeThaw_arm.inline.hpp | 4 +++ .../ppc/continuationFreezeThaw_ppc.inline.hpp | 3 ++ .../continuationFreezeThaw_riscv.inline.hpp | 3 ++ .../continuationFreezeThaw_s390.inline.hpp | 4 +++ .../x86/continuationFreezeThaw_x86.inline.hpp | 16 +++++++--- .../continuationFreezeThaw_zero.inline.hpp | 4 +++ .../share/runtime/continuationFreezeThaw.cpp | 29 ++++++++++++++++--- .../share/runtime/continuationHelper.hpp | 5 +++- 9 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp index e82162df4ab..1fd59b81d9e 100644 --- a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -101,9 +101,12 @@ frame FreezeBase::new_heap_frame(frame& f, frame& caller) { *hf.addr_at(frame::interpreter_frame_locals_offset) = locals_offset; return hf; } else { - // We need to re-read fp out of the frame because it may be an oop and we might have - // had a safepoint in finalize_freeze, after constructing f. - fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset); + // For a compiled frame we need to re-read fp out of the frame because it may be an + // oop and we might have had a safepoint in finalize_freeze, after constructing f. + // For stub/native frames the value is not used while frozen, and will be constructed again + // when thawing the frame (see ThawBase::new_stack_frame). We use a special bad address to + // help with debugging, particularly when inspecting frames and identifying invalid accesses. + fp = FKind::compiled ? *(intptr_t**)(f.sp() - frame::sender_sp_offset) : (intptr_t*)badAddressVal; int fsize = FKind::size(f); sp = caller.unextended_sp() - fsize; @@ -192,6 +195,11 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + intptr_t* fp_addr = sp - frame::sender_sp_offset; + *fp_addr = badAddressVal; +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp index b276a7d70b6..389cf4dc936 100644 --- a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp +++ b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp index 8eb33c3cd0b..fa878b07d43 100644 --- a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp @@ -334,6 +334,9 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { #endif } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp index 78975b8df89..461dc19f383 100644 --- a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp @@ -194,6 +194,9 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp index bee7bb72cbf..d39821bd034 100644 --- a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp +++ b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp index 9591c9f2c96..126f4043cad 100644 --- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp +++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -98,9 +98,12 @@ frame FreezeBase::new_heap_frame(frame& f, frame& caller) { *hf.addr_at(frame::interpreter_frame_locals_offset) = locals_offset; return hf; } else { - // We need to re-read fp out of the frame because it may be an oop and we might have - // had a safepoint in finalize_freeze, after constructing f. - fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset); + // For a compiled frame we need to re-read fp out of the frame because it may be an + // oop and we might have had a safepoint in finalize_freeze, after constructing f. + // For stub/native frames the value is not used while frozen, and will be constructed again + // when thawing the frame (see ThawBase::new_stack_frame). We use a special bad address to + // help with debugging, particularly when inspecting frames and identifying invalid accesses. + fp = FKind::compiled ? *(intptr_t**)(f.sp() - frame::sender_sp_offset) : (intptr_t*)badAddressVal; int fsize = FKind::size(f); sp = caller.unextended_sp() - fsize; @@ -183,6 +186,11 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + intptr_t* fp_addr = sp - frame::sender_sp_offset; + *fp_addr = badAddressVal; +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp index de2769fb376..eb6be8772f9 100644 --- a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp +++ b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index a928b0443ee..1027b4447c5 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -460,6 +460,7 @@ private: template frame new_heap_frame(frame& f, frame& caller); inline void set_top_frame_metadata_pd(const frame& hf); inline void patch_pd(frame& callee, const frame& caller); + inline void patch_pd_unused(intptr_t* sp); void adjust_interpreted_frame_unextended_sp(frame& f); static inline void prepare_freeze_interpreted_top_frame(frame& f); static inline void relativize_interpreted_frame_metadata(const frame& f, const frame& hf); @@ -783,9 +784,24 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J log_develop_trace(continuations)("freeze_fast start: " INTPTR_FORMAT " sp: %d chunk_top: " INTPTR_FORMAT, p2i(chunk->start_address()), chunk_new_sp, p2i(chunk_top)); - intptr_t* from = _cont_stack_top - frame::metadata_words_at_bottom; - intptr_t* to = chunk_top - frame::metadata_words_at_bottom; - copy_to_chunk(from, to, cont_size() + frame::metadata_words_at_bottom); + + int adjust = frame::metadata_words_at_bottom; +#if INCLUDE_ASAN && defined(AARCH64) + // Reading at offset frame::metadata_words_at_bottom from _cont_stack_top + // will accesss memory at the callee frame, which on preemption cases will + // be the VM native method being called. The Arm 64-bit ABI doesn't specify + // a location where the frame record (returnpc+fp) has to be stored within + // a stack frame, and GCC currently chooses to save it at the top of the + // frame (lowest address). ASan treats this memory access in the callee as + // an overflow access to one of the locals stored in that frame. For these + // preemption cases we don't need to read these words anyways so we avoid it. + if (_preempt) { + adjust = 0; + } +#endif + intptr_t* from = _cont_stack_top - adjust; + intptr_t* to = chunk_top - adjust; + copy_to_chunk(from, to, cont_size() + adjust); // Because we're not patched yet, the chunk is now in a bad state // patch return pc of the bottom-most frozen frame (now in the chunk) @@ -816,6 +832,11 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J address last_pc = _last_frame.pc(); ContinuationHelper::patch_return_address_at(chunk_top - frame::sender_sp_ret_address_offset(), last_pc); chunk->set_pc(last_pc); + // For stub/native frames the fp is not used while frozen, and will be constructed + // again when thawing the frame (see ThawBase::handle_preempted_continuation). We + // patch it with a special bad address to help with debugging, particularly when + // inspecting frames and identifying invalid accesses. + patch_pd_unused(chunk_top); } else { chunk->set_pc(ContinuationHelper::return_address_at( _cont_stack_top - frame::sender_sp_ret_address_offset())); @@ -2484,7 +2505,7 @@ intptr_t* ThawBase::handle_preempted_continuation(intptr_t* sp, Continuation::pr if (fast_case) { // If we thawed in the slow path the runtime stub/native wrapper frame already // has the correct fp (see ThawBase::new_stack_frame). On the fast path though, - // we copied the original fp at the time of freeze which now will have to be fixed. + // we copied the fp patched during freeze, which will now have to be fixed. assert(top.is_runtime_frame() || top.is_native_frame(), ""); int fsize = top.cb()->frame_size(); patch_pd(top, sp + fsize); diff --git a/src/hotspot/share/runtime/continuationHelper.hpp b/src/hotspot/share/runtime/continuationHelper.hpp index 0b3e6c72452..dffbf333bcc 100644 --- a/src/hotspot/share/runtime/continuationHelper.hpp +++ b/src/hotspot/share/runtime/continuationHelper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -65,6 +65,7 @@ public: class ContinuationHelper::Frame : public AllStatic { public: static const bool interpreted = false; + static const bool compiled = false; static const bool stub = false; static const bool native = false; @@ -127,6 +128,8 @@ public: class ContinuationHelper::CompiledFrame : public ContinuationHelper::NonInterpretedFrame { public: + static const bool compiled = true; + static bool is_instance(const frame& f); #ifdef ASSERT From 5ca8d7c2a79ed3d9a6def61ba0fbd0acd5d404dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 20 Aug 2025 14:52:04 +0000 Subject: [PATCH 156/471] 8284499: Add the ability to right-click and open in new tab JavaDoc Search results Reviewed-by: liach --- .../doclets/formats/html/resources/search.js.template | 10 ++++++++-- .../doclets/formats/html/resources/stylesheet.css | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template index 5a36ee06819..16ae5a4d221 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template @@ -423,7 +423,8 @@ $.widget("custom.catcomplete", $.ui.autocomplete, { var label = getResultLabel(item); var resultDesc = getResultDescription(item); return $("
  • ") - .append($("
    ") + .append($("") + .attr("href", item.indexItem ? pathtoroot + getURL(item.indexItem, item.category) : null) .append($("").addClass("search-result-label").html(label)) .append($("").addClass("search-result-desc").html(resultDesc))) .appendTo(ul); @@ -515,7 +516,7 @@ $(function() { this.menu.previousFilter = "_"; this.menu.filterTimer = this.menu._delay(function() { delete this.previousFilter; - }, 1000); + }, 500); return doSearch(request, response); }, response: function(event, ui) { @@ -531,6 +532,11 @@ $(function() { collision: "flip" }, select: function(event, ui) { + for (var e = event.originalEvent; e != null; e = e.originalEvent) { + if (e.type === "click") { + return; + } + } if (ui.item.indexItem) { var url = getURL(ui.item.indexItem, ui.item.category); window.location.href = pathtoroot + url; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 587121ad582..778ee5f03b3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -1235,11 +1235,11 @@ li.ui-static-link a, li.ui-static-link a:visited { grid-template-columns: auto auto; } .ui-autocomplete > li, -.ui-autocomplete > li > div { +.ui-autocomplete > li > a { grid-column: 1 / 3; } .ui-autocomplete > li.result-item, -.ui-autocomplete > li.result-item > div { +.ui-autocomplete > li.result-item > a { display: grid; grid-template-columns: subgrid; } @@ -1250,6 +1250,7 @@ li.ui-static-link a, li.ui-static-link a:visited { } .ui-autocomplete .search-result-label { padding: 1px 4px; + color: var(--block-text-color); overflow: hidden; text-overflow: ellipsis; } @@ -1263,6 +1264,7 @@ li.ui-static-link a, li.ui-static-link a:visited { .ui-autocomplete .result-highlight { font-weight:bold; } +.ui-menu .ui-state-active .search-result-label, .ui-menu .ui-state-active .search-result-desc { color: var(--selected-text-color); } @@ -1843,9 +1845,9 @@ table.striped > tbody > tr > th { grid-template-columns: none; } .ui-autocomplete > li, - .ui-autocomplete > li > div, + .ui-autocomplete > li > a, .ui-autocomplete > li.result-item, - .ui-autocomplete > li.result-item > div { + .ui-autocomplete > li.result-item > a { grid-column: unset; display: block; grid-template-columns: none; From 3e60ab51fea17098d852931a06f4f5a827ae0e78 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 20 Aug 2025 15:04:48 +0000 Subject: [PATCH 157/471] 8348611: Eliminate DeferredLintHandler and emit warnings after attribution 8224228: No way to locally suppress lint warnings in parser/tokenizer or preview features 8353758: Missing calls to Log.useSource() in JavacTrees Reviewed-by: mcimadamore, vromero, jlahoda --- .../sun/tools/javac/api/JavacTaskImpl.java | 7 +- .../sun/tools/javac/api/JavacTaskPool.java | 2 + .../com/sun/tools/javac/api/JavacTrees.java | 13 +- .../tools/javac/code/DeferredLintHandler.java | 176 --------- .../com/sun/tools/javac/code/Lint.java | 26 +- .../com/sun/tools/javac/code/LintMapper.java | 328 +++++++++++++++++ .../com/sun/tools/javac/code/Preview.java | 8 +- .../com/sun/tools/javac/comp/Annotate.java | 60 +--- .../com/sun/tools/javac/comp/Attr.java | 40 +-- .../com/sun/tools/javac/comp/Check.java | 180 ++++------ .../com/sun/tools/javac/comp/Flow.java | 335 ++++++++---------- .../com/sun/tools/javac/comp/MemberEnter.java | 44 +-- .../com/sun/tools/javac/comp/Modules.java | 33 +- .../tools/javac/comp/ThisEscapeAnalyzer.java | 86 ++--- .../com/sun/tools/javac/comp/TypeEnter.java | 32 +- .../sun/tools/javac/file/BaseFileManager.java | 2 +- .../com/sun/tools/javac/file/Locations.java | 23 +- .../com/sun/tools/javac/jvm/ClassReader.java | 17 +- .../com/sun/tools/javac/main/Arguments.java | 29 +- .../sun/tools/javac/main/JavaCompiler.java | 10 + .../sun/tools/javac/parser/JavaTokenizer.java | 40 +-- .../sun/tools/javac/parser/JavacParser.java | 29 +- .../com/sun/tools/javac/parser/Lexer.java | 12 +- .../sun/tools/javac/parser/ParserFactory.java | 5 +- .../com/sun/tools/javac/parser/Scanner.java | 9 +- .../tools/javac/parser/ScannerFactory.java | 5 +- .../sun/tools/javac/parser/VirtualParser.java | 10 +- .../tools/javac/processing/JavacFiler.java | 27 +- .../JavacProcessingEnvironment.java | 29 +- .../tools/javac/resources/compiler.properties | 42 ++- .../sun/tools/javac/util/JCDiagnostic.java | 34 ++ .../classes/com/sun/tools/javac/util/Log.java | 169 ++++++++- .../tools/javac/6304921/TestLog.java | 13 +- test/langtools/tools/javac/ImportModule.java | 2 +- .../OverrideChecks/6400189/T6400189a.out | 2 +- .../OverrideChecks/6400189/T6400189b.out | 2 +- .../DanglingDocCommentsClass.enabled.out | 4 +- .../DanglingDocCommentsClass_Line.enabled.out | 4 +- ...DanglingDocCommentsClass_Mixed.enabled.out | 2 +- .../DanglingDocCommentsEnum.enabled.out | 6 +- .../generics/diamond/7188968/T7188968.out | 6 +- .../tools/javac/lambda/TargetType22.out | 2 +- .../tools/javac/lint/LexicalLintNesting.java | 170 +++++++++ .../tools/javac/lint/LexicalLintNesting.out | 10 + .../tools/javac/lint/TextBlockSuppress.java | 61 ++++ .../tools/javac/lint/TextBlockSuppress.out | 5 + .../mandatoryWarnings/deprecated/Test5.out | 2 +- .../mandatoryWarnings/deprecated/Test5b.out | 2 +- .../javac/modules/AnnotationsOnModules.java | 4 +- .../tools/javac/preview/PreviewErrors.java | 6 +- .../tools/javac/preview/PreviewTest.java | 97 ++++- .../tools/javac/varargs/7097436/T7097436.out | 4 +- .../javac/warnings/6594914/T6594914a.out | 2 +- .../tools/javac/warnings/7090499/T7090499.out | 8 +- .../UnneededStrictfpWarningToolBox.java | 4 +- .../javac/warnings/suppress/T6480588.out | 12 +- 56 files changed, 1344 insertions(+), 948 deletions(-) delete mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java create mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java create mode 100644 test/langtools/tools/javac/lint/LexicalLintNesting.java create mode 100644 test/langtools/tools/javac/lint/LexicalLintNesting.out create mode 100644 test/langtools/tools/javac/lint/TextBlockSuppress.java create mode 100644 test/langtools/tools/javac/lint/TextBlockSuppress.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 980ce060c33..65ce640ef76 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -412,6 +412,7 @@ public class JavacTaskImpl extends BasicJavacTask { f.run(compiler.todo, classes); } } finally { + compiler.log.reportOutstandingWarnings(); compiler.log.flush(); } return results; @@ -483,8 +484,10 @@ public class JavacTaskImpl extends BasicJavacTask { } } finally { - if (compiler != null) + if (compiler != null) { + compiler.log.reportOutstandingWarnings(); compiler.log.flush(); + } } return results; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java index 6214c3775d3..65772cdccb3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java @@ -55,6 +55,7 @@ import com.sun.source.util.TaskEvent.Kind; import com.sun.source.util.TaskListener; import com.sun.source.util.TreeScanner; import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symtab; @@ -268,6 +269,7 @@ public class JavacTaskPool { if (ht.get(Log.logKey) instanceof ReusableLog) { //log already inited - not first round Log.instance(this).clear(); + LintMapper.instance(this).clear(); Enter.instance(this).newRound(); ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear(); Types.instance(this).newRound(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 4ced466d938..2eca26de838 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -360,9 +360,14 @@ public class JavacTrees extends DocTrees { Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); try { Env env = getAttrContext(path.getTreePath()); - Type t = attr.attribType(dcReference.qualifierExpression, env); - if (t != null && !t.isErroneous()) { - return t; + JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); + try { + Type t = attr.attribType(dcReference.qualifierExpression, env); + if (t != null && !t.isErroneous()) { + return t; + } + } finally { + log.useSource(prevSource); } } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; @@ -388,6 +393,7 @@ public class JavacTrees extends DocTrees { return null; } Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); + JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); try { final TypeSymbol tsym; final Name memberName; @@ -509,6 +515,7 @@ public class JavacTrees extends DocTrees { } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; } finally { + log.useSource(prevSource); log.popDiagnosticHandler(deferredDiagnosticHandler); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java deleted file mode 100644 index 11544b92b7f..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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. Oracle 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.javac.code; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Optional; -import java.util.function.Consumer; - -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.Tag; -import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.Context; - -/** - * Holds pending {@link Lint} warnings until the {@lint Lint} instance associated with the containing - * module, package, class, method, or variable declaration is known so that {@link @SupressWarnings} - * suppressions may be applied. - * - *

    - * Warnings are regsistered at any time prior to attribution via {@link #report}. The warning will be - * associated with the declaration placed in context by the most recent invocation of {@link #push push()} - * not yet {@link #pop}'d. Warnings are actually emitted later, during attribution, via {@link #flush}. - * - *

    - * There is also an "immediate" mode, where warnings are emitted synchronously; see {@link #pushImmediate}. - * - *

    - * Deferred warnings are grouped by the innermost containing module, package, class, method, or variable - * declaration (represented by {@link JCTree} nodes), so that the corresponding {@link Lint} configuration - * can be applied when the warning is eventually generated. - * - *

    This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class DeferredLintHandler { - - protected static final Context.Key deferredLintHandlerKey = new Context.Key<>(); - - public static DeferredLintHandler instance(Context context) { - DeferredLintHandler instance = context.get(deferredLintHandlerKey); - if (instance == null) - instance = new DeferredLintHandler(context); - return instance; - } - - /** - * Registered {@link LintLogger}s grouped by the innermost containing module, package, class, - * method, or variable declaration. - */ - private final HashMap> deferralMap = new HashMap<>(); - - /** - * The current "reporter" stack, reflecting calls to {@link #push} and {@link #pop}. - * - *

    - * The top of the stack determines how calls to {@link #report} are handled. - */ - private final ArrayDeque> reporterStack = new ArrayDeque<>(); - - @SuppressWarnings("this-escape") - protected DeferredLintHandler(Context context) { - context.put(deferredLintHandlerKey, this); - Lint rootLint = Lint.instance(context); - pushImmediate(rootLint); // default to "immediate" mode - } - -// LintLogger - - /**An interface for deferred lint reporting - loggers passed to - * {@link #report(LintLogger) } will be called when - * {@link #flush(DiagnosticPosition) } is invoked. - */ - public interface LintLogger { - - /** - * Generate a warning if appropriate. - * - * @param lint the applicable lint configuration - */ - void report(Lint lint); - } - -// Reporter Stack - - /** - * Defer {@link #report}ed warnings until the given declaration is flushed. - * - * @param decl module, package, class, method, or variable declaration - * @see #pop - */ - public void push(JCTree decl) { - Assert.check(decl.getTag() == Tag.MODULEDEF - || decl.getTag() == Tag.PACKAGEDEF - || decl.getTag() == Tag.CLASSDEF - || decl.getTag() == Tag.METHODDEF - || decl.getTag() == Tag.VARDEF); - reporterStack.push(logger -> deferralMap - .computeIfAbsent(decl, s -> new ArrayList<>()) - .add(logger)); - } - - /** - * Enter "immediate" mode so that {@link #report}ed warnings are emitted synchonously. - * - * @param lint lint configuration to use for reported warnings - */ - public void pushImmediate(Lint lint) { - reporterStack.push(logger -> logger.report(lint)); - } - - /** - * Revert to the previous configuration in effect prior to the most recent invocation - * of {@link #push} or {@link #pushImmediate}. - * - * @see #pop - */ - public void pop() { - Assert.check(reporterStack.size() > 1); // the bottom stack entry should never be popped - reporterStack.pop(); - } - - /** - * Report a warning. - * - *

    - * In immediate mode, the warning is emitted synchronously. Otherwise, the warning is emitted later - * when the current declaration is flushed. - */ - public void report(LintLogger logger) { - Assert.check(!reporterStack.isEmpty()); - reporterStack.peek().accept(logger); - } - -// Warning Flush - - /** - * Emit deferred warnings encompassed by the given declaration. - * - * @param decl module, package, class, method, or variable declaration - * @param lint lint configuration corresponding to {@code decl} - */ - public void flush(JCTree decl, Lint lint) { - Optional.of(decl) - .map(deferralMap::remove) - .stream() - .flatMap(ArrayList::stream) - .forEach(logger -> logger.report(lint)); - } -} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 6d83f95fce4..8eab238f82a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -374,11 +374,8 @@ public class Lint { /** * Warn about issues relating to use of text blocks - * - *

    - * This category is not supported by {@code @SuppressWarnings} (yet - see JDK-8224228). */ - TEXT_BLOCKS("text-blocks", false), + TEXT_BLOCKS("text-blocks"), /** * Warn about possible 'this' escapes before subclass instance is fully initialized. @@ -476,27 +473,6 @@ public class Lint { return suppressedValues.contains(lc); } - /** - * Helper method. Log a lint warning if its lint category is enabled. - * - * @param warning key for the localized warning message - */ - public void logIfEnabled(LintWarning warning) { - logIfEnabled(null, warning); - } - - /** - * Helper method. Log a lint warning if its lint category is enabled. - * - * @param pos source position at which to report the warning - * @param warning key for the localized warning message - */ - public void logIfEnabled(DiagnosticPosition pos, LintWarning warning) { - if (isEnabled(warning.getLintCategory())) { - log.warning(pos, warning); - } - } - /** * Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration. * diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java new file mode 100644 index 00000000000..b15ddae02e1 --- /dev/null +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.code; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.tree.EndPosTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +/** + * Maps source code positions to the applicable {@link Lint} instance. + * + *

    + * Because {@code @SuppressWarnings} is a Java symbol, in general this mapping can't be + * calculated until after attribution. As each top-level declaration (class, package, or module) + * is attributed, this singleton is notified and the {@link Lint}s that apply to every source + * position within that top-level declaration are calculated. + * + *

    + * The method {@link #lintAt} returns the {@link Lint} instance applicable to source position; + * if it can't be determined yet, an empty {@link Optional} is returned. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class LintMapper { + + // The key for the context singleton + private static final Context.Key CONTEXT_KEY = new Context.Key<>(); + + // Per-source file information. Note: during the parsing of a file, an entry exists but the FileInfo value is null + private final Map fileInfoMap = new HashMap<>(); + + // Compiler context + private final Context context; + + // These are initialized lazily; see initializeIfNeeded() + private Lint rootLint; + + /** + * Obtain the {@link LintMapper} context singleton. + */ + public static LintMapper instance(Context context) { + LintMapper instance = context.get(CONTEXT_KEY); + if (instance == null) + instance = new LintMapper(context); + return instance; + } + + /** + * Constructor. + */ + @SuppressWarnings("this-escape") + protected LintMapper(Context context) { + context.put(CONTEXT_KEY, this); + this.context = context; + } + + // Lazy initialization to avoid dependency loops + private void initializeIfNeeded() { + if (rootLint == null) + rootLint = Lint.instance(context); + } + +// Lint Operations + + /** + * Determine if the given file is known to this instance. + * + * @param sourceFile source file + * @return true if file is recognized + */ + public boolean isKnown(JavaFileObject sourceFile) { + return fileInfoMap.containsKey(sourceFile); + } + + /** + * Obtain the {@link Lint} configuration that applies at the given position, if known. + * + * @param sourceFile source file + * @param pos source position + * @return the applicable {@link Lint}, if known, otherwise empty + */ + public Optional lintAt(JavaFileObject sourceFile, DiagnosticPosition pos) { + initializeIfNeeded(); + return Optional.of(sourceFile) + .map(fileInfoMap::get) + .flatMap(fileInfo -> fileInfo.lintAt(pos)); + } + + /** + * Calculate {@lint Lint} configurations for all positions within the given top-level declaration. + * + * @param sourceFile source file + * @param tree top-level declaration (class, package, or module) + */ + public void calculateLints(JavaFileObject sourceFile, JCTree tree, EndPosTable endPositions) { + Assert.check(rootLint != null); + fileInfoMap.get(sourceFile).afterAttr(tree, endPositions); + } + + /** + * Reset this instance. + */ + public void clear() { + fileInfoMap.clear(); + } + +// Parsing Notifications + + /** + * Invoked when file parsing starts to create an entry for the new file (but with a null value). + */ + public void startParsingFile(JavaFileObject sourceFile) { + initializeIfNeeded(); + fileInfoMap.put(sourceFile, null); + } + + /** + * Invoked when file parsing completes to put in place a corresponding {@link FileInfo}. + */ + public void finishParsingFile(JCCompilationUnit tree) { + Assert.check(rootLint != null); + fileInfoMap.put(tree.sourcefile, new FileInfo(rootLint, tree)); + } + +// FileInfo + + /** + * Holds {@link Lint} information for a fully parsed source file. + * + *

    + * Initially (immediately after parsing), "unmappedDecls" contains a {@link Span} corresponding to each + * top-level declaration in the source file. As each top-level declaration is attributed, the corresponding + * {@link Span} is removed and the corresponding {@link LintRange} subtree is populated under "rootRange". + */ + private static class FileInfo { + + final LintRange rootRange; // the root LintRange (covering the entire source file) + final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution + + // After parsing: Add top-level declarations to our "unmappedDecls" list + FileInfo(Lint rootLint, JCCompilationUnit tree) { + rootRange = new LintRange(rootLint); + tree.defs.stream() + .filter(this::isTopLevelDecl) + .map(decl -> new Span(decl, tree.endPositions)) + .forEach(unmappedDecls::add); + } + + // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange" + void afterAttr(JCTree tree, EndPosTable endPositions) { + for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) { + if (i.next().contains(tree.pos())) { + rootRange.populateSubtree(tree, endPositions); + i.remove(); + return; + } + } + throw new AssertionError("top-level declaration not found"); + } + + // Find the most specific Lint configuration applying to the given position, unless the position has not been mapped yet + Optional lintAt(DiagnosticPosition pos) { + boolean mapped = unmappedDecls.stream().noneMatch(span -> span.contains(pos)); + return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty(); + } + + boolean isTopLevelDecl(JCTree tree) { + return tree.getTag() == Tag.MODULEDEF + || tree.getTag() == Tag.PACKAGEDEF + || tree.getTag() == Tag.CLASSDEF; + } + } + +// Span + + /** + * A lexical range. + */ + private record Span(int startPos, int endPos) { + + static final Span MAXIMAL = new Span(Integer.MIN_VALUE, Integer.MAX_VALUE); + + Span(JCTree tree, EndPosTable endPositions) { + this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions)); + } + + boolean contains(DiagnosticPosition pos) { + int offset = pos.getLintPosition(); + return offset == startPos || (offset > startPos && offset < endPos); + } + + boolean contains(Span that) { + return this.startPos <= that.startPos && this.endPos >= that.endPos; + } + } + +// LintRange + + /** + * A tree of nested lexical ranges and the {@link Lint} configurations that apply therein. + */ + private record LintRange( + Span span, // declaration's lexical range + Lint lint, // the Lint configuration that applies at this declaration + List children // the nested declarations one level below this node + ) { + + // Create a node representing the entire file, using the root lint configuration + LintRange(Lint rootLint) { + this(Span.MAXIMAL, rootLint, new ArrayList<>()); + } + + // Create a node representing the given declaration and its corresponding Lint configuration + LintRange(JCTree tree, EndPosTable endPositions, Lint lint) { + this(new Span(tree, endPositions), lint, new ArrayList<>()); + } + + // Find the most specific node in this tree (including me) that contains the given position, if any + LintRange bestMatch(DiagnosticPosition pos) { + return children.stream() + .map(child -> child.bestMatch(pos)) + .filter(Objects::nonNull) + .reduce((a, b) -> a.span.contains(b.span) ? b : a) + .orElseGet(() -> span.contains(pos) ? this : null); + } + + // Populate a sparse subtree corresponding to the given nested declaration. + // Only when the Lint configuration differs from the parent is a node added. + void populateSubtree(JCTree tree, EndPosTable endPositions) { + new TreeScanner() { + + private LintRange currentNode = LintRange.this; + + @Override + public void visitModuleDef(JCModuleDecl tree) { + scanDecl(tree, tree.sym, super::visitModuleDef); + } + @Override + public void visitPackageDef(JCPackageDecl tree) { + scanDecl(tree, tree.packge, super::visitPackageDef); + } + @Override + public void visitClassDef(JCClassDecl tree) { + scanDecl(tree, tree.sym, super::visitClassDef); + } + @Override + public void visitMethodDef(JCMethodDecl tree) { + scanDecl(tree, tree.sym, super::visitMethodDef); + } + @Override + public void visitVarDef(JCVariableDecl tree) { + scanDecl(tree, tree.sym, super::visitVarDef); + } + + private void scanDecl(T tree, Symbol symbol, Consumer recursor) { + + // The "symbol" can be null if there were earlier errors; skip this declaration if so + if (symbol == null) { + recursor.accept(tree); + return; + } + + // Update the Lint using the declaration; if there's no change, then we don't need a new node here + Lint newLint = currentNode.lint.augment(symbol); + if (newLint == currentNode.lint) { // note: lint.augment() returns the same instance if there's no change + recursor.accept(tree); + return; + } + + // Add a new node here and proceed + final LintRange previousNode = currentNode; + currentNode = new LintRange(tree, endPositions, newLint); + previousNode.children.add(currentNode); + try { + recursor.accept(tree); + } finally { + currentNode = previousNode; + } + } + }.scan(tree); + } + } +} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index e11a9c6754e..1c93c37698a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -67,9 +67,6 @@ public class Preview { /** flag: are preview features enabled */ private final boolean enabled; - /** flag: is the "preview" lint category enabled? */ - private final boolean verbose; - /** test flag: should all features be considered as preview features? */ private final boolean forcePreview; @@ -100,7 +97,6 @@ public class Preview { enabled = options.isSet(PREVIEW); log = Log.instance(context); source = Source.instance(context); - verbose = Lint.instance(context).isEnabled(LintCategory.PREVIEW); forcePreview = options.isSet("forcePreview"); majorVersionToSource = initMajorVersionToSourceMap(); } @@ -184,9 +180,7 @@ public class Preview { */ public void warnPreview(JavaFileObject classfile, int majorVersion) { Assert.check(isEnabled()); - if (verbose) { - log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name)); - } + log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name)); } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index 3da83248436..9f56bec4cca 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -89,9 +89,7 @@ public class Annotate { private final Attr attr; private final Check chk; private final ConstFold cfolder; - private final DeferredLintHandler deferredLintHandler; private final Enter enter; - private final Lint lint; private final Log log; private final Names names; private final Resolve resolve; @@ -110,10 +108,8 @@ public class Annotate { attr = Attr.instance(context); chk = Check.instance(context); cfolder = ConstFold.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); enter = Enter.instance(context); log = Log.instance(context); - lint = Lint.instance(context); make = TreeMaker.instance(context); names = Names.instance(context); resolve = Resolve.instance(context); @@ -235,10 +231,8 @@ public class Annotate { * @param annotations the list of JCAnnotations to attribute and enter * @param localEnv the enclosing env * @param s the Symbol on which to enter the annotations - * @param deferDecl enclosing declaration for DeferredLintHandler, or null for no deferral */ - public void annotateLater(List annotations, Env localEnv, - Symbol s, JCTree deferDecl) + public void annotateLater(List annotations, Env localEnv, Symbol s) { if (annotations.isEmpty()) { return; @@ -256,8 +250,6 @@ public class Annotate { // been handled, meaning that the set of annotations pending completion is now empty. Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - Assert.check(deferDecl != null); - deferredLintHandler.push(deferDecl); try { if (s.hasAnnotations() && annotations.nonEmpty()) log.error(annotations.head.pos, Errors.AlreadyAnnotated(Kinds.kindName(s), s)); @@ -268,7 +260,6 @@ public class Annotate { // never called for a type parameter annotateNow(s, annotations, localEnv, false, false); } finally { - deferredLintHandler.pop(); log.useSource(prev); } }); @@ -285,16 +276,13 @@ public class Annotate { /** Queue processing of an attribute default value. */ - public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv, - MethodSymbol m, JCTree deferDecl) + public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv, MethodSymbol m) { normal(() -> { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - deferredLintHandler.push(deferDecl); try { enterDefaultValue(defaultValue, localEnv, m); } finally { - deferredLintHandler.pop(); log.useSource(prev); } }); @@ -682,7 +670,7 @@ public class Annotate { // Scan the annotation element value and then attribute nested annotations if present if (tree.type != null && tree.type.tsym != null) { - queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym, null); + queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym); } result = cfolder.coerce(result, expectedElementType); @@ -1034,20 +1022,14 @@ public class Annotate { /** * Attribute the list of annotations and enter them onto s. */ - public void enterTypeAnnotations(List annotations, Env env, - Symbol s, JCTree deferDecl, boolean isTypeParam) + public void enterTypeAnnotations(List annotations, Env env, Symbol s, boolean isTypeParam) { Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - if (deferDecl != null) { - deferredLintHandler.push(deferDecl); - } try { annotateNow(s, annotations, env, true, isTypeParam); } finally { - if (deferDecl != null) - deferredLintHandler.pop(); log.useSource(prev); } } @@ -1055,10 +1037,10 @@ public class Annotate { /** * Enqueue tree for scanning of type annotations, attaching to the Symbol sym. */ - public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym, JCTree deferDecl) + public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym) { Assert.checkNonNull(sym); - normal(() -> tree.accept(new TypeAnnotate(env, sym, deferDecl))); + normal(() -> tree.accept(new TypeAnnotate(env, sym))); } /** @@ -1093,32 +1075,30 @@ public class Annotate { private class TypeAnnotate extends TreeScanner { private final Env env; private final Symbol sym; - private JCTree deferDecl; - public TypeAnnotate(Env env, Symbol sym, JCTree deferDecl) { + public TypeAnnotate(Env env, Symbol sym) { this.env = env; this.sym = sym; - this.deferDecl = deferDecl; } @Override public void visitAnnotatedType(JCAnnotatedType tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false); + enterTypeAnnotations(tree.annotations, env, sym, false); scan(tree.underlyingType); } @Override public void visitTypeParameter(JCTypeParameter tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, true); + enterTypeAnnotations(tree.annotations, env, sym, true); scan(tree.bounds); } @Override public void visitNewArray(JCNewArray tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false); + enterTypeAnnotations(tree.annotations, env, sym, false); for (List dimAnnos : tree.dimAnnotations) - enterTypeAnnotations(dimAnnos, env, sym, deferDecl, false); + enterTypeAnnotations(dimAnnos, env, sym, false); scan(tree.elemtype); scan(tree.elems); } @@ -1137,19 +1117,13 @@ public class Annotate { @Override public void visitVarDef(JCVariableDecl tree) { - JCTree prevDecl = deferDecl; - deferDecl = tree; - try { - if (sym != null && sym.kind == VAR) { - // Don't visit a parameter once when the sym is the method - // and once when the sym is the parameter. - scan(tree.mods); - scan(tree.vartype); - } - scan(tree.init); - } finally { - deferDecl = prevDecl; + if (sym != null && sym.kind == VAR) { + // Don't visit a parameter once when the sym is the method + // and once when the sym is the parameter. + scan(tree.mods); + scan(tree.vartype); } + scan(tree.init); } @Override diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index ea3b08e0338..45ece909ad7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -41,6 +41,7 @@ import com.sun.source.tree.TreeVisitor; import com.sun.source.util.SimpleTreeVisitor; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.*; @@ -98,6 +99,7 @@ public class Attr extends JCTree.Visitor { final Names names; final Log log; + final LintMapper lintMapper; final Symtab syms; final Resolve rs; final Operators operators; @@ -116,7 +118,6 @@ public class Attr extends JCTree.Visitor { final Preview preview; final JCDiagnostic.Factory diags; final TypeAnnotations typeAnnotations; - final DeferredLintHandler deferredLintHandler; final TypeEnvs typeEnvs; final Dependencies dependencies; final Annotate annotate; @@ -137,6 +138,7 @@ public class Attr extends JCTree.Visitor { names = Names.instance(context); log = Log.instance(context); + lintMapper = LintMapper.instance(context); syms = Symtab.instance(context); rs = Resolve.instance(context); operators = Operators.instance(context); @@ -156,7 +158,6 @@ public class Attr extends JCTree.Visitor { diags = JCDiagnostic.Factory.instance(context); annotate = Annotate.instance(context); typeAnnotations = TypeAnnotations.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); argumentAttr = ArgumentAttr.instance(context); @@ -853,7 +854,6 @@ public class Attr extends JCTree.Visitor { Env enclosingEnv, JCVariableDecl variable, Type type) { - deferredLintHandler.push(variable); final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); try { doQueueScanTreeAndTypeAnnotateForVarInit(variable, enclosingEnv); @@ -869,7 +869,6 @@ public class Attr extends JCTree.Visitor { } } finally { log.useSource(prevSource); - deferredLintHandler.pop(); } } @@ -998,7 +997,6 @@ public class Attr extends JCTree.Visitor { Assert.check(!env.info.ctorPrologue); MethodSymbol prevMethod = chk.setMethod(m); try { - deferredLintHandler.flush(tree, lint); chk.checkDeprecatedAnnotation(tree.pos(), m); @@ -1233,7 +1231,7 @@ public class Attr extends JCTree.Visitor { } // Attribute all type annotations in the body - annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null); + annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m); annotate.flush(); // Start of constructor prologue (if not in java.lang.Object constructor) @@ -1297,7 +1295,6 @@ public class Attr extends JCTree.Visitor { try { v.getConstValue(); // ensure compile-time constant initializer is evaluated - deferredLintHandler.flush(tree, lint); chk.checkDeprecatedAnnotation(tree.pos(), v); if (tree.init != null) { @@ -1342,7 +1339,7 @@ public class Attr extends JCTree.Visitor { env.info.scope.owner.kind != MTH && env.info.scope.owner.kind != VAR) { tree.mods.flags |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED; // Field initializer expression need to be entered. - annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym); annotate.flush(); } } @@ -1439,7 +1436,7 @@ public class Attr extends JCTree.Visitor { if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++; // Attribute all type annotations in the block - annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null); + annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner); annotate.flush(); attribStats(tree.stats, localEnv); @@ -1952,7 +1949,7 @@ public class Attr extends JCTree.Visitor { public void visitSynchronized(JCSynchronized tree) { chk.checkRefType(tree.pos(), attribExpr(tree.lock, env)); if (tree.lock.type != null && tree.lock.type.isValueBased()) { - env.info.lint.logIfEnabled(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass); + log.warning(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass); } attribStat(tree.body, env); result = null; @@ -2054,7 +2051,7 @@ public class Attr extends JCTree.Visitor { if (close.kind == MTH && close.overrides(syms.autoCloseableClose, resource.tsym, types, true) && chk.isHandled(syms.interruptedExceptionType, types.memberType(resource, close).getThrownTypes())) { - env.info.lint.logIfEnabled(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource)); + log.warning(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource)); } } } @@ -4226,9 +4223,9 @@ public class Attr extends JCTree.Visitor { setSyntheticVariableType(tree.var, type == Type.noType ? syms.errType : type); } - annotate.annotateLater(tree.var.mods.annotations, env, v, tree.var); + annotate.annotateLater(tree.var.mods.annotations, env, v); if (!tree.var.isImplicitlyTyped()) { - annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var); + annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v); } annotate.flush(); result = tree.type; @@ -4466,7 +4463,7 @@ public class Attr extends JCTree.Visitor { sym.kind == MTH && sym.name.equals(names.close) && sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true)) { - env.info.lint.logIfEnabled(tree, LintWarnings.TryExplicitCloseCall); + log.warning(tree, LintWarnings.TryExplicitCloseCall); } // Disallow selecting a type from an expression @@ -4493,9 +4490,9 @@ public class Attr extends JCTree.Visitor { // If the qualified item is not a type and the selected item is static, report // a warning. Make allowance for the class of an array type e.g. Object[].class) if (!sym.owner.isAnonymous()) { - chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); + log.warning(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); } else { - chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName())); + log.warning(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName())); } } @@ -5297,6 +5294,9 @@ public class Attr extends JCTree.Visitor { } annotate.flush(); + + // Now that this tree is attributed, we can calculate the Lint configuration everywhere within it + lintMapper.calculateLints(env.toplevel.sourcefile, env.tree, env.toplevel.endPositions); } public void attribPackage(DiagnosticPosition pos, PackageSymbol p) { @@ -5339,7 +5339,6 @@ public class Attr extends JCTree.Visitor { JavaFileObject prev = log.useSource(env.toplevel.sourcefile); try { - deferredLintHandler.flush(env.tree, lint); attrib.accept(env); } finally { log.useSource(prev); @@ -5523,7 +5522,6 @@ public class Attr extends JCTree.Visitor { } } - deferredLintHandler.flush(env.tree, env.info.lint); env.info.returnResult = null; // java.lang.Enum may not be subclassed by a non-enum if (st.tsym == syms.enumSym && @@ -5569,11 +5567,9 @@ public class Attr extends JCTree.Visitor { ModuleSymbol msym = tree.sym; Lint lint = env.outer.info.lint = env.outer.info.lint.augment(msym); Lint prevLint = chk.setLint(lint); - chk.checkModuleName(tree); - chk.checkDeprecatedAnnotation(tree, msym); - try { - deferredLintHandler.flush(tree, lint); + chk.checkModuleName(tree); + chk.checkDeprecatedAnnotation(tree, msym); } finally { chk.setLint(prevLint); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index ec328f391f9..3d9eff107da 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -121,7 +121,7 @@ public class Check { // The set of lint options currently in effect. It is initialized // from the context, and then is set/reset as needed by Attr as it // visits all the various parts of the trees during attribution. - Lint lint; + private Lint lint; // The method being analyzed in Attr - it is set/reset as needed by // Attr as it visits new method declarations. @@ -164,8 +164,6 @@ public class Check { profile = Profile.instance(context); preview = Preview.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); - allowModules = Feature.MODULES.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source); allowSealed = Feature.SEALED_CLASSES.allowedInSource(source); @@ -180,10 +178,6 @@ public class Check { */ private Map,ClassSymbol> compiled = new HashMap<>(); - /** A handler for deferred lint warnings. - */ - private DeferredLintHandler deferredLintHandler; - /** Are modules allowed */ private final boolean allowModules; @@ -229,24 +223,15 @@ public class Check { * @param sym The deprecated symbol. */ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { - LintWarning warningKey = null; - if (sym.isDeprecatedForRemoval()) { - if (!lint.isSuppressed(LintCategory.REMOVAL)) { - if (sym.kind == MDL) { - warningKey = LintWarnings.HasBeenDeprecatedForRemovalModule(sym); - } else { - warningKey = LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location()); - } - } - } else if (!lint.isSuppressed(LintCategory.DEPRECATION)) { - if (sym.kind == MDL) { - warningKey = LintWarnings.HasBeenDeprecatedModule(sym); - } else { - warningKey = LintWarnings.HasBeenDeprecated(sym, sym.location()); - } - } - if (warningKey != null) - log.warning(pos, warningKey); + Assert.check(!importSuppression); + LintWarning warningKey = sym.isDeprecatedForRemoval() ? + (sym.kind == MDL ? + LintWarnings.HasBeenDeprecatedForRemovalModule(sym) : + LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location())) : + (sym.kind == MDL ? + LintWarnings.HasBeenDeprecatedModule(sym) : + LintWarnings.HasBeenDeprecated(sym, sym.location())); + log.warning(pos, warningKey); } /** Log a preview warning. @@ -254,25 +239,16 @@ public class Check { * @param msg A Warning describing the problem. */ public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) { - if (!importSuppression && !lint.isSuppressed(LintCategory.PREVIEW)) + if (!importSuppression) log.warning(pos, warnKey); } - /** Log a preview warning. - * @param pos Position to be used for error reporting. - * @param msg A Warning describing the problem. - */ - public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) { - lint.logIfEnabled(pos, LintWarnings.RestrictedMethod(sym.enclClass(), sym)); - } - /** Warn about unchecked operation. * @param pos Position to be used for error reporting. * @param msg A string describing the problem. */ public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) { - if (!lint.isSuppressed(LintCategory.UNCHECKED)) - log.warning(pos, warnKey); + log.warning(pos, warnKey); } /** Report a failure to complete a class. @@ -608,9 +584,7 @@ public class Check { && types.isSameType(tree.expr.type, tree.clazz.type) && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz)) && !is292targetTypeCast(tree)) { - deferredLintHandler.report(_l -> { - lint.logIfEnabled(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type)); - }); + log.warning(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type)); } } //where @@ -914,7 +888,7 @@ public class Check { } } else if (hasTrustMeAnno && varargElemType != null && types.isReifiable(varargElemType)) { - lint.logIfEnabled(tree, LintWarnings.VarargsRedundantTrustmeAnno( + log.warning(tree.pos(), LintWarnings.VarargsRedundantTrustmeAnno( syms.trustMeType.tsym, diags.fragment(Fragments.VarargsTrustmeOnReifiableVarargs(varargElemType)))); } @@ -1173,7 +1147,7 @@ public class Check { mask = MethodFlags; } if ((flags & STRICTFP) != 0) { - warnOnExplicitStrictfp(tree); + log.warning(tree.pos(), LintWarnings.Strictfp); } // Imply STRICTFP if owner has STRICTFP set. if (((flags|implicit) & Flags.ABSTRACT) == 0 || @@ -1217,7 +1191,7 @@ public class Check { implicit |= FINAL; } if ((flags & STRICTFP) != 0) { - warnOnExplicitStrictfp(tree); + log.warning(tree.pos(), LintWarnings.Strictfp); } // Imply STRICTFP if owner has STRICTFP set. implicit |= sym.owner.flags_field & STRICTFP; @@ -1281,16 +1255,6 @@ public class Check { return flags & (mask | ~ExtendedStandardFlags) | implicit; } - private void warnOnExplicitStrictfp(JCTree tree) { - deferredLintHandler.push(tree); - try { - deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp)); - } finally { - deferredLintHandler.pop(); - } - } - - /** Determine if this enum should be implicitly final. * * If the enum has no specialized enum constants, it is final. @@ -1503,7 +1467,7 @@ public class Check { !TreeInfo.isDiamond(tree) && !withinAnonConstr(env) && tree.type.isRaw()) { - lint.logIfEnabled(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type)); + log.warning(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type)); } } //where @@ -1827,7 +1791,7 @@ public class Check { // Optional warning if varargs don't agree if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)) { - lint.logIfEnabled(TreeInfo.diagnosticPositionFor(m, tree), + log.warning(TreeInfo.diagnosticPositionFor(m, tree), ((m.flags() & Flags.VARARGS) != 0) ? LintWarnings.OverrideVarargsMissing(varargsOverrides(m, other)) : LintWarnings.OverrideVarargsExtra(varargsOverrides(m, other))); @@ -1841,12 +1805,7 @@ public class Check { // Warn if a deprecated method overridden by a non-deprecated one. if (!isDeprecatedOverrideIgnorable(other, origin)) { - Lint prevLint = setLint(lint.augment(m)); - try { - checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); - } finally { - setLint(prevLint); - } + checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); } } // where @@ -2915,42 +2874,33 @@ public class Check { // Apply special flag "-XDwarnOnAccessToMembers" which turns on just this particular warning for all types of access void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) { - final Lint prevLint = setLint(warnOnAnyAccessToMembers ? lint.enable(LintCategory.SERIAL) : lint); - try { - if (warnOnAnyAccessToMembers || isLambda) - checkAccessFromSerializableElementInner(tree, isLambda); - } finally { - setLint(prevLint); - } + if (warnOnAnyAccessToMembers || isLambda) + checkAccessFromSerializableElementInner(tree, isLambda); } private void checkAccessFromSerializableElementInner(final JCTree tree, boolean isLambda) { - if (lint.isEnabled(LintCategory.SERIAL)) { - Symbol sym = TreeInfo.symbol(tree); - if (!sym.kind.matches(KindSelector.VAL_MTH)) { + Symbol sym = TreeInfo.symbol(tree); + if (!sym.kind.matches(KindSelector.VAL_MTH)) { + return; + } + + if (sym.kind == VAR) { + if ((sym.flags() & PARAMETER) != 0 || + sym.isDirectlyOrIndirectlyLocal() || + sym.name == names._this || + sym.name == names._super) { return; } + } - if (sym.kind == VAR) { - if ((sym.flags() & PARAMETER) != 0 || - sym.isDirectlyOrIndirectlyLocal() || - sym.name == names._this || - sym.name == names._super) { - return; - } - } - - if (!types.isSubtype(sym.owner.type, syms.serializableType) && - isEffectivelyNonPublic(sym)) { - if (isLambda) { - if (belongsToRestrictedPackage(sym)) { - log.warning(tree.pos(), - LintWarnings.AccessToMemberFromSerializableLambda(sym)); - } - } else { - log.warning(tree.pos(), - LintWarnings.AccessToMemberFromSerializableElement(sym)); + if (!types.isSubtype(sym.owner.type, syms.serializableType) && isEffectivelyNonPublic(sym)) { + DiagnosticFlag flag = warnOnAnyAccessToMembers ? DiagnosticFlag.DEFAULT_ENABLED : null; + if (isLambda) { + if (belongsToRestrictedPackage(sym)) { + log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableLambda(sym)); } + } else { + log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableElement(sym)); } } } @@ -3737,8 +3687,7 @@ public class Check { // Note: @Deprecated has no effect on local variables, parameters and package decls. if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) { if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) { - log.warning(pos, - LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); + log.warning(pos, LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); } } } @@ -3752,15 +3701,13 @@ public class Check { && (s.isDeprecatedForRemoval() || s.isDeprecated() && !other.isDeprecated()) && (s.outermostClass() != other.outermostClass() || s.outermostClass() == null) && s.kind != Kind.PCK) { - deferredLintHandler.report(_l -> warnDeprecated(pos.get(), s)); + warnDeprecated(pos.get(), s); } } void checkSunAPI(final DiagnosticPosition pos, final Symbol s) { if ((s.flags() & PROPRIETARY) != 0) { - deferredLintHandler.report(_l -> { - log.warning(pos, Warnings.SunProprietary(s)); - }); + log.warning(pos, Warnings.SunProprietary(s)); } } @@ -3817,7 +3764,7 @@ public class Check { void checkRestricted(DiagnosticPosition pos, Symbol s) { if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) { - deferredLintHandler.report(_l -> warnRestrictedAPI(pos, s)); + log.warning(pos, LintWarnings.RestrictedMethod(s.enclClass(), s)); } } @@ -4089,7 +4036,7 @@ public class Check { int opc = ((OperatorSymbol)operator).opcode; if (opc == ByteCodes.idiv || opc == ByteCodes.imod || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { - deferredLintHandler.report(_ -> lint.logIfEnabled(pos, LintWarnings.DivZero)); + log.warning(pos, LintWarnings.DivZero); } } } @@ -4102,8 +4049,7 @@ public class Check { */ void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) { if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.PossibleLossOfPrecision(found, req))); + log.warning(pos, LintWarnings.PossibleLossOfPrecision(found, req)); } } @@ -4112,7 +4058,7 @@ public class Check { */ void checkEmptyIf(JCIf tree) { if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null) { - lint.logIfEnabled(tree.thenpart.pos(), LintWarnings.EmptyIf); + log.warning(tree.thenpart.pos(), LintWarnings.EmptyIf); } } @@ -4259,8 +4205,7 @@ public class Check { rs.isAccessible(env, c) && !fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile)) { - lint.logIfEnabled(pos, - LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); + log.warning(pos, LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); } } @@ -4302,8 +4247,7 @@ public class Check { // Warning may be suppressed by // annotations; check again for being // enabled in the deferred context. - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle))); + log.warning(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle)); } else { return; } @@ -4339,7 +4283,7 @@ public class Check { method.attribute(syms.trustMeType.tsym) != null && isTrustMeAllowedOnMethod(method) && !types.isReifiable(method.type.getParameterTypes().last())) { - Check.this.lint.logIfEnabled(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last())); + log.warning(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last())); } break; default: @@ -4637,28 +4581,24 @@ public class Check { void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) { if (msym.kind != MDL) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.ModuleNotFound(msym))); + log.warning(pos, LintWarnings.ModuleNotFound(msym)); } } void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) { if (packge.members().isEmpty() && ((packge.flags() & Flags.HAS_RESOURCE) == 0)) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.PackageEmptyOrNotFound(packge))); + log.warning(pos, LintWarnings.PackageEmptyOrNotFound(packge)); } } void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) { if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) { - deferredLintHandler.report(_ -> { - if (rd.isTransitive() && lint.isEnabled(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC)) { - log.warning(pos, LintWarnings.RequiresTransitiveAutomatic); - } else { - lint.logIfEnabled(pos, LintWarnings.RequiresAutomatic); - } - }); + if (rd.isTransitive()) { // see comment in Log.applyLint() for special logic that applies + log.warning(pos, LintWarnings.RequiresTransitiveAutomatic); + } else { + log.warning(pos, LintWarnings.RequiresAutomatic); + } } } @@ -5693,14 +5633,14 @@ public class Check { VarSymbol lastParam = ms.params.head; for (VarSymbol param: ms.params) { if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { - lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); } lastParam = param; argExps = argExps.tail; } while (argExps != null && !argExps.isEmpty() && lastParam != null) { if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { - lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); } argExps = argExps.tail; } @@ -5727,7 +5667,7 @@ public class Check { // we need to avoid recursion due to self referencing type vars or captures, this is why we need a set requiresIdentityVisitor.visit(t, new HashSet<>()); if (requiresIdentityVisitor.requiresWarning) { - lint.logIfEnabled(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); return true; } } @@ -5804,7 +5744,7 @@ public class Check { .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) && typeParamTrees.get(ta.position.parameter_index).type != null && typeParamTrees.get(ta.position.parameter_index).type.isValueBased()) - .forEach(ta -> lint.logIfEnabled(typeParamTrees.get(ta.position.parameter_index).pos(), + .forEach(ta -> log.warning(typeParamTrees.get(ta.position.parameter_index).pos(), CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected)); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index e685f139b68..3bbd007c66a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -214,7 +214,6 @@ public class Flow { private final Resolve rs; private final JCDiagnostic.Factory diags; private Env attrEnv; - private Lint lint; private final Infer infer; public static Flow instance(Context context) { @@ -337,7 +336,6 @@ public class Flow { syms = Symtab.instance(context); types = Types.instance(context); chk = Check.instance(context); - lint = Lint.instance(context); infer = Infer.instance(context); rs = Resolve.instance(context); diags = JCDiagnostic.Factory.instance(context); @@ -562,10 +560,8 @@ public class Flow { if (tree.sym == null) return; Liveness alivePrev = alive; ListBuffer pendingExitsPrev = pendingExits; - Lint lintPrev = lint; pendingExits = new ListBuffer<>(); - lint = lint.augment(tree.sym); try { // process all the nested classes @@ -596,30 +592,22 @@ public class Flow { } finally { pendingExits = pendingExitsPrev; alive = alivePrev; - lint = lintPrev; } } public void visitMethodDef(JCMethodDecl tree) { if (tree.body == null) return; - Lint lintPrev = lint; - - lint = lint.augment(tree.sym); Assert.check(pendingExits.isEmpty()); - try { - alive = Liveness.ALIVE; - scanStat(tree.body); - tree.completesNormally = alive != Liveness.DEAD; + alive = Liveness.ALIVE; + scanStat(tree.body); + tree.completesNormally = alive != Liveness.DEAD; - if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID)) - log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); + if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID)) + log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); - clearPendingExits(true); - } finally { - lint = lintPrev; - } + clearPendingExits(true); } private void clearPendingExits(boolean inMethod) { @@ -634,15 +622,7 @@ public class Flow { } public void visitVarDef(JCVariableDecl tree) { - if (tree.init != null) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - scan(tree.init); - } finally { - lint = lintPrev; - } - } + scan(tree.init); } public void visitBlock(JCBlock tree) { @@ -724,8 +704,7 @@ public class Flow { // Warn about fall-through if lint switch fallthrough enabled. if (alive == Liveness.ALIVE && c.stats.nonEmpty() && l.tail.nonEmpty()) - lint.logIfEnabled(l.tail.head.pos(), - LintWarnings.PossibleFallThroughIntoCase); + log.warning(l.tail.head.pos(), LintWarnings.PossibleFallThroughIntoCase); } tree.isExhaustive = tree.hasUnconditionalPattern || TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); @@ -1232,7 +1211,7 @@ public class Flow { scanStat(tree.finalizer); tree.finallyCanCompleteNormally = alive != Liveness.DEAD; if (alive == Liveness.DEAD) { - lint.logIfEnabled(TreeInfo.diagEndPos(tree.finalizer), + log.warning(TreeInfo.diagEndPos(tree.finalizer), LintWarnings.FinallyCannotComplete); } else { while (exits.nonEmpty()) { @@ -1453,7 +1432,6 @@ public class Flow { List thrownPrev = thrown; List caughtPrev = caught; ListBuffer pendingExitsPrev = pendingExits; - Lint lintPrev = lint; boolean anonymousClass = tree.name == names.empty; pendingExits = new ListBuffer<>(); if (!anonymousClass) { @@ -1461,7 +1439,6 @@ public class Flow { } classDef = tree; thrown = List.nil(); - lint = lint.augment(tree.sym); try { // process all the nested classes @@ -1510,7 +1487,6 @@ public class Flow { pendingExits = pendingExitsPrev; caught = caughtPrev; classDef = classDefPrev; - lint = lintPrev; } } @@ -1519,9 +1495,6 @@ public class Flow { List caughtPrev = caught; List mthrown = tree.sym.type.getThrownTypes(); - Lint lintPrev = lint; - - lint = lint.augment(tree.sym); Assert.check(pendingExits.isEmpty()); @@ -1554,20 +1527,11 @@ public class Flow { } } finally { caught = caughtPrev; - lint = lintPrev; } } public void visitVarDef(JCVariableDecl tree) { - if (tree.init != null) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - scan(tree.init); - } finally { - lint = lintPrev; - } - } + scan(tree.init); } public void visitBlock(JCBlock tree) { @@ -2387,82 +2351,76 @@ public class Flow { return; } - Lint lintPrev = lint; - lint = lint.augment(tree.sym); + JCClassDecl classDefPrev = classDef; + int firstadrPrev = firstadr; + int nextadrPrev = nextadr; + ListBuffer pendingExitsPrev = pendingExits; + + pendingExits = new ListBuffer<>(); + if (tree.name != names.empty) { + firstadr = nextadr; + } + classDef = tree; try { - JCClassDecl classDefPrev = classDef; - int firstadrPrev = firstadr; - int nextadrPrev = nextadr; - ListBuffer pendingExitsPrev = pendingExits; - - pendingExits = new ListBuffer<>(); - if (tree.name != names.empty) { - firstadr = nextadr; + // define all the static fields + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(VARDEF)) { + JCVariableDecl def = (JCVariableDecl)l.head; + if ((def.mods.flags & STATIC) != 0) { + VarSymbol sym = def.sym; + if (trackable(sym)) { + newVar(def); + } + } + } } - classDef = tree; - try { - // define all the static fields - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(VARDEF)) { - JCVariableDecl def = (JCVariableDecl)l.head; - if ((def.mods.flags & STATIC) != 0) { - VarSymbol sym = def.sym; - if (trackable(sym)) { - newVar(def); - } + + // process all the static initializers + forEachInitializer(tree, true, def -> { + scan(def); + clearPendingExits(false); + }); + + // verify all static final fields got initialized + for (int i = firstadr; i < nextadr; i++) { + JCVariableDecl vardecl = vardecls[i]; + VarSymbol var = vardecl.sym; + if (var.owner == classDef.sym && var.isStatic()) { + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); + } + } + + // define all the instance fields + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(VARDEF)) { + JCVariableDecl def = (JCVariableDecl)l.head; + if ((def.mods.flags & STATIC) == 0) { + VarSymbol sym = def.sym; + if (trackable(sym)) { + newVar(def); } } } + } - // process all the static initializers - forEachInitializer(tree, true, def -> { - scan(def); - clearPendingExits(false); - }); - - // verify all static final fields got initialized - for (int i = firstadr; i < nextadr; i++) { - JCVariableDecl vardecl = vardecls[i]; - VarSymbol var = vardecl.sym; - if (var.owner == classDef.sym && var.isStatic()) { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); - } + // process all the methods + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(METHODDEF)) { + scan(l.head); } + } - // define all the instance fields - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(VARDEF)) { - JCVariableDecl def = (JCVariableDecl)l.head; - if ((def.mods.flags & STATIC) == 0) { - VarSymbol sym = def.sym; - if (trackable(sym)) { - newVar(def); - } - } - } + // process all the nested classes + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(CLASSDEF)) { + scan(l.head); } - - // process all the methods - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(METHODDEF)) { - scan(l.head); - } - } - - // process all the nested classes - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(CLASSDEF)) { - scan(l.head); - } - } - } finally { - pendingExits = pendingExitsPrev; - nextadr = nextadrPrev; - firstadr = firstadrPrev; - classDef = classDefPrev; } } finally { - lint = lintPrev; + pendingExits = pendingExitsPrev; + nextadr = nextadrPrev; + firstadr = firstadrPrev; + classDef = classDefPrev; } } @@ -2477,87 +2435,81 @@ public class Flow { return; } - Lint lintPrev = lint; - lint = lint.augment(tree.sym); + final Bits initsPrev = new Bits(inits); + final Bits uninitsPrev = new Bits(uninits); + int nextadrPrev = nextadr; + int firstadrPrev = firstadr; + int returnadrPrev = returnadr; + + Assert.check(pendingExits.isEmpty()); + boolean isConstructorPrev = isConstructor; try { - final Bits initsPrev = new Bits(inits); - final Bits uninitsPrev = new Bits(uninits); - int nextadrPrev = nextadr; - int firstadrPrev = firstadr; - int returnadrPrev = returnadr; + isConstructor = TreeInfo.isConstructor(tree); - Assert.check(pendingExits.isEmpty()); - boolean isConstructorPrev = isConstructor; - try { - isConstructor = TreeInfo.isConstructor(tree); + // We only track field initialization inside constructors + if (!isConstructor) { + firstadr = nextadr; + } - // We only track field initialization inside constructors - if (!isConstructor) { - firstadr = nextadr; - } + // Mark all method parameters as DA + for (List l = tree.params; l.nonEmpty(); l = l.tail) { + JCVariableDecl def = l.head; + scan(def); + Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); + /* If we are executing the code from Gen, then there can be + * synthetic or mandated variables, ignore them. + */ + initParam(def); + } + // else we are in an instance initializer block; + // leave caught unchanged. + scan(tree.body); - // Mark all method parameters as DA - for (List l = tree.params; l.nonEmpty(); l = l.tail) { - JCVariableDecl def = l.head; - scan(def); - Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); - /* If we are executing the code from Gen, then there can be - * synthetic or mandated variables, ignore them. - */ - initParam(def); - } - // else we are in an instance initializer block; - // leave caught unchanged. - scan(tree.body); - - boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 || - (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD); - if (isConstructor) { - boolean isSynthesized = (tree.sym.flags() & - GENERATEDCONSTR) != 0; - for (int i = firstadr; i < nextadr; i++) { - JCVariableDecl vardecl = vardecls[i]; - VarSymbol var = vardecl.sym; - if (var.owner == classDef.sym && !var.isStatic()) { - // choose the diagnostic position based on whether - // the ctor is default(synthesized) or not - if (isSynthesized && !isCompactOrGeneratedRecordConstructor) { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), - var, Errors.VarNotInitializedInDefaultConstructor(var)); - } else if (isCompactOrGeneratedRecordConstructor) { - boolean isInstanceRecordField = var.enclClass().isRecord() && - (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 && - var.owner.kind == TYP; - if (isInstanceRecordField) { - boolean notInitialized = !inits.isMember(var.adr); - if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) { - /* this way we indicate Lower that it should generate an initialization for this field - * in the compact constructor - */ - var.flags_field |= UNINITIALIZED_FIELD; - } else { - checkInit(TreeInfo.diagEndPos(tree.body), var); - } + boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 || + (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD); + if (isConstructor) { + boolean isSynthesized = (tree.sym.flags() & + GENERATEDCONSTR) != 0; + for (int i = firstadr; i < nextadr; i++) { + JCVariableDecl vardecl = vardecls[i]; + VarSymbol var = vardecl.sym; + if (var.owner == classDef.sym && !var.isStatic()) { + // choose the diagnostic position based on whether + // the ctor is default(synthesized) or not + if (isSynthesized && !isCompactOrGeneratedRecordConstructor) { + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), + var, Errors.VarNotInitializedInDefaultConstructor(var)); + } else if (isCompactOrGeneratedRecordConstructor) { + boolean isInstanceRecordField = var.enclClass().isRecord() && + (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 && + var.owner.kind == TYP; + if (isInstanceRecordField) { + boolean notInitialized = !inits.isMember(var.adr); + if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) { + /* this way we indicate Lower that it should generate an initialization for this field + * in the compact constructor + */ + var.flags_field |= UNINITIALIZED_FIELD; } else { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); + checkInit(TreeInfo.diagEndPos(tree.body), var); } } else { - checkInit(TreeInfo.diagEndPos(tree.body), var); + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); } + } else { + checkInit(TreeInfo.diagEndPos(tree.body), var); } } } - clearPendingExits(true); - } finally { - inits.assign(initsPrev); - uninits.assign(uninitsPrev); - nextadr = nextadrPrev; - firstadr = firstadrPrev; - returnadr = returnadrPrev; - isConstructor = isConstructorPrev; } + clearPendingExits(true); } finally { - lint = lintPrev; + inits.assign(initsPrev); + uninits.assign(uninitsPrev); + nextadr = nextadrPrev; + firstadr = firstadrPrev; + returnadr = returnadrPrev; + isConstructor = isConstructorPrev; } } @@ -2585,21 +2537,15 @@ public class Flow { } public void visitVarDef(JCVariableDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - boolean track = trackable(tree.sym); - if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) { - newVar(tree); + boolean track = trackable(tree.sym); + if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) { + newVar(tree); + } + if (tree.init != null) { + scanExpr(tree.init); + if (track) { + letInit(tree.pos(), tree.sym); } - if (tree.init != null) { - scanExpr(tree.init); - if (track) { - letInit(tree.pos(), tree.sym); - } - } - } finally { - lint = lintPrev; } } @@ -2851,8 +2797,7 @@ public class Flow { final Bits uninitsEnd = new Bits(uninits); int nextadrCatch = nextadr; - if (!resourceVarDecls.isEmpty() && - lint.isEnabled(Lint.LintCategory.TRY)) { + if (!resourceVarDecls.isEmpty()) { for (JCVariableDecl resVar : resourceVarDecls) { if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) { log.warning(resVar.pos(), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index b726cc7a61d..d63ba1677d6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -66,7 +66,6 @@ public class MemberEnter extends JCTree.Visitor { private final Annotate annotate; private final Types types; private final Names names; - private final DeferredLintHandler deferredLintHandler; public static MemberEnter instance(Context context) { MemberEnter instance = context.get(memberEnterKey); @@ -87,7 +86,6 @@ public class MemberEnter extends JCTree.Visitor { types = Types.instance(context); source = Source.instance(context); names = Names.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); } /** Construct method type from method signature. @@ -194,16 +192,11 @@ public class MemberEnter extends JCTree.Visitor { } Env localEnv = methodEnv(tree, env); - deferredLintHandler.push(tree); - try { - // Compute the method type - m.type = signature(m, tree.typarams, tree.params, - tree.restype, tree.recvparam, - tree.thrown, - localEnv); - } finally { - deferredLintHandler.pop(); - } + // Compute the method type + m.type = signature(m, tree.typarams, tree.params, + tree.restype, tree.recvparam, + tree.thrown, + localEnv); if (types.isSignaturePolymorphic(m)) { m.flags_field |= SIGNATURE_POLYMORPHIC; @@ -227,14 +220,14 @@ public class MemberEnter extends JCTree.Visitor { enclScope.enter(m); } - annotate.annotateLater(tree.mods.annotations, localEnv, m, tree); + annotate.annotateLater(tree.mods.annotations, localEnv, m); // Visit the signature of the method. Note that // TypeAnnotate doesn't descend into the body. - annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree); + annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m); if (tree.defaultValue != null) { m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now - annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree); + annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m); } } @@ -263,18 +256,13 @@ public class MemberEnter extends JCTree.Visitor { localEnv = env.dup(tree, env.info.dup()); localEnv.info.staticLevel++; } - deferredLintHandler.push(tree); - try { - if (TreeInfo.isEnumInit(tree)) { - attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); - } else if (!tree.isImplicitlyTyped()) { - attr.attribType(tree.vartype, localEnv); - if (TreeInfo.isReceiverParam(tree)) - checkReceiver(tree, localEnv); - } - } finally { - deferredLintHandler.pop(); + if (TreeInfo.isEnumInit(tree)) { + attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); + } else if (!tree.isImplicitlyTyped()) { + attr.attribType(tree.vartype, localEnv); + if (TreeInfo.isReceiverParam(tree)) + checkReceiver(tree, localEnv); } if ((tree.mods.flags & VARARGS) != 0) { @@ -315,9 +303,9 @@ public class MemberEnter extends JCTree.Visitor { } } - annotate.annotateLater(tree.mods.annotations, localEnv, v, tree); + annotate.annotateLater(tree.mods.annotations, localEnv, v); if (!tree.isImplicitlyTyped()) { - annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v); } v.pos = tree.pos; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 4d0af014d83..0cef9cc6602 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -52,7 +52,6 @@ import javax.tools.JavaFileObject.Kind; import javax.tools.StandardLocation; import com.sun.source.tree.ModuleTree.ModuleKind; -import com.sun.tools.javac.code.DeferredLintHandler; import com.sun.tools.javac.code.Directive; import com.sun.tools.javac.code.Directive.ExportsDirective; import com.sun.tools.javac.code.Directive.ExportsFlag; @@ -141,7 +140,6 @@ public class Modules extends JCTree.Visitor { private final Attr attr; private final Check chk; private final Preview preview; - private final DeferredLintHandler deferredLintHandler; private final TypeEnvs typeEnvs; private final Types types; private final JavaFileManager fileManager; @@ -169,8 +167,6 @@ public class Modules extends JCTree.Visitor { private final String moduleVersionOpt; private final boolean sourceLauncher; - private final boolean lintOptions; - private Set rootModules = null; private final Set warnedMissing = new HashSet<>(); @@ -193,7 +189,6 @@ public class Modules extends JCTree.Visitor { attr = Attr.instance(context); chk = Check.instance(context); preview = Preview.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); typeEnvs = TypeEnvs.instance(context); moduleFinder = ModuleFinder.instance(context); types = Types.instance(context); @@ -205,8 +200,6 @@ public class Modules extends JCTree.Visitor { allowAccessIntoSystem = options.isUnset(Option.RELEASE); - lintOptions = !options.isLintDisabled(LintCategory.OPTIONS); - multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); ClassWriter classWriter = ClassWriter.instance(context); classWriter.multiModuleMode = multiModuleMode; @@ -746,7 +739,6 @@ public class Modules extends JCTree.Visitor { ModuleVisitor v = new ModuleVisitor(); JavaFileObject prev = log.useSource(tree.sourcefile); JCModuleDecl moduleDecl = tree.getModuleDecl(); - deferredLintHandler.push(moduleDecl); try { moduleDecl.accept(v); @@ -754,7 +746,6 @@ public class Modules extends JCTree.Visitor { checkCyclicDependencies(moduleDecl); } finally { log.useSource(prev); - deferredLintHandler.pop(); msym.flags_field &= ~UNATTRIBUTED; } } @@ -991,13 +982,11 @@ public class Modules extends JCTree.Visitor { UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); JCModuleDecl decl = env.toplevel.getModuleDecl(); - deferredLintHandler.push(decl); try { decl.accept(v); } finally { log.useSource(prev); - deferredLintHandler.pop(); } }; } @@ -1263,12 +1252,9 @@ public class Modules extends JCTree.Visitor { } observable = computeTransitiveClosure(limitMods, rootModules, null); observable.addAll(rootModules); - if (lintOptions) { - for (ModuleSymbol msym : limitMods) { - if (!observable.contains(msym)) { - log.warning( - LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); - } + for (ModuleSymbol msym : limitMods) { + if (!observable.contains(msym)) { + log.warning(LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); } } } @@ -1721,10 +1707,7 @@ public class Modules extends JCTree.Visitor { } if (!unknownModules.contains(msym)) { - if (lintOptions) { - log.warning( - LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); unknownModules.add(msym); } return false; @@ -1760,9 +1743,7 @@ public class Modules extends JCTree.Visitor { ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); if (!allModules.contains(msym)) { - if (lintOptions) { - log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); continue; } @@ -1780,9 +1761,7 @@ public class Modules extends JCTree.Visitor { continue; targetModule = syms.enterModule(names.fromString(targetName)); if (!allModules.contains(targetModule)) { - if (lintOptions) { - log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); continue; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java index 9119278660f..6fb1feed08d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java @@ -45,6 +45,7 @@ import java.util.stream.Stream; import com.sun.tools.javac.code.Directive; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; @@ -57,6 +58,7 @@ import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Log; @@ -67,6 +69,7 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.Lint.LintCategory.THIS_ESCAPE; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import static com.sun.tools.javac.util.Position.NOPOS; /** * Looks for possible 'this' escapes and generates corresponding warnings. @@ -156,7 +159,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { private final Types types; private final Resolve rs; private final Log log; - private Lint lint; + private final LintMapper lintMapper; // These fields are scoped to the entire compilation unit @@ -168,10 +171,6 @@ public class ThisEscapeAnalyzer extends TreeScanner { */ private final Map methodMap = new LinkedHashMap<>(); - /** Contains symbols of fields and constructors that have warnings suppressed. - */ - private final Set suppressed = new HashSet<>(); - /** Contains classes whose outer instance (if any) is non-public. */ private final Set nonPublicOuters = new HashSet<>(); @@ -231,7 +230,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { syms = Symtab.instance(context); types = Types.instance(context); rs = Resolve.instance(context); - lint = Lint.instance(context); + lintMapper = LintMapper.instance(context); } // @@ -262,8 +261,8 @@ public class ThisEscapeAnalyzer extends TreeScanner { Assert.check(checkInvariants(false, false)); Assert.check(methodMap.isEmpty()); // we are not prepared to be used more than once - // Short circuit if warnings are totally disabled - if (!lint.isEnabled(THIS_ESCAPE)) + // Short circuit if this calculation is unnecessary + if (!lintMapper.lintAt(env.toplevel.sourcefile, env.tree.pos()).get().isEnabled(THIS_ESCAPE)) return; // Determine which packages are exported by the containing module, if any. @@ -278,11 +277,9 @@ public class ThisEscapeAnalyzer extends TreeScanner { // Build a mapping from symbols of methods to their declarations. // Classify all ctors and methods as analyzable and/or invokable. - // Track which constructors and fields have warnings suppressed. // Record classes whose outer instance (if any) is non-public. new TreeScanner() { - private Lint lint = ThisEscapeAnalyzer.this.lint; private JCClassDecl currentClass; private boolean nonPublicOuter; @@ -290,8 +287,6 @@ public class ThisEscapeAnalyzer extends TreeScanner { public void visitClassDef(JCClassDecl tree) { JCClassDecl currentClassPrev = currentClass; boolean nonPublicOuterPrev = nonPublicOuter; - Lint lintPrev = lint; - lint = lint.augment(tree.sym); try { currentClass = tree; @@ -306,57 +301,29 @@ public class ThisEscapeAnalyzer extends TreeScanner { } finally { currentClass = currentClassPrev; nonPublicOuter = nonPublicOuterPrev; - lint = lintPrev; - } - } - - @Override - public void visitVarDef(JCVariableDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try { - - // Track warning suppression of fields - if (tree.sym.owner.kind == TYP && !lint.isEnabled(THIS_ESCAPE)) - suppressed.add(tree.sym); - - // Recurse - super.visitVarDef(tree); - } finally { - lint = lintPrev; } } @Override public void visitMethodDef(JCMethodDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try { - // Track warning suppression of constructors - if (TreeInfo.isConstructor(tree) && !lint.isEnabled(THIS_ESCAPE)) - suppressed.add(tree.sym); + // Gather some useful info + boolean constructor = TreeInfo.isConstructor(tree); + boolean extendableClass = currentClassIsExternallyExtendable(); + boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0; + boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0; - // Gather some useful info - boolean constructor = TreeInfo.isConstructor(tree); - boolean extendableClass = currentClassIsExternallyExtendable(); - boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0; - boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0; + // Determine if this is a constructor we should analyze + boolean analyzable = extendableClass && constructor && nonPrivate; - // Determine if this is a constructor we should analyze - boolean analyzable = extendableClass && constructor && nonPrivate; + // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden) + boolean invokable = !extendableClass || constructor || finalish; - // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden) - boolean invokable = !extendableClass || constructor || finalish; + // Add this method or constructor to our map + methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable)); - // Add this method or constructor to our map - methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable)); - - // Recurse - super.visitMethodDef(tree); - } finally { - lint = lintPrev; - } + // Recurse + super.visitMethodDef(tree); } // Determines if the current class could be extended in some other package/module @@ -401,7 +368,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { for (Warning warning : warningList) { LintWarning key = LintWarnings.PossibleThisEscape; for (StackFrame frame : warning.stack) { - log.warning(frame.site.pos(), key); + log.warning(frame.warningPos(), key); key = LintWarnings.PossibleThisEscapeLocation; } } @@ -1746,9 +1713,16 @@ public class ThisEscapeAnalyzer extends TreeScanner { this.suppressible = initializer != null || (method.constructor && method.declaringClass == targetClass); } + DiagnosticPosition warningPos() { + return site.pos().withLintPosition(NOPOS); // disable normal Lint suppression + } + + Lint lint() { + return lintMapper.lintAt(topLevelEnv.toplevel.sourcefile, site.pos()).get(); + } + boolean isSuppressed() { - return suppressible && - suppressed.contains(initializer instanceof JCVariableDecl v ? v.sym : method.declaration.sym); + return suppressible && !lint().isEnabled(THIS_ESCAPE); } int comparePos(StackFrame that) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index eb4ab96dfd2..8648b929a04 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -34,7 +34,6 @@ import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Directive.ExportsDirective; import com.sun.tools.javac.code.Directive.RequiresDirective; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Scope.ImportFilter; import com.sun.tools.javac.code.Scope.NamedImportScope; import com.sun.tools.javac.code.Scope.StarImportScope; @@ -108,8 +107,6 @@ public class TypeEnter implements Completer { private final Annotate annotate; private final TypeAnnotations typeAnnotations; private final Types types; - private final DeferredLintHandler deferredLintHandler; - private final Lint lint; private final TypeEnvs typeEnvs; private final Dependencies dependencies; @@ -135,8 +132,6 @@ public class TypeEnter implements Completer { annotate = Annotate.instance(context); typeAnnotations = TypeAnnotations.instance(context); types = Types.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); - lint = Lint.instance(context); typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); Source source = Source.instance(context); @@ -274,7 +269,6 @@ public class TypeEnter implements Completer { queue.add(env); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - deferredLintHandler.push(tree); try { dependencies.push(env.enclClass.sym, phaseName); runPhase(env); @@ -282,7 +276,6 @@ public class TypeEnter implements Completer { chk.completionError(tree.pos(), ex); } finally { dependencies.pop(); - deferredLintHandler.pop(); log.useSource(prev); } } @@ -351,8 +344,6 @@ public class TypeEnter implements Completer { ImportFilter prevStaticImportFilter = staticImportFilter; ImportFilter prevTypeImportFilter = typeImportFilter; - deferredLintHandler.pushImmediate(lint); - Lint prevLint = chk.setLint(lint); Env prevEnv = this.env; try { this.env = env; @@ -376,20 +367,13 @@ public class TypeEnter implements Completer { handleImports(tree.getImports()); if (decl != null) { - deferredLintHandler.push(decl); - try { - //check @Deprecated: - markDeprecated(decl.sym, decl.mods.annotations, env); - } finally { - deferredLintHandler.pop(); - } + //check for @Deprecated annotations + markDeprecated(decl.sym, decl.mods.annotations, env); // process module annotations - annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle, decl); + annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle); } } finally { this.env = prevEnv; - chk.setLint(prevLint); - deferredLintHandler.pop(); this.staticImportFilter = prevStaticImportFilter; this.typeImportFilter = prevTypeImportFilter; } @@ -422,7 +406,7 @@ public class TypeEnter implements Completer { } } // process package annotations - annotate.annotateLater(tree.annotations, env, env.toplevel.packge, tree); + annotate.annotateLater(tree.annotations, env, env.toplevel.packge); } private void doImport(JCImport tree, boolean fromModuleImport) { @@ -914,9 +898,9 @@ public class TypeEnter implements Completer { Env baseEnv = baseEnv(tree, env); if (tree.extending != null) - annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym); for (JCExpression impl : tree.implementing) - annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym); annotate.flush(); attribSuperTypes(env, baseEnv); @@ -931,11 +915,11 @@ public class TypeEnter implements Completer { chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet); } - annotate.annotateLater(tree.mods.annotations, baseEnv, sym, tree); + annotate.annotateLater(tree.mods.annotations, baseEnv, sym); attr.attribTypeVariables(tree.typarams, baseEnv, false); for (JCTypeParameter tp : tree.typarams) - annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym); // check that no package exists with same fully qualified name, // but admit classes in the unnamed package which have the same diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java index 73f86239713..5964c16c151 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java @@ -92,7 +92,7 @@ public abstract class BaseFileManager implements JavaFileManager { options = Options.instance(context); // Initialize locations - locations.update(log, lint, FSInfo.instance(context)); + locations.update(log, FSInfo.instance(context)); // Apply options options.whenReady(this::applyOptions); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java index ff02de705fb..c4573b9a364 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java @@ -77,12 +77,11 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardJavaFileManager.PathFactory; import javax.tools.StandardLocation; -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import jdk.internal.jmod.JmodFile; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.resources.CompilerProperties.Errors; +import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.ListBuffer; @@ -123,11 +122,6 @@ public class Locations { */ private FSInfo fsInfo; - /** - * The root {@link Lint} instance. - */ - private Lint lint; - private ModuleNameReader moduleNameReader; private PathFactory pathFactory = Paths::get; @@ -168,9 +162,8 @@ public class Locations { } } - void update(Log log, Lint lint, FSInfo fsInfo) { + void update(Log log, FSInfo fsInfo) { this.log = log; - this.lint = lint; this.fsInfo = fsInfo; } @@ -221,7 +214,7 @@ public class Locations { try { entries.add(getPath(s)); } catch (IllegalArgumentException e) { - lint.logIfEnabled(LintWarnings.InvalidPath(s)); + log.warning(LintWarnings.InvalidPath(s)); } } } @@ -316,7 +309,7 @@ public class Locations { private void addDirectory(Path dir, boolean warn) { if (!Files.isDirectory(dir)) { if (warn) { - lint.logIfEnabled(LintWarnings.DirPathElementNotFound(dir)); + log.warning(LintWarnings.DirPathElementNotFound(dir)); } return; } @@ -361,7 +354,7 @@ public class Locations { if (!fsInfo.exists(file)) { /* No such file or directory exists */ if (warn) { - lint.logIfEnabled(LintWarnings.PathElementNotFound(file)); + log.warning(LintWarnings.PathElementNotFound(file)); } super.add(file); return; @@ -383,12 +376,12 @@ public class Locations { try { FileSystems.newFileSystem(file, (ClassLoader)null).close(); if (warn) { - lint.logIfEnabled(LintWarnings.UnexpectedArchiveFile(file)); + log.warning(LintWarnings.UnexpectedArchiveFile(file)); } } catch (IOException | ProviderNotFoundException e) { // FIXME: include e.getLocalizedMessage in warning if (warn) { - lint.logIfEnabled(LintWarnings.InvalidArchiveFile(file)); + log.warning(LintWarnings.InvalidArchiveFile(file)); } return; } @@ -1651,7 +1644,7 @@ public class Locations { void add(Map> map, Path prefix, Path suffix) { if (!Files.isDirectory(prefix)) { - lint.logIfEnabled(Files.exists(prefix) ? + log.warning(Files.exists(prefix) ? LintWarnings.DirPathElementNotDirectory(prefix) : LintWarnings.DirPathElementNotFound(prefix)); return; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index cf751ff6b30..6f1ad28586d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -51,7 +51,6 @@ import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Directive.*; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; @@ -139,9 +138,6 @@ public class ClassReader { /** The symbol table. */ Symtab syms; - /** The root Lint config. */ - Lint lint; - Types types; /** The name table. */ @@ -303,8 +299,6 @@ public class ClassReader { typevars = WriteableScope.create(syms.noSymbol); - lint = Lint.instance(context); - initAttributeReaders(); } @@ -854,8 +848,7 @@ public class ClassReader { if (!warnedAttrs.contains(name)) { JavaFileObject prev = log.useSource(currentClassFile); try { - lint.logIfEnabled( - LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion)); + log.warning(LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion)); } finally { log.useSource(prev); } @@ -1609,7 +1602,7 @@ public class ClassReader { } else if (parameterAnnotations.length != numParameters) { //the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations //provide annotations for a different number of parameters, ignore: - lint.logIfEnabled(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile)); + log.warning(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile)); for (int pnum = 0; pnum < numParameters; pnum++) { readAnnotations(); } @@ -2075,9 +2068,9 @@ public class ClassReader { JavaFileObject prevSource = log.useSource(requestingOwner.classfile); try { if (failure == null) { - lint.logIfEnabled(LintWarnings.AnnotationMethodNotFound(container, name)); + log.warning(LintWarnings.AnnotationMethodNotFound(container, name)); } else { - lint.logIfEnabled(LintWarnings.AnnotationMethodNotFoundReason(container, + log.warning(LintWarnings.AnnotationMethodNotFoundReason(container, name, failure.getDetailValue()));//diagnostic, if present } @@ -2954,7 +2947,7 @@ public class ClassReader { private void dropParameterAnnotations() { parameterAnnotations = null; - lint.logIfEnabled(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile)); + log.warning(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile)); } /** * Creates the parameter at the position {@code mpIndex} in the parameter list of the owning method. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java index 7aa1cc473b5..58beee78af2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java @@ -52,7 +52,6 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import com.sun.tools.doclint.DocLint; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.JavacFileManager; @@ -503,12 +502,9 @@ public class Arguments { } } else { // single-module or legacy mode - boolean lintPaths = !options.isLintDisabled(LintCategory.PATH); - if (lintPaths) { - Path outDirParent = outDir.getParent(); - if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) { - log.warning(LintWarnings.OutdirIsInExplodedModule(outDir)); - } + Path outDirParent = outDir.getParent(); + if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) { + log.warning(LintWarnings.OutdirIsInExplodedModule(outDir)); } } } @@ -576,15 +572,14 @@ public class Arguments { reportDiag(Errors.SourcepathModulesourcepathConflict); } - boolean lintOptions = !options.isLintDisabled(LintCategory.OPTIONS); - if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) { + if (source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) { if (fm instanceof BaseFileManager baseFileManager) { if (source.compareTo(Source.JDK8) <= 0) { - if (baseFileManager.isDefaultBootClassPath()) + if (baseFileManager.isDefaultBootClassPath()) { log.warning(LintWarnings.SourceNoBootclasspath(source.name, releaseNote(source, targetString))); - } else { - if (baseFileManager.isDefaultSystemModulesPath()) - log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString))); + } + } else if (baseFileManager.isDefaultSystemModulesPath()) { + log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString))); } } } @@ -593,14 +588,14 @@ public class Arguments { if (source.compareTo(Source.MIN) < 0) { log.error(Errors.OptionRemovedSource(source.name, Source.MIN.name)); - } else if (source == Source.MIN && lintOptions) { + } else if (source == Source.MIN) { log.warning(LintWarnings.OptionObsoleteSource(source.name)); obsoleteOptionFound = true; } if (target.compareTo(Target.MIN) < 0) { log.error(Errors.OptionRemovedTarget(target, Target.MIN)); - } else if (target == Target.MIN && lintOptions) { + } else if (target == Target.MIN) { log.warning(LintWarnings.OptionObsoleteTarget(target)); obsoleteOptionFound = true; } @@ -634,7 +629,7 @@ public class Arguments { log.error(Errors.ProcessorpathNoProcessormodulepath); } - if (obsoleteOptionFound && lintOptions) { + if (obsoleteOptionFound) { log.warning(LintWarnings.OptionObsoleteSuppression); } @@ -645,7 +640,7 @@ public class Arguments { validateLimitModules(sv); validateDefaultModuleForCreatedFiles(sv); - if (lintOptions && options.isSet(Option.ADD_OPENS)) { + if (options.isSet(Option.ADD_OPENS)) { log.warning(LintWarnings.AddopensIgnored); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 83106ff2278..ee11304dce9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -258,6 +258,10 @@ public class JavaCompiler { */ protected JNIWriter jniWriter; + /** The Lint mapper. + */ + protected LintMapper lintMapper; + /** The module for the symbol table entry phases. */ protected Enter enter; @@ -384,6 +388,7 @@ public class JavaCompiler { names = Names.instance(context); log = Log.instance(context); + lintMapper = LintMapper.instance(context); diagFactory = JCDiagnostic.Factory.instance(context); finder = ClassFinder.instance(context); reader = ClassReader.instance(context); @@ -575,6 +580,7 @@ public class JavaCompiler { /** The number of errors reported so far. */ public int errorCount() { + log.reportOutstandingWarnings(); if (werror && log.nerrors == 0 && log.nwarnings > 0) { log.error(Errors.WarningsAndWerror); } @@ -625,6 +631,7 @@ public class JavaCompiler { private JCCompilationUnit parse(JavaFileObject filename, CharSequence content, boolean silent) { long msec = now(); JCCompilationUnit tree = make.TopLevel(List.nil()); + lintMapper.startParsingFile(filename); if (content != null) { if (verbose) { log.printVerbose("parsing.started", filename); @@ -644,6 +651,7 @@ public class JavaCompiler { } tree.sourcefile = filename; + lintMapper.finishParsingFile(tree); if (content != null && !taskListener.isEmpty() && !silent) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree); @@ -1843,6 +1851,7 @@ public class JavaCompiler { else log.warning(Warnings.ProcUseProcOrImplicit); } + log.reportOutstandingWarnings(); log.reportOutstandingNotes(); if (log.compressedOutput) { log.note(Notes.CompressedDiags); @@ -1916,6 +1925,7 @@ public class JavaCompiler { attr = null; chk = null; gen = null; + lintMapper = null; flow = null; transTypes = null; lower = null; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index f3d0837398c..f40cb0fb6b7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -25,8 +25,6 @@ package com.sun.tools.javac.parser; -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Source.Feature; @@ -83,7 +81,7 @@ public class JavaTokenizer extends UnicodeReader { /** * The log to be used for error reporting. Copied from scanner factory. */ - private final Log log; + protected final Log log; /** * The token factory. Copied from scanner factory. @@ -135,13 +133,6 @@ public class JavaTokenizer extends UnicodeReader { */ protected boolean hasEscapeSequences; - /** - * The set of lint options currently in effect. It is initialized - * from the context, and then is set/reset as needed by Attr as it - * visits all the various parts of the trees during attribution. - */ - protected final Lint lint; - /** * Construct a Java token scanner from the input character buffer. * @@ -168,7 +159,6 @@ public class JavaTokenizer extends UnicodeReader { this.source = fac.source; this.preview = fac.preview; this.enableLineDocComments = fac.enableLineDocComments; - this.lint = fac.lint; this.sb = new StringBuilder(256); } @@ -205,17 +195,6 @@ public class JavaTokenizer extends UnicodeReader { errPos = pos; } - /** - * Report a warning at the given position using the provided arguments. - * - * @param pos position in input buffer. - * @param key error key to report. - */ - protected void lexWarning(int pos, JCDiagnostic.LintWarning key) { - DiagnosticPosition dp = new SimpleDiagnosticPosition(pos) ; - log.warning(dp, key); - } - /** * Add a character to the literal buffer. * @@ -1060,17 +1039,12 @@ public class JavaTokenizer extends UnicodeReader { // If a text block. if (isTextBlock) { // Verify that the incidental indentation is consistent. - if (lint.isEnabled(LintCategory.TEXT_BLOCKS)) { - Set checks = - TextBlockSupport.checkWhitespace(string); - if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) { - lexWarning(pos, - LintWarnings.InconsistentWhiteSpaceIndentation); - } - if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) { - lexWarning(pos, - LintWarnings.TrailingWhiteSpaceWillBeRemoved); - } + Set checks = TextBlockSupport.checkWhitespace(string); + if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) { + log.warning(pos, LintWarnings.InconsistentWhiteSpaceIndentation); + } + if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) { + log.warning(pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved); } // Remove incidental indentation. try { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index b63374d9c6d..4a990701315 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -116,8 +116,6 @@ public class JavacParser implements Parser { /** A map associating "other nearby documentation comments" * with the preferred documentation comment for a declaration. */ protected Map> danglingComments = new HashMap<>(); - /** Handler for deferred diagnostics. */ - protected final DeferredLintHandler deferredLintHandler; // Because of javac's limited lookahead, some contexts are ambiguous in // the presence of type annotations even though they are not ambiguous @@ -190,7 +188,6 @@ public class JavacParser implements Parser { this.names = fac.names; this.source = fac.source; this.preview = fac.preview; - this.deferredLintHandler = fac.deferredLintHandler; this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true); this.keepDocComments = keepDocComments; this.parseModuleInfo = parseModuleInfo; @@ -216,7 +213,6 @@ public class JavacParser implements Parser { this.names = parser.names; this.source = parser.source; this.preview = parser.preview; - this.deferredLintHandler = parser.deferredLintHandler; this.allowStringFolding = parser.allowStringFolding; this.keepDocComments = parser.keepDocComments; this.parseModuleInfo = false; @@ -591,8 +587,7 @@ public class JavacParser implements Parser { * 4. When the tree node for the declaration is finally * available, and the primary comment, if any, * is "attached", (in {@link #attach}) any related - * dangling comments are also attached to the tree node - * by registering them using the {@link #deferredLintHandler}. + * dangling comments are reported to the log as warnings. * 5. (Later) Warnings may be generated for the dangling * comments, subject to the {@code -Xlint} and * {@code @SuppressWarnings}. @@ -653,32 +648,22 @@ public class JavacParser implements Parser { void reportDanglingComments(JCTree tree, Comment dc) { var list = danglingComments.remove(dc); if (list != null) { - deferredLintHandler.push(tree); - try { - list.forEach(this::reportDanglingDocComment); - } finally { - deferredLintHandler.pop(); - } + list.forEach(c -> reportDanglingDocComment(tree, c)); } } /** - * Reports an individual dangling comment using the {@link #deferredLintHandler}. + * Reports an individual dangling comment as a warning to the log. * The comment may or not may generate an actual diagnostic, depending on * the settings for {@code -Xlint} and/or {@code @SuppressWarnings}. * * @param c the comment */ - void reportDanglingDocComment(Comment c) { + void reportDanglingDocComment(JCTree tree, Comment c) { var pos = c.getPos(); - if (pos != null) { - deferredLintHandler.report(lint -> { - if (lint.isEnabled(Lint.LintCategory.DANGLING_DOC_COMMENTS) && - !shebang(c, pos)) { - log.warning( - pos, LintWarnings.DanglingDocComment); - } - }); + if (pos != null && !shebang(c, pos)) { + pos = pos.withLintPosition(tree.getStartPosition()); + S.lintWarning(pos, LintWarnings.DanglingDocComment); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java index bff4e027db7..1d1e08194f7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -28,6 +28,8 @@ package com.sun.tools.javac.parser; import java.util.Queue; import com.sun.tools.javac.parser.Tokens.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.Position.LineMap; /** @@ -103,4 +105,12 @@ public interface Lexer { * token. */ Queue getDocComments(); + + /** + * Report a warning that is subject to possible suppression by {@code @SuppressWarnings}. + * + * @param pos the lexical position at which the warning occurs + * @param key the warning to report + */ + void lintWarning(DiagnosticPosition pos, LintWarning key); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java index c873c6f31b7..f9e187315ba 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,6 @@ package com.sun.tools.javac.parser; import java.util.Locale; import com.sun.tools.javac.api.JavacTrees; -import com.sun.tools.javac.code.DeferredLintHandler; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; @@ -70,7 +69,6 @@ public class ParserFactory { final Options options; final ScannerFactory scannerFactory; final Locale locale; - final DeferredLintHandler deferredLintHandler; private final JavacTrees trees; @@ -88,7 +86,6 @@ public class ParserFactory { this.options = Options.instance(context); this.scannerFactory = ScannerFactory.instance(context); this.locale = context.get(Locale.class); - this.deferredLintHandler = DeferredLintHandler.instance(context); this.trees = JavacTrees.instance(context); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java index a24e73a4141..7fcb87eac7a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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 @@ -31,6 +31,8 @@ import java.util.List; import java.util.ArrayList; import java.util.Queue; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.Position.LineMap; import static com.sun.tools.javac.parser.Tokens.*; @@ -150,6 +152,11 @@ public class Scanner implements Lexer { return docComments; } + @Override + public void lintWarning(DiagnosticPosition pos, LintWarning key) { + tokenizer.log.warning(pos, key); + } + public int errPos() { return tokenizer.errPos(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java index 188fe838b18..66f2b66fabf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,6 @@ package com.sun.tools.javac.parser; import java.nio.CharBuffer; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.main.Option; @@ -62,7 +61,6 @@ public class ScannerFactory { final Source source; final Preview preview; final Tokens tokens; - final Lint lint; final boolean enableLineDocComments; /** Create a new scanner factory. */ @@ -74,7 +72,6 @@ public class ScannerFactory { this.source = Source.instance(context); this.preview = Preview.instance(context); this.tokens = Tokens.instance(context); - this.lint = Lint.instance(context); var options = Options.instance(context); this.enableLineDocComments = !options.isSet(Option.DISABLE_LINE_DOC_COMMENTS); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java index ec3a373ab4e..2a819152eed 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCErroneous; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.Error; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Position.LineMap; @@ -167,10 +168,9 @@ public class VirtualParser extends JavacParser { return S.getLineMap(); } - public void commit() { - for (int i = 0 ; i < offset ; i++) { - S.nextToken(); // advance underlying lexer until position matches - } + @Override + public void lintWarning(DiagnosticPosition pos, LintWarning key) { + // ignore } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java index 012ac628ecd..dc25de30b36 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java @@ -51,7 +51,6 @@ import javax.tools.JavaFileManager.Location; import static javax.tools.StandardLocation.SOURCE_OUTPUT; import static javax.tools.StandardLocation.CLASS_OUTPUT; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symtab; @@ -62,7 +61,6 @@ import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; -import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.main.Option; @@ -338,7 +336,6 @@ public class JavacFiler implements Filer, Closeable { JavaFileManager fileManager; JavacElements elementUtils; Log log; - Lint lint; Modules modules; Names names; Symtab syms; @@ -421,8 +418,6 @@ public class JavacFiler implements Filer, Closeable { aggregateGeneratedClassNames = new LinkedHashSet<>(); initialClassNames = new LinkedHashSet<>(); - lint = Lint.instance(context); - Options options = Options.instance(context); defaultTargetModule = options.get(Option.DEFAULT_MODULE_FOR_CREATED_FILES); @@ -486,14 +481,12 @@ public class JavacFiler implements Filer, Closeable { private JavaFileObject createSourceOrClassFile(ModuleSymbol mod, boolean isSourceFile, String name, Element... originatingElements) throws IOException { Assert.checkNonNull(mod); - if (lint.isEnabled(PROCESSING)) { - int periodIndex = name.lastIndexOf("."); - if (periodIndex != -1) { - String base = name.substring(periodIndex); - String extn = (isSourceFile ? ".java" : ".class"); - if (base.equals(extn)) - log.warning(LintWarnings.ProcSuspiciousClassName(name, extn)); - } + int periodIndex = name.lastIndexOf("."); + if (periodIndex != -1) { + String base = name.substring(periodIndex); + String extn = (isSourceFile ? ".java" : ".class"); + if (base.equals(extn)) + log.warning(LintWarnings.ProcSuspiciousClassName(name, extn)); } checkNameAndExistence(mod, name, isSourceFile); Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT); @@ -707,7 +700,7 @@ public class JavacFiler implements Filer, Closeable { private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException { if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) { - lint.logIfEnabled(LintWarnings.ProcIllegalFileName(name)); + log.warning(LintWarnings.ProcIllegalFileName(name)); throw new FilerException("Illegal name " + name); } } @@ -735,11 +728,11 @@ public class JavacFiler implements Filer, Closeable { initialClassNames.contains(typename) || containedInInitialInputs(typename); if (alreadySeen) { - lint.logIfEnabled(LintWarnings.ProcTypeRecreate(typename)); + log.warning(LintWarnings.ProcTypeRecreate(typename)); throw new FilerException("Attempt to recreate a file for type " + typename); } if (existing != null) { - lint.logIfEnabled(LintWarnings.ProcTypeAlreadyExists(typename)); + log.warning(LintWarnings.ProcTypeAlreadyExists(typename)); } if (!mod.isUnnamed() && !typename.contains(".")) { throw new FilerException("Attempt to create a type in unnamed package of a named module: " + typename); @@ -768,7 +761,7 @@ public class JavacFiler implements Filer, Closeable { */ private void checkFileReopening(FileObject fileObject, boolean forWriting) throws FilerException { if (isInFileObjectHistory(fileObject, forWriting)) { - lint.logIfEnabled(LintWarnings.ProcFileReopening(fileObject.getName())); + log.warning(LintWarnings.ProcFileReopening(fileObject.getName())); throw new FilerException("Attempt to reopen a file for path " + fileObject.getName()); } if (forWriting) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 7bc538a1d1e..b28f19bd3af 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -123,7 +123,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private final Modules modules; private final Types types; private final Annotate annotate; - private final Lint lint; /** * Holds relevant state history of which processors have been @@ -206,7 +205,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea printProcessorInfo = options.isSet(Option.XPRINTPROCESSORINFO); printRounds = options.isSet(Option.XPRINTROUNDS); verbose = options.isSet(Option.VERBOSE); - lint = Lint.instance(context); compiler = JavaCompiler.instance(context); if (options.isSet(Option.PROC, "only") || options.isSet(Option.XPRINT)) { compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; @@ -626,7 +624,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private Set supportedOptionNames; ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh, - boolean allowModules, ProcessingEnvironment env, Lint lint) { + boolean allowModules, ProcessingEnvironment env) { processor = p; contributed = false; @@ -647,10 +645,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea boolean patternAdded = supportedAnnotationStrings.add(annotationPattern); supportedAnnotationPatterns. - add(importStringToPattern(allowModules, annotationPattern, - processor, log, lint)); + add(importStringToPattern(allowModules, annotationPattern, processor, log)); if (!patternAdded) { - lint.logIfEnabled(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern, + log.warning(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern, p.getClass().getName())); } } @@ -663,7 +660,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // and "foo.bar.*". if (supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) && supportedAnnotationPatterns.size() > 1) { - lint.logIfEnabled(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); + log.warning(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); } supportedOptionNames = new LinkedHashSet<>(); @@ -671,8 +668,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (checkOptionName(optionName, log)) { boolean optionAdded = supportedOptionNames.add(optionName); if (!optionAdded) { - lint.logIfEnabled(LintWarnings.ProcDuplicateOptionName(optionName, - p.getClass().getName())); + log.warning(LintWarnings.ProcDuplicateOptionName(optionName, p.getClass().getName())); } } } @@ -759,8 +755,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea ProcessorState ps = new ProcessorState(psi.processorIterator.next(), log, source, dcfh, Feature.MODULES.allowedInSource(source), - JavacProcessingEnvironment.this, - lint); + JavacProcessingEnvironment.this); psi.procStateList.add(ps); return ps; } else @@ -888,7 +883,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } unmatchedAnnotations.remove(""); - if (lint.isEnabled(PROCESSING) && unmatchedAnnotations.size() > 0) { + if (unmatchedAnnotations.size() > 0) { // Remove annotations processed by javac unmatchedAnnotations.keySet().removeAll(platformAnnotations); if (unmatchedAnnotations.size() > 0) { @@ -1649,7 +1644,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea * regex matching that string. If the string is not a valid * import-style string, return a regex that won't match anything. */ - private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, Lint lint) { + private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log) { String module; String pkg; int slash = s.indexOf('/'); @@ -1662,7 +1657,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } else { String moduleName = s.substring(0, slash); if (!SourceVersion.isName(moduleName)) { - return warnAndNoMatches(s, p, log, lint); + return warnAndNoMatches(s, p, log); } module = Pattern.quote(moduleName + "/"); // And warn if module is specified if modules aren't supported, conditional on -Xlint:proc? @@ -1671,12 +1666,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (MatchingUtils.isValidImportString(pkg)) { return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg)); } else { - return warnAndNoMatches(s, p, log, lint); + return warnAndNoMatches(s, p, log); } } - private static Pattern warnAndNoMatches(String s, Processor p, Log log, Lint lint) { - lint.logIfEnabled(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName())); + private static Pattern warnAndNoMatches(String s, Processor p, Log log) { + log.warning(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName())); return noMatches; // won't match any valid identifier } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 7dde6cc963f..a226b2f5960 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1600,6 +1600,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=\ # 0: path # lint: path +# flags: default-enabled compiler.warn.outdir.is.in.exploded.module=\ the output directory is within an exploded module: {0} @@ -1924,19 +1925,19 @@ compiler.warn.incubating.modules=\ # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated=\ {0} in {1} has been deprecated # 0: symbol, 1: symbol # lint: removal -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal=\ {0} in {1} has been deprecated and marked for removal # 0: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview=\ {0} is a preview API and may be removed in a future release. @@ -1947,7 +1948,7 @@ compiler.err.is.preview=\ # 0: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview.reflective=\ {0} is a reflective preview API and may be removed in a future release. @@ -1959,13 +1960,13 @@ compiler.warn.restricted.method=\ # 0: symbol # lint: deprecation -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.module=\ module {0} has been deprecated # 0: symbol # lint: removal -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal.module=\ module {0} has been deprecated and marked for removal @@ -2194,11 +2195,13 @@ compiler.warn.static.not.qualified.by.type2=\ # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.bootclasspath=\ bootstrap class path is not set in conjunction with -source {0}\n{1} # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.system.modules.path=\ location of system modules is not set in conjunction with -source {0}\n{1} @@ -2224,11 +2227,13 @@ compiler.misc.source.no.system.modules.path.with.target=\ # 0: string # lint: options +# flags: default-enabled compiler.warn.option.obsolete.source=\ source value {0} is obsolete and will be removed in a future release # 0: target # lint: options +# flags: default-enabled compiler.warn.option.obsolete.target=\ target value {0} is obsolete and will be removed in a future release @@ -2241,6 +2246,7 @@ compiler.err.option.removed.target=\ Target option {0} is no longer supported. Use {1} or later. # lint: options +# flags: default-enabled compiler.warn.option.obsolete.suppression=\ To suppress warnings about obsolete options, use -Xlint:-options. @@ -2365,13 +2371,13 @@ compiler.warn.unchecked.assign=\ # 0: symbol, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.assign.to.var=\ unchecked assignment to variable {0} as member of raw type {1} # 0: symbol, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.call.mbr.of.raw.type=\ unchecked call to {0} as a member of the raw type {1} @@ -2381,7 +2387,7 @@ compiler.warn.unchecked.cast.to.type=\ # 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.meth.invocation.applied=\ unchecked method invocation: {0} {1} in {4} {5} is applied to given types\n\ required: {2}\n\ @@ -2389,13 +2395,13 @@ compiler.warn.unchecked.meth.invocation.applied=\ # 0: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.generic.array.creation=\ unchecked generic array creation for varargs parameter of type {0} # 0: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.varargs.non.reifiable.type=\ Possible heap pollution from parameterized vararg type {0} @@ -2794,7 +2800,7 @@ compiler.misc.prob.found.req=\ # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.prob.found.req=\ {0}\n\ required: {2}\n\ @@ -3191,14 +3197,14 @@ compiler.err.override.incompatible.ret=\ # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.ret=\ {0}\n\ return type requires unchecked conversion from {1} to {2} # 0: message segment, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.thrown=\ {0}\n\ overridden method does not throw {1} @@ -3302,13 +3308,13 @@ compiler.err.preview.feature.disabled.classfile=\ # 0: message segment (feature) # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use=\ {0} is a preview feature and may be removed in a future release. # 0: message segment (feature) # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use.plural=\ {0} are a preview feature and may be removed in a future release. @@ -3879,6 +3885,7 @@ compiler.err.bad.name.for.option=\ # 0: option name, 1: symbol # lint: options +# flags: default-enabled compiler.warn.module.for.option.not.found=\ module name in {0} option not found: {1} @@ -3895,6 +3902,7 @@ compiler.err.add.reads.with.release=\ adding read edges for system module {0} is not allowed with --release # lint: options +# flags: default-enabled compiler.warn.addopens.ignored=\ --add-opens has no effect at compile time @@ -4272,7 +4280,7 @@ compiler.err.incorrect.number.of.nested.patterns=\ # 0: kind name, 1: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.declared.using.preview=\ {0} {1} is declared using a preview feature, which may be removed in a future release. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index 06a1d9fc7a3..c9f529eae55 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -368,6 +368,36 @@ public class JCDiagnostic implements Diagnostic { * the end position of the tree node. Otherwise, just returns the * same as getPreferredPosition(). */ int getEndPosition(EndPosTable endPosTable); + /** Get the position that determines which Lint configuration applies. */ + default int getLintPosition() { + return getStartPosition(); + } + /** Create a new instance from this instance and the given lint position. */ + default DiagnosticPosition withLintPosition(int lintPos) { + DiagnosticPosition orig = this; + return new DiagnosticPosition() { + @Override + public JCTree getTree() { + return orig.getTree(); + } + @Override + public int getStartPosition() { + return orig.getStartPosition(); + } + @Override + public int getPreferredPosition() { + return orig.getPreferredPosition(); + } + @Override + public int getEndPosition(EndPosTable endPosTable) { + return orig.getEndPosition(endPosTable); + } + @Override + public int getLintPosition() { + return lintPos; + } + }; + } } /** @@ -405,6 +435,10 @@ public class JCDiagnostic implements Diagnostic { RECOVERABLE, NON_DEFERRABLE, COMPRESSED, + /** Flag for lint diagnostics that should be emitted even when their category + * is not explicitly enabled, as long as it is not explicitly suppressed. + */ + DEFAULT_ENABLED, /** Flags mandatory warnings that should pass through a mandatory warning aggregator. */ AGGREGATE, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 576344a3d2a..95458f339a1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -32,29 +32,45 @@ import java.util.Comparator; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.EndPosTable; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticInfo; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import static com.sun.tools.javac.main.Option.*; import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; +import static com.sun.tools.javac.code.Lint.LintCategory.*; +import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresAutomatic; +import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresTransitiveAutomatic; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** A class for error logs. Reports errors and warnings, and * keeps track of error numbers and positions. @@ -103,6 +119,11 @@ public class Log extends AbstractLog { */ protected final DiagnosticHandler prev; + /** + * Diagnostics waiting for an applicable {@link Lint} instance. + */ + protected Map> lintWaitersMap = new LinkedHashMap<>(); + /** * Install this diagnostic handler as the current one, * recording the previous one. @@ -113,9 +134,92 @@ public class Log extends AbstractLog { } /** - * Handle a diagnostic. + * Step 1: Handle a diagnostic for which the applicable Lint instance (if any) may not be known yet. */ - public abstract void report(JCDiagnostic diag); + public final void report(JCDiagnostic diag) { + Lint lint = null; + LintCategory category = diag.getLintCategory(); + if (category != null) { // this is a lint warning; find the applicable Lint + DiagnosticPosition pos = diag.getDiagnosticPosition(); + if (pos != null && category.annotationSuppression) { // we should apply the Lint from the warning's position + if ((lint = lintFor(diag)) == null) { + addLintWaiter(currentSourceFile(), diag); // ...but we don't know it yet, so defer + return; + } + } else // we should apply the root Lint + lint = rootLint(); + } + reportWithLint(diag, lint); + } + + /** + * Step 2: Handle a diagnostic for which the applicable Lint instance (if any) is known and provided. + */ + public final void reportWithLint(JCDiagnostic diag, Lint lint) { + + // Apply hackery for REQUIRES_TRANSITIVE_AUTOMATIC (see also Check.checkModuleRequires()) + if (diag.getCode().equals(RequiresTransitiveAutomatic.key()) && !lint.isEnabled(REQUIRES_TRANSITIVE_AUTOMATIC)) { + reportWithLint( + diags.warning(null, diag.getDiagnosticSource(), diag.getDiagnosticPosition(), RequiresAutomatic), lint); + return; + } + + // Apply the lint configuration (if any) and discard the warning if it gets filtered out + if (lint != null) { + LintCategory category = diag.getLintCategory(); + boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default? + lint.isEnabled(category) : // then emit if the category is enabled + category.annotationSuppression ? // else emit if the category is not suppressed, where + !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings + !options.isLintDisabled(category); // ...suppression happens via -Xlint:-category + if (!emit) + return; + } + + // Proceed + reportReady(diag); + } + + /** + * Step 3: Handle a diagnostic to which the applicable Lint instance (if any) has been applied. + */ + protected abstract void reportReady(JCDiagnostic diag); + + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) { + lintWaitersMap.computeIfAbsent(sourceFile, s -> new LinkedList<>()).add(diagnostic); + } + + /** + * Flush any lint waiters whose {@link Lint} configurations are now known. + */ + public void flushLintWaiters() { + lintWaitersMap.entrySet().removeIf(entry -> { + + // Is the source file no longer recognized? If so, discard warnings (e.g., this can happen with JShell) + JavaFileObject sourceFile = entry.getKey(); + if (!lintMapper.isKnown(sourceFile)) + return true; + + // Flush those diagnostics for which we now know the applicable Lint + List diagnosticList = entry.getValue(); + JavaFileObject prevSourceFile = useSource(sourceFile); + try { + diagnosticList.removeIf(diag -> { + Lint lint = lintFor(diag); + if (lint != null) { + reportWithLint(diag, lint); + return true; + } + return false; + }); + } finally { + useSource(prevSourceFile); + } + + // Discard list if empty + return diagnosticList.isEmpty(); + }); + } } /** @@ -124,7 +228,10 @@ public class Log extends AbstractLog { public class DiscardDiagnosticHandler extends DiagnosticHandler { @Override - public void report(JCDiagnostic diag) { } + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) { } + + @Override + protected void reportReady(JCDiagnostic diag) { } } /** @@ -157,11 +264,20 @@ public class Log extends AbstractLog { } @Override - public void report(JCDiagnostic diag) { + protected void reportReady(JCDiagnostic diag) { if (deferrable(diag)) { deferred.add(diag); } else { - prev.report(diag); + prev.reportReady(diag); + } + } + + @Override + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diag) { + if (deferrable(diag)) { + super.addLintWaiter(sourceFile, diag); + } else { + prev.addLintWaiter(sourceFile, diag); } } @@ -182,6 +298,13 @@ public class Log extends AbstractLog { .filter(accepter) .forEach(prev::report); deferred = null; // prevent accidental ongoing use + + // Flush matching Lint waiters to the previous handler + lintWaitersMap.forEach( + (sourceFile, diagnostics) -> diagnostics.stream() + .filter(accepter) + .forEach(diagnostic -> prev.addLintWaiter(sourceFile, diagnostic))); + lintWaitersMap = null; // prevent accidental ongoing use } /** Report all deferred diagnostics in the specified order. */ @@ -247,6 +370,16 @@ public class Log extends AbstractLog { */ private final Context context; + /** + * The {@link Options} singleton. + */ + private final Options options; + + /** + * The lint positions table. + */ + private final LintMapper lintMapper; + /** * The root {@link Lint} singleton. */ @@ -350,6 +483,8 @@ public class Log extends AbstractLog { super(JCDiagnostic.Factory.instance(context)); context.put(logKey, this); this.context = context; + this.options = Options.instance(context); + this.lintMapper = LintMapper.instance(context); this.writers = writers; @SuppressWarnings("unchecked") // FIXME @@ -369,7 +504,6 @@ public class Log extends AbstractLog { this.diagFormatter = new BasicDiagnosticFormatter(messages); // Once Options is ready, complete the initialization - final Options options = Options.instance(context); options.whenReady(this::initOptions); } // where @@ -689,6 +823,21 @@ public class Log extends AbstractLog { diagnosticHandler.report(diagnostic); } +// Deferred Lint Calculation + + /** + * Report unreported lint warnings for which the applicable {@link Lint} configuration is now known. + */ + public void reportOutstandingWarnings() { + diagnosticHandler.flushLintWaiters(); + } + + // Get the Lint config for the given warning (if known) + private Lint lintFor(JCDiagnostic diag) { + Assert.check(diag.getLintCategory() != null); + return lintMapper.lintAt(diag.getSource(), diag.getDiagnosticPosition()).orElse(null); + } + // Obtain root Lint singleton lazily to avoid init loops private Lint rootLint() { if (rootLint == null) @@ -756,7 +905,7 @@ public class Log extends AbstractLog { private class DefaultDiagnosticHandler extends DiagnosticHandler { @Override - public void report(JCDiagnostic diagnostic) { + protected void reportReady(JCDiagnostic diagnostic) { if (expectDiagKeys != null) expectDiagKeys.remove(diagnostic.getCode()); @@ -783,13 +932,13 @@ public class Log extends AbstractLog { // Apply the appropriate mandatory warning aggregator, if needed if (diagnostic.isFlagSet(AGGREGATE)) { LintCategory category = diagnostic.getLintCategory(); - boolean verbose = rootLint().isEnabled(category); + boolean verbose = lintFor(diagnostic).isEnabled(category); if (!aggregatorFor(category).aggregate(diagnostic, verbose)) return; } // Strict warnings are always emitted - if (diagnostic.isFlagSet(DiagnosticFlag.STRICT)) { + if (diagnostic.isFlagSet(STRICT)) { writeDiagnostic(diagnostic); nwarnings++; return; diff --git a/test/langtools/tools/javac/6304921/TestLog.java b/test/langtools/tools/javac/6304921/TestLog.java index 41695554a88..8f00a14b9e2 100644 --- a/test/langtools/tools/javac/6304921/TestLog.java +++ b/test/langtools/tools/javac/6304921/TestLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ import javax.tools.SimpleJavaFileObject; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; -import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; +import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; @@ -130,10 +130,11 @@ public class TestLog log.error(tree.pos(), Errors.NotStmt); log.error(nil, Errors.NotStmt); - log.warning(LintWarnings.DivZero); - log.warning(tree.pos, LintWarnings.DivZero); - log.warning(tree.pos(), LintWarnings.DivZero); - log.warning(nil, LintWarnings.DivZero); + // some warnings that will be emitted during parsing + log.warning(Warnings.ExtraneousSemicolon); + log.warning(tree.pos, Warnings.ExtraneousSemicolon); + log.warning(tree.pos(), Warnings.ExtraneousSemicolon); + log.warning(nil, Warnings.ExtraneousSemicolon); } private Log log; diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index f088dbef658..d26b73c0289 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -730,8 +730,8 @@ public class ImportModule extends TestRunner { .getOutputLines(Task.OutputKind.DIRECT); List expectedErrors = List.of( - "module-info.java:3:18: compiler.warn.module.not.found: M1", "module-info.java:6:9: compiler.err.cant.resolve: kindname.class, A, , ", + "module-info.java:3:18: compiler.warn.module.not.found: M1", "1 error", "1 warning" ); diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out index 2a12111fe40..23dcddc1e93 100644 --- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out +++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out @@ -1,4 +1,4 @@ -T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor T6400189a.java:14:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.annotation.Annotation, java.lang.annotation.Documented) +T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor 1 error 1 warning diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out index 904cd3e677f..91e34b5beca 100644 --- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out +++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out @@ -1,4 +1,4 @@ -T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B T6400189b.java:24:24: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.Integer) +T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B 1 error 1 warning diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out index 78285aa45d9..b2dde3ff0ef 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out @@ -1,7 +1,7 @@ +DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:10:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:14:8: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:14:69: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment 6 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out index 3ed89c5f5bc..e97bd630ad8 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out @@ -1,7 +1,7 @@ +DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:11:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:15:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:17:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:19:9: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment 6 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out index 1eda729da19..13e15493579 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out @@ -1,4 +1,4 @@ -DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Mixed.java:17:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Mixed.java:21:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment 3 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out index ddf1b2964de..33938e86078 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out @@ -1,8 +1,8 @@ +DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:10:1: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:14:8: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:14:67: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment 7 warnings diff --git a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out index efceb84c8c7..3c93e1711d6 100644 --- a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out +++ b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out @@ -1,11 +1,11 @@ T7188968.java:20:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) -T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:21:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) -T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:22:22: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo +T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:22:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo T7188968.java:22:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List -T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) T7188968.java:23:20: compiler.warn.unchecked.meth.invocation.applied: kindname.method, makeFoo, java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo T7188968.java:23:21: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List 4 errors diff --git a/test/langtools/tools/javac/lambda/TargetType22.out b/test/langtools/tools/javac/lambda/TargetType22.out index d94b2cc60b3..c19aef2411f 100644 --- a/test/langtools/tools/javac/lambda/TargetType22.out +++ b/test/langtools/tools/javac/lambda/TargetType22.out @@ -1,4 +1,4 @@ -TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A TargetType22.java:40:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType22.Sam1), TargetType22, kindname.method, call(TargetType22.SamX), TargetType22 +TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A 1 error 1 warning diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.java b/test/langtools/tools/javac/lint/LexicalLintNesting.java new file mode 100644 index 00000000000..f167921df81 --- /dev/null +++ b/test/langtools/tools/javac/lint/LexicalLintNesting.java @@ -0,0 +1,170 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8224228 + * @summary Verify lexical lint warnings handle nested declarations with SuppressWarnings correctly + * @compile/fail/ref=LexicalLintNesting.out -XDrawDiagnostics -Xlint:text-blocks -Werror LexicalLintNesting.java + */ + +//@SuppressWarnings("text-blocks") +public class LexicalLintNesting { + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s1 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s2 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested1 { + + @SuppressWarnings("text-blocks") + String s3 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s4 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested1A { + + //@SuppressWarnings("text-blocks") + String s5 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s6 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s7 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s8 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested1B { + + @SuppressWarnings("text-blocks") + String s9 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s10 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s11 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s12 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s13 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s14 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested2 { + + @SuppressWarnings("text-blocks") + String s15 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s16 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested2A { + + //@SuppressWarnings("text-blocks") + String s17 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s18 = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + + } + + @SuppressWarnings("text-blocks") + String s19 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s20 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested2B { + + @SuppressWarnings("text-blocks") + String s21 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s22 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s23 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s24 = """ + trailing space here:\u0020 + """; + + } + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s25 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s26 = """ + trailing space here:\u0020 + """; +} diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.out b/test/langtools/tools/javac/lint/LexicalLintNesting.out new file mode 100644 index 00000000000..b16db47cf52 --- /dev/null +++ b/test/langtools/tools/javac/lint/LexicalLintNesting.out @@ -0,0 +1,10 @@ +LexicalLintNesting.java:12:36: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:30:40: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:55:40: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:68:45: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:80:41: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:92:37: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:162:37: compiler.warn.trailing.white.space.will.be.removed +- compiler.err.warnings.and.werror +1 error +7 warnings diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.java b/test/langtools/tools/javac/lint/TextBlockSuppress.java new file mode 100644 index 00000000000..05019be6bc2 --- /dev/null +++ b/test/langtools/tools/javac/lint/TextBlockSuppress.java @@ -0,0 +1,61 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8224228 + * @summary Verify SuppressWarnings works for LintCategore.TEXT_BLOCKS + * @compile/fail/ref=TextBlockSuppress.out -XDrawDiagnostics -Xlint:text-blocks -Werror TextBlockSuppress.java + */ + +public class TextBlockSuppress { + + public static class Example1 { + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD get a warning here + } + } + + @SuppressWarnings("text-blocks") + public static class Example2 { + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example3 { + @SuppressWarnings("text-blocks") + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example4 { + { + String s = """ + trailing space here:\u0020 + """; // SHOULD get a warning here + } + } + + @SuppressWarnings("text-blocks") + public static class Example5 { + { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example6 { + public void method() { + @SuppressWarnings("text-blocks") + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } +} diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.out b/test/langtools/tools/javac/lint/TextBlockSuppress.out new file mode 100644 index 00000000000..d16f080a133 --- /dev/null +++ b/test/langtools/tools/javac/lint/TextBlockSuppress.out @@ -0,0 +1,5 @@ +TextBlockSuppress.java:12:24: compiler.warn.trailing.white.space.will.be.removed +TextBlockSuppress.java:38:24: compiler.warn.trailing.white.space.will.be.removed +- compiler.err.warnings.and.werror +1 error +2 warnings diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out index 6fe57b8979d..1656d8eeff5 100644 --- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out +++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out @@ -1,4 +1,4 @@ -Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q +Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 Q.java:17:25: compiler.warn.has.been.deprecated: foo(), Q 3 warnings diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out index fe4a91e2584..5dee9c1414c 100644 --- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out +++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out @@ -1,4 +1,4 @@ -Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q +Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 - compiler.note.deprecated.filename.additional: Q.java 2 warnings diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index 6d9bfaad406..f9858a105eb 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -599,8 +599,8 @@ public class AnnotationsOnModules extends ModuleTestBase { "1 warning"); } else if (suppress.equals(DEPRECATED_JAVADOC)) { expected = Arrays.asList( - "module-info.java:1:19: compiler.warn.missing.deprecated.annotation", "module-info.java:2:14: compiler.warn.has.been.deprecated.module: m1x", + "module-info.java:1:19: compiler.warn.missing.deprecated.annotation", "2 warnings"); } else { expected = Arrays.asList(""); diff --git a/test/langtools/tools/javac/preview/PreviewErrors.java b/test/langtools/tools/javac/preview/PreviewErrors.java index eab5b2af9bf..db17aabbd42 100644 --- a/test/langtools/tools/javac/preview/PreviewErrors.java +++ b/test/langtools/tools/javac/preview/PreviewErrors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -324,7 +324,9 @@ public class PreviewErrors extends ComboInstance { ok = true; switch (elementType) { case LANGUAGE -> { - if (lint == Lint.ENABLE_PREVIEW) { + if (suppress == Suppress.YES) { + expected = Set.of(); + } else if (lint == Lint.ENABLE_PREVIEW) { expected = Set.of("5:41:compiler.warn.preview.feature.use"); } else { expected = Set.of("-1:-1:compiler.note.preview.filename", diff --git a/test/langtools/tools/javac/preview/PreviewTest.java b/test/langtools/tools/javac/preview/PreviewTest.java index 36f1e70acd0..e681f3f837e 100644 --- a/test/langtools/tools/javac/preview/PreviewTest.java +++ b/test/langtools/tools/javac/preview/PreviewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -587,12 +587,12 @@ public class PreviewTest extends TestRunner { "Test.java:19:11: compiler.err.is.preview: test()", "Test.java:20:11: compiler.err.is.preview: test()", "Test.java:21:11: compiler.err.is.preview: test()", - "Test.java:24:11: compiler.warn.is.preview.reflective: test()", "Test.java:29:16: compiler.err.is.preview: preview.api.Preview", "Test.java:32:21: compiler.err.is.preview: test()", "Test.java:36:21: compiler.err.is.preview: test()", "Test.java:40:13: compiler.err.is.preview: test()", "Test.java:41:21: compiler.err.is.preview: FIELD", + "Test.java:24:11: compiler.warn.is.preview.reflective: test()", "17 errors", "1 warning"); @@ -792,6 +792,99 @@ public class PreviewTest extends TestRunner { throw new Exception("expected output not found" + log); } + @Test //JDK-8224228: + public void testSuppressWarnings(Path base) throws Exception { + Path apiSrc = base.resolve("api-src"); + tb.writeJavaFiles(apiSrc, + """ + package preview.api; + @jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST) + public class Preview { + public static int test() { + return 0; + } + } + """); + Path apiClasses = base.resolve("api-classes"); + + new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(apiClasses) + .options("--patch-module", "java.base=" + apiSrc.toString(), + "-Werror") + .files(tb.findJavaFiles(apiSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + Path testSrc = base.resolve("test-src"); + tb.writeJavaFiles(testSrc, + """ + package test; + import preview.api.Preview; + public class Test { + + public static class Example1 { + public void method() { + Preview.test(); // SHOULD get a warning here + } + } + + @SuppressWarnings("preview") + public static class Example2 { + public void method() { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example3 { + @SuppressWarnings("preview") + public void method() { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example4 { + { + Preview.test(); // SHOULD get a warning here + } + } + + @SuppressWarnings("preview") + public static class Example5 { + { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example6 { + @SuppressWarnings("preview") + int x = Preview.test(); // SHOULD NOT get a warning here + } + } + """); + Path testClasses = base.resolve("test-classes"); + List log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", + "-Xlint:preview", + "-source", String.valueOf(Runtime.version().feature()), + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = + List.of("Test.java:7:11: compiler.warn.is.preview: preview.api.Preview", + "Test.java:27:11: compiler.warn.is.preview: preview.api.Preview", + "2 warnings"); + + if (!log.equals(expected)) + throw new Exception("expected output not found: " + log); + } + @Test //JDK-8343540: public void nonPreviewImplementsPreview5(Path base) throws Exception { Path apiSrc = base.resolve("api-src"); diff --git a/test/langtools/tools/javac/varargs/7097436/T7097436.out b/test/langtools/tools/javac/varargs/7097436/T7097436.out index 5e35910d2fa..392869f3b9f 100644 --- a/test/langtools/tools/javac/varargs/7097436/T7097436.out +++ b/test/langtools/tools/javac/varargs/7097436/T7097436.out @@ -1,6 +1,6 @@ -T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls -T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.String) T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.Integer[]) +T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls 2 errors 2 warnings diff --git a/test/langtools/tools/javac/warnings/6594914/T6594914a.out b/test/langtools/tools/javac/warnings/6594914/T6594914a.out index 62f99072a7a..d3d759ca044 100644 --- a/test/langtools/tools/javac/warnings/6594914/T6594914a.out +++ b/test/langtools/tools/javac/warnings/6594914/T6594914a.out @@ -1,7 +1,7 @@ T6594914a.java:11:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:16:16: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:16:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:17:20: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:24:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package 6 warnings diff --git a/test/langtools/tools/javac/warnings/7090499/T7090499.out b/test/langtools/tools/javac/warnings/7090499/T7090499.out index 1ff9e164e48..2241c0a04bb 100644 --- a/test/langtools/tools/javac/warnings/7090499/T7090499.out +++ b/test/langtools/tools/javac/warnings/7090499/T7090499.out @@ -1,14 +1,14 @@ +T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:18:5: compiler.warn.raw.class.use: T7090499, T7090499 T7090499.java:18:22: compiler.warn.raw.class.use: T7090499, T7090499 T7090499.java:20:10: compiler.warn.raw.class.use: T7090499.A.X, T7090499.A.X T7090499.java:21:10: compiler.warn.raw.class.use: T7090499.A.Z, T7090499.A.Z T7090499.java:24:17: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param -T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:28:18: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:28:11: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:30:32: compiler.warn.raw.class.use: T7090499.B, T7090499.B T7090499.java:33:13: compiler.warn.raw.class.use: T7090499.A, T7090499.A T7090499.java:33:24: compiler.warn.raw.class.use: T7090499.A, T7090499.A diff --git a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java index b5062a9b63f..a9101b47e42 100644 --- a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java +++ b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -116,8 +116,8 @@ public class UnneededStrictfpWarningToolBox extends TestRunner { var expected = List.of("UnneededStrictfpWarning1.java:1:17: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:10:10: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:12:29: compiler.warn.strictfp", - "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:18:21: compiler.warn.strictfp", + "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp", "5 warnings"); checkLog(log, expected); } diff --git a/test/langtools/tools/javac/warnings/suppress/T6480588.out b/test/langtools/tools/javac/warnings/suppress/T6480588.out index 630ba55523d..267ef32c964 100644 --- a/test/langtools/tools/javac/warnings/suppress/T6480588.out +++ b/test/langtools/tools/javac/warnings/suppress/T6480588.out @@ -1,19 +1,19 @@ T6480588.java:16:24: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:16:51: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package T6480588.java:15:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package +T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:18:12: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:18:65: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package +T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:17:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package -T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:19:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:19:34: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:21:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:21:25: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable T6480588.java:21:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:30:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package -T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package 18 warnings From 9041f4c47f3c9b90abe825f652f572351060c96a Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 20 Aug 2025 15:32:17 +0000 Subject: [PATCH 158/471] 8309400: JDI spec needs to clarify when OpaqueFrameException and NativeMethodException are thrown Reviewed-by: sspitsyn, alanb, amenkov --- .../classes/com/sun/jdi/ThreadReference.java | 10 ++--- .../com/sun/tools/jdi/StackFrameImpl.java | 39 ++++++++----------- .../sun/tools/jdi/ThreadReferenceImpl.java | 6 +-- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java index bccdf4cc8bf..67b8e391bf3 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -402,8 +402,8 @@ public interface ThreadReference extends ObjectReference { * @throws java.lang.IllegalArgumentException if frame * is not on this thread's call stack. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM was unable to pop the frames. + * @throws OpaqueFrameException if the target VM is unable to pop this frame + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if one of the frames that would be * popped is that of a native method or if the frame previous to @@ -484,8 +484,8 @@ public interface ThreadReference extends ObjectReference { * @throws IncompatibleThreadStateException if this * thread is not suspended. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM is unable to force the method to return. + * @throws OpaqueFrameException if the target VM is unable to force the method to return + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if the frame to be returned from * is that of a native method. diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java index e242bd7313b..a36e5695f69 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -395,29 +395,24 @@ public class StackFrameImpl extends MirrorImpl } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (thread.isVirtual()) { - // We first need to find out if the current frame is native, or if the - // previous frame is native, in which case we throw NativeMethodException - for (int i = 0; i < 2; i++) { - StackFrameImpl sf; - try { - sf = (StackFrameImpl)thread.frame(i); - } catch (IndexOutOfBoundsException e) { - // This should never happen, but we need to check for it. - break; - } - sf.validateStackFrame(); - MethodImpl meth = (MethodImpl)sf.location().method(); - if (meth.isNative()) { - throw new NativeMethodException(); - } + // We first need to find out if the current frame is native, or if the + // previous frame is native, in which case we throw NativeMethodException + for (int i = 0; i < 2; i++) { + StackFrame sf; + try { + sf = thread.frame(i); + } catch (IndexOutOfBoundsException e) { + // This should never happen, but we need to check for it. + break; + } + Method meth = sf.location().method(); + if (meth.isNative()) { + throw new NativeMethodException(); } - // No native frames involved. Must have been due to thread - // not being mounted. - throw new OpaqueFrameException(); - } else { - throw new NativeMethodException(); } + // No native frames involved. Must have been due to virtual thread + // not being mounted or some other reason such as failure to deopt. + throw new OpaqueFrameException(); case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( "Thread not current or suspended"); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java index 0f99fe99871..e5dce0718f4 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java @@ -597,10 +597,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (isVirtual() && !meth.isNative()) { - throw new OpaqueFrameException(); - } else { + if (meth.isNative()) { throw new NativeMethodException(); + } else { + throw new OpaqueFrameException(); } case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( From be6c15ecb490e86bafc15b5cd552784f7aa3ee69 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 20 Aug 2025 16:07:38 +0000 Subject: [PATCH 159/471] 8365671: Typo in Joiner.allUntil example Reviewed-by: liach --- .../classes/java/util/concurrent/StructuredTaskScope.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index fb16e0a615e..0088e486d4a 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -700,12 +700,12 @@ public sealed interface StructuredTaskScope * } * } * - * var joiner = Joiner.all(new CancelAfterTwoFailures()); + * var joiner = Joiner.allUntil(new CancelAfterTwoFailures()); * } * *

    The following example uses {@code allUntil} to wait for all subtasks to * complete without any cancellation. This is similar to {@link #awaitAll()} - * except that it yields a stream of the completed subtasks. + * except that it yields a list of the completed subtasks. * {@snippet lang=java : * List> invokeAll(Collection> tasks) throws InterruptedException { * try (var scope = StructuredTaskScope.open(Joiner.allUntil(_ -> false))) { From ed7d5fe840fed853b8a7db3347d6400f142ad154 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 20 Aug 2025 17:16:38 +0000 Subject: [PATCH 160/471] 8360304: Redundant condition in LibraryCallKit::inline_vector_nary_operation Reviewed-by: shade, vlivanov --- src/hotspot/share/opto/vectorIntrinsics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 10430a09e72..43ca51fca67 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -383,7 +383,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { // When using mask, mask use type needs to be VecMaskUseLoad. VectorMaskUseType mask_use_type = is_vector_mask(vbox_klass) ? VecMaskUseAll : is_masked_op ? VecMaskUseLoad : VecMaskNotUsed; - if ((sopc != 0) && !arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) { + if (!arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) { log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=%d is_masked_op=%d", n, sopc, num_elem, type2name(elem_bt), is_vector_mask(vbox_klass) ? 1 : 0, is_masked_op ? 1 : 0); @@ -391,7 +391,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { } // Return true if current platform has implemented the masked operation with predicate feature. - bool use_predicate = is_masked_op && sopc != 0 && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred); + bool use_predicate = is_masked_op && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred); if (is_masked_op && !use_predicate && !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad)) { log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=0 is_masked_op=1", n, sopc, num_elem, type2name(elem_bt)); From ecab52c09b078201ebeb8d45c0982b0481e15dc3 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 20 Aug 2025 17:21:22 +0000 Subject: [PATCH 161/471] 8365610: Sort share/jfr includes Reviewed-by: shade, mgronlun --- src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 2 +- .../instrumentation/jfrClassTransformer.cpp | 2 +- src/hotspot/share/jfr/jfr.cpp | 6 ++---- src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 5 ++--- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 20 +++++++++---------- .../jfr/leakprofiler/chains/bfsClosure.cpp | 2 +- .../jfr/leakprofiler/chains/edgeQueue.hpp | 2 +- .../chains/pathToGcRootsOperation.cpp | 6 ++---- .../leakprofiler/checkpoint/eventEmitter.hpp | 2 +- .../checkpoint/objectSampleCheckpoint.cpp | 2 +- .../checkpoint/objectSampleCheckpoint.hpp | 2 +- .../checkpoint/objectSampleWriter.cpp | 2 +- .../leakprofiler/checkpoint/rootResolver.cpp | 4 ++-- .../share/jfr/leakprofiler/leakProfiler.cpp | 4 ++-- .../leakprofiler/sampling/objectSampler.cpp | 4 ++-- .../share/jfr/metadata/jfrSerializer.hpp | 2 +- .../jfr/periodic/jfrNetworkUtilization.cpp | 2 +- .../share/jfr/periodic/jfrPeriodic.cpp | 6 +++--- .../jfr/periodic/jfrThreadCPULoadEvent.cpp | 4 ++-- .../sampling/jfrCPUTimeThreadSampler.cpp | 5 ++--- .../periodic/sampling/jfrThreadSampler.cpp | 4 ++-- .../recorder/checkpoint/jfrMetadataEvent.cpp | 2 +- .../checkpoint/types/jfrThreadState.cpp | 2 +- .../types/traceid/jfrTraceId.inline.hpp | 2 +- .../types/traceid/jfrTraceIdLoadBarrier.cpp | 2 +- .../share/jfr/recorder/jfrEventSetting.hpp | 2 +- .../share/jfr/recorder/jfrRecorder.cpp | 6 +++--- .../recorder/service/jfrEventThrottler.hpp | 2 +- .../recorder/service/jfrRecorderService.cpp | 8 ++++---- .../recorder/service/jfrRecorderThread.cpp | 2 +- .../service/jfrRecorderThreadLoop.cpp | 1 - .../stacktrace/jfrStackFilterRegistry.hpp | 2 +- .../share/jfr/recorder/storage/jfrStorage.cpp | 2 +- .../jfr/recorder/storage/jfrStorageUtils.hpp | 2 +- .../jfr/recorder/stringpool/jfrStringPool.cpp | 2 +- .../stringpool/jfrStringPoolWriter.hpp | 2 +- .../share/jfr/support/jfrAdaptiveSampler.cpp | 1 + .../support/jfrAnnotationElementIterator.hpp | 2 +- .../jfr/support/jfrDeprecationEventWriter.cpp | 2 +- .../jfr/support/jfrDeprecationEventWriter.hpp | 2 +- .../jfr/support/jfrDeprecationManager.cpp | 7 +++---- .../jfr/support/jfrDeprecationManager.hpp | 2 +- src/hotspot/share/jfr/support/jfrFlush.cpp | 2 +- .../share/jfr/support/jfrResolution.cpp | 3 +-- .../share/jfr/support/jfrStackTraceMark.hpp | 4 ++-- .../methodtracer/jfrClassFilterClosure.hpp | 4 ++-- .../jfr/support/methodtracer/jfrFilter.hpp | 2 +- .../support/methodtracer/jfrFilterManager.hpp | 2 +- .../support/methodtracer/jfrMethodTracer.hpp | 2 +- .../jfr/utilities/jfrEpochQueue.inline.hpp | 1 + src/hotspot/share/jfr/utilities/jfrSet.hpp | 2 +- .../share/jfr/utilities/jfrTimeConverter.cpp | 2 +- .../share/jfr/utilities/jfrTryLock.hpp | 2 +- .../writers/jfrStreamWriterHost.inline.hpp | 3 ++- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 55 files changed, 84 insertions(+), 89 deletions(-) diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index e7ba0e8f7ca..d18136e1570 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -24,8 +24,8 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmSymbols.hpp" -#include "jfr/jfr.hpp" #include "jfr/dcmd/jfrDcmds.hpp" +#include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" diff --git a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp index b9bedff0f9d..aa3b14e32f1 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp @@ -28,8 +28,8 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "jfr/instrumentation/jfrClassTransformer.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index a273df61922..7abf5c89945 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -26,18 +26,16 @@ #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/support/methodtracer/jfrTraceTagging.hpp" -#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index 3b566868f07..59a9d8a9090 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -39,11 +39,11 @@ #include "memory/resourceArea.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" -#include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" -#include "runtime/handles.inline.hpp" +#include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/javaThread.hpp" @@ -52,7 +52,6 @@ #include "runtime/synchronizer.hpp" #include "runtime/threadSMR.hpp" #include "utilities/growableArray.hpp" -#include "classfile/vmSymbols.hpp" #ifdef ASSERT static void check_java_thread_state(JavaThread* t, JavaThreadState state) { diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index a09da529b1b..1d1f3a62866 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -22,19 +22,24 @@ * */ +#include "jfr/instrumentation/jfrEventClassTransformer.hpp" +#include "jfr/instrumentation/jfrJvmtiAgent.hpp" #include "jfr/jfr.hpp" #include "jfr/jfrEvents.hpp" +#include "jfr/jni/jfrJavaSupport.hpp" +#include "jfr/jni/jfrJniMethodRegistration.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" -#include "jfr/recorder/jfrEventSetting.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/jfrEventSetting.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunk.hpp" -#include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.hpp" +#include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" @@ -42,18 +47,13 @@ #include "jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" -#include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/jni/jfrJniMethodRegistration.hpp" -#include "jfr/instrumentation/jfrEventClassTransformer.hpp" -#include "jfr/instrumentation/jfrJvmtiAgent.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrJdkJfrEvent.hpp" #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/utilities/jfrJavaLog.hpp" -#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "jfrfiles/jfrPeriodic.hpp" #include "jfrfiles/jfrTypes.hpp" @@ -67,8 +67,8 @@ #include "runtime/os.hpp" #include "utilities/debug.hpp" #ifdef LINUX -#include "osContainer_linux.hpp" #include "os_linux.hpp" +#include "osContainer_linux.hpp" #endif #define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header { diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp index 45fd4a7dc57..5bdddc4fd68 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp @@ -24,8 +24,8 @@ #include "jfr/leakprofiler/chains/bfsClosure.hpp" #include "jfr/leakprofiler/chains/dfsClosure.hpp" #include "jfr/leakprofiler/chains/edge.hpp" -#include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/edgeQueue.hpp" +#include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/jfrbitset.hpp" #include "jfr/leakprofiler/utilities/granularTimer.hpp" #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp index 774bd10d353..18cee5de7f2 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP #define SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP -#include "memory/allocation.hpp" #include "jfr/leakprofiler/chains/edge.hpp" #include "jfr/leakprofiler/utilities/unifiedOopRef.hpp" +#include "memory/allocation.hpp" class JfrVirtualMemory; diff --git a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp index ca7650d6876..83dc71f3827 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp @@ -24,7 +24,6 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/chains/bfsClosure.hpp" #include "jfr/leakprofiler/chains/dfsClosure.hpp" #include "jfr/leakprofiler/chains/edge.hpp" @@ -32,12 +31,11 @@ #include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/jfrbitset.hpp" #include "jfr/leakprofiler/chains/objectSampleMarker.hpp" -#include "jfr/leakprofiler/chains/rootSetClosure.hpp" -#include "jfr/leakprofiler/chains/edgeStore.hpp" -#include "jfr/leakprofiler/chains/objectSampleMarker.hpp" #include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp" +#include "jfr/leakprofiler/chains/rootSetClosure.hpp" #include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/sampling/objectSample.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/utilities/granularTimer.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp index 1d40c001c43..3965d0c0ff7 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "memory/allocation.hpp" typedef u8 traceid; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index 300786daf05..d8834e65b60 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -39,8 +39,8 @@ #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrMethodLookup.hpp" #include "jfr/utilities/jfrHashtable.hpp" -#include "jfr/utilities/jfrSet.hpp" #include "jfr/utilities/jfrRelation.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "memory/resourceArea.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp index 2ab2e12302f..63e251d3b67 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP -#include "memory/allStatic.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allStatic.hpp" class EdgeStore; class InstanceKlass; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp index ff1f9efd017..5b7ee3ddb3d 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp @@ -22,7 +22,6 @@ * */ -#include "jfrfiles/jfrTypes.hpp" #include "jfr/leakprofiler/chains/edge.hpp" #include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/edgeUtils.hpp" @@ -34,6 +33,7 @@ #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/metadata/jfrSerializer.hpp" #include "jfr/writers/jfrTypeWriterHost.hpp" +#include "jfrfiles/jfrTypes.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp index cf94293f0a3..4d7ccba5262 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -27,13 +27,13 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/strongRootsScope.hpp" -#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" +#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "memory/iterator.hpp" -#include "prims/jvmtiDeferredUpdates.hpp" #include "oops/klass.hpp" #include "oops/oop.hpp" +#include "prims/jvmtiDeferredUpdates.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/frame.inline.hpp" #include "runtime/jniHandles.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp index a5b4babb2b1..e8ad79783c0 100644 --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp @@ -22,11 +22,11 @@ * */ +#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" +#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/startOperation.hpp" #include "jfr/leakprofiler/stopOperation.hpp" -#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" -#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp index 86b8712698b..83873e2e500 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp @@ -31,11 +31,11 @@ #include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/sampling/sampleList.hpp" #include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp" -#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" -#include "jfr/utilities/jfrSignal.hpp" #include "jfr/support/jfrThreadLocal.hpp" +#include "jfr/utilities/jfrSignal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp index 57ae3554b0d..34ea94acbe8 100644 --- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp +++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_METADATA_JFRSERIALIZER_HPP #define SHARE_JFR_METADATA_JFRSERIALIZER_HPP -#include "memory/allocation.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfrfiles/jfrTypes.hpp" +#include "memory/allocation.hpp" /* * A "type" in Jfr is a binary relation defined by enumerating a set of ordered pairs: diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp index c18248e1056..11e211f6505 100644 --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp @@ -22,13 +22,13 @@ * */ -#include "logging/log.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/metadata/jfrSerializer.hpp" #include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "logging/log.hpp" #include "runtime/os_perf.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c..49669d1675d 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -38,11 +38,11 @@ #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/periodic/jfrModuleEvent.hpp" +#include "jfr/periodic/jfrNativeMemoryEvent.hpp" +#include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/periodic/jfrThreadDumpEvent.hpp" -#include "jfr/periodic/jfrNativeMemoryEvent.hpp" -#include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -61,8 +61,8 @@ #include "runtime/os_perf.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threads.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmThread.hpp" #include "services/classLoadingService.hpp" #include "services/management.hpp" #include "services/memoryPool.hpp" diff --git a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp index 1863b1af800..e2c92af2fb3 100644 --- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp @@ -22,14 +22,14 @@ * */ -#include "logging/log.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" -#include "utilities/globalDefinitions.hpp" +#include "logging/log.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" jlong JfrThreadCPULoadEvent::get_wallclock_time() { return os::javaTimeNanos(); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 2793a1fb984..db3ca758cc1 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -29,8 +29,8 @@ #if defined(LINUX) #include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" +#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "jfrfiles/jfrEventClasses.hpp" #include "memory/resourceArea.hpp" @@ -41,9 +41,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/vmOperation.hpp" #include "runtime/vmThread.hpp" -#include "utilities/ticks.hpp" - #include "signals_posix.hpp" +#include "utilities/ticks.hpp" static const int64_t RECOMPUTE_INTERVAL_MS = 100; diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 4c44c43772d..6347abd654f 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -23,11 +23,11 @@ */ #include "jfr/metadata/jfrSerializer.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/periodic/sampling/jfrSampleMonitor.hpp" #include "jfr/periodic/sampling/jfrSampleRequest.hpp" -#include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" +#include "jfr/periodic/sampling/jfrThreadSampling.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "jfr/utilities/jfrTypes.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp index 20e9c1e6798..937a0ca58c7 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp @@ -25,8 +25,8 @@ #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/jni/jfrUpcalls.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" -#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/jfrEventSetting.inline.hpp" +#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp index cdd7adebe4f..ed7e7d8195e 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp @@ -23,8 +23,8 @@ */ #include "classfile/javaClasses.inline.hpp" -#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" +#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jvmtifiles/jvmti.h" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp index 03647bdeae2..2af1080820f 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp @@ -27,9 +27,9 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp" -#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "oops/instanceKlass.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp index 8f600431333..12a73fd76c5 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp @@ -22,8 +22,8 @@ * */ -#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrEpochQueue.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp index e935dff3b27..3b2888bf505 100644 --- a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp +++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_RECORDER_JFREVENTSETTING_HPP #define SHARE_JFR_RECORDER_JFREVENTSETTING_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" #include "jfrfiles/jfrEventControl.hpp" +#include "jni.h" // // Native event settings as an associative array using the event id as key. diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 4ef278ab522..f5214ff7942 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -31,17 +31,17 @@ #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/types/jfrThreadGroupManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrPostBox.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" -#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" +#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -49,8 +49,8 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.inline.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/handles.inline.hpp" #include "utilities/growableArray.hpp" #ifdef ASSERT #include "prims/jvmtiEnvBase.hpp" diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp index b3c56183630..be6f8127205 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp @@ -26,8 +26,8 @@ #ifndef SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP #define SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/support/jfrAdaptiveSampler.hpp" +#include "jfrfiles/jfrEventIds.hpp" class JfrEventThrottler : public JfrAdaptiveSampler { friend class JfrRecorder; diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 7784148aee5..e8a3ea935de 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -22,14 +22,13 @@ * */ -#include "jfrfiles/jfrEventClasses.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" @@ -43,8 +42,9 @@ #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" -#include "jfr/writers/jfrJavaEventWriter.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfr/writers/jfrJavaEventWriter.hpp" +#include "jfrfiles/jfrEventClasses.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp index aa594ea6d1f..a63a55386a0 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp @@ -33,8 +33,8 @@ #include "memory/universe.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.hpp" -#include "utilities/preserveException.hpp" #include "utilities/macros.hpp" +#include "utilities/preserveException.hpp" static Thread* start_thread(instanceHandle thread_oop, ThreadFunction proc, TRAPS) { assert(thread_oop.not_null(), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp index 8aeb745b35e..de015e9a502 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp @@ -27,7 +27,6 @@ #include "jfr/recorder/service/jfrPostBox.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "logging/log.hpp" #include "runtime/handles.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp index e35fb90938f..a3564506924 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP #define SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" class JavaThread; class JfrStackFilter; diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp index ca54b297b38..934d2ba9d28 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp @@ -24,8 +24,8 @@ #include "jfr/jfrEvents.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrPostBox.hpp" diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp index fdfd32d1f90..690a5730804 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP #define SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP -#include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" +#include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp index dc28818b0f9..e1733b0ed5a 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp @@ -27,9 +27,9 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" -#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp" diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp index c91b6e585ce..5fc41550b66 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP #define SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP -#include "memory/allocation.hpp" #include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp" #include "jfr/writers/jfrEventWriterHost.hpp" #include "jfr/writers/jfrMemoryWriterHost.hpp" #include "jfr/writers/jfrStorageAdapter.hpp" +#include "memory/allocation.hpp" class Thread; diff --git a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp index aa351a81ff3..769a6b4a3e8 100644 --- a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp +++ b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp @@ -32,6 +32,7 @@ #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" + #include JfrSamplerWindow::JfrSamplerWindow() : diff --git a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp index 9d8b35080fb..289f0ead2fe 100644 --- a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp +++ b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp @@ -26,8 +26,8 @@ #define SHARE_JFR_SUPPORT_JFRANNOTATIONELEMENTITERATOR_HPP #include "jni.h" -#include "utilities/globalDefinitions.hpp" #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" class InstanceKlass; class Symbol; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp index 49b5e20e49a..7225dd60182 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp @@ -22,13 +22,13 @@ * */ -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/support/jfrDeprecationEventWriter.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "runtime/thread.inline.hpp" // This dual state machine for the level setting is because when multiple recordings are running, diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp index 1d73d4dc3a3..85a7ba51732 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP #define SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "memory/allocation.hpp" class JfrCheckpointWriter; class JfrChunkWriter; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp index 8fc35ca8dc1..5d2e180cae9 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp @@ -24,12 +24,11 @@ #include "classfile/moduleEntry.hpp" #include "interpreter/bytecodes.hpp" -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/recorder/jfrRecorder.hpp" -#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/jfrEventSetting.inline.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp" @@ -41,6 +40,7 @@ #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrLinkedList.inline.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" #include "memory/resourceArea.inline.hpp" #include "oops/instanceKlass.inline.hpp" @@ -49,7 +49,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.inline.hpp" -// for strstr #include static bool _enqueue_klasses = false; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp index d156679521a..86fe3cd35df 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP #define SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allocation.hpp" class JavaThread; class JfrCheckpointWriter; diff --git a/src/hotspot/share/jfr/support/jfrFlush.cpp b/src/hotspot/share/jfr/support/jfrFlush.cpp index 0179cde3d4a..a8ad2f531fd 100644 --- a/src/hotspot/share/jfr/support/jfrFlush.cpp +++ b/src/hotspot/share/jfr/support/jfrFlush.cpp @@ -23,8 +23,8 @@ */ #include "jfr/recorder/jfrEventSetting.inline.hpp" -#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" +#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/support/jfrFlush.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/support/jfrResolution.cpp b/src/hotspot/share/jfr/support/jfrResolution.cpp index 4027de2fb3d..3a00d24d455 100644 --- a/src/hotspot/share/jfr/support/jfrResolution.cpp +++ b/src/hotspot/share/jfr/support/jfrResolution.cpp @@ -26,8 +26,8 @@ #include "ci/ciMethod.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/stacktrace/jfrStackTrace.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrResolution.hpp" @@ -42,7 +42,6 @@ #include "opto/parse.hpp" #endif - // for strstr #include // The following packages are internal implmentation details used by reflection. diff --git a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp index e56dc64e400..1429c48a278 100644 --- a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp +++ b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP #define SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP -#include "memory/allocation.hpp" -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfrfiles/jfrEventIds.hpp" +#include "memory/allocation.hpp" class Thread; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp index 6cf1b321f1e..2febb43ce3a 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP -#include "jni.h" -#include "memory/iterator.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jni.h" +#include "memory/iterator.hpp" class JavaThread; class JfrFilter; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp index 665a2cafad3..d4c2414fa84 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" #include "oops/annotations.hpp" class InstanceKlass; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp index 904c8447a2e..687e2d700bc 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" class JfrFilter; class JavaThread; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp index d67de9daa59..8a214ab675b 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP -#include "jni.h" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/support/methodtracer/jfrTracedMethod.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jni.h" #include "memory/allocation.hpp" class ClassFileParser; diff --git a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp index cc2274408ec..553d61582c0 100644 --- a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_JFR_UTILITIES_JFREPOCHQUEUE_INLINE_HPP #include "jfr/utilities/jfrEpochQueue.hpp" + #include "jfr/recorder/storage/jfrEpochStorage.inline.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index b6458d3f9a4..1432d40e4b2 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allocation.hpp" template class JfrSetConfig : public AllStatic { diff --git a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp index 2ea0fd383d6..d03a15b31b5 100644 --- a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp +++ b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp @@ -22,8 +22,8 @@ * */ -#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfr/utilities/jfrTimeConverter.hpp" #include "runtime/os.inline.hpp" static double ft_counter_to_nanos_factor = .0; diff --git a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp index 5c76fa66321..513e550348b 100644 --- a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp +++ b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp @@ -26,8 +26,8 @@ #define SHARE_JFR_UTILITIES_JFRTRYLOCK_HPP #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" class JfrTryLock { diff --git a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp index 72fd3485aa3..83451148c70 100644 --- a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp +++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp @@ -25,8 +25,9 @@ #ifndef SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP #define SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP -#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/writers/jfrStreamWriterHost.hpp" + +#include "jfr/jni/jfrJavaSupport.hpp" #include "runtime/os.hpp" template diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 7460a160ee6..5d8c60e23e0 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -51,6 +51,7 @@ public class TestIncludesAreSorted { "share/code", "share/compiler", "share/interpreter", + "share/jfr", "share/jvmci", "share/libadt", "share/metaprogramming", From 2e06a917659d76fa1b4c63f38894564679209625 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 21 Aug 2025 01:20:16 +0000 Subject: [PATCH 162/471] 8365841: RISC-V: Several IR verification tests fail after JDK-8350960 without Zvfh Reviewed-by: fyang, fjiang, mli --- src/hotspot/cpu/riscv/riscv_v.ad | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 8b5759ce11c..f2845ee2a6c 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -110,6 +110,7 @@ source %{ if (vlen < 4) { return false; } + break; case Op_VectorCastHF2F: case Op_VectorCastF2HF: case Op_AddVHF: From 78d50c02152d3d02953cc468d50c7c40c43c1527 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Thu, 21 Aug 2025 03:53:30 +0000 Subject: [PATCH 163/471] 8358756: [s390x] Test StartupOutput.java crash due to CodeCache size Reviewed-by: lucy, dfenacci --- test/hotspot/jtreg/compiler/startup/StartupOutput.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/startup/StartupOutput.java b/test/hotspot/jtreg/compiler/startup/StartupOutput.java index 22f2887a266..14897f7ab87 100644 --- a/test/hotspot/jtreg/compiler/startup/StartupOutput.java +++ b/test/hotspot/jtreg/compiler/startup/StartupOutput.java @@ -36,6 +36,7 @@ package compiler.startup; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; @@ -60,8 +61,11 @@ public class StartupOutput { throw new Exception("VM crashed with exit code " + exitCode); } + // On s390x, generated code is ~6x larger in fastdebug and ~1.4x in release builds vs. other archs, + // hence we require slightly more minimum space. + int minInitialSize = 800 + (Platform.isS390x() ? 800 : 0); for (int i = 0; i < 200; i++) { - int initialCodeCacheSizeInKb = 800 + rand.nextInt(400); + int initialCodeCacheSizeInKb = minInitialSize + rand.nextInt(400); int reservedCodeCacheSizeInKb = initialCodeCacheSizeInKb + rand.nextInt(200); pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:InitialCodeCacheSize=" + initialCodeCacheSizeInKb + "K", "-XX:ReservedCodeCacheSize=" + reservedCodeCacheSizeInKb + "k", "-version"); out = new OutputAnalyzer(pb.start()); From c74c60fb8b8aa5c917fc4e1c157cc8083f5797a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 21 Aug 2025 07:09:25 +0000 Subject: [PATCH 164/471] 8308094: Add a compilation timeout flag to catch long running compilations Co-authored-by: Dean Long Reviewed-by: dlong, chagedorn --- .../os/linux/compilerThreadTimeout_linux.cpp | 128 ++++++++++++++++++ .../os/linux/compilerThreadTimeout_linux.hpp | 51 +++++++ src/hotspot/os/linux/globals_linux.hpp | 5 + src/hotspot/share/compiler/compileBroker.cpp | 6 + src/hotspot/share/compiler/compilerThread.cpp | 2 + src/hotspot/share/compiler/compilerThread.hpp | 33 ++++- .../arguments/TestCompileTaskTimeout.java | 56 ++++++++ .../jtreg/runtime/signal/TestSigalrm.java | 4 +- 8 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp create mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp new file mode 100644 index 00000000000..609c78616f3 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" +#include "compilerThreadTimeout_linux.hpp" +#include "oops/method.hpp" +#include "runtime/osThread.hpp" +#include "signals_posix.hpp" +#include "utilities/globalDefinitions.hpp" + +#include + +#ifdef ASSERT +void compiler_signal_handler(int signo, siginfo_t* info, void* context) { + CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context); +} + +void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) { + switch (signo) { + case TIMEOUT_SIGNAL: { + CompileTask* task = CompilerThread::current()->task(); + const int SIZE = 512; + char method_name_buf[SIZE]; + task->method()->name_and_sig_as_C_string(method_name_buf, SIZE); + assert(false, "compile task %d (%s) timed out after %zd ms", + task->compile_id(), method_name_buf, CompileTaskTimeout); + } + default: { + assert(false, "unexpected signal %d", signo); + } + } +} +#endif // ASSERT + +void CompilerThreadTimeoutLinux::arm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC; + const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC; + const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; + const struct itimerspec its {.it_interval = ts, .it_value = ts}; + + // Start the timer. + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +void CompilerThreadTimeoutLinux::disarm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + // Reset the timer by setting it to zero. + const struct itimerspec its { + .it_interval = {.tv_sec = 0, .tv_nsec=0}, + .it_value = {.tv_sec = 0, .tv_nsec=0} + }; + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +bool CompilerThreadTimeoutLinux::init_timeout() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return true; + } + + JavaThread* thread = JavaThread::current(); + + // Create a POSIX timer sending SIGALRM to this thread only. + sigevent_t sev; + sev.sigev_value.sival_ptr = nullptr; + sev.sigev_signo = TIMEOUT_SIGNAL; + sev.sigev_notify = SIGEV_THREAD_ID; + #ifdef MUSL_LIBC + sev.sigev_notify_thread_id = thread->osthread()->thread_id(); + #else + sev._sigev_un._tid = thread->osthread()->thread_id(); + #endif // MUSL_LIBC + clockid_t clock; + int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock); + if (err != 0) { + return false; + } + err = timer_create(clock, &sev, &_timer); + if (err != 0) { + return false; + } + + // Install the signal handler and check that we do not have a conflicting handler. + struct sigaction sigact, sigact_old; + err = PosixSignals::install_sigaction_signal_handler(&sigact, + &sigact_old, + TIMEOUT_SIGNAL, + (sa_sigaction_t)::compiler_signal_handler); + if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction && + sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) { + return false; + } +#endif // ASSERT + return true; +} diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp new file mode 100644 index 00000000000..2dc6fa7b9c9 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP +#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP + +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" +#include "utilities/macros.hpp" + +#include +#include + +class CompilerThreadTimeoutLinux : public CHeapObj { +#ifdef ASSERT + public: + static const int TIMEOUT_SIGNAL = SIGALRM; + void compiler_signal_handler(int signo, siginfo_t* info, void* context); + private: + timer_t _timer; +#endif // ASSERT + public: + CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {}; + + bool init_timeout(); + void arm(); + void disarm(); +}; + +#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 542e034f59f..90e1e5e5f3f 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -89,6 +89,11 @@ product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \ "Print an annotated memory map at exit") \ \ + develop(intx, CompileTaskTimeout, 0, \ + "Set the timeout for compile tasks' CPU time in milliseconds."\ + " 0 = no timeout (default)") \ + range(0,1000000) \ + \ // end of RUNTIME_OS_FLAGS // diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 36663ab1088..432b0e6a346 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -218,6 +218,7 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); CompileLog* log = thread->log(); + thread->timeout()->arm(); if (log != nullptr && !task->is_unloaded()) task->log_task_start(log); } @@ -228,6 +229,7 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (log != nullptr && !task->is_unloaded()) task->log_task_done(log); thread->set_task(nullptr); thread->set_env(nullptr); + thread->timeout()->disarm(); if (task->is_blocking()) { bool free_task = false; { @@ -1925,6 +1927,10 @@ void CompileBroker::compiler_thread_loop() { log->end_elem(); } + if (!thread->init_compilation_timeout()) { + return; + } + // If compiler thread/runtime initialization fails, exit the compiler thread if (!init_compiler_runtime()) { return; diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 4034e63bc10..7cf494aad56 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -40,6 +40,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, _can_call_java = false; _compiler = nullptr; _arena_stat = nullptr; + _timeout = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -49,6 +50,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; + delete _timeout; // arenastat should have been deleted at the end of the compilation assert(_arena_stat == nullptr, "Should be null"); } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index e20e3017d1f..e4641780a12 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,7 +25,14 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" #include "runtime/javaThread.hpp" +#include "utilities/macros.hpp" + +#ifdef LINUX +#include "compilerThreadTimeout_linux.hpp" +#endif //LINUX class AbstractCompiler; class ArenaStatCounter; @@ -38,10 +45,27 @@ class CompileQueue; class CompilerCounters; class IdealGraphPrinter; +#ifndef LINUX +class CompilerThreadTimeoutGeneric : public CHeapObj { + public: + CompilerThreadTimeoutGeneric() {}; + void arm() {}; + void disarm() {}; + bool init_timeout() { return true; }; +}; +#endif // !LINUX + // A thread used for Compilation. class CompilerThread : public JavaThread { friend class VMStructs; JVMCI_ONLY(friend class CompilerThreadCanCallJava;) + +#ifdef LINUX + typedef CompilerThreadTimeoutLinux Timeout; +#else // LINUX + typedef CompilerThreadTimeoutGeneric Timeout; +#endif // LINUX + private: CompilerCounters* _counters; @@ -57,6 +81,7 @@ class CompilerThread : public JavaThread { ArenaStatCounter* _arena_stat; + Timeout* _timeout; public: static CompilerThread* current() { @@ -113,7 +138,13 @@ class CompilerThread : public JavaThread { public: IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; } void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; } -#endif +#endif // !PRODUCT + + Timeout* timeout() const { return _timeout; }; + bool init_compilation_timeout() { + _timeout = new Timeout(); + return _timeout->init_timeout(); + }; // Get/set the thread's current task CompileTask* task() { return _task; } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java new file mode 100644 index 00000000000..42f13744cae --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arguments; + +/* + * @test TestCompileTaskTimeout + * @bug 8308094 + * @requires vm.debug & vm.flagless & os.name == "Linux" + * @summary Check functionality of CompileTaskTimeout + * @library /test/lib + * @run driver compiler.arguments.TestCompileTaskTimeout + */ + +import jdk.test.lib.process.ProcessTools; + +public class TestCompileTaskTimeout { + + public static void main(String[] args) throws Throwable { + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") + .shouldHaveExitValue(0) + .shouldContain("java version"); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java index b9a3c3e5060..2e485a46cf9 100644 --- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java +++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test - * @requires os.family != "windows" & os.family != "aix" + * @requires os.family != "windows" & os.family != "aix" & vm.flagless * * @summary converted from VM testbase runtime/signal/sigalrm01. * VM testbase keywords: [signal, runtime, linux, macosx] From a7c0f4b845c314099966f5669bfc7947bdf28004 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Thu, 21 Aug 2025 07:47:26 +0000 Subject: [PATCH 165/471] 8365146: Remove LockingMode related code from ppc64 Reviewed-by: aboldtch, mdoerr --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 48 +--- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 76 +---- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 220 ++------------- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 266 ------------------ src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 8 - src/hotspot/cpu/ppc/ppc.ad | 37 +-- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 21 +- .../ppc/templateInterpreterGenerator_ppc.cpp | 2 +- 8 files changed, 50 insertions(+), 628 deletions(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index b548444bb48..73509c22134 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -228,11 +228,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ b(*stub->entry()); - } else { - __ unlock_object(R5, R6, R4, *stub->entry()); - } + __ unlock_object(R5, R6, R4, *stub->entry()); __ bind(*stub->continuation()); } @@ -2618,44 +2614,20 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { // Obj may not be an oop. if (op->code() == lir_lock) { MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - if (LockingMode != LM_MONITOR) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - // Add debug info for NullPointerException only if one is possible. - if (op->info() != nullptr) { - if (!os::zero_page_read_protected() || !ImplicitNullChecks) { - explicit_null_check(obj, op->info()); - } else { - add_debug_info_for_null_check_here(op->info()); - } - } - __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); - } else { - // always do slow locking - // note: The slow locking code could be inlined here, however if we use - // slow locking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow locking code is the same in either case which simplifies - // debugging. - if (op->info() != nullptr) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + // Add debug info for NullPointerException only if one is possible. + if (op->info() != nullptr) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(obj, op->info()); + } else { add_debug_info_for_null_check_here(op->info()); - __ null_check(obj); } - __ b(*op->stub()->entry()); } + __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); } else { assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - if (LockingMode != LM_MONITOR) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj, lock, *op->stub()->entry()); - } else { - // always do slow unlocking - // note: The slow unlocking code could be inlined here, however if we use - // slow unlocking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow unlocking code is the same in either case which simplifies - // debugging. - __ b(*op->stub()->entry()); - } + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } __ bind(*op->stub()->continuation()); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 23050bff453..04af473c99b 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -82,59 +82,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Rscratch, Roop); - lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); - testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_int); - } - - // ... and mark it unlocked. - ori(Rmark, Rmark, markWord::unlocked_value); - - // Save unlocked object header into the displaced header location on the stack. - std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); - - // Compare object markWord with Rmark and if equal exchange Rscratch with object markWord. - assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement"); - cmpxchgd(/*flag=*/CR0, - /*current_value=*/Rscratch, - /*compare_value=*/Rmark, - /*exchange_value=*/Rbox, - /*where=*/Roop/*+0==mark_offset_in_bytes*/, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - // If compare/exchange succeeded we found an unlocked object and we now have locked it - // hence we are done. - } else { - assert(false, "Unhandled LockingMode:%d", LockingMode); - } + lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); b(done); bind(slow_int); b(slow_case); // far - if (LockingMode == LM_LEGACY) { - bind(cas_failed); - // We did not find an unlocked object so see if this is a recursive case. - sub(Rscratch, Rscratch, R1_SP); - load_const_optimized(R0, (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - and_(R0/*==0?*/, Rscratch, R0); - std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox); - bne(CR0, slow_int); - } - bind(done); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(Rmark /*tmp*/); - } } @@ -146,43 +100,17 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - if (LockingMode != LM_LIGHTWEIGHT) { - // Test first if it is a fast recursive unlock. - ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); - cmpdi(CR0, Rmark, 0); - beq(CR0, done); - } - // Load object. ld(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); verify_oop(Roop, FILE_AND_LINE); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(Roop, Rmark, slow_int); - } else if (LockingMode == LM_LEGACY) { - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object. - cmpxchgd(/*flag=*/CR0, - /*current_value=*/R0, - /*compare_value=*/Rbox, - /*exchange_value=*/Rmark, - /*where=*/Roop, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &slow_int); - } else { - assert(false, "Unhandled LockingMode:%d", LockingMode); - } + lightweight_unlock(Roop, Rmark, slow_int); b(done); bind(slow_int); b(slow_case); // far // Done bind(done); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(Rmark /*tmp*/); - } } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 29fb54250c2..8df2cc5d273 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -946,121 +946,20 @@ void InterpreterMacroAssembler::leave_jfr_critical_section() { // object - Address of the object to be locked. // void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - } else { - // template code (for LM_LEGACY): - // - // markWord displaced_header = obj->mark().set_unlocked(); - // monitor->lock()->set_displaced_header(displaced_header); - // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { - // // We stored the monitor address into the object's mark word. - // } else if (THREAD->is_lock_owned((address)displaced_header)) - // // Simple recursive case. - // monitor->lock()->set_displaced_header(nullptr); - // } else { - // // Slow path. - // InterpreterRuntime::monitorenter(THREAD, monitor); - // } + const Register header = R7_ARG5; + const Register tmp = R8_ARG6; - const Register header = R7_ARG5; - const Register object_mark_addr = R8_ARG6; - const Register current_header = R9_ARG7; - const Register tmp = R10_ARG8; + Label done, slow_case; - Label count_locking, done, slow_case, cas_failed; + assert_different_registers(header, tmp); - assert_different_registers(header, object_mark_addr, current_header, tmp); + lightweight_lock(monitor, object, header, tmp, slow_case); + b(done); - // markWord displaced_header = obj->mark().set_unlocked(); + bind(slow_case); + call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(monitor, object, header, tmp, slow_case); - b(done); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); - testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_case); - } - - // Load markWord from object into header. - ld(header, oopDesc::mark_offset_in_bytes(), object); - - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - ori(header, header, markWord::unlocked_value); - - // monitor->lock()->set_displaced_header(displaced_header); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); - - // Initialize the box (Must happen before we update the object mark!). - std(header, mark_offset, monitor); - - // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { - - // Store stack address of the BasicObjectLock (this is monitor) into object. - addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); - - // Must fence, otherwise, preceding store(s) may float below cmpxchg. - // CmpxchgX sets CR0 to cmpX(current, displaced). - cmpxchgd(/*flag=*/CR0, - /*current_value=*/current_header, - /*compare_value=*/header, /*exchange_value=*/monitor, - /*where=*/object_mark_addr, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object and we have now locked it. - b(count_locking); - bind(cas_failed); - - // } else if (THREAD->is_lock_owned((address)displaced_header)) - // // Simple recursive case. - // monitor->lock()->set_displaced_header(nullptr); - - // We did not see an unlocked object so try the fast recursive case. - - // Check if owner is self by comparing the value in the markWord of object - // (current_header) with the stack pointer. - sub(current_header, current_header, R1_SP); - - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - load_const_optimized(tmp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place); - - and_(R0/*==0?*/, current_header, tmp); - // If condition is true we are done and hence we can store 0 in the displaced - // header indicating it is a recursive lock. - bne(CR0, slow_case); - std(R0/*==0!*/, mark_offset, monitor); - b(count_locking); - } - - // } else { - // // Slow path. - // InterpreterRuntime::monitorenter(THREAD, monitor); - - // None of the above fast optimizations worked so we have to get into the - // slow case of monitor enter. - bind(slow_case); - call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - // } - - if (LockingMode == LM_LEGACY) { - b(done); - align(32, 12); - bind(count_locking); - inc_held_monitor_count(current_header /*tmp*/); - } - bind(done); - } + bind(done); } // Unlocks an object. Used in monitorexit bytecode and remove_activation. @@ -1071,95 +970,34 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // // Throw IllegalMonitorException if object is not locked by current thread. void InterpreterMacroAssembler::unlock_object(Register monitor) { - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - } else { + const Register object = R7_ARG5; + const Register header = R8_ARG6; + const Register current_header = R10_ARG8; - // template code (for LM_LEGACY): - // - // if ((displaced_header = monitor->displaced_header()) == nullptr) { - // // Recursive unlock. Mark the monitor unlocked by setting the object field to null. - // monitor->set_obj(nullptr); - // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) { - // // We swapped the unlocked mark in displaced_header into the object's mark word. - // monitor->set_obj(nullptr); - // } else { - // // Slow path. - // InterpreterRuntime::monitorexit(monitor); - // } + Label free_slot; + Label slow_case; - const Register object = R7_ARG5; - const Register header = R8_ARG6; - const Register object_mark_addr = R9_ARG7; - const Register current_header = R10_ARG8; + assert_different_registers(object, header, current_header); - Label free_slot; - Label slow_case; + // The object address from the monitor is in object. + ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor); - assert_different_registers(object, header, object_mark_addr, current_header); + lightweight_unlock(object, header, slow_case); - if (LockingMode != LM_LIGHTWEIGHT) { - // Test first if we are in the fast recursive case. - ld(header, in_bytes(BasicObjectLock::lock_offset()) + - BasicLock::displaced_header_offset_in_bytes(), monitor); + b(free_slot); - // If the displaced header is zero, we have a recursive unlock. - cmpdi(CR0, header, 0); - beq(CR0, free_slot); // recursive unlock - } + bind(slow_case); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) { - // // We swapped the unlocked mark in displaced_header into the object's mark word. - // monitor->set_obj(nullptr); + Label done; + b(done); // Monitor register may be overwritten! Runtime has already freed the slot. - // If we still have a lightweight lock, unlock the object and be done. - - // The object address from the monitor is in object. - ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor); - - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(object, header, slow_case); - } else { - addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); - - // We have the displaced header in displaced_header. If the lock is still - // lightweight, it will contain the monitor address and we'll store the - // displaced header back into the object's mark word. - // CmpxchgX sets CR0 to cmpX(current, monitor). - cmpxchgd(/*flag=*/CR0, - /*current_value=*/current_header, - /*compare_value=*/monitor, /*exchange_value=*/header, - /*where=*/object_mark_addr, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &slow_case); - } - b(free_slot); - - // } else { - // // Slow path. - // InterpreterRuntime::monitorexit(monitor); - - // The lock has been converted into a heavy lock and hence - // we need to get into the slow case. - bind(slow_case); - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - // } - - Label done; - b(done); // Monitor register may be overwritten! Runtime has already freed the slot. - - // Exchange worked, do monitor->set_obj(nullptr); - align(32, 12); - bind(free_slot); - li(R0, 0); - std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(current_header /*tmp*/); - } - bind(done); - } + // Do monitor->set_obj(nullptr); + align(32, 12); + bind(free_slot); + li(R0, 0); + std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor); + bind(done); } // Load compiled (i2c) or interpreter entry when calling from interpreted and diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 396a50427f8..00a46504e14 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2671,238 +2671,6 @@ address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, } // "The box" is the space on the stack where we copy the object mark. -void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { - assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_lock_lightweight"); - assert_different_registers(oop, box, temp, displaced_header, current_header); - Label object_has_monitor; - Label cas_failed; - Label success, failure; - - // Load markWord from object into displaced_header. - ld(displaced_header, oopDesc::mark_offset_in_bytes(), oop); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(temp, oop); - lbz(temp, in_bytes(Klass::misc_flags_offset()), temp); - testbitdi(flag, R0, temp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(flag, failure); - } - - // Handle existing monitor. - // The object has an existing monitor iff (mark & monitor_value) != 0. - andi_(temp, displaced_header, markWord::monitor_value); - bne(CR0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - // Set NE to indicate 'failure' -> take slow-path. - crandc(flag, Assembler::equal, flag, Assembler::equal); - b(failure); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - ori(displaced_header, displaced_header, markWord::unlocked_value); - - // Load Compare Value application register. - - // Initialize the box. (Must happen before we update the object mark!) - std(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - - // Must fence, otherwise, preceding store(s) may float below cmpxchg. - // Compare object markWord with mark and if equal exchange scratch1 with object markWord. - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/displaced_header, - /*exchange_value=*/box, - /*where=*/oop, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - // If the compare-and-exchange succeeded, then we found an unlocked - // object and we have now locked it. - b(success); - - bind(cas_failed); - // We did not see an unlocked object so try the fast recursive case. - - // Check if the owner is self by comparing the value in the markWord of object - // (current_header) with the stack pointer. - sub(current_header, current_header, R1_SP); - load_const_optimized(temp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place); - - and_(R0/*==0?*/, current_header, temp); - // If condition is true we are cont and hence we can store 0 as the - // displaced header in the box, which indicates that it is a recursive lock. - std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), box); - - if (flag != CR0) { - mcrf(flag, CR0); - } - beq(CR0, success); - b(failure); - } - - // Handle existing monitor. - bind(object_has_monitor); - - // Try to CAS owner (no owner => current thread's _monitor_owner_id). - addi(temp, displaced_header, in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value); - Register thread_id = displaced_header; - ld(thread_id, in_bytes(JavaThread::monitor_owner_id_offset()), R16_thread); - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/(intptr_t)0, - /*exchange_value=*/thread_id, - /*where=*/temp, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock()); - - // Store a non-null value into the box. - std(box, BasicLock::displaced_header_offset_in_bytes(), box); - beq(flag, success); - - // Check for recursive locking. - cmpd(flag, current_header, thread_id); - bne(flag, failure); - - // Current thread already owns the lock. Just increment recursions. - Register recursions = displaced_header; - ld(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp); - addi(recursions, recursions, 1); - std(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp); - - // flag == EQ indicates success, increment held monitor count if LM_LEGACY is enabled - // flag == NE indicates failure - bind(success); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(temp); - } -#ifdef ASSERT - // Check that unlocked label is reached with flag == EQ. - Label flag_correct; - beq(flag, flag_correct); - stop("compiler_fast_lock_object: Flag != EQ"); -#endif - bind(failure); -#ifdef ASSERT - // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); - stop("compiler_fast_lock_object: Flag != NE"); - bind(flag_correct); -#endif -} - -void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { - assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_unlock_lightweight"); - assert_different_registers(oop, box, temp, displaced_header, current_header); - Label success, failure, object_has_monitor, not_recursive; - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - - // If the displaced header is 0, we have a recursive unlock. - cmpdi(flag, displaced_header, 0); - beq(flag, success); - } - - // Handle existing monitor. - // The object has an existing monitor iff (mark & monitor_value) != 0. - ld(current_header, oopDesc::mark_offset_in_bytes(), oop); - andi_(R0, current_header, markWord::monitor_value); - bne(CR0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - // Set NE to indicate 'failure' -> take slow-path. - crandc(flag, Assembler::equal, flag, Assembler::equal); - b(failure); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object. - // Cmpxchg sets flag to cmpd(current_header, box). - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/box, - /*exchange_value=*/displaced_header, - /*where=*/oop, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &failure); - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - b(success); - } - - // Handle existing monitor. - bind(object_has_monitor); - STATIC_ASSERT(markWord::monitor_value <= INT_MAX); - addi(current_header, current_header, -(int)markWord::monitor_value); // monitor - - ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); - addic_(displaced_header, displaced_header, -1); - blt(CR0, not_recursive); // Not recursive if negative after decrement. - - // Recursive unlock - std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); - if (flag == CR0) { // Otherwise, flag is already EQ, here. - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Set CR0 EQ - } - b(success); - - bind(not_recursive); - - // Set owner to null. - // Release to satisfy the JMM - release(); - li(temp, 0); - std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - ld(temp, in_bytes(ObjectMonitor::entry_list_offset()), current_header); - cmpdi(flag, temp, 0); - beq(flag, success); // If so we are done. - - // Check if there is a successor. - ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header); - cmpdi(flag, temp, 0); - // Invert equal bit - crnand(flag, Assembler::equal, flag, Assembler::equal); - beq(flag, success); // If there is a successor we are done. - - // Save the monitor pointer in the current thread, so we can try - // to reacquire the lock in SharedRuntime::monitor_exit_helper(). - std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); - b(failure); // flag == NE - - // flag == EQ indicates success, decrement held monitor count if LM_LEGACY is enabled - // flag == NE indicates failure - bind(success); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(temp); - } -#ifdef ASSERT - // Check that unlocked label is reached with flag == EQ. - Label flag_correct; - beq(flag, flag_correct); - stop("compiler_fast_unlock_object: Flag != EQ"); -#endif - bind(failure); -#ifdef ASSERT - // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); - stop("compiler_fast_unlock_object: Flag != NE"); - bind(flag_correct); -#endif -} - void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box, Register tmp1, Register tmp2, Register tmp3) { assert_different_registers(obj, box, tmp1, tmp2, tmp3); @@ -4769,38 +4537,6 @@ void MacroAssembler::pop_cont_fastpath() { bind(done); } -// Note: Must preserve CR0 EQ (invariant). -void MacroAssembler::inc_held_monitor_count(Register tmp) { - assert(LockingMode == LM_LEGACY, ""); - ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -#ifdef ASSERT - Label ok; - cmpdi(CR0, tmp, 0); - bge_predict_taken(CR0, ok); - stop("held monitor count is negativ at increment"); - bind(ok); - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ -#endif - addi(tmp, tmp, 1); - std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -} - -// Note: Must preserve CR0 EQ (invariant). -void MacroAssembler::dec_held_monitor_count(Register tmp) { - assert(LockingMode == LM_LEGACY, ""); - ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -#ifdef ASSERT - Label ok; - cmpdi(CR0, tmp, 0); - bgt_predict_taken(CR0, ok); - stop("held monitor count is <= 0 at decrement"); - bind(ok); - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ -#endif - addi(tmp, tmp, -1); - std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -} - // Function to flip between unlocked and locked state (fast locking). // Branches to failed if the state is not as expected with CR0 NE. // Falls through upon success with CR0 EQ. @@ -4842,7 +4578,6 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, // - obj: the object to be locked // - t1, t2: temporary register void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(box, obj, t1, t2, R0); Label push; @@ -4899,7 +4634,6 @@ void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, R // - obj: the object to be unlocked // - t1: temporary register void MacroAssembler::lightweight_unlock(Register obj, Register t1, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, t1); #ifdef ASSERT diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 471ebb7459a..63be608094f 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -697,8 +697,6 @@ class MacroAssembler: public Assembler { void push_cont_fastpath(); void pop_cont_fastpath(); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); void atomically_flip_locked_state(bool is_unlock, Register obj, Register tmp, Label& failed, int semantics); void lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow); void lightweight_unlock(Register obj, Register t1, Label& slow); @@ -715,12 +713,6 @@ class MacroAssembler: public Assembler { enum { trampoline_stub_size = 6 * 4 }; address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); - void compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, - Register tmp1, Register tmp2, Register tmp3); - - void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, - Register tmp1, Register tmp2, Register tmp3); - void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index bf43ecaba79..cd71e298b7d 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -11573,40 +11573,8 @@ instruct partialSubtypeCheckConstSuper(rarg3RegP sub, rarg2RegP super_reg, immP // inlined locking and unlocking -instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set crx (FastLock oop box)); - effect(TEMP tmp1, TEMP tmp2); - - format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %} - ins_encode %{ - __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp1$$Register, $tmp2$$Register, /*tmp3*/ R0); - // If locking was successful, crx should indicate 'EQ'. - // The compiler generates a branch to the runtime call to - // _complete_monitor_locking_Java for the case where crx is 'NE'. - %} - ins_pipe(pipe_class_compare); -%} - -instruct cmpFastUnlock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set crx (FastUnlock oop box)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); - - format %{ "FASTUNLOCK $oop, $box, $tmp1, $tmp2" %} - ins_encode %{ - __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); - // If unlocking was successful, crx should indicate 'EQ'. - // The compiler generates a branch to the runtime call to - // _complete_monitor_unlocking_Java for the case where crx is 'NE'. - %} - ins_pipe(pipe_class_compare); -%} - instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ - predicate(LockingMode == LM_LIGHTWEIGHT && !UseObjectMonitorTable); + predicate(!UseObjectMonitorTable); match(Set crx (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2); @@ -11622,7 +11590,7 @@ instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRe %} instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{ - predicate(LockingMode == LM_LIGHTWEIGHT && UseObjectMonitorTable); + predicate(UseObjectMonitorTable); match(Set crx (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr1); @@ -11638,7 +11606,6 @@ instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iR %} instruct cmpFastUnlockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set crx (FastUnlock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 64bd8dc7812..2a9bad059ba 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2446,14 +2446,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for locking. - if (LockingMode == LM_LIGHTWEIGHT) { - // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg; - __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg); - } else { - // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - __ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } + // fast_lock kills r_temp_1, r_temp_2, r_temp_3. + Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg; + __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg); __ beq(CR0, locked); // None of the above fast optimizations worked so we have to get into the @@ -2620,7 +2615,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ stw(R0, thread_(thread_state)); // Check preemption for Object.wait() - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { Label not_preempted; __ ld(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread); __ cmpdi(CR0, R0, 0); @@ -2672,11 +2667,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for unlocking. - if (LockingMode == LM_LIGHTWEIGHT) { - __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } else { - __ compiler_fast_unlock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } + __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); __ beq(CR0, done); // Save and restore any potential method result value around the unlocking operation. @@ -2717,7 +2708,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- // Last java frame won't be set if we're resuming after preemption - bool maybe_preempted = LockingMode != LM_LEGACY && method->is_object_wait0(); + bool maybe_preempted = method->is_object_wait0(); __ reset_last_Java_frame(!maybe_preempted /* check_last_java_sp */); // Unbox oop result, e.g. JNIHandles::resolve value. diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index b5f1c76c5da..199b578a36f 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1362,7 +1362,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // convenient and the slow signature handler can use this same frame // anchor. - bool support_vthread_preemption = Continuations::enabled() && LockingMode != LM_LEGACY; + bool support_vthread_preemption = Continuations::enabled(); // We have a TOP_IJAVA_FRAME here, which belongs to us. Label last_java_pc; From 5febc4e3bb1f47f69fc28c266a775e19cbac9e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 21 Aug 2025 08:23:32 +0000 Subject: [PATCH 166/471] 8365910: [BACKOUT] Add a compilation timeout flag to catch long running compilations Reviewed-by: chagedorn, dholmes --- .../os/linux/compilerThreadTimeout_linux.cpp | 128 ------------------ .../os/linux/compilerThreadTimeout_linux.hpp | 51 ------- src/hotspot/os/linux/globals_linux.hpp | 5 - src/hotspot/share/compiler/compileBroker.cpp | 6 - src/hotspot/share/compiler/compilerThread.cpp | 2 - src/hotspot/share/compiler/compilerThread.hpp | 33 +---- .../arguments/TestCompileTaskTimeout.java | 56 -------- .../jtreg/runtime/signal/TestSigalrm.java | 4 +- 8 files changed, 3 insertions(+), 282 deletions(-) delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp delete mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp deleted file mode 100644 index 609c78616f3..00000000000 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "compiler/compilerThread.hpp" -#include "compiler/compileTask.hpp" -#include "compilerThreadTimeout_linux.hpp" -#include "oops/method.hpp" -#include "runtime/osThread.hpp" -#include "signals_posix.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -#ifdef ASSERT -void compiler_signal_handler(int signo, siginfo_t* info, void* context) { - CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context); -} - -void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) { - switch (signo) { - case TIMEOUT_SIGNAL: { - CompileTask* task = CompilerThread::current()->task(); - const int SIZE = 512; - char method_name_buf[SIZE]; - task->method()->name_and_sig_as_C_string(method_name_buf, SIZE); - assert(false, "compile task %d (%s) timed out after %zd ms", - task->compile_id(), method_name_buf, CompileTaskTimeout); - } - default: { - assert(false, "unexpected signal %d", signo); - } - } -} -#endif // ASSERT - -void CompilerThreadTimeoutLinux::arm() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return; - } - - const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC; - const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC; - const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; - const struct itimerspec its {.it_interval = ts, .it_value = ts}; - - // Start the timer. - timer_settime(_timer, 0, &its, nullptr); -#endif // ASSERT -} - -void CompilerThreadTimeoutLinux::disarm() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return; - } - - // Reset the timer by setting it to zero. - const struct itimerspec its { - .it_interval = {.tv_sec = 0, .tv_nsec=0}, - .it_value = {.tv_sec = 0, .tv_nsec=0} - }; - timer_settime(_timer, 0, &its, nullptr); -#endif // ASSERT -} - -bool CompilerThreadTimeoutLinux::init_timeout() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return true; - } - - JavaThread* thread = JavaThread::current(); - - // Create a POSIX timer sending SIGALRM to this thread only. - sigevent_t sev; - sev.sigev_value.sival_ptr = nullptr; - sev.sigev_signo = TIMEOUT_SIGNAL; - sev.sigev_notify = SIGEV_THREAD_ID; - #ifdef MUSL_LIBC - sev.sigev_notify_thread_id = thread->osthread()->thread_id(); - #else - sev._sigev_un._tid = thread->osthread()->thread_id(); - #endif // MUSL_LIBC - clockid_t clock; - int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock); - if (err != 0) { - return false; - } - err = timer_create(clock, &sev, &_timer); - if (err != 0) { - return false; - } - - // Install the signal handler and check that we do not have a conflicting handler. - struct sigaction sigact, sigact_old; - err = PosixSignals::install_sigaction_signal_handler(&sigact, - &sigact_old, - TIMEOUT_SIGNAL, - (sa_sigaction_t)::compiler_signal_handler); - if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction && - sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) { - return false; - } -#endif // ASSERT - return true; -} diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp deleted file mode 100644 index 2dc6fa7b9c9..00000000000 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP -#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP - -#include "memory/allocation.hpp" -#include "nmt/memTag.hpp" -#include "utilities/macros.hpp" - -#include -#include - -class CompilerThreadTimeoutLinux : public CHeapObj { -#ifdef ASSERT - public: - static const int TIMEOUT_SIGNAL = SIGALRM; - void compiler_signal_handler(int signo, siginfo_t* info, void* context); - private: - timer_t _timer; -#endif // ASSERT - public: - CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {}; - - bool init_timeout(); - void arm(); - void disarm(); -}; - -#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 90e1e5e5f3f..542e034f59f 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -89,11 +89,6 @@ product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \ "Print an annotated memory map at exit") \ \ - develop(intx, CompileTaskTimeout, 0, \ - "Set the timeout for compile tasks' CPU time in milliseconds."\ - " 0 = no timeout (default)") \ - range(0,1000000) \ - \ // end of RUNTIME_OS_FLAGS // diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 432b0e6a346..36663ab1088 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -218,7 +218,6 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); CompileLog* log = thread->log(); - thread->timeout()->arm(); if (log != nullptr && !task->is_unloaded()) task->log_task_start(log); } @@ -229,7 +228,6 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (log != nullptr && !task->is_unloaded()) task->log_task_done(log); thread->set_task(nullptr); thread->set_env(nullptr); - thread->timeout()->disarm(); if (task->is_blocking()) { bool free_task = false; { @@ -1927,10 +1925,6 @@ void CompileBroker::compiler_thread_loop() { log->end_elem(); } - if (!thread->init_compilation_timeout()) { - return; - } - // If compiler thread/runtime initialization fails, exit the compiler thread if (!init_compiler_runtime()) { return; diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 7cf494aad56..4034e63bc10 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -40,7 +40,6 @@ CompilerThread::CompilerThread(CompileQueue* queue, _can_call_java = false; _compiler = nullptr; _arena_stat = nullptr; - _timeout = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -50,7 +49,6 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; - delete _timeout; // arenastat should have been deleted at the end of the compilation assert(_arena_stat == nullptr, "Should be null"); } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index e4641780a12..e20e3017d1f 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,14 +25,7 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP -#include "memory/allocation.hpp" -#include "nmt/memTag.hpp" #include "runtime/javaThread.hpp" -#include "utilities/macros.hpp" - -#ifdef LINUX -#include "compilerThreadTimeout_linux.hpp" -#endif //LINUX class AbstractCompiler; class ArenaStatCounter; @@ -45,27 +38,10 @@ class CompileQueue; class CompilerCounters; class IdealGraphPrinter; -#ifndef LINUX -class CompilerThreadTimeoutGeneric : public CHeapObj { - public: - CompilerThreadTimeoutGeneric() {}; - void arm() {}; - void disarm() {}; - bool init_timeout() { return true; }; -}; -#endif // !LINUX - // A thread used for Compilation. class CompilerThread : public JavaThread { friend class VMStructs; JVMCI_ONLY(friend class CompilerThreadCanCallJava;) - -#ifdef LINUX - typedef CompilerThreadTimeoutLinux Timeout; -#else // LINUX - typedef CompilerThreadTimeoutGeneric Timeout; -#endif // LINUX - private: CompilerCounters* _counters; @@ -81,7 +57,6 @@ class CompilerThread : public JavaThread { ArenaStatCounter* _arena_stat; - Timeout* _timeout; public: static CompilerThread* current() { @@ -138,13 +113,7 @@ class CompilerThread : public JavaThread { public: IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; } void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; } -#endif // !PRODUCT - - Timeout* timeout() const { return _timeout; }; - bool init_compilation_timeout() { - _timeout = new Timeout(); - return _timeout->init_timeout(); - }; +#endif // Get/set the thread's current task CompileTask* task() { return _task; } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java deleted file mode 100644 index 42f13744cae..00000000000 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package compiler.arguments; - -/* - * @test TestCompileTaskTimeout - * @bug 8308094 - * @requires vm.debug & vm.flagless & os.name == "Linux" - * @summary Check functionality of CompileTaskTimeout - * @library /test/lib - * @run driver compiler.arguments.TestCompileTaskTimeout - */ - -import jdk.test.lib.process.ProcessTools; - -public class TestCompileTaskTimeout { - - public static void main(String[] args) throws Throwable { - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") - .shouldHaveExitValue(0) - .shouldContain("java version"); - } -} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java index 2e485a46cf9..b9a3c3e5060 100644 --- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java +++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test - * @requires os.family != "windows" & os.family != "aix" & vm.flagless + * @requires os.family != "windows" & os.family != "aix" * * @summary converted from VM testbase runtime/signal/sigalrm01. * VM testbase keywords: [signal, runtime, linux, macosx] From 5ede5b47d4291a18acc16833978ded038332cf9c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:18:58 +0000 Subject: [PATCH 167/471] 8364650: G1: Use InvalidCSetIndex instead of UINT_MAX for "invalid" sentinel value of young_index_in_cset Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 03610ab520b..86b22486517 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -245,7 +245,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index, _parsable_bottom(nullptr), _garbage_bytes(0), _incoming_refs(0), - _young_index_in_cset(-1), + _young_index_in_cset(InvalidCSetIndex), _surv_rate_group(nullptr), _age_index(G1SurvRateGroup::InvalidAgeIndex), _node_index(G1NUMA::UnknownNodeIndex), diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index 1962d3173b7..7d49633d0bc 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -496,10 +496,10 @@ public: void set_index_in_opt_cset(uint index) { _index_in_opt_cset = index; } void clear_index_in_opt_cset() { _index_in_opt_cset = InvalidCSetIndex; } - uint young_index_in_cset() const { return _young_index_in_cset; } + uint young_index_in_cset() const { return _young_index_in_cset; } void clear_young_index_in_cset() { _young_index_in_cset = 0; } void set_young_index_in_cset(uint index) { - assert(index != UINT_MAX, "just checking"); + assert(index != InvalidCSetIndex, "just checking"); assert(index != 0, "just checking"); assert(is_young(), "pre-condition"); _young_index_in_cset = index; From b735ef99b2285ec55a68896de25d29a02fdfcaf7 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:19:14 +0000 Subject: [PATCH 168/471] 8364925: G1: Improve program flow around incremental collection set building Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 43 +++++++++++++++------ src/hotspot/share/gc/g1/g1CollectionSet.hpp | 16 +++----- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 075951ab07c..747f5664b55 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -38,6 +38,15 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/quickSort.hpp" +uint G1CollectionSet::selected_groups_cur_length() const { + assert(_inc_build_state == CSetBuildType::Inactive, "must be"); + return _collection_set_groups.length(); +} + +uint G1CollectionSet::collection_groups_increment_length() const { + return selected_groups_cur_length() - _selected_groups_inc_part_start; +} + G1CollectorState* G1CollectionSet::collector_state() const { return _g1h->collector_state(); } @@ -54,7 +63,6 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _collection_set_cur_length(0), _collection_set_max_length(0), _collection_set_groups(), - _selected_groups_cur_length(0), _selected_groups_inc_part_start(0), _eden_region_length(0), _survivor_region_length(0), @@ -122,9 +130,23 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { void G1CollectionSet::start_incremental_building() { assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); + assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); + assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set."); + + continue_incremental_building(); +} + +void G1CollectionSet::continue_incremental_building() { assert(_inc_build_state == Inactive, "Precondition"); - update_incremental_marker(); + _inc_part_start = _collection_set_cur_length; + _selected_groups_inc_part_start = selected_groups_cur_length(); + + _inc_build_state = CSetBuildType::Active; +} + +void G1CollectionSet::stop_incremental_building() { + _inc_build_state = Inactive; } void G1CollectionSet::finalize_incremental_building() { @@ -343,9 +365,6 @@ static int compare_region_idx(const uint a, const uint b) { void G1CollectionSet::finalize_old_part(double time_remaining_ms) { double non_young_start_time_sec = os::elapsedTime(); - _selected_groups_cur_length = 0; - _selected_groups_inc_part_start = 0; - if (!candidates()->is_empty()) { candidates()->verify(); @@ -363,13 +382,8 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { log_debug(gc, ergo, cset)("No candidates to reclaim."); } - _selected_groups_cur_length = collection_set_groups()->length(); - stop_incremental_building(); - double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); - - QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); } static void print_finish_message(const char* reason, bool from_marking) { @@ -670,16 +684,21 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { } void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { + assert(_inc_part_start == 0, "must be"); + assert(_selected_groups_inc_part_start == 0, "must be"); + double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); finalize_old_part(time_remaining_ms); + + stop_incremental_building(); + QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); } bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) { - update_incremental_marker(); + continue_incremental_building(); uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time); - _selected_groups_cur_length = collection_set_groups()->length(); stop_incremental_building(); _g1h->verify_region_attr_remset_is_tracked(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index c703e13a056..963b43d2432 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -149,9 +149,7 @@ class G1CollectionSet { // Old gen groups selected for evacuation. G1CSetCandidateGroupList _collection_set_groups; - // Groups are added to the collection set in increments when performing optional evacuations. - // We use the value below to track these increments. - uint _selected_groups_cur_length; + uint selected_groups_cur_length() const; uint _selected_groups_inc_part_start; uint _eden_region_length; @@ -258,14 +256,10 @@ public: // Initialize incremental collection set info. void start_incremental_building(); - // Start a new collection set increment. - void update_incremental_marker() { - _inc_build_state = Active; - _inc_part_start = _collection_set_cur_length; - _selected_groups_inc_part_start = _selected_groups_cur_length; - } + // Start a new collection set increment, continuing the incremental building. + void continue_incremental_building(); // Stop adding regions to the current collection set increment. - void stop_incremental_building() { _inc_build_state = Inactive; } + void stop_incremental_building(); // Iterate over the current collection set increment applying the given G1HeapRegionClosure // from a starting position determined by the given worker id. @@ -276,7 +270,7 @@ public: // Returns the length of the whole current collection set in number of regions size_t cur_length() const { return _collection_set_cur_length; } - uint collection_groups_increment_length() const { return _selected_groups_cur_length - _selected_groups_inc_part_start; } + uint collection_groups_increment_length() const; // Iterate over the entire collection set (all increments calculated so far), applying // the given G1HeapRegionClosure on all of them. From 9439d7630901d3e29141adf46bbe9284b86683f4 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:35:57 +0000 Subject: [PATCH 169/471] 8364532: G1: In liveness tracing, print more significant digits for the liveness value Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp | 5 ++--- src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 6c13c015eff..63b1d29f535 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -63,10 +63,9 @@ void G1CSetCandidateGroup::calculate_efficiency() { _gc_efficiency = _reclaimable_bytes / predict_group_total_time_ms(); } -size_t G1CSetCandidateGroup::liveness() const { +double G1CSetCandidateGroup::liveness_percent() const { size_t capacity = length() * G1HeapRegion::GrainBytes; - - return (size_t) ceil(((capacity - _reclaimable_bytes) * 100.0) / capacity); + return ((capacity - _reclaimable_bytes) * 100.0) / capacity; } void G1CSetCandidateGroup::clear(bool uninstall_group_cardset) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 73421d40ee9..d45fe07cd6e 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -102,7 +102,7 @@ public: void calculate_efficiency(); - size_t liveness() const; + double liveness_percent() const; // Comparison function to order regions in decreasing GC efficiency order. This // will cause regions with a lot of live objects and large remembered sets to end // up at the end of the list. diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index c5b8c89e2f0..210d78098b3 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2981,6 +2981,7 @@ G1CMTask::G1CMTask(uint worker_id, #define G1PPRL_LEN_FORMAT " " UINT32_FORMAT_W(14) #define G1PPRL_LEN_H_FORMAT " %14s" #define G1PPRL_GID_GCEFF_FORMAT " %14.1f" +#define G1PPRL_GID_LIVENESS_FORMAT " %9.2f" // For summary info #define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT @@ -3114,13 +3115,13 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSet G1PPRL_GID_FORMAT G1PPRL_LEN_FORMAT G1PPRL_GID_GCEFF_FORMAT - G1PPRL_BYTE_FORMAT + G1PPRL_GID_LIVENESS_FORMAT G1PPRL_BYTE_FORMAT G1PPRL_TYPE_H_FORMAT, group->group_id(), group->length(), group->gc_efficiency(), - group->liveness(), + group->liveness_percent(), group->card_set()->mem_size(), type); _total_remset_bytes += group->card_set()->mem_size(); From f0e706698df5ac199198b252d77d27a05abad1da Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:36:16 +0000 Subject: [PATCH 170/471] 8364414: G1: Use simpler data structure for holding collection set candidates during calculation Reviewed-by: ayang, iwalulya --- .../share/gc/g1/g1CollectionSetCandidates.cpp | 52 ++++------------ .../share/gc/g1/g1CollectionSetCandidates.hpp | 9 +-- .../share/gc/g1/g1CollectionSetChooser.cpp | 60 +++++++++++++------ .../share/gc/g1/g1CollectionSetChooser.hpp | 2 +- 4 files changed, 57 insertions(+), 66 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 63b1d29f535..2118bf997a7 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -44,12 +44,7 @@ G1CSetCandidateGroup::G1CSetCandidateGroup() : void G1CSetCandidateGroup::add(G1HeapRegion* hr) { G1CollectionSetCandidateInfo c(hr); - add(c); -} - -void G1CSetCandidateGroup::add(G1CollectionSetCandidateInfo& hr_info) { - G1HeapRegion* hr = hr_info._r; - _candidates.append(hr_info); + _candidates.append(c); hr->install_cset_group(this); } @@ -133,31 +128,6 @@ int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CS } } -int G1CollectionSetCandidateInfo::compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) { - // Make sure that null entries are moved to the end. - if (ci1->_r == nullptr) { - if (ci2->_r == nullptr) { - return 0; - } else { - return 1; - } - } else if (ci2->_r == nullptr) { - return -1; - } - - G1Policy* p = G1CollectedHeap::heap()->policy(); - double gc_efficiency1 = p->predict_gc_efficiency(ci1->_r); - double gc_efficiency2 = p->predict_gc_efficiency(ci2->_r); - - if (gc_efficiency1 > gc_efficiency2) { - return -1; - } else if (gc_efficiency1 < gc_efficiency2) { - return 1; - } else { - return 0; - } -} - G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { } void G1CSetCandidateGroupList::append(G1CSetCandidateGroup* group) { @@ -279,9 +249,9 @@ void G1CollectionSetCandidates::sort_marking_by_efficiency() { _from_marking_groups.verify(); } -void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos, - uint num_infos) { - if (num_infos == 0) { +void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candidates, + uint num_candidates) { + if (num_candidates == 0) { log_debug(gc, ergo, cset) ("No regions selected from marking."); return; } @@ -294,7 +264,7 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi // the G1MixedGCCountTarget. For the first collection in a Mixed GC cycle, we can add all regions // required to meet this threshold to the same remset group. We are certain these will be collected in // the same MixedGC. - uint group_limit = p->calc_min_old_cset_length(num_infos); + uint group_limit = p->calc_min_old_cset_length(num_candidates); uint num_added_to_group = 0; @@ -303,8 +273,8 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi current = new G1CSetCandidateGroup(); - for (uint i = 0; i < num_infos; i++) { - G1HeapRegion* r = candidate_infos[i]._r; + for (uint i = 0; i < num_candidates; i++) { + G1HeapRegion* r = candidates[i]; assert(!contains(r), "must not contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Marking; @@ -318,16 +288,16 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi current = new G1CSetCandidateGroup(); num_added_to_group = 0; } - current->add(candidate_infos[i]); + current->add(r); num_added_to_group++; } _from_marking_groups.append(current); - assert(_from_marking_groups.num_regions() == num_infos, "Must be!"); + assert(_from_marking_groups.num_regions() == num_candidates, "Must be!"); - log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_infos); - _last_marking_candidates_length = num_infos; + log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_candidates); + _last_marking_candidates_length = num_candidates; verify(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index d45fe07cd6e..02a4d5f6d76 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -48,8 +48,6 @@ struct G1CollectionSetCandidateInfo { ++_num_unreclaimed; return _num_unreclaimed < G1NumCollectionsKeepPinned; } - - static int compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2); }; using G1CSetCandidateGroupIterator = GrowableArrayIterator; @@ -91,7 +89,6 @@ public: } void add(G1HeapRegion* hr); - void add(G1CollectionSetCandidateInfo& hr_info); uint length() const { return (uint)_candidates.length(); } @@ -235,10 +232,10 @@ public: void clear(); - // Merge collection set candidates from marking into the current marking list + // Merge collection set candidates from marking into the current marking candidates // (which needs to be empty). - void set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos, - uint num_infos); + void set_candidates_from_marking(G1HeapRegion** candidates, + uint num_candidates); // The most recent length of the list that had been merged last via // set_candidates_from_marking(). Used for calculating minimum collection set // regions. diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index 20d6b125b4d..aa4bd3f1e5b 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -31,15 +31,13 @@ #include "utilities/quickSort.hpp" // Determine collection set candidates (from marking): For all regions determine -// whether they should be a collection set candidate, calculate their efficiency, -// sort and put them into the candidates. +// whether they should be a collection set candidate. Calculate their efficiency, +// sort, and put them into the collection set candidates. +// // Threads calculate the GC efficiency of the regions they get to process, and // put them into some work area without sorting. At the end that array is sorted and // moved to the destination. class G1BuildCandidateRegionsTask : public WorkerTask { - - using CandidateInfo = G1CollectionSetCandidateInfo; - // Work area for building the set of collection set candidates. Contains references // to heap regions with their GC efficiencies calculated. To reduce contention // on claiming array elements, worker threads claim parts of this array in chunks; @@ -47,14 +45,40 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // up their chunks completely. // Final sorting will remove them. class G1BuildCandidateArray : public StackObj { - uint const _max_size; uint const _chunk_size; - CandidateInfo* _data; + G1HeapRegion** _data; uint volatile _cur_claim_idx; + static int compare_region_gc_efficiency(G1HeapRegion** rr1, G1HeapRegion** rr2) { + G1HeapRegion* r1 = *rr1; + G1HeapRegion* r2 = *rr2; + // Make sure that null entries are moved to the end. + if (r1 == nullptr) { + if (r2 == nullptr) { + return 0; + } else { + return 1; + } + } else if (r2 == nullptr) { + return -1; + } + + G1Policy* p = G1CollectedHeap::heap()->policy(); + double gc_efficiency1 = p->predict_gc_efficiency(r1); + double gc_efficiency2 = p->predict_gc_efficiency(r2); + + if (gc_efficiency1 > gc_efficiency2) { + return -1; + } else if (gc_efficiency1 < gc_efficiency2) { + return 1; + } else { + return 0; + } + } + // Calculates the maximum array size that will be used. static uint required_array_size(uint num_regions, uint chunk_size, uint num_workers) { uint const max_waste = num_workers * chunk_size; @@ -68,15 +92,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask { G1BuildCandidateArray(uint max_num_regions, uint chunk_size, uint num_workers) : _max_size(required_array_size(max_num_regions, chunk_size, num_workers)), _chunk_size(chunk_size), - _data(NEW_C_HEAP_ARRAY(CandidateInfo, _max_size, mtGC)), + _data(NEW_C_HEAP_ARRAY(G1HeapRegion*, _max_size, mtGC)), _cur_claim_idx(0) { for (uint i = 0; i < _max_size; i++) { - _data[i] = CandidateInfo(); + _data[i] = nullptr; } } ~G1BuildCandidateArray() { - FREE_C_HEAP_ARRAY(CandidateInfo, _data); + FREE_C_HEAP_ARRAY(G1HeapRegion*, _data); } // Claim a new chunk, returning its bounds [from, to[. @@ -92,8 +116,8 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // Set element in array. void set(uint idx, G1HeapRegion* hr) { assert(idx < _max_size, "Index %u out of bounds %u", idx, _max_size); - assert(_data[idx]._r == nullptr, "Value must not have been set."); - _data[idx] = CandidateInfo(hr); + assert(_data[idx] == nullptr, "Value must not have been set."); + _data[idx] = hr; } void sort_by_gc_efficiency() { @@ -101,15 +125,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask { return; } for (uint i = _cur_claim_idx; i < _max_size; i++) { - assert(_data[i]._r == nullptr, "must be"); + assert(_data[i] == nullptr, "must be"); } - qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)G1CollectionSetCandidateInfo::compare_region_gc_efficiency); + qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)compare_region_gc_efficiency); for (uint i = _cur_claim_idx; i < _max_size; i++) { - assert(_data[i]._r == nullptr, "must be"); + assert(_data[i] == nullptr, "must be"); } } - CandidateInfo* array() const { return _data; } + G1HeapRegion** array() const { return _data; } }; // Per-region closure. In addition to determining whether a region should be @@ -193,7 +217,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // available (for forward progress in evacuation) or the waste accumulated by the // removed regions is above the maximum allowed waste. // Updates number of candidates and reclaimable bytes given. - void prune(CandidateInfo* data) { + void prune(G1HeapRegion** data) { G1Policy* p = G1CollectedHeap::heap()->policy(); uint num_candidates = Atomic::load(&_num_regions_added); @@ -211,7 +235,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { uint max_to_prune = num_candidates - min_old_cset_length; while (true) { - G1HeapRegion* r = data[num_candidates - num_pruned - 1]._r; + G1HeapRegion* r = data[num_candidates - num_pruned - 1]; size_t const reclaimable = r->reclaimable_bytes(); if (num_pruned >= max_to_prune || wasted_bytes + reclaimable > allowed_waste) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp index 691017b9d87..cb9727b3413 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp @@ -38,11 +38,11 @@ class WorkerThreads; class G1CollectionSetChooser : public AllStatic { static uint calculate_work_chunk_size(uint num_workers, uint num_regions); -public: static size_t mixed_gc_live_threshold_bytes() { return G1HeapRegion::GrainBytes * (size_t)G1MixedGCLiveThresholdPercent / 100; } +public: static bool region_occupancy_low_enough_for_evac(size_t live_bytes) { return live_bytes < mixed_gc_live_threshold_bytes(); } From ed260e8cae329a0c077e91ff76d104ee197fb7fd Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:37:34 +0000 Subject: [PATCH 171/471] 8365026: G1: Initialization should start a "full" new collection set Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 ++ src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 ++- src/hotspot/share/gc/g1/g1Policy.cpp | 4 ---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e964ecefb18..ed08d43bbbe 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1487,6 +1487,8 @@ jint G1CollectedHeap::initialize() { _collection_set.initialize(max_num_regions()); + start_new_collection_set(); + allocation_failure_injector()->reset(); CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 210d78098b3..237704c12a8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1962,7 +1962,8 @@ public: }; void G1ConcurrentMark::verify_no_collection_set_oops() { - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || !is_init_completed(), + "should be at a safepoint or initializing"); if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) { return; } diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index bb54d344ca0..53f0a7bf7a6 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -97,10 +97,6 @@ void G1Policy::init(G1CollectedHeap* g1h, G1CollectionSet* collection_set) { _free_regions_at_end_of_collection = _g1h->num_free_regions(); update_young_length_bounds(); - - // We immediately start allocating regions placing them in the collection set. - // Initialize the collection set info. - _collection_set->start_incremental_building(); } void G1Policy::record_young_gc_pause_start() { From f61b247fe3a818fc60a61c6f42a676ad94e8e976 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:44:41 +0000 Subject: [PATCH 172/471] 8364962: G1: Inline G1CollectionSet::finalize_incremental_building Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 10 +++------- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 3 --- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 747f5664b55..90189cfdf8a 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -149,11 +149,6 @@ void G1CollectionSet::stop_incremental_building() { _inc_build_state = Inactive; } -void G1CollectionSet::finalize_incremental_building() { - assert(_inc_build_state == Active, "Precondition"); - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); -} - void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); _collection_set_cur_length = 0; @@ -306,9 +301,10 @@ void G1CollectionSet::print(outputStream* st) { // pinned by JNI) to allow faster future evacuation. We already "paid" for this work // when sizing the young generation. double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) { - Ticks start_time = Ticks::now(); + assert(_inc_build_state == Active, "Precondition"); + assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); - finalize_incremental_building(); + Ticks start_time = Ticks::now(); guarantee(target_pause_time_ms > 0.0, "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index 963b43d2432..e12f3a82d12 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -198,9 +198,6 @@ class G1CollectionSet { // as Eden and calculate a prediction on how long the evacuation of all young regions // will take. double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); - // Perform any final calculations on the incremental collection set fields before we - // can use them. - void finalize_incremental_building(); // Select the regions comprising the initial and optional collection set from marking // and retained collection set candidates. From a3fd4248b74ed800ff124cc3e7c259dca36ea446 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:46:02 +0000 Subject: [PATCH 173/471] 8365115: G1: Refactor rem set statistics gather code for group Reviewed-by: kbarrett, ayang --- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 55 ++++++++++----------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index ec876d020ec..cf032bc5d17 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -268,44 +268,39 @@ public: return false; } - void do_cset_groups() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1CSetCandidateGroup* young_only_cset_group = g1h->young_regions_cset_group(); - + void accumulate_stats_for_group(G1CSetCandidateGroup* group, G1PerRegionTypeRemSetCounters* gen_counter) { // If the group has only a single region, then stats were accumulated - // during region iteration. - if (young_only_cset_group->length() > 1) { - G1CardSet* young_only_card_set = young_only_cset_group->card_set(); - size_t rs_mem_sz = young_only_card_set->mem_size(); - size_t rs_unused_mem_sz = young_only_card_set->unused_mem_size(); - size_t occupied_cards = young_only_card_set->occupied(); + // during region iteration. Skip these. + if (group->length() > 1) { + G1CardSet* card_set = group->card_set(); - _max_group_cardset_mem_sz = rs_mem_sz; - _max_cardset_mem_sz_group = young_only_cset_group; + size_t rs_mem_sz = card_set->mem_size(); + size_t rs_unused_mem_sz = card_set->unused_mem_size(); + size_t occupied_cards = card_set->occupied(); - // Only update cardset details - _young.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); + if (rs_mem_sz > _max_group_cardset_mem_sz) { + _max_group_cardset_mem_sz = rs_mem_sz; + _max_cardset_mem_sz_group = group; + } + + gen_counter->add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); _all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); } + } + void do_cset_groups() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1PerRegionTypeRemSetCounters* current = &_old; - for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) { - if (group->length() > 1) { - G1CardSet* group_card_set = group->card_set(); - size_t rs_mem_sz = group_card_set->mem_size(); - size_t rs_unused_mem_sz = group_card_set->unused_mem_size(); - size_t occupied_cards = group_card_set->occupied(); + accumulate_stats_for_group(g1h->young_regions_cset_group(), &_young); - if (rs_mem_sz > _max_group_cardset_mem_sz) { - _max_group_cardset_mem_sz = rs_mem_sz; - _max_cardset_mem_sz_group = group; - } - - // Only update cardset details - _old.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); - _all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); - } + G1CollectionSetCandidates* candidates = g1h->policy()->candidates(); + for (G1CSetCandidateGroup* group : candidates->from_marking_groups()) { + accumulate_stats_for_group(group, &_old); + } + // Skip gathering statistics for retained regions. Just verify that they have + // the expected amount of regions. + for (G1CSetCandidateGroup* group : candidates->retained_groups()) { + assert(group->length() == 1, "must be"); } } From 02fe095d29994bec28c85beb6bf2a69b0f49b206 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 11:53:57 +0000 Subject: [PATCH 174/471] 8364934: G1: Rename members of G1CollectionSet Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 101 +++++++++--------- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 88 ++++++++------- .../share/gc/g1/g1CollectionSet.inline.hpp | 6 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 2 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- 7 files changed, 107 insertions(+), 96 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index ed08d43bbbe..e50821e96c1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3159,5 +3159,5 @@ void G1CollectedHeap::finish_codecache_marking_cycle() { void G1CollectedHeap::prepare_group_cardsets_for_scan() { young_regions_cardset()->reset_table_scanner_for_groups(); - collection_set()->prepare_groups_for_scan(); + collection_set()->prepare_for_scan(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 90189cfdf8a..804ded144bd 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -38,13 +38,13 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/quickSort.hpp" -uint G1CollectionSet::selected_groups_cur_length() const { +uint G1CollectionSet::groups_cur_length() const { assert(_inc_build_state == CSetBuildType::Inactive, "must be"); - return _collection_set_groups.length(); + return _groups.length(); } -uint G1CollectionSet::collection_groups_increment_length() const { - return selected_groups_cur_length() - _selected_groups_inc_part_start; +uint G1CollectionSet::groups_increment_length() const { + return groups_cur_length() - _groups_inc_part_start; } G1CollectorState* G1CollectionSet::collector_state() const { @@ -59,21 +59,21 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _g1h(g1h), _policy(policy), _candidates(), - _collection_set_regions(nullptr), - _collection_set_cur_length(0), - _collection_set_max_length(0), - _collection_set_groups(), - _selected_groups_inc_part_start(0), + _regions(nullptr), + _regions_max_length(0), + _regions_cur_length(0), + _groups(), _eden_region_length(0), _survivor_region_length(0), _initial_old_region_length(0), _optional_groups(), - _inc_build_state(Inactive), - _inc_part_start(0) { + _inc_build_state(CSetBuildType::Inactive), + _regions_inc_part_start(0), + _groups_inc_part_start(0) { } G1CollectionSet::~G1CollectionSet() { - FREE_C_HEAP_ARRAY(uint, _collection_set_regions); + FREE_C_HEAP_ARRAY(uint, _regions); abandon_all_candidates(); } @@ -84,8 +84,8 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, _eden_region_length = eden_cset_region_length; _survivor_region_length = survivor_cset_region_length; - assert((size_t)young_region_length() == _collection_set_cur_length, - "Young region length %u should match collection set length %u", young_region_length(), _collection_set_cur_length); + assert((size_t)young_region_length() == _regions_cur_length, + "Young region length %u should match collection set length %u", young_region_length(), _regions_cur_length); _initial_old_region_length = 0; assert(_optional_groups.length() == 0, "Should not have any optional groups yet"); @@ -93,9 +93,9 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, } void G1CollectionSet::initialize(uint max_region_length) { - guarantee(_collection_set_regions == nullptr, "Must only initialize once."); - _collection_set_max_length = max_region_length; - _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC); + guarantee(_regions == nullptr, "Must only initialize once."); + _regions_max_length = max_region_length; + _regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC); _candidates.initialize(max_region_length); } @@ -105,14 +105,14 @@ void G1CollectionSet::abandon_all_candidates() { _initial_old_region_length = 0; } -void G1CollectionSet::prepare_groups_for_scan () { - collection_set_groups()->prepare_for_scan(); +void G1CollectionSet::prepare_for_scan () { + groups()->prepare_for_scan(); } void G1CollectionSet::add_old_region(G1HeapRegion* hr) { assert_at_safepoint_on_vm_thread(); - assert(_inc_build_state == Active, + assert(_inc_build_state == CSetBuildType::Active, "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); @@ -121,46 +121,46 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { assert(!hr->in_collection_set(), "should not already be in the collection set"); _g1h->register_old_region_with_region_attr(hr); - assert(_collection_set_cur_length < _collection_set_max_length, "Collection set now larger than maximum size."); - _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index(); + assert(_regions_cur_length < _regions_max_length, "Collection set now larger than maximum size."); + _regions[_regions_cur_length++] = hr->hrm_index(); _initial_old_region_length++; _g1h->old_set_remove(hr); } void G1CollectionSet::start_incremental_building() { - assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); - assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); + assert(_regions_cur_length == 0, "Collection set must be empty before starting a new collection set."); + assert(groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set."); continue_incremental_building(); } void G1CollectionSet::continue_incremental_building() { - assert(_inc_build_state == Inactive, "Precondition"); + assert(_inc_build_state == CSetBuildType::Inactive, "Precondition"); - _inc_part_start = _collection_set_cur_length; - _selected_groups_inc_part_start = selected_groups_cur_length(); + _regions_inc_part_start = _regions_cur_length; + _groups_inc_part_start = groups_cur_length(); _inc_build_state = CSetBuildType::Active; } void G1CollectionSet::stop_incremental_building() { - _inc_build_state = Inactive; + _inc_build_state = CSetBuildType::Inactive; } void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); - _collection_set_cur_length = 0; - _collection_set_groups.clear(); + _regions_cur_length = 0; + _groups.clear(); } void G1CollectionSet::iterate(G1HeapRegionClosure* cl) const { - size_t len = _collection_set_cur_length; + size_t len = _regions_cur_length; OrderAccess::loadload(); for (uint i = 0; i < len; i++) { - G1HeapRegion* r = _g1h->region_at(_collection_set_regions[i]); + G1HeapRegion* r = _g1h->region_at(_regions[i]); bool result = cl->do_heap_region(r); if (result) { cl->set_incomplete(); @@ -187,7 +187,7 @@ void G1CollectionSet::iterate_optional(G1HeapRegionClosure* cl) const { void G1CollectionSet::iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const { - iterate_part_from(cl, hr_claimer, _inc_part_start, increment_length(), worker_id); + iterate_part_from(cl, hr_claimer, _regions_inc_part_start, regions_cur_length(), worker_id); } void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl, @@ -197,29 +197,29 @@ void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl, uint worker_id) const { _g1h->par_iterate_regions_array(cl, hr_claimer, - &_collection_set_regions[offset], + &_regions[offset], length, worker_id); } void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) { assert(hr->is_young(), "invariant"); - assert(_inc_build_state == Active, "Precondition"); + assert(_inc_build_state == CSetBuildType::Active, "Precondition"); assert(!hr->in_collection_set(), "invariant"); _g1h->register_young_region_with_region_attr(hr); // We use UINT_MAX as "invalid" marker in verification. - assert(_collection_set_cur_length < (UINT_MAX - 1), - "Collection set is too large with %u entries", _collection_set_cur_length); - hr->set_young_index_in_cset(_collection_set_cur_length + 1); + assert(_regions_cur_length < (UINT_MAX - 1), + "Collection set is too large with %u entries", _regions_cur_length); + hr->set_young_index_in_cset(_regions_cur_length + 1); - assert(_collection_set_cur_length < _collection_set_max_length, "Collection set larger than maximum allowed."); - _collection_set_regions[_collection_set_cur_length] = hr->hrm_index(); + assert(_regions_cur_length < _regions_max_length, "Collection set larger than maximum allowed."); + _regions[_regions_cur_length] = hr->hrm_index(); // Concurrent readers must observe the store of the value in the array before an // update to the length field. OrderAccess::storestore(); - _collection_set_cur_length++; + _regions_cur_length++; } void G1CollectionSet::add_survivor_regions(G1HeapRegion* hr) { @@ -301,7 +301,7 @@ void G1CollectionSet::print(outputStream* st) { // pinned by JNI) to allow faster future evacuation. We already "paid" for this work // when sizing the young generation. double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) { - assert(_inc_build_state == Active, "Precondition"); + assert(_inc_build_state == CSetBuildType::Active, "Precondition"); assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); Ticks start_time = Ticks::now(); @@ -626,7 +626,8 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai selected.append(group); } - log_debug(gc, ergo, cset) ("Completed with groups, selected %u", num_regions_selected); + log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups", + num_regions_selected, num_groups_selected); // Remove selected groups from candidate list. if (num_groups_selected > 0) { _optional_groups.remove(&selected); @@ -635,7 +636,7 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai return total_prediction_ms; } -uint G1CollectionSet::select_optional_collection_set_regions(double time_remaining_ms) { +uint G1CollectionSet::select_optional_groups(double time_remaining_ms) { uint optional_regions_count = num_optional_regions(); assert(optional_regions_count > 0, "Should only be called when there are optional regions"); @@ -670,7 +671,7 @@ void G1CollectionSet::add_group_to_collection_set(G1CSetCandidateGroup* gr) { assert(r->rem_set()->is_complete(), "must be"); add_region_to_collection_set(r); } - _collection_set_groups.append(gr); + _groups.append(gr); } void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { @@ -680,20 +681,20 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { } void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { - assert(_inc_part_start == 0, "must be"); - assert(_selected_groups_inc_part_start == 0, "must be"); + assert(_regions_inc_part_start == 0, "must be"); + assert(_groups_inc_part_start == 0, "must be"); double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); finalize_old_part(time_remaining_ms); stop_incremental_building(); - QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); + QuickSort::sort(_regions, _regions_cur_length, compare_region_idx); } bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) { continue_incremental_building(); - uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time); + uint num_regions_selected = select_optional_groups(remaining_pause_time); stop_incremental_building(); @@ -756,7 +757,7 @@ public: void G1CollectionSet::verify_young_cset_indices() const { assert_at_safepoint_on_vm_thread(); - G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length); + G1VerifyYoungCSetIndicesClosure cl(_regions_cur_length); iterate(&cl); } #endif diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e12f3a82d12..2bde960fbc4 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -41,19 +41,19 @@ class G1HeapRegionClosure; // The collection set. // -// The set of regions that are evacuated during an evacuation pause. +// The set of regions and candidate groups that were evacuated during an +// evacuation pause. // -// At the end of a collection, before freeing the collection set, this set -// contains all regions that were evacuated during this collection: +// At the end of a collection, before freeing it, this set contains all regions +// and collection set groups that were evacuated during this collection: // // - survivor regions from the last collection (if any) // - eden regions allocated by the mutator // - old gen regions evacuated during mixed gc // -// This set is built incrementally at mutator time as regions are retired, and -// if this had been a mixed gc, some additional (during gc) incrementally added -// old regions from the collection set candidates built during the concurrent -// cycle. +// This set is initially built at mutator time as regions are retired. If the +// collection is a mixed gc, it contains some additional (during the pause) +// incrementally added old regions from the collection set candidates. // // A more detailed overview of how the collection set changes over time follows: // @@ -129,6 +129,7 @@ class G1HeapRegionClosure; // || ... after step b6) // |SSS| ... after step 7), with three survivor regions // +// Candidate groups are kept in sync with the contents of the collection set regions. class G1CollectionSet { G1CollectedHeap* _g1h; G1Policy* _policy; @@ -137,46 +138,52 @@ class G1CollectionSet { G1CollectionSetCandidates _candidates; // The actual collection set as a set of region indices. - // All entries in _collection_set_regions below _collection_set_cur_length are - // assumed to be part of the collection set. + // + // All regions in _regions below _regions_cur_length are assumed to be part of the + // collection set. // We assume that at any time there is at most only one writer and (one or more) - // concurrent readers. This means we are good with using storestore and loadload - // barriers on the writer and reader respectively only. - uint* _collection_set_regions; - volatile uint _collection_set_cur_length; - uint _collection_set_max_length; + // concurrent readers. This means synchronization using storestore and loadload + // barriers on the writer and reader respectively only are sufficient. + // + // This corresponds to the regions referenced by the candidate groups further below. + uint* _regions; + uint _regions_max_length; + + volatile uint _regions_cur_length; // Old gen groups selected for evacuation. - G1CSetCandidateGroupList _collection_set_groups; + G1CSetCandidateGroupList _groups; - uint selected_groups_cur_length() const; - uint _selected_groups_inc_part_start; + uint groups_cur_length() const; uint _eden_region_length; uint _survivor_region_length; uint _initial_old_region_length; // When doing mixed collections we can add old regions to the collection set, which - // will be collected only if there is enough time. We call these optional (old) regions. + // will be collected only if there is enough time. We call these optional (old) + // groups. Regions are reachable via this list as well. G1CSetCandidateGroupList _optional_groups; - enum CSetBuildType { + enum class CSetBuildType { Active, // We are actively building the collection set Inactive // We are not actively building the collection set }; CSetBuildType _inc_build_state; - size_t _inc_part_start; + // Index into the _regions indicating the start of the current collection set increment. + size_t _regions_inc_part_start; + // Index into the _groups indicating the start of the current collection set increment. + uint _groups_inc_part_start; G1CollectorState* collector_state() const; G1GCPhaseTimes* phase_times(); void verify_young_cset_indices() const NOT_DEBUG_RETURN; - // Update the incremental collection set information when adding a region. void add_young_region_common(G1HeapRegion* hr); - // Add the given old region to the head of the current collection set. + // Add the given old region to the current collection set. void add_old_region(G1HeapRegion* hr); void prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index); @@ -189,14 +196,14 @@ class G1CollectionSet { void select_candidates_from_retained(double time_remaining_ms); - // Select regions for evacuation from the optional candidates given the remaining time - // and return the number of actually selected regions. - uint select_optional_collection_set_regions(double time_remaining_ms); - double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_regions_selected); + // Select groups for evacuation from the optional candidates given the remaining time + // and return the number of actually selected regions. + uint select_optional_groups(double time_remaining_ms); + double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_groups_selected); // Finalize the young part of the initial collection set. Relabel survivor regions // as Eden and calculate a prediction on how long the evacuation of all young regions - // will take. + // will take. Returns the time remaining from the given target pause time. double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); // Select the regions comprising the initial and optional collection set from marking @@ -218,27 +225,29 @@ public: // Initializes the collection set giving the maximum possible length of the collection set. void initialize(uint max_region_length); + // Drop all collection set candidates (only the candidates). void abandon_all_candidates(); G1CollectionSetCandidates* candidates() { return &_candidates; } const G1CollectionSetCandidates* candidates() const { return &_candidates; } - G1CSetCandidateGroupList* collection_set_groups() { return &_collection_set_groups; } - const G1CSetCandidateGroupList* collection_set_groups() const { return &_collection_set_groups; } + G1CSetCandidateGroupList* groups() { return &_groups; } + const G1CSetCandidateGroupList* groups() const { return &_groups; } - void prepare_groups_for_scan(); + void prepare_for_scan(); void init_region_lengths(uint eden_cset_region_length, uint survivor_cset_region_length); - uint region_length() const { return young_region_length() + - initial_old_region_length(); } + // Total length of the initial collection set in regions. + uint initial_region_length() const { return young_region_length() + + initial_old_region_length(); } uint young_region_length() const { return eden_region_length() + survivor_region_length(); } - uint eden_region_length() const { return _eden_region_length; } + uint eden_region_length() const { return _eden_region_length; } uint survivor_region_length() const { return _survivor_region_length; } - uint initial_old_region_length() const { return _initial_old_region_length; } + uint initial_old_region_length() const { return _initial_old_region_length; } uint num_optional_regions() const { return _optional_groups.num_regions(); } bool only_contains_young_regions() const { return (initial_old_region_length() + num_optional_regions()) == 0; } @@ -263,14 +272,14 @@ public: void iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const; // Returns the length of the current increment in number of regions. - size_t increment_length() const { return _collection_set_cur_length - _inc_part_start; } + size_t regions_cur_length() const { return _regions_cur_length - _regions_inc_part_start; } // Returns the length of the whole current collection set in number of regions - size_t cur_length() const { return _collection_set_cur_length; } + size_t cur_length() const { return _regions_cur_length; } - uint collection_groups_increment_length() const; + uint groups_increment_length() const; // Iterate over the entire collection set (all increments calculated so far), applying - // the given G1HeapRegionClosure on all of them. + // the given G1HeapRegionClosure on all of the regions. void iterate(G1HeapRegionClosure* cl) const; void par_iterate(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, @@ -278,10 +287,11 @@ public: void iterate_optional(G1HeapRegionClosure* cl) const; - // Finalize the initial collection set consisting of all young regions potentially a + // Finalize the initial collection set consisting of all young regions and potentially a // few old gen regions. void finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor); // Finalize the next collection set from the set of available optional old gen regions. + // Returns whether there still were some optional regions. bool finalize_optional_for_evacuation(double remaining_pause_time); // Abandon (clean up) optional collection set regions that were not evacuated in this // pause. diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp index 717f6860eb6..0f166cdf9ff 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp @@ -31,8 +31,8 @@ template inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) { - uint length = collection_groups_increment_length(); - uint offset = _selected_groups_inc_part_start; + uint length = groups_increment_length(); + uint offset = _groups_inc_part_start; if (length == 0) { return; } @@ -41,7 +41,7 @@ inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVis uint cur_pos = start_pos; uint count = 0; do { - G1HeapRegionRemSet::iterate_for_merge(collection_set_groups()->at(offset + cur_pos)->card_set(), cl); + G1HeapRegionRemSet::iterate_for_merge(groups()->at(offset + cur_pos)->card_set(), cl); cur_pos++; count++; if (cur_pos == length) { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 44b3234d26b..6b7532a99aa 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1426,7 +1426,7 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { } WorkerThreads* workers = g1h->workers(); - size_t const increment_length = g1h->collection_set()->increment_length(); + size_t const increment_length = g1h->collection_set()->regions_cur_length(); uint const num_workers = initial_evacuation ? workers->active_workers() : MIN2(workers->active_workers(), (uint)increment_length); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index c61c766bbdc..29eab44d4a8 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -271,7 +271,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou allocator()->release_mutator_alloc_regions(); collection_set()->finalize_initial_collection_set(target_pause_time_ms, survivor_regions()); - evacuation_info->set_collection_set_regions(collection_set()->region_length() + + evacuation_info->set_collection_set_regions(collection_set()->initial_region_length() + collection_set()->num_optional_regions()); concurrent_mark()->verify_no_collection_set_oops(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index bb567e2af5c..b13e7b8a62f 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -887,7 +887,7 @@ public: p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0); } - double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); } + double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->initial_region_length(); } void set_max_workers(uint max_workers) override { _active_workers = max_workers; From 1548ac4f54edbd370aa071fa1db4474574d2987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Thu, 21 Aug 2025 14:00:18 +0000 Subject: [PATCH 175/471] 8365378: Redundant code in Deoptimization::print_statistics Reviewed-by: jsjolen, coleenp --- src/hotspot/share/runtime/deoptimization.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 243903ed233..dd8ee7c93fa 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -2926,8 +2926,6 @@ void Deoptimization::print_statistics() { if (counter != 0) { char name[1*K]; Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK); - if (bc_case == BC_CASE_LIMIT && (int)bc == 0) - bc = Bytecodes::_illegal; os::snprintf_checked(name, sizeof(name), "%s/%s/%s", trap_reason_name(reason), trap_action_name(action), From fb651fd6d246e69b42363e050eb8d96afb633eed Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Thu, 21 Aug 2025 14:05:36 +0000 Subject: [PATCH 176/471] 8364638: Refactor and make accumulated GC CPU time code generic Reviewed-by: ayang, sjohanss --- src/hotspot/share/gc/shared/collectedHeap.cpp | 55 ------------ src/hotspot/share/gc/shared/collectedHeap.hpp | 6 +- .../gc/shared/stringdedup/stringDedup.hpp | 4 +- .../stringdedup/stringDedupProcessor.hpp | 4 +- src/hotspot/share/memory/universe.cpp | 59 +++++++++++++ src/hotspot/share/memory/universe.hpp | 2 + src/hotspot/share/runtime/java.cpp | 14 +--- src/hotspot/share/runtime/vmThread.cpp | 4 +- src/hotspot/share/runtime/vmThread.hpp | 2 +- src/hotspot/share/services/cpuTimeUsage.cpp | 84 +++++++++++++++++++ src/hotspot/share/services/cpuTimeUsage.hpp | 50 +++++++++++ 11 files changed, 205 insertions(+), 79 deletions(-) create mode 100644 src/hotspot/share/services/cpuTimeUsage.cpp create mode 100644 src/hotspot/share/services/cpuTimeUsage.hpp diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index b636e3890d3..e82ec1439ea 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -201,34 +201,6 @@ void CollectedHeap::print_relative_to_gc(GCWhen::Type when) const { } } -class CPUTimeThreadClosure : public ThreadClosure { -private: - jlong _cpu_time = 0; - -public: - virtual void do_thread(Thread* thread) { - jlong cpu_time = os::thread_cpu_time(thread); - if (cpu_time != -1) { - _cpu_time += cpu_time; - } - } - jlong cpu_time() { return _cpu_time; }; -}; - -double CollectedHeap::elapsed_gc_cpu_time() const { - double string_dedup_cpu_time = UseStringDeduplication ? - os::thread_cpu_time((Thread*)StringDedup::_processor->_thread) : 0; - - if (string_dedup_cpu_time == -1) { - string_dedup_cpu_time = 0; - } - - CPUTimeThreadClosure cl; - gc_threads_do(&cl); - - return (double)(cl.cpu_time() + _vmthread_cpu_time + string_dedup_cpu_time) / NANOSECS_PER_SEC; -} - void CollectedHeap::print_before_gc() const { print_relative_to_gc(GCWhen::BeforeGC); } @@ -633,36 +605,9 @@ void CollectedHeap::post_initialize() { initialize_serviceability(); } -void CollectedHeap::log_gc_cpu_time() const { - LogTarget(Info, gc, cpu) out; - if (os::is_thread_cpu_time_supported() && out.is_enabled()) { - double process_cpu_time = os::elapsed_process_cpu_time(); - double gc_cpu_time = elapsed_gc_cpu_time(); - - if (process_cpu_time == -1 || gc_cpu_time == -1) { - log_warning(gc, cpu)("Could not sample CPU time"); - return; - } - - double usage; - if (gc_cpu_time > process_cpu_time || - process_cpu_time == 0 || gc_cpu_time == 0) { - // This can happen e.g. for short running processes with - // low CPU utilization - usage = 0; - } else { - usage = 100 * gc_cpu_time / process_cpu_time; - } - out.print("GC CPU usage: %.2f%% (Process: %.4fs GC: %.4fs)", usage, process_cpu_time, gc_cpu_time); - } -} - void CollectedHeap::before_exit() { print_tracing_info(); - // Log GC CPU usage. - log_gc_cpu_time(); - // Stop any on-going concurrent work and prepare for exit. stop(); } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 621f3a0bbc7..33d2fad8bba 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -36,6 +36,7 @@ #include "runtime/handles.hpp" #include "runtime/perfDataTypes.hpp" #include "runtime/safepoint.hpp" +#include "services/cpuTimeUsage.hpp" #include "services/memoryUsage.hpp" #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" @@ -89,6 +90,7 @@ public: // ZCollectedHeap // class CollectedHeap : public CHeapObj { + friend class CPUTimeUsage::GC; friend class VMStructs; friend class JVMCIVMStructs; friend class IsSTWGCActiveMark; // Block structured external access to _is_stw_gc_active @@ -429,8 +431,6 @@ protected: void print_relative_to_gc(GCWhen::Type when) const; - void log_gc_cpu_time() const; - public: void pre_full_gc_dump(GCTimer* timer); void post_full_gc_dump(GCTimer* timer); @@ -463,8 +463,6 @@ protected: // Iterator for all GC threads (other than VM thread) virtual void gc_threads_do(ThreadClosure* tc) const = 0; - double elapsed_gc_cpu_time() const; - void print_before_gc() const; void print_after_gc() const; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp index 43cb513df33..24d17d7d45b 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp @@ -103,9 +103,9 @@ #include "memory/allocation.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/globalDefinitions.hpp" -class CollectedHeap; class Klass; class StringDedupThread; class ThreadClosure; @@ -116,7 +116,7 @@ class ThreadClosure; // feature. Other functions in the StringDedup class are called where // needed, without requiring GC-specific code. class StringDedup : public AllStatic { - friend class CollectedHeap; + friend class CPUTimeUsage::GC; friend class StringDedupThread; class Config; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp index 5d3929c5817..7e5e64df9b4 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp @@ -27,9 +27,9 @@ #include "gc/shared/stringdedup/stringDedup.hpp" #include "memory/allocation.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/macros.hpp" -class CollectedHeap; class JavaThread; class OopStorage; @@ -43,7 +43,7 @@ class OopStorage; // incremental operations for resizing and for removing dead entries, so // safepoint checks can be performed between steps in those operations. class StringDedup::Processor : public CHeapObj { - friend class CollectedHeap; + friend class CPUTimeUsage::GC; Processor(); ~Processor() = default; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index bd47a054bc0..8afa17b0b3d 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -81,11 +81,13 @@ #include "runtime/threads.hpp" #include "runtime/timerTrace.hpp" #include "sanitizers/leak.hpp" +#include "services/cpuTimeUsage.hpp" #include "services/memoryService.hpp" #include "utilities/align.hpp" #include "utilities/autoRestore.hpp" #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/preserveException.hpp" @@ -1300,6 +1302,63 @@ void Universe::verify(VerifyOption option, const char* prefix) { } } +static void log_cpu_time() { + LogTarget(Info, cpu) cpuLog; + if (!cpuLog.is_enabled()) { + return; + } + + const double process_cpu_time = os::elapsed_process_cpu_time(); + if (process_cpu_time == 0 || process_cpu_time == -1) { + // 0 can happen e.g. for short running processes with + // low CPU utilization + return; + } + + const double gc_threads_cpu_time = (double) CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_SEC; + const double gc_vm_thread_cpu_time = (double) CPUTimeUsage::GC::vm_thread() / NANOSECS_PER_SEC; + const double gc_string_dedup_cpu_time = (double) CPUTimeUsage::GC::stringdedup() / NANOSECS_PER_SEC; + const double gc_cpu_time = (double) gc_threads_cpu_time + gc_vm_thread_cpu_time + gc_string_dedup_cpu_time; + + const double elasped_time = os::elapsedTime(); + const bool has_error = CPUTimeUsage::Error::has_error(); + + if (gc_cpu_time < process_cpu_time) { + cpuLog.print("=== CPU time Statistics ============================================================="); + if (has_error) { + cpuLog.print("WARNING: CPU time sampling reported errors, numbers may be unreliable"); + } + cpuLog.print(" CPUs"); + cpuLog.print(" s %% utilized"); + cpuLog.print(" Process"); + cpuLog.print(" Total %30.4f %6.2f %8.1f", process_cpu_time, 100.0, process_cpu_time / elasped_time); + cpuLog.print(" Garbage Collection %30.4f %6.2f %8.1f", gc_cpu_time, percent_of(gc_cpu_time, process_cpu_time), gc_cpu_time / elasped_time); + cpuLog.print(" GC Threads %30.4f %6.2f %8.1f", gc_threads_cpu_time, percent_of(gc_threads_cpu_time, process_cpu_time), gc_threads_cpu_time / elasped_time); + cpuLog.print(" VM Thread %30.4f %6.2f %8.1f", gc_vm_thread_cpu_time, percent_of(gc_vm_thread_cpu_time, process_cpu_time), gc_vm_thread_cpu_time / elasped_time); + + if (UseStringDeduplication) { + cpuLog.print(" String Deduplication %30.4f %6.2f %8.1f", gc_string_dedup_cpu_time, percent_of(gc_string_dedup_cpu_time, process_cpu_time), gc_string_dedup_cpu_time / elasped_time); + } + cpuLog.print("====================================================================================="); + } +} + +void Universe::before_exit() { + log_cpu_time(); + heap()->before_exit(); + + // Print GC/heap related information. + Log(gc, exit) log; + if (log.is_info()) { + LogStream ls_info(log.info()); + Universe::print_on(&ls_info); + if (log.is_trace()) { + LogStream ls_trace(log.trace()); + MutexLocker mcld(ClassLoaderDataGraph_lock); + ClassLoaderDataGraph::print_on(&ls_trace); + } + } +} #ifndef PRODUCT void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) { diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 5d481e889c4..ee4c05e1e06 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -305,6 +305,8 @@ class Universe: AllStatic { // The particular choice of collected heap. static CollectedHeap* heap() { return _collectedHeap; } + static void before_exit(); + DEBUG_ONLY(static bool is_stw_gc_active();) DEBUG_ONLY(static bool is_in_heap(const void* p);) DEBUG_ONLY(static bool is_in_heap_or_null(const void* p) { return p == nullptr || is_in_heap(p); }) diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 3361ecf1558..2aaf020d6d6 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -475,19 +475,7 @@ void before_exit(JavaThread* thread, bool halt) { NativeHeapTrimmer::cleanup(); // Run before exit and then stop concurrent GC threads - Universe::heap()->before_exit(); - - // Print GC/heap related information. - Log(gc, exit) log; - if (log.is_info()) { - LogStream ls_info(log.info()); - Universe::print_on(&ls_info); - if (log.is_trace()) { - LogStream ls_trace(log.trace()); - MutexLocker mcld(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::print_on(&ls_trace); - } - } + Universe::before_exit(); if (PrintBytecodeHistogram) { BytecodeHistogram::print(); diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 1f8265484f1..c93469c1362 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -28,8 +28,8 @@ #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrThreadId.hpp" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" @@ -46,8 +46,8 @@ #include "runtime/safepoint.hpp" #include "runtime/synchronizer.hpp" #include "runtime/timerTrace.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp index 668ea4ce4e2..d2033f66ea5 100644 --- a/src/hotspot/share/runtime/vmThread.hpp +++ b/src/hotspot/share/runtime/vmThread.hpp @@ -27,8 +27,8 @@ #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" -#include "runtime/perfDataTypes.hpp" #include "runtime/nonJavaThread.hpp" +#include "runtime/perfDataTypes.hpp" #include "runtime/task.hpp" #include "runtime/vmOperation.hpp" diff --git a/src/hotspot/share/services/cpuTimeUsage.cpp b/src/hotspot/share/services/cpuTimeUsage.cpp new file mode 100644 index 00000000000..aa658a67bad --- /dev/null +++ b/src/hotspot/share/services/cpuTimeUsage.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" +#include "gc/shared/stringdedup/stringDedupProcessor.hpp" +#include "memory/universe.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "runtime/perfData.hpp" +#include "runtime/vmThread.hpp" +#include "services/cpuTimeUsage.hpp" + +volatile bool CPUTimeUsage::Error::_has_error = false; + +static inline jlong thread_cpu_time_or_zero(Thread* thread) { + jlong cpu_time = os::thread_cpu_time(thread); + if (cpu_time == -1) { + CPUTimeUsage::Error::mark_error(); + return 0; + } + return cpu_time; +} + +class CPUTimeThreadClosure : public ThreadClosure { +private: + jlong _cpu_time = 0; + +public: + virtual void do_thread(Thread* thread) { + _cpu_time += thread_cpu_time_or_zero(thread); + } + jlong cpu_time() { return _cpu_time; }; +}; + +jlong CPUTimeUsage::GC::vm_thread() { + return Universe::heap()->_vmthread_cpu_time; +} + +jlong CPUTimeUsage::GC::gc_threads() { + CPUTimeThreadClosure cl; + Universe::heap()->gc_threads_do(&cl); + return cl.cpu_time(); +} + +jlong CPUTimeUsage::GC::total() { + return gc_threads() + vm_thread() + stringdedup(); +} + +jlong CPUTimeUsage::GC::stringdedup() { + if (UseStringDeduplication) { + return thread_cpu_time_or_zero((Thread*)StringDedup::_processor->_thread); + } + return 0; +} + +bool CPUTimeUsage::Error::has_error() { + return Atomic::load(&_has_error); +} + +void CPUTimeUsage::Error::mark_error() { + Atomic::store(&_has_error, true); +} diff --git a/src/hotspot/share/services/cpuTimeUsage.hpp b/src/hotspot/share/services/cpuTimeUsage.hpp new file mode 100644 index 00000000000..ae4d04947a7 --- /dev/null +++ b/src/hotspot/share/services/cpuTimeUsage.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_SERVICES_CPUTIMEUSAGE_HPP +#define SHARE_SERVICES_CPUTIMEUSAGE_HPP + +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" + +namespace CPUTimeUsage { + class GC : public AllStatic { + public: + static jlong total(); + static jlong gc_threads(); + static jlong vm_thread(); + static jlong stringdedup(); + }; + + class Error : public AllStatic { + private: + static volatile bool _has_error; + + public: + static bool has_error(); + static void mark_error(); + }; +} + +#endif // SHARE_SERVICES_CPUTIMEUSAGE_HPP From cf70cb70bcd5292ed10d8fb08019f0da82db25dd Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 15:32:25 +0000 Subject: [PATCH 177/471] 8365024: G1: Make G1CollectionSet::_inc_build_state assert-only Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 +++--- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 804ded144bd..6fbbeb41a82 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -67,7 +67,7 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _survivor_region_length(0), _initial_old_region_length(0), _optional_groups(), - _inc_build_state(CSetBuildType::Inactive), + DEBUG_ONLY(_inc_build_state(CSetBuildType::Inactive) COMMA) _regions_inc_part_start(0), _groups_inc_part_start(0) { } @@ -142,11 +142,11 @@ void G1CollectionSet::continue_incremental_building() { _regions_inc_part_start = _regions_cur_length; _groups_inc_part_start = groups_cur_length(); - _inc_build_state = CSetBuildType::Active; + DEBUG_ONLY(_inc_build_state = CSetBuildType::Active;) } void G1CollectionSet::stop_incremental_building() { - _inc_build_state = CSetBuildType::Inactive; + DEBUG_ONLY(_inc_build_state = CSetBuildType::Inactive;) } void G1CollectionSet::clear() { diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index 2bde960fbc4..7038cd4e677 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -165,12 +165,14 @@ class G1CollectionSet { // groups. Regions are reachable via this list as well. G1CSetCandidateGroupList _optional_groups; +#ifdef ASSERT enum class CSetBuildType { Active, // We are actively building the collection set Inactive // We are not actively building the collection set }; CSetBuildType _inc_build_state; +#endif // Index into the _regions indicating the start of the current collection set increment. size_t _regions_inc_part_start; // Index into the _groups indicating the start of the current collection set increment. From d75724682390efa7cb63ae973fd9c504f7f64852 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 21 Aug 2025 16:37:07 +0000 Subject: [PATCH 178/471] 8365891: failed: Completed task should not be in the queue Reviewed-by: dlong --- src/hotspot/share/compiler/compileBroker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 36663ab1088..804345d95c5 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -480,6 +480,7 @@ void CompileQueue::purge_stale_tasks() { MutexUnlocker ul(MethodCompileQueue_lock); for (CompileTask* task = head; task != nullptr; ) { CompileTask* next_task = task->next(); + task->set_next(nullptr); CompileTaskWrapper ctw(task); // Frees the task task->set_failure_reason("stale task"); task = next_task; From bdf9834b81f0565e3572de42ebd42981d1d05a5c Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 21 Aug 2025 16:46:19 +0000 Subject: [PATCH 179/471] 8365425: [macos26] javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java fails on macOS 26 Reviewed-by: dnguyen, kizune --- .../8160248/JInternalFrameDraggingTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java index 81f5e0d0802..7c3732925be 100644 --- a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java +++ b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -21,6 +21,7 @@ * questions. */ +import java.io.File; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Point; @@ -28,6 +29,7 @@ import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; @@ -51,6 +53,7 @@ public class JInternalFrameDraggingTest { private static JInternalFrame internalFrame; private static int FRAME_SIZE = 500; private static Color BACKGROUND_COLOR = Color.ORANGE; + private static final int tolerance = 10; public static void main(String[] args) throws Exception { try { @@ -69,14 +72,24 @@ public class JInternalFrameDraggingTest { BufferedImage img = robot.createScreenCapture(rect); int testRGB = BACKGROUND_COLOR.getRGB(); + Color testColor = new Color(testRGB); for (int i = 1; i < size; i++) { int rgbCW = img.getRGB(i, size / 2); int rgbCH = img.getRGB(size / 2, i); - if (rgbCW != testRGB || rgbCH != testRGB) { + Color rgbCWColor = new Color(rgbCW); + Color rgbCHColor = new Color(rgbCH); + + if (Math.abs(rgbCWColor.getRed() - testColor.getRed()) > tolerance + || Math.abs(rgbCWColor.getGreen() - testColor.getGreen()) > tolerance + || Math.abs(rgbCWColor.getBlue() - testColor.getBlue()) > tolerance + || Math.abs(rgbCHColor.getRed() - testColor.getRed()) > tolerance + || Math.abs(rgbCHColor.getGreen() - testColor.getGreen()) > tolerance + || Math.abs(rgbCHColor.getBlue() - testColor.getBlue()) > tolerance) { System.out.println("i " + i + " rgbCW " + Integer.toHexString(rgbCW) + " testRGB " + Integer.toHexString(testRGB) + " rgbCH " + Integer.toHexString(rgbCH)); + ImageIO.write(img, "png", new File("JInternalFrameDraggingTest.png")); throw new RuntimeException("Background color is wrong!"); } } From 11eccfc85f8495b0cbc3965fd69911a6c7ed0140 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 21 Aug 2025 18:58:27 +0000 Subject: [PATCH 180/471] 8365917: Sort share/logging includes Reviewed-by: ayang, phh --- src/hotspot/share/logging/log.hpp | 2 +- src/hotspot/share/logging/logDecorators.hpp | 2 +- src/hotspot/share/logging/logFileStreamOutput.cpp | 1 + src/hotspot/share/logging/logTag.cpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/logging/log.hpp b/src/hotspot/share/logging/log.hpp index 87c7cd926fb..7820e2c21d1 100644 --- a/src/hotspot/share/logging/log.hpp +++ b/src/hotspot/share/logging/log.hpp @@ -26,8 +26,8 @@ #include "logging/logLevel.hpp" #include "logging/logPrefix.hpp" -#include "logging/logTagSet.hpp" #include "logging/logTag.hpp" +#include "logging/logTagSet.hpp" #include "utilities/debug.hpp" class LogMessageBuffer; diff --git a/src/hotspot/share/logging/logDecorators.hpp b/src/hotspot/share/logging/logDecorators.hpp index 9e38f429974..5b245626ade 100644 --- a/src/hotspot/share/logging/logDecorators.hpp +++ b/src/hotspot/share/logging/logDecorators.hpp @@ -24,8 +24,8 @@ #ifndef SHARE_LOGGING_LOGDECORATORS_HPP #define SHARE_LOGGING_LOGDECORATORS_HPP -#include "utilities/globalDefinitions.hpp" #include "logging/logSelection.hpp" +#include "utilities/globalDefinitions.hpp" class outputStream; diff --git a/src/hotspot/share/logging/logFileStreamOutput.cpp b/src/hotspot/share/logging/logFileStreamOutput.cpp index bc753676706..394c310b940 100644 --- a/src/hotspot/share/logging/logFileStreamOutput.cpp +++ b/src/hotspot/share/logging/logFileStreamOutput.cpp @@ -29,6 +29,7 @@ #include "logging/logMessageBuffer.hpp" #include "memory/allocation.inline.hpp" #include "utilities/defaultStream.hpp" + #include const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines"; diff --git a/src/hotspot/share/logging/logTag.cpp b/src/hotspot/share/logging/logTag.cpp index d2aeeebfc79..41554c3acb8 100644 --- a/src/hotspot/share/logging/logTag.cpp +++ b/src/hotspot/share/logging/logTag.cpp @@ -22,9 +22,9 @@ * */ #include "logging/logTag.hpp" -#include "utilities/stringUtils.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/stringUtils.hpp" const char* const LogTag::_name[] = { "", // __NO_TAG diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 5d8c60e23e0..1a304a44944 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -54,6 +54,7 @@ public class TestIncludesAreSorted { "share/jfr", "share/jvmci", "share/libadt", + "share/logging", "share/metaprogramming", "share/oops", "share/opto", From 52747256bbd5490dba9ef9832025a0f7057e338f Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 21 Aug 2025 19:56:46 +0000 Subject: [PATCH 181/471] 8154364: (fs) Files.isSameFile() throws NoSuchFileException with broken symbolic links Reviewed-by: alanb --- .../sun/nio/fs/UnixFileAttributes.java | 27 +- .../sun/nio/fs/UnixFileSystemProvider.java | 56 ++- .../sun/nio/fs/WindowsFileSystemProvider.java | 20 +- test/jdk/java/nio/file/Files/IsSameFile.java | 456 ++++++++++++++++++ test/jdk/java/nio/file/Files/Misc.java | 30 +- 5 files changed, 549 insertions(+), 40 deletions(-) create mode 100644 test/jdk/java/nio/file/Files/IsSameFile.java diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 6fc86b66735..48dc4c07d0d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -81,8 +81,11 @@ class UnixFileAttributes return attrs; } - // get the UnixFileAttributes for a given file. Returns null if the file does not exist. - static UnixFileAttributes getIfExists(UnixPath path) throws UnixException { + // get the UnixFileAttributes for a given file. + // Returns null if the file does not exist. + static UnixFileAttributes getIfExists(UnixPath path) + throws UnixException + { UnixFileAttributes attrs = new UnixFileAttributes(); int errno = UnixNativeDispatcher.stat2(path, attrs); if (errno == 0) { @@ -94,6 +97,26 @@ class UnixFileAttributes } } + // get the UnixFileAttributes for a given file, optionally following links. + // Returns null if the file does not exist. + static UnixFileAttributes getIfExists(UnixPath path, boolean followLinks) + throws UnixException + { + UnixFileAttributes attrs = new UnixFileAttributes(); + int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW; + try { + UnixNativeDispatcher.fstatat(UnixConstants.AT_FDCWD, + path.asByteArray(), flag, attrs); + } catch (UnixException x) { + if (x.errno() == UnixConstants.ENOENT) + return null; + + throw x; + } + + return attrs; + } + // get the UnixFileAttributes for an open file static UnixFileAttributes get(int fd) throws UnixException { UnixFileAttributes attrs = new UnixFileAttributes(); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index beb9a1af41b..a1c68934604 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -53,6 +53,7 @@ import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.spi.FileTypeDetector; import java.util.Map; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -348,8 +349,32 @@ public abstract class UnixFileSystemProvider return access(file, X_OK) == 0; } + // find the key of the last accessible link in the chain + private UnixFileKey lastFileKey(UnixPath path) throws UnixException { + var fileKeys = new HashSet(); + UnixFileKey lastFileKey = null; + while (path != null) { + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(path, false); + if (attrs == null) { + break; + } + UnixFileKey fileKey = attrs.fileKey(); + if (!attrs.isSymbolicLink()) { + break; + } + if (!fileKeys.add(fileKey)) { + throw new UnixException(ELOOP); + } + lastFileKey = fileKey; + byte[] target = readlink(path); + path = new UnixPath(theFileSystem, target); + } + return lastFileKey; + } + @Override public boolean isSameFile(Path obj1, Path obj2) throws IOException { + // toUnixPath verifies its argument is a non-null UnixPath UnixPath file1 = UnixPath.toUnixPath(obj1); if (file1.equals(obj2)) return true; @@ -358,21 +383,28 @@ public abstract class UnixFileSystemProvider if (!(obj2 instanceof UnixPath file2)) return false; - UnixFileAttributes attrs1; - UnixFileAttributes attrs2; + UnixFileKey key1; try { - attrs1 = UnixFileAttributes.get(file1, true); - } catch (UnixException x) { - x.rethrowAsIOException(file1); - return false; // keep compiler happy + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file1); + key1 = (attrs != null) ? attrs.fileKey() : lastFileKey(file1); + } catch (UnixException e) { + e.rethrowAsIOException(file1); + return false; } + + if (key1 == null) + return false; + + UnixFileKey key2; try { - attrs2 = UnixFileAttributes.get(file2, true); - } catch (UnixException x) { - x.rethrowAsIOException(file2); - return false; // keep compiler happy + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file2); + key2 = (attrs != null) ? attrs.fileKey() : lastFileKey(file2); + } catch (UnixException e) { + e.rethrowAsIOException(file2); + return false; } - return attrs1.isSameFile(attrs2); + + return key1.equals(key2); } @Override diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index 3a1bb416fe7..5e740ec1f4d 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -434,8 +434,15 @@ class WindowsFileSystemProvider try { h1 = file1.openForReadAttributeAccess(true); } catch (WindowsException x) { - x.rethrowAsIOException(file1); + if (x.lastError() != ERROR_FILE_NOT_FOUND && + x.lastError() != ERROR_PATH_NOT_FOUND) + x.rethrowAsIOException(file1); } + + // if file1 does not exist, it cannot equal file2 + if (h1 == 0L) + return false; + try { WindowsFileAttributes attrs1 = null; try { @@ -447,8 +454,15 @@ class WindowsFileSystemProvider try { h2 = file2.openForReadAttributeAccess(true); } catch (WindowsException x) { - x.rethrowAsIOException(file2); + if (x.lastError() != ERROR_FILE_NOT_FOUND && + x.lastError() != ERROR_PATH_NOT_FOUND) + x.rethrowAsIOException(file2); } + + // if file2 does not exist, it cannot equal file1, which does + if (h2 == 0L) + return false; + try { WindowsFileAttributes attrs2 = null; try { diff --git a/test/jdk/java/nio/file/Files/IsSameFile.java b/test/jdk/java/nio/file/Files/IsSameFile.java new file mode 100644 index 00000000000..00bac0fb5a7 --- /dev/null +++ b/test/jdk/java/nio/file/Files/IsSameFile.java @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8154364 + * @summary Test of Files.isSameFile + * @requires (os.family != "windows") + * @library .. /test/lib + * @build IsSameFile jdk.test.lib.util.FileUtils + * @run junit IsSameFile + */ +import java.io.IOException; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import jdk.test.lib.util.FileUtils; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestInstance(Lifecycle.PER_CLASS) +public class IsSameFile { + private Path home; + private Path a; + private Path aa; + private Path b; + private Path c; + private List allFiles; + + @BeforeAll + public void init() throws IOException { + home = Files.createTempDirectory("TestIsSameFile"); + + allFiles = new ArrayList(); + allFiles.add(a = home.resolve("a")); + allFiles.add(aa = home.resolve("a")); + allFiles.add(b = home.resolve("b")); + allFiles.add(c = home.resolve("c")); + } + + public void deleteFiles() throws IOException { + for (Path p : allFiles) + Files.deleteIfExists(p); + } + + @AfterAll + public void deleteHome() throws IOException { + TestUtil.removeAll(home); + } + + public void test(boolean expect, Path x, Path y) throws IOException { + assertTrue(Files.isSameFile(x, y) == expect); + } + + private Stream stringCompareSource() throws IOException { + deleteFiles(); + List list = new ArrayList(); + Path x = Path.of("x/y/z"); + list.add(Arguments.of(true, x, x)); + list.add(Arguments.of(false, Path.of("w/x/y/z"), x)); + Path y = Path.of("v/w/x/../y/z"); + list.add(Arguments.of(false, y, Path.of("v/w/y/z"))); + list.add(Arguments.of(false, y, Path.of("v/w/x/y/../z"))); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("stringCompareSource") + public void stringCompare(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream noneExistSource() throws IOException { + deleteFiles(); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + return list.stream(); + } + + @Test + public void obj2Null() { + Path x = Path.of("x/y"); + assertThrows(NullPointerException.class, () -> Files.isSameFile(x, null)); + } + + private static void zipStringToFile(String entry, String content, + Path path) + throws IOException + { + FileOutputStream fos = new FileOutputStream(path.toString()); + ZipOutputStream zos = new ZipOutputStream(fos); + + ZipEntry zipEntry = new ZipEntry(entry); + zos.putNextEntry(zipEntry); + zos.write(content.getBytes()); + + zos.close(); + fos.close(); + } + + private Stream obj2ZipSource() throws IOException { + deleteFiles(); + Files.createFile(a); + zipStringToFile("quote.txt", "To be determined", b); + FileSystem zipfs = FileSystems.newFileSystem(b); + List list = new ArrayList(); + list.add(Arguments.of(false, a, zipfs.getPath(b.toString()))); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("obj2ZipSource") + public void obj2Zip(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + @ParameterizedTest + @MethodSource("noneExistSource") + public void noneExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream aExistsSource() throws IOException { + deleteFiles(); + Files.createFile(a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("aExistsSource") + public void aExists(boolean expect, Path x, Path y) throws IOException { + test(expect, x, y); + } + + private Stream abExistSource() throws IOException { + deleteFiles(); + Files.createFile(a); + Files.createFile(b); + List list = new ArrayList(); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + list.add(Arguments.of(false, a, c)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("abExistSource") + public void abExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream abcExistSource() throws IOException { + deleteFiles(); + Files.createFile(a); + Files.createFile(b); + Files.createSymbolicLink(c, a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, c)); + list.add(Arguments.of(false, a, b)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("abcExistSource") + public void abcExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream bcExistSource() throws IOException { + deleteFiles(); + Files.createFile(b); + Files.createSymbolicLink(c, a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + list.add(Arguments.of(false, a, c)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("bcExistSource") + public void bcExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => target + // L3 => L4 => target + // + private Stream equalFollowingSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, target); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, target); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(true, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("equalFollowingSource") + public void equalFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => target + // L3 => L4 => cible + // + private Stream unequalFollowingSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, target); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path cible = home.resolve("cible"); + Files.createFile(cible); + allFiles.add(cible); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, cible); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(false, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("unequalFollowingSource") + public void unequalFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => + // L3 => L4 => + // + private Stream unequalNotFollowingSource() throws IOException { + deleteFiles(); + + Path doesNotExist = Path.of("doesNotExist"); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, doesNotExist); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, doesNotExist); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(false, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("unequalNotFollowingSource") + public void unequalNotFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => L3 => L4 => target + // + // isSameFile(LX,LY) should be true for all X, Y + // + private Stream multiLinkSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + Path[] links = new Path[4]; + links[3] = Files.createSymbolicLink(Path.of("link4"), target); + allFiles.add(links[3]); + for (int i = 3; i > 0; i--) { + links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]); + allFiles.add(links[i-1]); + } + + List list = new ArrayList(); + for (int i = 0; i < 4; i++) { + list.add(Arguments.of(true, links[i], target)); + for (int j = i+1; j < 4; j++) + list.add(Arguments.of(true, links[i], links[j])); + } + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("multiLinkSource") + public void multiLink(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => L3 => L4 => + // + // isSameFile(LX,LY) should be true for all X, Y + // + private Stream multiLinkNoTargetSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + Path[] links = new Path[4]; + links[3] = Files.createSymbolicLink(Path.of("link4"), target); + allFiles.add(links[3]); + Files.delete(target); + allFiles.remove(target); + for (int i = 3; i > 0; i--) { + links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]); + allFiles.add(links[i-1]); + } + + List list = new ArrayList(); + for (int i = 0; i < 4; i++) { + list.add(Arguments.of(false, links[i], target)); + for (int j = i+1; j < 4; j++) + list.add(Arguments.of(true, links[i], links[j])); + } + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("multiLinkNoTargetSource") + public void multiLinkNoTarget(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 -> L2 -> L3 -> L1... + // + // This is a loop and should throw FileSystemException. + // + private Stream linkLoopSource() throws IOException { + deleteFiles(); + + Path link1 = home.resolve("L1"); + Path link2 = home.resolve("L2"); + Path link3 = home.resolve("L3"); + allFiles.add(Files.createSymbolicLink(link1, link2)); + allFiles.add(Files.createSymbolicLink(link2, link3)); + allFiles.add(Files.createSymbolicLink(link3, link1)); + + List list = new ArrayList(); + list.add(Arguments.of(true, link1, link2)); + list.add(Arguments.of(true, link2, link3)); + list.add(Arguments.of(true, link3, link1)); + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("linkLoopSource") + public void linkLoop(boolean expect, Path x, Path y) throws IOException { + assertThrows(FileSystemException.class, () -> Files.isSameFile(x, y)); + } +} diff --git a/test/jdk/java/nio/file/Files/Misc.java b/test/jdk/java/nio/file/Files/Misc.java index 024b518141b..9ec8d7c252e 100644 --- a/test/jdk/java/nio/file/Files/Misc.java +++ b/test/jdk/java/nio/file/Files/Misc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 8005566 8215467 8255576 8286160 + * @bug 4313887 6838333 8005566 8154364 8215467 8255576 8286160 * @summary Unit test for miscellaneous methods in java.nio.file.Files * @library .. /test/lib * @build jdk.test.lib.Platform @@ -113,34 +113,18 @@ public class Misc { assertTrue(isSameFile(thisFile, thisFile)); /** - * Test: Neither files exist + * Test: Neither file exists */ - try { - isSameFile(thisFile, thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - isSameFile(thatFile, thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } + assertTrue(!isSameFile(thisFile, thatFile)); + assertTrue(!isSameFile(thatFile, thisFile)); createFile(thisFile); try { /** * Test: One file exists */ - try { - isSameFile(thisFile, thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - isSameFile(thatFile, thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } + assertTrue(!isSameFile(thisFile, thatFile)); + assertTrue(!isSameFile(thatFile, thisFile)); /** * Test: Both file exists From 3468c6e5ef7e7592cf9484736ce333fbe0eaf34d Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 21 Aug 2025 20:49:04 +0000 Subject: [PATCH 182/471] 8365389: Remove static color fields from SwingUtilities3 and WindowsMenuItemUI Reviewed-by: psadhukhan, aivanov, dnguyen --- .../com/sun/java/swing/SwingUtilities3.java | 21 ++------ .../swing/plaf/basic/BasicMenuItemUI.java | 9 ++-- .../windows/WindowsCheckBoxMenuItemUI.java | 4 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 51 +++++-------------- .../swing/plaf/windows/WindowsMenuUI.java | 3 +- .../windows/WindowsRadioButtonMenuItemUI.java | 4 +- 6 files changed, 28 insertions(+), 64 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java index 5e1e149eb9e..91e0f8dc54d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -69,10 +69,6 @@ public class SwingUtilities3 { private static final Object DELEGATE_REPAINT_MANAGER_KEY = new StringBuilder("DelegateRepaintManagerKey"); - private static Color disabledForeground; - private static Color acceleratorSelectionForeground; - private static Color acceleratorForeground; - /** * Registers delegate RepaintManager for {@code JComponent}. */ @@ -204,7 +200,10 @@ public class SwingUtilities3 { public static void paintAccText(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr) { + MenuItemLayoutHelper.LayoutResult lr, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground) { if (!lh.getAccText().isEmpty()) { ButtonModel model = lh.getMenuItem().getModel(); g.setFont(lh.getAccFontMetrics().getFont()); @@ -243,18 +242,6 @@ public class SwingUtilities3 { } } - public static void setDisabledForeground(Color disabledFg) { - disabledForeground = disabledFg; - } - - public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) { - acceleratorSelectionForeground = acceleratorSelectionFg; - } - - public static void setAcceleratorForeground(Color acceleratorFg) { - acceleratorForeground = acceleratorFg; - } - public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color foreground) { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java index 524f0337a8f..d361906b291 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -716,11 +716,10 @@ public class BasicMenuItemUI extends MenuItemUI private void paintAccText(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr) { - SwingUtilities3.setDisabledForeground(disabledForeground); - SwingUtilities3.setAcceleratorSelectionForeground( - acceleratorSelectionForeground); - SwingUtilities3.setAcceleratorForeground(acceleratorForeground); - SwingUtilities3.paintAccText(g, lh, lr); + SwingUtilities3.paintAccText(g, lh, lr, + disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); } private void paintText(Graphics g, MenuItemLayoutHelper lh, diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index f59a59a5125..02054575d77 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -84,7 +84,9 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { int defaultTextIconGap) { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, - arrowIcon, background, foreground, defaultTextIconGap, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index a8bafc54c33..aa90b2f35b3 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -67,9 +67,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { * The instance of {@code PropertyChangeListener}. */ private PropertyChangeListener changeListener; - private static Color disabledForeground; - private static Color acceleratorSelectionForeground; - private static Color acceleratorForeground; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { @@ -167,36 +164,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { changeListener = null; } - private static void applyInsets(Rectangle rect, Insets insets) { - SwingUtilities3.applyInsets(rect, insets); - } - - private static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, - Color holdc, Color foreground) { - SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); - } - - private static void paintIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, Color holdc) { - SwingUtilities3.paintIcon(g, lh, lr, holdc); - } - - private static void paintAccText(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr) { - SwingUtilities3.setDisabledForeground(disabledForeground); - SwingUtilities3.setAcceleratorSelectionForeground( - acceleratorSelectionForeground); - SwingUtilities3.setAcceleratorForeground(acceleratorForeground); - SwingUtilities3.paintAccText(g, lh, lr); - } - - private static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, - Color foreground) { - SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); - } - protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, @@ -204,7 +171,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, background, foreground, - defaultTextIconGap, menuItem, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } @@ -215,6 +183,9 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { static void paintMenuItem(WindowsMenuItemUIAccessor accessor, Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground, int defaultTextIconGap, JMenuItem menuItem, String prefix) { // Save original graphics font and color Font holdf = g.getFont(); @@ -224,7 +195,7 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { g.setFont(mi.getFont()); Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); - applyInsets(viewRect, mi.getInsets()); + SwingUtilities3.applyInsets(viewRect, mi.getInsets()); String acceleratorDelimiter = UIManager.getString("MenuItem.acceleratorDelimiter"); @@ -242,8 +213,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); paintBackground(accessor, g, mi, background); - paintCheckIcon(g, lh, lr, holdc, foreground); - paintIcon(g, lh, lr, holdc); + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); + SwingUtilities3.paintIcon(g, lh, lr, holdc); if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { Rectangle rect = lr.getTextRect(); @@ -267,8 +238,10 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { rect.x += lh.getAfterCheckIconGap(); lr.setAccRect(rect); } - paintAccText(g, lh, lr); - paintArrowIcon(g, lh, lr, foreground); + SwingUtilities3.paintAccText(g, lh, lr, disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); // Restore original graphics font and color g.setColor(holdc); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 81c01c11036..1476c6fc152 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -140,7 +140,8 @@ public final class WindowsMenuUI extends BasicMenuUI { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, background, foreground, - defaultTextIconGap, menuItem, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 385ab6b3634..628a4be1637 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -84,7 +84,9 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem int defaultTextIconGap) { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, - arrowIcon, background, foreground, defaultTextIconGap, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } From 584137cf968bdfd4fdb88b5bb210bbbfa5f2d537 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Fri, 22 Aug 2025 01:42:57 +0000 Subject: [PATCH 183/471] 8365844: RISC-V: TestBadFormat.java fails when running without RVV Reviewed-by: fjiang, chagedorn, epeter, fyang --- .../testlibrary_tests/ir_framework/tests/TestBadFormat.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java index ac8867f3985..a33aacd924e 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java @@ -1124,8 +1124,8 @@ class BadIRAnnotationsAfterTestVM { @Test @FailCount(8) - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"}) - @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}) // valid + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_ANY, "> 0"}) // valid @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "", "> 0"}) @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "xxx", "> 0"}) From 558d06399c7a13b247ee3d0f36f4fe6118004c55 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 22 Aug 2025 03:43:01 +0000 Subject: [PATCH 184/471] 8361536: [s390x] Saving return_pc at wrong offset Reviewed-by: lucy, mdoerr --- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 38 +++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 34696f18848..2aa365be999 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -164,15 +164,16 @@ class StubGenerator: public StubCodeGenerator { // Save non-volatile registers to ABI of caller frame. BLOCK_COMMENT("save registers, push frame {"); - __ z_stmg(Z_R6, Z_R14, 16, Z_SP); - __ z_std(Z_F8, 96, Z_SP); - __ z_std(Z_F9, 104, Z_SP); - __ z_std(Z_F10, 112, Z_SP); - __ z_std(Z_F11, 120, Z_SP); - __ z_std(Z_F12, 128, Z_SP); - __ z_std(Z_F13, 136, Z_SP); - __ z_std(Z_F14, 144, Z_SP); - __ z_std(Z_F15, 152, Z_SP); + __ save_return_pc(); + __ z_stmg(Z_R6, Z_R13, 16, Z_SP); + __ z_std(Z_F8, 80, Z_SP); + __ z_std(Z_F9, 88, Z_SP); + __ z_std(Z_F10, 96, Z_SP); + __ z_std(Z_F11, 104, Z_SP); + __ z_std(Z_F12, 112, Z_SP); + __ z_std(Z_F13, 120, Z_SP); + __ z_std(Z_F14, 128, Z_SP); + __ z_std(Z_F15, 136, Z_SP); // // Push ENTRY_FRAME including arguments: @@ -337,15 +338,16 @@ class StubGenerator: public StubCodeGenerator { __ z_lg(r_arg_result_type, result_type_offset, r_entryframe_fp); // Restore non-volatiles. - __ z_lmg(Z_R6, Z_R14, 16, Z_SP); - __ z_ld(Z_F8, 96, Z_SP); - __ z_ld(Z_F9, 104, Z_SP); - __ z_ld(Z_F10, 112, Z_SP); - __ z_ld(Z_F11, 120, Z_SP); - __ z_ld(Z_F12, 128, Z_SP); - __ z_ld(Z_F13, 136, Z_SP); - __ z_ld(Z_F14, 144, Z_SP); - __ z_ld(Z_F15, 152, Z_SP); + __ restore_return_pc(); + __ z_lmg(Z_R6, Z_R13, 16, Z_SP); + __ z_ld(Z_F8, 80, Z_SP); + __ z_ld(Z_F9, 88, Z_SP); + __ z_ld(Z_F10, 96, Z_SP); + __ z_ld(Z_F11, 104, Z_SP); + __ z_ld(Z_F12, 112, Z_SP); + __ z_ld(Z_F13, 120, Z_SP); + __ z_ld(Z_F14, 128, Z_SP); + __ z_ld(Z_F15, 136, Z_SP); BLOCK_COMMENT("} restore"); // From 8e4485699235caff0074c4d25ee78539e57da63a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 22 Aug 2025 04:28:56 +0000 Subject: [PATCH 185/471] 8365180: Remove sun.awt.windows.WInputMethod.finalize() Reviewed-by: serb, azvegint --- .../classes/sun/awt/windows/WInputMethod.java | 38 ++++++++++++------- .../native/libawt/windows/awt_InputMethod.cpp | 4 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java index e893a58f9ed..0e4e5bd585e 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java @@ -44,6 +44,8 @@ import java.util.Map; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.im.InputMethodAdapter; +import sun.java2d.Disposer; +import sun.java2d.DisposerRecord; final class WInputMethod extends InputMethodAdapter { @@ -124,6 +126,8 @@ final class WInputMethod extends InputMethodAdapter public WInputMethod() { context = createNativeContext(); + disposerRecord = new ContextDisposerRecord(context); + Disposer.addRecord(this, disposerRecord); cmode = getConversionStatus(context); open = getOpenStatus(context); currentLocale = getNativeLocale(); @@ -132,16 +136,23 @@ final class WInputMethod extends InputMethodAdapter } } - @Override - @SuppressWarnings("removal") - protected void finalize() throws Throwable - { - // Release the resources used by the native input context. - if (context!=0) { - destroyNativeContext(context); - context=0; + private final ContextDisposerRecord disposerRecord; + + private static final class ContextDisposerRecord implements DisposerRecord { + + private final int context; + private volatile boolean disposed; + + ContextDisposerRecord(int c) { + context = c; + } + + public synchronized void dispose() { + if (!disposed) { + destroyNativeContext(context); + } + disposed = true; } - super.finalize(); } @Override @@ -151,9 +162,7 @@ final class WInputMethod extends InputMethodAdapter @Override public void dispose() { - // Due to a memory management problem in Windows 98, we should retain - // the native input context until this object is finalized. So do - // nothing here. + disposerRecord.dispose(); } /** @@ -448,6 +457,7 @@ final class WInputMethod extends InputMethodAdapter @Override public void removeNotify() { endCompositionNative(context, DISCARD_INPUT); + disableNativeIME(awtFocussedComponentPeer); awtFocussedComponent = null; awtFocussedComponentPeer = null; } @@ -658,8 +668,8 @@ final class WInputMethod extends InputMethodAdapter } - private native int createNativeContext(); - private native void destroyNativeContext(int context); + private static native int createNativeContext(); + private static native void destroyNativeContext(int context); private native void enableNativeIME(WComponentPeer peer, int context, boolean useNativeCompWindow); private native void disableNativeIME(WComponentPeer peer); private native void handleNativeIMEEvent(WComponentPeer peer, AWTEvent e); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp index fcc6e4c2cb8..87087870b5d 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp @@ -52,7 +52,7 @@ extern BOOL g_bUserHasChangedInputLang; * Signature: ()I */ JNIEXPORT jint JNICALL -Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self) +Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jclass cls) { TRY; @@ -69,7 +69,7 @@ Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self) * Signature: (I)V */ JNIEXPORT void JNICALL -Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jobject self, jint context) +Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jclass cls, jint context) { TRY_NO_VERIFY; From f0498c2aed761d4023917bc9cd1f852a02ce977a Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 22 Aug 2025 08:16:55 +0000 Subject: [PATCH 186/471] 8364764: java/nio/channels/vthread/BlockingChannelOps.java subtests timed out Reviewed-by: jpai --- .../channels/vthread/BlockingChannelOps.java | 140 ++++++++++++++---- 1 file changed, 109 insertions(+), 31 deletions(-) diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index 7ff02cdfea4..1cdd090d1be 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -21,7 +21,7 @@ * questions. */ -/** +/* * @test id=default * @bug 8284161 * @summary Test virtual threads doing blocking I/O on NIO channels @@ -29,7 +29,7 @@ * @run junit BlockingChannelOps */ -/** +/* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib @@ -37,7 +37,7 @@ * @run junit/othervm -Djdk.pollerMode=2 BlockingChannelOps */ -/** +/* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib @@ -62,6 +62,7 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; +import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; @@ -161,6 +162,22 @@ class BlockingChannelOps { }); } + /** + * SocketChannel shutdownInput while virtual thread blocked in read. + */ + @Test + void testSocketChannelReadAsyncShutdownInput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + SocketChannel sc = connection.channel1(); + runAfterParkedAsync(sc::shutdownInput); + int n = sc.read(ByteBuffer.allocate(100)); + assertEquals(-1, n); + assertTrue(sc.isOpen()); + } + }); + } + /** * Virtual thread interrupted while blocked in SocketChannel read. */ @@ -190,13 +207,15 @@ class BlockingChannelOps { @Test void testSocketChannelWriteAsyncClose() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { try (var connection = new Connection()) { SocketChannel sc = connection.channel1(); // close sc when current thread blocks in write - runAfterParkedAsync(sc::close); + runAfterParkedAsync(sc::close, true); + + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -206,30 +225,59 @@ class BlockingChannelOps { } } catch (AsynchronousCloseException expected) { // closed when blocked in write - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } }); } + + /** + * SocketChannel shutdownOutput while virtual thread blocked in write. + */ + @Test + void testSocketChannelWriteAsyncShutdownOutput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + SocketChannel sc = connection.channel1(); + + // shutdown output when current thread blocks in write + runAfterParkedAsync(sc::shutdownOutput); + try { + ByteBuffer bb = ByteBuffer.allocate(100*1024); + for (;;) { + int n = sc.write(bb); + assertTrue(n > 0); + bb.clear(); + } + } catch (ClosedChannelException e) { + // expected + } + assertTrue(sc.isOpen()); + } + }); + } + /** * Virtual thread interrupted while blocked in SocketChannel write. */ @Test void testSocketChannelWriteInterrupt() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { try (var connection = new Connection()) { SocketChannel sc = connection.channel1(); // interrupt current thread when it blocks in write Thread thisThread = Thread.currentThread(); - runAfterParkedAsync(thisThread::interrupt); + runAfterParkedAsync(thisThread::interrupt, true); + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -240,9 +288,10 @@ class BlockingChannelOps { } catch (ClosedByInterruptException e) { // closed when blocked in write assertTrue(Thread.interrupted()); - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -734,14 +783,16 @@ class BlockingChannelOps { @Test void testPipeWriteAsyncClose() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { Pipe p = Pipe.open(); try (Pipe.SinkChannel sink = p.sink(); Pipe.SourceChannel source = p.source()) { // close sink when current thread blocks in write - runAfterParkedAsync(sink::close); + runAfterParkedAsync(sink::close, true); + + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -751,9 +802,10 @@ class BlockingChannelOps { } } catch (AsynchronousCloseException e) { // closed when blocked in write - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -766,16 +818,17 @@ class BlockingChannelOps { @Test void testPipeWriteInterrupt() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { Pipe p = Pipe.open(); try (Pipe.SinkChannel sink = p.sink(); Pipe.SourceChannel source = p.source()) { // interrupt current thread when it blocks in write Thread thisThread = Thread.currentThread(); - runAfterParkedAsync(thisThread::interrupt); + runAfterParkedAsync(thisThread::interrupt, true); + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -786,9 +839,10 @@ class BlockingChannelOps { } catch (ClosedByInterruptException expected) { // closed when blocked in write assertTrue(Thread.interrupted()); - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -848,26 +902,50 @@ class BlockingChannelOps { } /** - * Runs the given task asynchronously after the current virtual thread has parked. + * Runs the given task asynchronously after the current virtual thread parks. + * @param writing if the thread will block in write * @return the thread started to run the task */ - static Thread runAfterParkedAsync(ThrowingRunnable task) { + private static Thread runAfterParkedAsync(ThrowingRunnable task, boolean writing) { Thread target = Thread.currentThread(); if (!target.isVirtual()) throw new WrongThreadException(); return Thread.ofPlatform().daemon().start(() -> { try { - Thread.State state = target.getState(); - while (state != Thread.State.WAITING - && state != Thread.State.TIMED_WAITING) { + // wait for target thread to park + while (!isWaiting(target)) { Thread.sleep(20); - state = target.getState(); } - Thread.sleep(20); // give a bit more time to release carrier + + // if the target thread is parked in write then we nudge it a few times + // to avoid wakeup with some bytes written + if (writing) { + for (int i = 0; i < 3; i++) { + LockSupport.unpark(target); + while (!isWaiting(target)) { + Thread.sleep(20); + } + } + } + task.run(); + } catch (Exception e) { e.printStackTrace(); } }); } + + private static Thread runAfterParkedAsync(ThrowingRunnable task) { + return runAfterParkedAsync(task, false); + } + + /** + * Return true if the given Thread is parked. + */ + private static boolean isWaiting(Thread target) { + Thread.State state = target.getState(); + assertNotEquals(Thread.State.TERMINATED, state); + return (state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING); + } } From e1c58f858a64853c2d454fd00a84455ca6700055 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 22 Aug 2025 09:01:21 +0000 Subject: [PATCH 187/471] 8360540: nmethod entry barriers of new nmethods should be disarmed Reviewed-by: eosterlund, tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +++ src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 3 +++ src/hotspot/share/gc/serial/serialHeap.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e50821e96c1..bf512cfa19d 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -74,6 +74,7 @@ #include "gc/g1/g1VMOperations.hpp" #include "gc/g1/g1YoungCollector.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/fullGCForwarding.hpp" @@ -3079,6 +3080,8 @@ void G1CollectedHeap::register_nmethod(nmethod* nm) { guarantee(nm != nullptr, "sanity"); RegisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void G1CollectedHeap::unregister_nmethod(nmethod* nm) { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index c6a9a312e5c..07ae097c5b8 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -32,6 +32,7 @@ #include "gc/parallel/psPromotionManager.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psVMOperations.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/fullGCForwarding.inline.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcLocker.inline.hpp" @@ -861,6 +862,8 @@ void ParallelScavengeHeap::complete_loaded_archive_space(MemRegion archive_space void ParallelScavengeHeap::register_nmethod(nmethod* nm) { ScavengableNMethods::register_nmethod(nm); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void ParallelScavengeHeap::unregister_nmethod(nmethod* nm) { diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 6b9328b8697..72f8ad85a4e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -34,6 +34,7 @@ #include "gc/serial/serialMemoryPools.hpp" #include "gc/serial/serialVMOperations.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/collectedHeap.inline.hpp" @@ -432,6 +433,8 @@ bool SerialHeap::do_young_collection(bool clear_soft_refs) { void SerialHeap::register_nmethod(nmethod* nm) { ScavengableNMethods::register_nmethod(nm); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void SerialHeap::unregister_nmethod(nmethod* nm) { From f5f414f9fc67e55acb83e04ea270d39041cb6198 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 22 Aug 2025 15:57:11 +0000 Subject: [PATCH 188/471] 8365186: Reduce size of j.t.f.DateTimePrintContext::adjust Reviewed-by: rriggs --- .../time/format/DateTimePrintContext.java | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java index c7eed23b7bc..d755ba3ee78 100644 --- a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java +++ b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -120,6 +120,19 @@ final class DateTimePrintContext { this.formatter = formatter; } + /** + * Adjusts the given {@link TemporalAccessor} using chronology and time-zone from a formatter if present. + *

    + * This method serves as an optimization front-end that checks for non-null overrides in the formatter. + * If neither chronology nor time-zone is specified in the formatter, returns the original temporal unchanged. + * Otherwise, delegates to the core adjustment method {@link #adjustWithOverride(TemporalAccessor, Chronology, ZoneId)}. + * + * @implNote Optimizes for the common case where formatters don't specify chronology/time-zone + * by avoiding unnecessary processing. Most formatters have null for these properties. + * @param temporal the temporal object to adjust, not null + * @param formatter the formatter providing potential chronology and time-zone overrides + * @return the adjusted temporal, or the original if no overrides are present in the formatter + */ private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) { // normal case first (early return is an optimization) Chronology overrideChrono = formatter.getChronology(); @@ -128,6 +141,32 @@ final class DateTimePrintContext { return temporal; } + // Placing the non-null cases in a separate method allows more flexible code optimizations + return adjustWithOverride(temporal, overrideChrono, overrideZone); + } + + /** + * Adjusts the given {@link TemporalAccessor} with optional overriding chronology and time-zone. + *

    + * This method minimizes changes by returning the original temporal if the override parameters + * are either {@code null} or equivalent to those already present in the temporal. When overrides + * are applied: + *

      + *
    • If a time-zone override is provided and the temporal supports {@link ChronoField#INSTANT_SECONDS}, + * the result is a zoned date-time using the override time-zone and chronology (defaulting to ISO if not overridden).
    • + *
    • Other cases (including partial date-times or mixed chronology/time-zone changes) are delegated + * to a secondary adjustment method.
    • + *
    + * + * @param temporal the temporal object to adjust, not null + * @param overrideChrono the chronology to override (null retains the original chronology) + * @param overrideZone the time-zone to override (null retains the original time-zone) + * @return the adjusted temporal, which may be the original object if no effective changes were made, + * or a new object with the applied overrides + * @implNote Optimizes for common cases where overrides are identical to existing values + * or where instant-based temporals can be directly converted with a time-zone. + */ + private static TemporalAccessor adjustWithOverride(TemporalAccessor temporal, Chronology overrideChrono, ZoneId overrideZone) { // ensure minimal change (early return is an optimization) Chronology temporalChrono = temporal.query(TemporalQueries.chronology()); ZoneId temporalZone = temporal.query(TemporalQueries.zoneId()); @@ -149,6 +188,53 @@ final class DateTimePrintContext { Chronology chrono = Objects.requireNonNullElse(effectiveChrono, IsoChronology.INSTANCE); return chrono.zonedDateTime(Instant.from(temporal), overrideZone); } + } + + // Split uncommon code branches into a separate method + return adjustSlow(temporal, overrideZone, temporalZone, overrideChrono, effectiveChrono, temporalChrono); + } + + /** + * Internal helper method to adjust temporal fields using override chronology and time-zone in complex cases. + *

    + * Handles non-instant temporal objects by creating a delegate {@link TemporalAccessor} that combines: + *

      + *
    • The original temporal's time-related fields
    • + *
    • Date fields converted to the effective chronology (if available)
    • + *
    • Override zone/chronology information for temporal queries
    • + *
    + * + * Performs critical validation before processing: + *
      + *
    • Rejects offset changes for non-instant temporal objects with existing offsets
    • + *
    • Verifies date field integrity when applying chronology overrides to partial dates
    • + *
    + * + * @param temporal the original temporal object to adjust, not null + * @param overrideZone override time-zone (nullable) + * @param temporalZone original time-zone from temporal (nullable) + * @param overrideChrono override chronology (nullable) + * @param effectiveChrono precomputed effective chronology (override if present, otherwise temporal's chronology) + * @param temporalChrono original chronology from temporal (nullable) + * @return adjusted temporal accessor combining original fields with overrides + * @throws DateTimeException if: + *
      + *
    • Applying a {@link ZoneOffset} override to a temporal with conflicting existing offset that doesn't represent an instant
    • + *
    • Applying chronology override to temporal with partial date fields
    • + *
    + * @implNote Creates an anonymous temporal accessor that: + *
      + *
    • Delegates time-based fields to original temporal
    • + *
    • Uses converted date fields when chronology override is applied
    • + *
    • Responds to chronology/zone queries with effective values
    • + *
    • Preserves precision queries from original temporal
    • + *
    + */ + private static TemporalAccessor adjustSlow( + TemporalAccessor temporal, + ZoneId overrideZone, ZoneId temporalZone, + Chronology overrideChrono, Chronology effectiveChrono, Chronology temporalChrono) { + if (overrideZone != null) { // block changing zone on OffsetTime, and similar problem cases if (overrideZone.normalized() instanceof ZoneOffset && temporal.isSupported(OFFSET_SECONDS) && temporal.get(OFFSET_SECONDS) != overrideZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()) { From dba0d545053fb73e57ea6fda829a5bf3d0135ac5 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 22 Aug 2025 16:44:47 +0000 Subject: [PATCH 189/471] 8365832: Optimize FloatingDecimal and DigitList with byte[] and cleanup Reviewed-by: rgiulietti, liach --- .../share/classes/java/text/DigitList.java | 69 +++--- .../jdk/internal/math/FloatingDecimal.java | 218 ++++-------------- 2 files changed, 87 insertions(+), 200 deletions(-) diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 41c143178da..2895126f93b 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -41,6 +41,9 @@ package java.text; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; + +import jdk.internal.access.SharedSecrets; import jdk.internal.math.FloatingDecimal; import jdk.internal.util.ArraysSupport; @@ -103,9 +106,9 @@ final class DigitList implements Cloneable { */ public int decimalAt = 0; public int count = 0; - public char[] digits = new char[MAX_COUNT]; + public byte[] digits = new byte[MAX_COUNT]; - private char[] data; + private byte[] data; private RoundingMode roundingMode = RoundingMode.HALF_EVEN; private boolean isNegative = false; @@ -154,11 +157,11 @@ final class DigitList implements Cloneable { */ public void append(char digit) { if (count == digits.length) { - char[] data = new char[ArraysSupport.newLength(count, 1, count)]; + byte[] data = new byte[ArraysSupport.newLength(count, 1, count)]; System.arraycopy(digits, 0, data, 0, count); digits = data; } - digits[count++] = digit; + digits[count++] = (byte) digit; } /** @@ -188,7 +191,7 @@ final class DigitList implements Cloneable { // Parse as unsigned to handle Long.MIN_VALUE, which is the one NEGATIVE value // we represent. If we tried to just pass the digits off to parseLong, // we'd get a parse failure. - long v = Long.parseUnsignedLong(new String(digits, 0, count)); + long v = Long.parseUnsignedLong(new String(digits, 0, count, StandardCharsets.ISO_8859_1)); if (v < 0) { if (v == Long.MIN_VALUE) { return Long.MIN_VALUE; @@ -209,15 +212,20 @@ final class DigitList implements Cloneable { * unlike BigDecimal(""). */ public BigDecimal getBigDecimal() { + int count = this.count; if (count == 0) { return BigDecimal.valueOf(0, -decimalAt); } - if (decimalAt == count) { - return new BigDecimal(digits, 0, count); - } else { - return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count); - } + char[] chars = new char[count]; + SharedSecrets.getJavaLangAccess() + .inflateBytesToChars(digits, 0, chars, 0, count); + BigDecimal value = new BigDecimal(chars, 0, count); + if (decimalAt == count) { + return value; + } else { + return value.scaleByPowerOfTen(decimalAt - count); + } } /** @@ -256,7 +264,7 @@ final class DigitList implements Cloneable { // The number will overflow if it is larger than 9223372036854775807 // or smaller than -9223372036854775808. for (int i=0; i max) return false; if (dig < max) return true; } @@ -317,9 +325,10 @@ final class DigitList implements Cloneable { boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); assert !fdConverter.isExceptional(); - String digitsString = fdConverter.toJavaFormatString(); - set(isNegative, digitsString, + byte[] chars = getDataChars(26); + int len = fdConverter.getChars(chars); + set(isNegative, chars, len, hasBeenRoundedUp, valueExactAsDecimal, maximumDigits, fixedPoint); } @@ -331,14 +340,11 @@ final class DigitList implements Cloneable { * @param valueExactAsDecimal whether or not collected digits provide * an exact decimal representation of the value. */ - private void set(boolean isNegative, String s, + private void set(boolean isNegative, byte[] source, int len, boolean roundedUp, boolean valueExactAsDecimal, int maximumDigits, boolean fixedPoint) { this.isNegative = isNegative; - int len = s.length(); - char[] source = getDataChars(len); - s.getChars(0, len, source, 0); decimalAt = -1; count = 0; @@ -349,7 +355,7 @@ final class DigitList implements Cloneable { boolean nonZeroDigitSeen = false; for (int i = 0; i < len; ) { - char c = source[i++]; + byte c = source[i++]; if (c == '.') { decimalAt = count; } else if (c == 'e' || c == 'E') { @@ -633,7 +639,7 @@ final class DigitList implements Cloneable { int left = MAX_COUNT; int right; while (source > 0) { - digits[--left] = (char)('0' + (source % 10)); + digits[--left] = (byte)('0' + (source % 10)); source /= 10; } decimalAt = MAX_COUNT - left; @@ -661,11 +667,15 @@ final class DigitList implements Cloneable { * @param fixedPoint If true, then maximumDigits is the maximum * fractional digits to be converted. If false, total digits. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { String s = source.toString(); extendDigits(s.length()); - set(isNegative, s, + int len = s.length(); + byte[] chars = getDataChars(len); + s.getBytes(0, len, chars, 0); + set(isNegative, chars, len, false, true, maximumDigits, fixedPoint); } @@ -678,12 +688,13 @@ final class DigitList implements Cloneable { * If maximumDigits is lower than the number of significant digits * in source, the representation will be rounded. Ignored if <= 0. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigInteger source, int maximumDigits) { this.isNegative = isNegative; String s = source.toString(); int len = s.length(); extendDigits(len); - s.getChars(0, len, digits, 0); + s.getBytes(0, len, digits, 0); decimalAt = len; int right = len - 1; @@ -734,7 +745,7 @@ final class DigitList implements Cloneable { public Object clone() { try { DigitList other = (DigitList) super.clone(); - char[] newDigits = new char[digits.length]; + byte[] newDigits = new byte[digits.length]; System.arraycopy(digits, 0, newDigits, 0, digits.length); other.digits = newDigits; @@ -749,8 +760,8 @@ final class DigitList implements Cloneable { } } - private static int parseInt(char[] str, int offset, int strLen) { - char c; + private static int parseInt(byte[] str, int offset, int strLen) { + byte c; boolean positive = true; if ((c = str[offset]) == '-') { positive = false; @@ -772,25 +783,25 @@ final class DigitList implements Cloneable { } // The digit part of -9223372036854775808L - private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray(); + private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); public String toString() { if (isZero()) { return "0"; } - return "0." + new String(digits, 0, count) + "x10^" + decimalAt; + return "0." + new String(digits, 0, count, StandardCharsets.ISO_8859_1) + "x10^" + decimalAt; } private void extendDigits(int len) { if (len > digits.length) { - digits = new char[len]; + digits = new byte[len]; } } - private char[] getDataChars(int length) { + private byte[] getDataChars(int length) { if (data == null || data.length < length) { - data = new char[length]; + data = new byte[length]; } return data; } diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java index 168f76fad8f..32399310bd3 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -60,44 +60,6 @@ public class FloatingDecimal{ static final int INT_DECIMAL_DIGITS = 9; - /** - * Converts a double precision floating point value to a String. - * - * @param d The double precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(double d) { - return getBinaryToASCIIConverter(d).toJavaFormatString(); - } - - /** - * Converts a single precision floating point value to a String. - * - * @param f The single precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(float f) { - return getBinaryToASCIIConverter(f).toJavaFormatString(); - } - - /** - * Appends a double precision floating point value to an Appendable. - * @param d The double precision value. - * @param buf The Appendable with the value appended. - */ - public static void appendTo(double d, Appendable buf) { - getBinaryToASCIIConverter(d).appendTo(buf); - } - - /** - * Appends a single precision floating point value to an Appendable. - * @param f The single precision value. - * @param buf The Appendable with the value appended. - */ - public static void appendTo(float f, Appendable buf) { - getBinaryToASCIIConverter(f).appendTo(buf); - } - /** * Converts a String to a double precision floating point value. * @@ -131,7 +93,7 @@ public class FloatingDecimal{ * @param length Number of digits to use * @return The double-precision value of the conversion */ - public static double parseDoubleSignlessDigits(int decExp, char[] digits, int length) { + public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int length) { return readDoubleSignlessDigits(decExp, digits, length).doubleValue(); } @@ -140,17 +102,7 @@ public class FloatingDecimal{ * values into an ASCII String representation. */ public interface BinaryToASCIIConverter { - /** - * Converts a floating point value into an ASCII String. - * @return The value converted to a String. - */ - String toJavaFormatString(); - - /** - * Appends a floating point value to an Appendable. - * @param buf The Appendable to receive the value. - */ - void appendTo(Appendable buf); + int getChars(byte[] result); /** * Retrieves the decimal exponent most closely corresponding to this value. @@ -209,19 +161,10 @@ public class FloatingDecimal{ } @Override - public String toJavaFormatString() { - return image; - } - - @Override - public void appendTo(Appendable buf) { - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(image); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(image); - } else { - assert false; - } + @SuppressWarnings("deprecation") + public int getChars(byte[] chars) { + image.getBytes(0, image.length(), chars, 0); + return image.length(); } @Override @@ -261,8 +204,8 @@ public class FloatingDecimal{ private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); - private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); - private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); + private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new byte[]{'0'}); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'}); /** * A buffered implementation of BinaryToASCIIConverter. @@ -272,8 +215,7 @@ public class FloatingDecimal{ private int decExponent; private int firstDigitIndex; private int nDigits; - private final char[] digits; - private final char[] buffer = new char[26]; + private final byte[] digits; // // The fields below provide additional information about the result of @@ -293,13 +235,13 @@ public class FloatingDecimal{ * BinaryToASCIIBuffer may be thread-local and reused */ BinaryToASCIIBuffer(){ - this.digits = new char[20]; + this.digits = new byte[20]; } /** * Creates a specialized value (positive and negative zeros). */ - BinaryToASCIIBuffer(boolean isNegative, char[] digits){ + BinaryToASCIIBuffer(boolean isNegative, byte[] digits){ this.isNegative = isNegative; this.decExponent = 0; this.digits = digits; @@ -307,24 +249,6 @@ public class FloatingDecimal{ this.nDigits = digits.length; } - @Override - public String toJavaFormatString() { - int len = getChars(buffer); - return new String(buffer, 0, len); - } - - @Override - public void appendTo(Appendable buf) { - int len = getChars(buffer); - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(buffer, 0, len); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(buffer, 0, len); - } else { - assert false; - } - } - @Override public int getDecimalExponent() { return decExponent; @@ -403,12 +327,12 @@ public class FloatingDecimal{ ivalue /= 10; } while ( ivalue != 0){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte)(c+'0'); decExponent++; c = ivalue%10; ivalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } else { // same algorithm as above (same bugs, too ) // but using long arithmetic. @@ -420,12 +344,12 @@ public class FloatingDecimal{ lvalue /= 10L; } while ( lvalue != 0L ){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte) (c+'0'); decExponent++; c = (int)(lvalue%10L); lvalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } this.decExponent = decExponent+1; this.firstDigitIndex = digitno; @@ -626,7 +550,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -654,7 +578,7 @@ public class FloatingDecimal{ low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -680,7 +604,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -708,7 +632,7 @@ public class FloatingDecimal{ low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -741,7 +665,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -758,7 +682,7 @@ public class FloatingDecimal{ Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); low = (Bval.cmp( Mval ) < 0); high = tenSval.addAndCmp(Bval,Mval)<=0; - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } if ( high && low ){ Bval = Bval.leftShift(1); @@ -812,7 +736,7 @@ public class FloatingDecimal{ } // else fall through. } - digits[i] = (char) (q + 1); + digits[i] = (byte) (q + 1); decimalDigitsRoundedUp = true; } @@ -845,19 +769,8 @@ public class FloatingDecimal{ } } - private static int insignificantDigits(long insignificant) { - int i; - for ( i = 0; insignificant >= 10L; i++ ) { - insignificant /= 10L; - } - return i; - } - /** * Calculates - *
    -         * insignificantDigitsForPow2(v) == insignificantDigits(1L<
              */
             private static int insignificantDigitsForPow2(int p2) {
                 if (p2 > 1 && p2 < insignificantDigitsNumber.length) {
    @@ -913,7 +826,14 @@ public class FloatingDecimal{
                     61,
             };
     
    -        private int getChars(char[] result) {
    +        /**
    +         * Converts the decimal representation of a floating-point number into its
    +         * ASCII character representation and stores it in the provided byte array.
    +         *
    +         * @param result the byte array to store the ASCII representation, must have length at least 26
    +         * @return the number of characters written to the result array
    +         */
    +        public int getChars(byte[] result) {
                 assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
                 int i = 0;
                 if (isNegative) {
    @@ -927,7 +847,7 @@ public class FloatingDecimal{
                     i += charLength;
                     if (charLength < decExponent) {
                         charLength = decExponent - charLength;
    -                    Arrays.fill(result,i,i+charLength,'0');
    +                    Arrays.fill(result, i, i + charLength, (byte) '0');
                         i += charLength;
                         result[i++] = '.';
                         result[i++] = '0';
    @@ -935,7 +855,7 @@ public class FloatingDecimal{
                         result[i++] = '.';
                         if (charLength < nDigits) {
                             int t = nDigits - charLength;
    -                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
    +                        System.arraycopy(digits, firstDigitIndex + charLength, result, i, t);
                             i += t;
                         } else {
                             result[i++] = '0';
    @@ -945,7 +865,7 @@ public class FloatingDecimal{
                     result[i++] = '0';
                     result[i++] = '.';
                     if (decExponent != 0) {
    -                    Arrays.fill(result, i, i-decExponent, '0');
    +                    Arrays.fill(result, i, i-decExponent, (byte) '0');
                         i -= decExponent;
                     }
                     System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
    @@ -969,15 +889,15 @@ public class FloatingDecimal{
                     }
                     // decExponent has 1, 2, or 3, digits
                     if (e <= 9) {
    -                    result[i++] = (char) (e + '0');
    +                    result[i++] = (byte) (e + '0');
                     } else if (e <= 99) {
    -                    result[i++] = (char) (e / 10 + '0');
    -                    result[i++] = (char) (e % 10 + '0');
    +                    result[i++] = (byte) (e / 10 + '0');
    +                    result[i++] = (byte) (e % 10 + '0');
                     } else {
    -                    result[i++] = (char) (e / 100 + '0');
    +                    result[i++] = (byte) (e / 100 + '0');
                         e %= 100;
    -                    result[i++] = (char) (e / 10 + '0');
    -                    result[i++] = (char) (e % 10 + '0');
    +                    result[i++] = (byte) (e / 10 + '0');
    +                    result[i++] = (byte) (e % 10 + '0');
                     }
                 }
                 return i;
    @@ -1043,10 +963,10 @@ public class FloatingDecimal{
          * A buffered implementation of ASCIIToBinaryConverter.
          */
         static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
    -        boolean     isNegative;
    -        int         decExponent;
    -        byte[]      digits;
    -        int         nDigits;
    +        final boolean isNegative;
    +        final int     decExponent;
    +        final byte[]  digits;
    +        int           nDigits;
     
             ASCIIToBinaryBuffer( boolean negSign, int decExponent, byte[] digits, int n)
             {
    @@ -1765,10 +1685,10 @@ public class FloatingDecimal{
             buf.decimalDigitsRoundedUp = dec.getAway();
     
             long f = dec.getSignificand();
    -        char[] digits = buf.digits;
    +        byte[] digits = buf.digits;
             for (int i = buf.nDigits - 1; i >= 0; --i) {
                 long q = f / 10;
    -            digits[i] = (char) ((f - 10 * q) + '0');
    +            digits[i] = (byte) ((f - 10 * q) + '0');
                 f = q;
             }
             return buf;
    @@ -1819,58 +1739,14 @@ public class FloatingDecimal{
             return buf;
         }
     
    -    private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
    -        int fBits = Float.floatToRawIntBits( f );
    -        boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
    -        int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
    -        int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
    -        // Discover obvious special cases of NaN and Infinity.
    -        if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
    -            if ( fractBits == 0L ){
    -                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
    -            } else {
    -                return B2AC_NOT_A_NUMBER;
    -            }
    -        }
    -        // Finish unpacking
    -        // Normalize denormalized numbers.
    -        // Insert assumed high-order bit for normalized numbers.
    -        // Subtract exponent bias.
    -        int  nSignificantBits;
    -        if ( binExp == 0 ){
    -            if ( fractBits == 0 ){
    -                // not a denorm, just a 0!
    -                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
    -            }
    -            int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
    -            int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
    -            fractBits <<= shift;
    -            binExp = 1 - shift;
    -            nSignificantBits =  32 - leadingZeros; // recall binExp is  - shift count.
    -        } else {
    -            fractBits |= SINGLE_FRACT_HOB;
    -            nSignificantBits = SINGLE_EXP_SHIFT+1;
    -        }
    -        binExp -= FloatConsts.EXP_BIAS;
    -        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
    -        buf.setSign(isNegative);
    -        // call the routine that actually does all the hard work.
    -        buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
    -        return buf;
    -    }
    -
    -    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, char[] digits, int length) {
    +    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, byte[] digits, int length) {
     
             // Prevent an extreme negative exponent from causing overflow issues in doubleValue().
             // Large positive values are handled within doubleValue();
             if (decExp < MIN_DECIMAL_EXPONENT) {
                 return A2BC_POSITIVE_ZERO;
             }
    -        byte[] buf = new byte[length];
    -        for (int i = 0; i < length; i++) {
    -            buf[i] = (byte) digits[i];
    -        }
    -        return new ASCIIToBinaryBuffer(false, decExp, buf, length);
    +        return new ASCIIToBinaryBuffer(false, decExp, digits, length);
         }
     
         /**
    
    From e916ce8ce9af906cf86f1801fcb43e08f8188665 Mon Sep 17 00:00:00 2001
    From: altrisi 
    Date: Fri, 22 Aug 2025 17:10:40 +0000
    Subject: [PATCH 190/471] 8365878: jshell TOOLING's javap should use binary
     names
    
    Reviewed-by: liach, cstein
    ---
     .../jdk/jshell/tool/resources/TOOLING.jsh     |  4 +--
     test/langtools/jdk/jshell/ToolingTest.java    | 31 +++++++++++++++++--
     2 files changed, 31 insertions(+), 4 deletions(-)
    
    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    index b97b6341cfa..16436514383 100644
    --- a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    +++ b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    @@ -8,9 +8,9 @@ void jmod(String... args) { run("jmod", args); }
     void jpackage(String... args) { run("jpackage", args); }
     
     void javap(Class type) throws Exception {
    +    if (type.isPrimitive() || type.isHidden() || type.isArray()) throw new IllegalArgumentException("Type has no class file: " + type);
         try {
    -        var name = type.getCanonicalName();
    -        if (name == null) throw new IllegalArgumentException("Type not supported: " + type);
    +        var name = type.getName();
             if (type == Class.forName(name, false, ClassLoader.getSystemClassLoader())) {
                 run("javap", "-c", "-v", "-s", name);
                 return;
    diff --git a/test/langtools/jdk/jshell/ToolingTest.java b/test/langtools/jdk/jshell/ToolingTest.java
    index b36fdc03c19..f0d0e3f68eb 100644
    --- a/test/langtools/jdk/jshell/ToolingTest.java
    +++ b/test/langtools/jdk/jshell/ToolingTest.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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
    @@ -23,7 +23,7 @@
     
     /*
      * @test
    - * @bug 8306560
    + * @bug 8306560 8365878
      * @summary Tests for snippets and methods defined in TOOLING.jsh
      * @modules jdk.compiler/com.sun.tools.javac.api
      *          jdk.compiler/com.sun.tools.javac.main
    @@ -79,4 +79,31 @@ public class ToolingTest extends ReplToolTesting {
                     )
             );
         }
    +
    +    @Test
    +    public void testDisassembleBuiltinInnerClass() {
    +        test(
    +            a -> assertCommand(a, "/open TOOLING",
    +                        ""),
    +            a -> assertCommandUserOutputContains(a, "javap(Base64.Decoder.class)",
    +                        "Classfile jrt:/java.base/java/util/Base64$Decoder.class",
    +                        "class java.util.Base64$Decoder",
    +                        "SourceFile: \"Base64.java\"")
    +        );
    +    }
    +
    +    @Test
    +    public void testDisassembleAnonymousClass() {
    +        test(
    +            a -> assertCommand(a, "Object o() {return new ArrayList<>(){ };}", // must be in a method or it won't be anonymous
    +                        "|  created method o()"),
    +            a -> assertCommand(a, "/open TOOLING",
    +                        ""),
    +            a -> assertCommandUserOutputContains(a, "javap(o().getClass())",
    +                        "Classfile ", // Classfile /.../TOOLING-16063368030094702464.class
    +                        " extends java.util.ArrayList", // class REPL.$JShell$22$1 extends java.util.ArrayList
    +                        "SourceFile: \"$JShell$" // SourceFile: "$JShell$22.java"
    +            )
    +        );
    +    }
     }
    
    From 19882220ecb3eeaef763ccbb0aa4d7760c906222 Mon Sep 17 00:00:00 2001
    From: Francesco Andreuzzi 
    Date: Fri, 22 Aug 2025 17:36:52 +0000
    Subject: [PATCH 191/471] 8365829: Multiple definitions of static 'phase_names'
    
    Reviewed-by: kbarrett
    ---
     src/hotspot/share/opto/phasetype.cpp | 46 ++++++++++++++++++++++++++++
     src/hotspot/share/opto/phasetype.hpp | 35 ++++++---------------
     2 files changed, 56 insertions(+), 25 deletions(-)
     create mode 100644 src/hotspot/share/opto/phasetype.cpp
    
    diff --git a/src/hotspot/share/opto/phasetype.cpp b/src/hotspot/share/opto/phasetype.cpp
    new file mode 100644
    index 00000000000..3e18bd089ba
    --- /dev/null
    +++ b/src/hotspot/share/opto/phasetype.cpp
    @@ -0,0 +1,46 @@
    +/*
    + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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.
    + *
    + * 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.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + *
    + */
    +
    +#include "phasetype.hpp"
    +
    +const char* const CompilerPhaseTypeHelper::_phase_descriptions[] = {
    +#define array_of_labels(name, description) description,
    +       COMPILER_PHASES(array_of_labels)
    +#undef array_of_labels
    +};
    +
    +const char* const CompilerPhaseTypeHelper::_phase_names[] = {
    +#define array_of_labels(name, description) #name,
    +       COMPILER_PHASES(array_of_labels)
    +#undef array_of_labels
    +};
    +
    +CompilerPhaseType CompilerPhaseTypeHelper::find_phase(const char* str) {
    +  for (int i = 0; i < PHASE_NUM_TYPES; i++) {
    +    if (strcmp(CompilerPhaseTypeHelper::_phase_names[i], str) == 0) {
    +      return (CompilerPhaseType)i;
    +    }
    +  }
    +  return PHASE_NONE;
    +}
    diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp
    index 942850cf892..5c733c7dc0a 100644
    --- a/src/hotspot/share/opto/phasetype.hpp
    +++ b/src/hotspot/share/opto/phasetype.hpp
    @@ -138,36 +138,21 @@ enum CompilerPhaseType {
     };
     #undef table_entry
     
    -static const char* phase_descriptions[] = {
    -#define array_of_labels(name, description) description,
    -       COMPILER_PHASES(array_of_labels)
    -#undef array_of_labels
    -};
    -
    -static const char* phase_names[] = {
    -#define array_of_labels(name, description) #name,
    -       COMPILER_PHASES(array_of_labels)
    -#undef array_of_labels
    -};
    -
     class CompilerPhaseTypeHelper {
    -  public:
    + private:
    +  static const char* const _phase_descriptions[];
    +  static const char* const _phase_names[];
    +
    + public:
       static const char* to_name(CompilerPhaseType cpt) {
    -    return phase_names[cpt];
    +    return _phase_names[cpt];
       }
       static const char* to_description(CompilerPhaseType cpt) {
    -    return phase_descriptions[cpt];
    +    return _phase_descriptions[cpt];
       }
    -};
     
    -static CompilerPhaseType find_phase(const char* str) {
    -  for (int i = 0; i < PHASE_NUM_TYPES; i++) {
    -    if (strcmp(phase_names[i], str) == 0) {
    -      return (CompilerPhaseType)i;
    -    }
    -  }
    -  return PHASE_NONE;
    -}
    +  static CompilerPhaseType find_phase(const char* str);
    +};
     
     class PhaseNameValidator {
      private:
    @@ -183,7 +168,7 @@ class PhaseNameValidator {
       {
         for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) {
     
    -      CompilerPhaseType cpt = find_phase(*iter);
    +      CompilerPhaseType cpt = CompilerPhaseTypeHelper::find_phase(*iter);
           if (PHASE_NONE == cpt) {
             const size_t len = MIN2(strlen(*iter), 63) + 1;  // cap len to a value we know is enough for all phase descriptions
             _bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler);
    
    From ae0dac43c09377c87e9b0452618a5b32c8568150 Mon Sep 17 00:00:00 2001
    From: Naoto Sato 
    Date: Fri, 22 Aug 2025 17:50:22 +0000
    Subject: [PATCH 192/471] 8361613: System.console() should only be available
     for interactive terminal
    
    Reviewed-by: jlahoda, smarks, alanb
    ---
     .../share/classes/java/lang/System.java       |   3 +-
     .../org/jline/JdkConsoleProviderImpl.java     |   2 +-
     .../java/io/Console/DefaultCharsetTest.java   |  69 +++++--
     test/jdk/java/io/Console/LocaleTest.java      | 127 ++++++------
     .../java/io/Console/ModuleSelectionTest.java  |  69 +++++--
     test/jdk/java/io/Console/defaultCharset.exp   |  32 ++++
     test/jdk/java/io/Console/locale.exp           |  37 ++++
     test/jdk/java/io/Console/moduleSelection.exp  |  30 +++
     test/jdk/java/lang/IO/IO.java                 |  54 +-----
     .../jline/JLineConsoleProviderTest.java       |  30 ++-
     .../jline/LazyJdkConsoleProvider.java         |  40 ++--
     .../jdk/internal/jline/RedirectedStdOut.java  | 181 ------------------
     12 files changed, 330 insertions(+), 344 deletions(-)
     create mode 100644 test/jdk/java/io/Console/defaultCharset.exp
     create mode 100644 test/jdk/java/io/Console/locale.exp
     create mode 100644 test/jdk/java/io/Console/moduleSelection.exp
     delete mode 100644 test/jdk/jdk/internal/jline/RedirectedStdOut.java
    
    diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java
    index f046ed4111a..a40c27bbf47 100644
    --- a/src/java.base/share/classes/java/lang/System.java
    +++ b/src/java.base/share/classes/java/lang/System.java
    @@ -237,10 +237,11 @@ public final class System {
         private static volatile Console cons;
     
         /**
    -     * Returns the unique {@link java.io.Console Console} object associated
    +     * Returns the unique {@link Console Console} object associated
          * with the current Java virtual machine, if any.
          *
          * @return  The system console, if any, otherwise {@code null}.
    +     * @see Console
          *
          * @since   1.6
          */
    diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    index 365f6d1e68a..4e4751b264e 100644
    --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    @@ -50,7 +50,7 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
          */
         @Override
         public JdkConsole console(boolean isTTY, Charset inCharset, Charset outCharset) {
    -        return new LazyDelegatingJdkConsoleImpl(inCharset, outCharset);
    +        return isTTY ? new LazyDelegatingJdkConsoleImpl(inCharset, outCharset) : null;
         }
     
         private static class LazyDelegatingJdkConsoleImpl implements JdkConsole {
    diff --git a/test/jdk/java/io/Console/DefaultCharsetTest.java b/test/jdk/java/io/Console/DefaultCharsetTest.java
    index 0fca8a3cc3f..981d92ce282 100644
    --- a/test/jdk/java/io/Console/DefaultCharsetTest.java
    +++ b/test/jdk/java/io/Console/DefaultCharsetTest.java
    @@ -21,33 +21,66 @@
      * questions.
      */
     
    -import org.junit.jupiter.api.Test;
    -import static org.junit.jupiter.api.Assertions.*;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +
    +import jdk.test.lib.process.OutputAnalyzer;
    +import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.api.BeforeAll;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.ValueSource;
    +
    +import static jdk.test.lib.Utils.*;
     
     /**
      * @test
    - * @bug 8341975 8351435
    + * @bug 8341975 8351435 8361613
      * @summary Tests the default charset. It should honor `stdout.encoding`
      *          which should be the same as System.out.charset()
    - * @modules jdk.internal.le
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=UTF-8 DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=ISO-8859-1 DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=US-ASCII DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=foo DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le DefaultCharsetTest
    + * @requires (os.family == "linux") | (os.family == "mac")
    + * @library /test/lib
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.JDKToolFinder
    + *        jdk.test.lib.process.ProcessTools
    + * @run junit DefaultCharsetTest
      */
     public class DefaultCharsetTest {
    -    @Test
    -    public void testDefaultCharset() {
    +    @BeforeAll
    +    static void checkExpectAvailability() {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
    +    }
    +    @ParameterizedTest
    +    @ValueSource(strings = {"UTF-8", "ISO-8859-1", "US-ASCII", "foo", ""})
    +    void testDefaultCharset(String stdoutEncoding) throws Exception {
    +        // invoking "expect" command
    +        OutputAnalyzer oa = ProcessTools.executeProcess(
    +            "expect",
    +            "-n",
    +            TEST_SRC + "/defaultCharset.exp",
    +            TEST_CLASSES,
    +            TEST_JDK + "/bin/java",
    +            "-Dstdout.encoding=" + stdoutEncoding,
    +            getClass().getName());
    +        oa.reportDiagnosticSummary();
    +        oa.shouldHaveExitValue(0);
    +    }
    +
    +    public static void main(String... args) {
             var stdoutEncoding = System.getProperty("stdout.encoding");
             var sysoutCharset = System.out.charset();
             var consoleCharset = System.console().charset();
    -        System.out.println("""
    -                    stdout.encoding = %s
    -                    System.out.charset() = %s
    -                    System.console().charset() = %s
    -                """.formatted(stdoutEncoding, sysoutCharset.name(), consoleCharset.name()));
    -        assertEquals(consoleCharset, sysoutCharset,
    -            "Charsets for System.out and Console differ for stdout.encoding: %s".formatted(stdoutEncoding));
    +        System.out.printf("""
    +                stdout.encoding = %s
    +                System.out.charset() = %s
    +                System.console().charset() = %s
    +            """, stdoutEncoding, sysoutCharset.name(), consoleCharset.name());
    +        if (!consoleCharset.equals(sysoutCharset)) {
    +            System.err.printf("Charsets for System.out and Console differ for stdout.encoding: %s%n", stdoutEncoding);
    +            System.exit(-1);
    +        }
         }
     }
    diff --git a/test/jdk/java/io/Console/LocaleTest.java b/test/jdk/java/io/Console/LocaleTest.java
    index 1cab84a9af7..e9a281749b1 100644
    --- a/test/jdk/java/io/Console/LocaleTest.java
    +++ b/test/jdk/java/io/Console/LocaleTest.java
    @@ -21,28 +21,40 @@
      * questions.
      */
     
    -import java.io.File;
     import java.util.Calendar;
     import java.util.GregorianCalendar;
     import java.util.List;
     import java.util.Locale;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +import java.util.function.Predicate;
     
    +import jdk.test.lib.process.OutputAnalyzer;
     import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.api.Test;
    +
    +import static jdk.test.lib.Utils.*;
     
     /**
      * @test
    - * @bug 8330276 8351435
    + * @bug 8330276 8351435 8361613
      * @summary Tests Console methods that have Locale as an argument
    + * @requires (os.family == "linux") | (os.family == "mac")
      * @library /test/lib
    - * @modules jdk.internal.le jdk.localedata
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.JDKToolFinder
    + *        jdk.test.lib.process.ProcessTools
    + * @modules jdk.localedata
    + * @run junit LocaleTest
      */
     public class LocaleTest {
    -    private static Calendar TODAY  = new GregorianCalendar(2024, Calendar.APRIL, 22);
    -    private static String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
    +    private static final Calendar TODAY = new GregorianCalendar(2024, Calendar.APRIL, 22);
    +    private static final String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
         // We want to limit the expected strings within US-ASCII charset, as
         // the native encoding is determined as such, which is used by
         // the `Process` class under jtreg environment.
    -    private static List EXPECTED = List.of(
    +    private static final List EXPECTED = List.of(
             String.format(Locale.UK, FORMAT, TODAY),
             String.format(Locale.FRANCE, FORMAT, TODAY),
             String.format(Locale.GERMANY, FORMAT, TODAY),
    @@ -53,56 +65,61 @@ public class LocaleTest {
             String.format((Locale)null, FORMAT, TODAY)
         );
     
    -    public static void main(String... args) throws Throwable {
    -        if (args.length == 0) {
    -            // no arg will launch the child process that actually perform tests
    -            var pb = ProcessTools.createTestJavaProcessBuilder(
    -                    "-Djdk.console=jdk.internal.le",
    -                    "LocaleTest", "dummy");
    -            var input = new File(System.getProperty("test.src", "."), "input.txt");
    -            pb.redirectInput(input);
    -            var oa = ProcessTools.executeProcess(pb);
    -            if (oa.getExitValue() == -1) {
    -                System.out.println("System.console() returns null. Ignoring the test.");
    -            } else {
    -                var output = oa.asLines();
    -                var resultText =
    -                    """
    -                    Actual output: %s
    -                    Expected output: %s
    -                    """.formatted(output, EXPECTED);
    -                if (!output.equals(EXPECTED)) {
    -                    throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
    -                } else {
    -                    oa.shouldHaveExitValue(0);
    -                    System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
    -                }
    -            }
    -        } else {
    -            var con = System.console();
    -            if (con != null) {
    -                // tests these additional methods that take a Locale
    -                con.format(Locale.UK, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.printf(Locale.FRANCE, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readLine(Locale.GERMANY, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readPassword(Locale.of("es"), FORMAT, TODAY);
    -                con.printf("\n");
    +    @Test
    +    void testLocale() throws Exception {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
     
    -                // tests null locale
    -                con.format((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.printf((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readLine((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readPassword((Locale)null, FORMAT, TODAY);
    -            } else {
    -                // Exit with -1
    -                System.exit(-1);
    -            }
    +        // invoking "expect" command
    +        OutputAnalyzer oa = ProcessTools.executeProcess(
    +            "expect",
    +            "-n",
    +            TEST_SRC + "/locale.exp",
    +            TEST_CLASSES,
    +            TEST_JDK + "/bin/java",
    +            getClass().getName());
    +
    +        var stdout =
    +            oa.stdoutAsLines().stream().filter(Predicate.not(String::isEmpty)).toList();
    +        var resultText =
    +            """
    +            Actual output: %s
    +            Expected output: %s
    +            """.formatted(stdout, EXPECTED);
    +        if (!stdout.equals(EXPECTED)) {
    +            throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
    +        } else {
    +            oa.shouldHaveExitValue(0);
    +            System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
    +        }
    +    }
    +
    +    public static void main(String... args) throws Throwable {
    +        var con = System.console();
    +        if (con != null) {
    +            // tests these additional methods that take a Locale
    +            con.format(Locale.UK, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.printf(Locale.FRANCE, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readLine(Locale.GERMANY, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readPassword(Locale.of("es"), FORMAT, TODAY);
    +            con.printf("\n");
    +
    +            // tests null locale
    +            con.format((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.printf((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readLine((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readPassword((Locale)null, FORMAT, TODAY);
    +        } else {
    +            // Exit with -1
    +            System.exit(-1);
             }
         }
     }
    diff --git a/test/jdk/java/io/Console/ModuleSelectionTest.java b/test/jdk/java/io/Console/ModuleSelectionTest.java
    index d9885699ebf..332acf83fbd 100644
    --- a/test/jdk/java/io/Console/ModuleSelectionTest.java
    +++ b/test/jdk/java/io/Console/ModuleSelectionTest.java
    @@ -23,21 +23,71 @@
     
     /**
      * @test
    - * @bug 8295803 8299689 8351435
    + * @bug 8295803 8299689 8351435 8361613
      * @summary Tests System.console() returns correct Console (or null) from the expected
      *          module.
    - * @modules java.base/java.io:+open
    - * @run main/othervm ModuleSelectionTest java.base
    - * @run main/othervm -Djdk.console=jdk.internal.le ModuleSelectionTest jdk.internal.le
    - * @run main/othervm -Djdk.console=java.base ModuleSelectionTest java.base
    - * @run main/othervm --limit-modules java.base ModuleSelectionTest java.base
    + * @library /test/lib
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.process.ProcessTools
    + * @run junit ModuleSelectionTest
      */
     
     import java.io.Console;
     import java.lang.invoke.MethodHandles;
     import java.lang.invoke.MethodType;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +import java.util.stream.Stream;
    +
    +import jdk.test.lib.process.OutputAnalyzer;
    +import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
    +
    +import static jdk.test.lib.Utils.*;
     
     public class ModuleSelectionTest {
    +    private static Stream options() {
    +        return Stream.of(
    +            Arguments.of("-Djdk.console=foo", "java.base"),
    +            Arguments.of("-Djdk.console=java.base", "java.base"),
    +            Arguments.of("-Djdk.console=jdk.internal.le", "jdk.internal.le"),
    +            Arguments.of("--limit-modules java.base", "java.base")
    +        );
    +    }
    +
    +    @ParameterizedTest
    +    @MethodSource("options")
    +    void testNonTTY(String opts) throws Exception {
    +        opts = opts +
    +            " --add-opens java.base/java.io=ALL-UNNAMED ModuleSelectionTest null";
    +        OutputAnalyzer output = ProcessTools.executeTestJava(opts.split(" "));
    +        output.reportDiagnosticSummary();
    +        output.shouldHaveExitValue(0);
    +    }
    +
    +    @ParameterizedTest
    +    @MethodSource("options")
    +    void testTTY(String opts, String expected) throws Exception {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
    +
    +        opts = "expect -n " + TEST_SRC + "/moduleSelection.exp " +
    +            TEST_CLASSES + " " +
    +            expected + " " +
    +            TEST_JDK + "/bin/java" +
    +            " --add-opens java.base/java.io=ALL-UNNAMED "
    +            + opts;
    +        // invoking "expect" command
    +        OutputAnalyzer output = ProcessTools.executeProcess(opts.split(" "));
    +        output.reportDiagnosticSummary();
    +        output.shouldHaveExitValue(0);
    +    }
    +
         public static void main(String... args) throws Throwable {
             var con = System.console();
             var pc = Class.forName("java.io.ProxyingConsole");
    @@ -49,10 +99,7 @@ public class ModuleSelectionTest {
                     .findGetter(pc, "delegate", jdkc)
                     .invoke(con) : null;
     
    -        var expected = switch (args[0]) {
    -            case "java.base" -> istty ? "java.base" : "null";
    -            default -> args[0];
    -        };
    +        var expected = args[0];
             var actual = con == null ? "null" : impl.getClass().getModule().getName();
     
             if (!actual.equals(expected)) {
    @@ -62,7 +109,7 @@ public class ModuleSelectionTest {
                     Actual: %s
                     """.formatted(expected, actual));
             } else {
    -            System.out.printf("%s is the expected implementation. (tty: %s)\n", impl, istty);
    +            System.out.printf("%s is the expected implementation. (tty: %s)\n", actual, istty);
             }
         }
     }
    diff --git a/test/jdk/java/io/Console/defaultCharset.exp b/test/jdk/java/io/Console/defaultCharset.exp
    new file mode 100644
    index 00000000000..5b1418db28c
    --- /dev/null
    +++ b/test/jdk/java/io/Console/defaultCharset.exp
    @@ -0,0 +1,32 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. 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.
    +#
    +# 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.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set java [lrange $argv 1 1]
    +set stdoutProp [lrange $argv 2 2]
    +set clsname [lrange $argv 3 3]
    +eval spawn $java -classpath $classpath $stdoutProp $clsname
    +expect eof
    +set result [wait]
    +exit [lindex $result 3]
    diff --git a/test/jdk/java/io/Console/locale.exp b/test/jdk/java/io/Console/locale.exp
    new file mode 100644
    index 00000000000..a88ea43feac
    --- /dev/null
    +++ b/test/jdk/java/io/Console/locale.exp
    @@ -0,0 +1,37 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. 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.
    +#
    +# 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.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set java [lrange $argv 1 1]
    +set clsname [lrange $argv 2 2]
    +eval spawn -noecho $java -classpath $classpath $clsname
    +
    +# sends CR 4 times (readLine x 2, readPassword x 2)
    +send "\r"
    +send "\r"
    +send "\r"
    +send "\r"
    +expect eof
    +set result [wait]
    +exit [lindex $result 3]
    diff --git a/test/jdk/java/io/Console/moduleSelection.exp b/test/jdk/java/io/Console/moduleSelection.exp
    new file mode 100644
    index 00000000000..2b44afe72e4
    --- /dev/null
    +++ b/test/jdk/java/io/Console/moduleSelection.exp
    @@ -0,0 +1,30 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. 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.
    +#
    +# 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.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set expected [lrange $argv 1 1]
    +set java [lrange $argv 2 2]
    +set opts [lrange $argv 3 end]
    +eval spawn $java $opts -classpath $classpath ModuleSelectionTest $expected
    +expect eof
    diff --git a/test/jdk/java/lang/IO/IO.java b/test/jdk/java/lang/IO/IO.java
    index dbb83db5f80..2b13657b58e 100644
    --- a/test/jdk/java/lang/IO/IO.java
    +++ b/test/jdk/java/lang/IO/IO.java
    @@ -50,10 +50,9 @@ import static org.junit.jupiter.api.Assertions.*;
     
     /*
      * @test
    - * @bug 8305457 8342936 8351435 8344706
    + * @bug 8305457 8342936 8351435 8344706 8361613
      * @summary java.lang.IO tests
      * @library /test/lib
    - * @modules jdk.internal.le
      * @run junit IO
      */
     @ExtendWith(IO.TimingExtension.class)
    @@ -78,22 +77,6 @@ public class IO {
                 } catch (Exception _) { }
             }
     
    -        /*
    -         * Unlike printTest, which tests a _default_ console that is normally
    -         * jdk.internal.org.jline.JdkConsoleProviderImpl, this test tests
    -         * jdk.internal.io.JdkConsoleImpl. Those console implementations operate
    -         * in different conditions and, thus, are tested separately.
    -         *
    -         * To test jdk.internal.io.JdkConsoleImpl one needs to ensure that both
    -         * conditions are met:
    -         *
    -         *   - a non-existent console provider is requested
    -         *   - isatty is true
    -         *
    -         * To achieve isatty, the test currently uses the EXPECT(1) Unix command,
    -         * which does not work for Windows. Later, a library like pty4j or JPty
    -         * might be used instead of EXPECT, to cover both Unix and Windows.
    -         */
             @ParameterizedTest
             @ValueSource(strings = {"println", "print"})
             public void outputTestInteractive(String mode) throws Exception {
    @@ -102,8 +85,6 @@ public class IO {
                         expect.toString(),
                         Path.of(testSrc, "output.exp").toAbsolutePath().toString(),
                         System.getProperty("test.jdk") + "/bin/java",
    -                    "--enable-preview",
    -                    "-Djdk.console=gibberish",
                         Path.of(testSrc, "Output.java").toAbsolutePath().toString(),
                         mode);
                 assertEquals(0, output.getExitValue());
    @@ -130,7 +111,7 @@ public class IO {
              */
             @ParameterizedTest
             @MethodSource("args")
    -        public void inputTestInteractive(String console, String prompt) throws Exception {
    +        public void inputTestInteractive(String prompt) throws Exception {
                 var testSrc = System.getProperty("test.src", ".");
                 var command = new ArrayList();
                 command.add(expect.toString());
    @@ -138,9 +119,6 @@ public class IO {
                                                                     : "input";
                 command.add(Path.of(testSrc, expectInputName + ".exp").toAbsolutePath().toString());
                 command.add(System.getProperty("test.jdk") + "/bin/java");
    -            command.add("--enable-preview");
    -            if (console != null)
    -                command.add("-Djdk.console=" + console);
                 command.add(Path.of(testSrc, "Input.java").toAbsolutePath().toString());
                 command.add(prompt == null ? "0" : PROMPT_NONE.equals(prompt) ? "2" : "1");
                 command.add(String.valueOf(prompt));
    @@ -152,33 +130,11 @@ public class IO {
             private static final String PROMPT_NONE = "prompt-none";
     
             public static Stream args() {
    -            // cross product: consoles x prompts
    -            return Stream.of("jdk.internal.le", "gibberish").flatMap(console -> Stream.of(null, "?", "%s", PROMPT_NONE)
    -                    .map(prompt -> new String[]{console, prompt}).map(Arguments::of));
    +            // prompts
    +            return Stream.of(null, "?", "%s", PROMPT_NONE).map(Arguments::of);
             }
         }
     
    -    @ParameterizedTest
    -    @ValueSource(strings = {"println", "print"})
    -    public void printTest(String mode) throws Exception {
    -        var file = Path.of(System.getProperty("test.src", "."), "Output.java")
    -                .toAbsolutePath().toString();
    -        var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file, mode);
    -        OutputAnalyzer output = ProcessTools.executeProcess(pb);
    -        assertEquals(0, output.getExitValue());
    -        assertTrue(output.getStderr().isEmpty());
    -        output.reportDiagnosticSummary();
    -        String out = output.getStdout();
    -        // The first half of the output is produced by Console, the second
    -        // half is produced by IO: those halves must match.
    -        // Executing Console and IO in the same VM (as opposed to
    -        // consecutive VM runs, which are cleaner) to be able to compare string
    -        // representation of objects.
    -        assertFalse(out.isBlank());
    -        assertEquals(out.substring(0, out.length() / 2),
    -                out.substring(out.length() / 2));
    -    }
    -
         @Test //JDK-8342936
         public void printlnNoParamsTest() throws Exception {
             var file = Path.of("PrintlnNoParams.java");
    @@ -193,7 +149,7 @@ public class IO {
                         }
                         """);
             }
    -        var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file.toString());
    +        var pb = ProcessTools.createTestJavaProcessBuilder(file.toString());
             OutputAnalyzer output = ProcessTools.executeProcess(pb);
             assertEquals(0, output.getExitValue());
             assertTrue(output.getStderr().isEmpty());
    diff --git a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    index 71590040685..445da167c5f 100644
    --- a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    +++ b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    @@ -23,16 +23,19 @@
     
     /**
      * @test
    - * @bug 8331535 8351435 8347050
    + * @bug 8331535 8351435 8347050 8361613
      * @summary Verify the jdk.internal.le's console provider works properly.
    - * @modules jdk.internal.le
    + * @modules java.base/jdk.internal.io
    + *          jdk.internal.le/jdk.internal.org.jline
      * @library /test/lib
    - * @run main/othervm -Djdk.console=jdk.internal.le JLineConsoleProviderTest
    + * @run main JLineConsoleProviderTest
      */
     
     import java.lang.reflect.Method;
    +import java.nio.charset.StandardCharsets;
     import java.util.Objects;
     
    +import jdk.internal.org.jline.JdkConsoleProviderImpl;
     import jdk.test.lib.process.OutputAnalyzer;
     import jdk.test.lib.process.ProcessTools;
     
    @@ -66,8 +69,13 @@ public class JLineConsoleProviderTest {
                               String input,
                               String expectedOut) throws Exception {
             ProcessBuilder builder =
    -                ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName(),
    -                                                          testName);
    +                ProcessTools.createTestJavaProcessBuilder(
    +                    "--add-exports",
    +                    "java.base/jdk.internal.io=ALL-UNNAMED",
    +                    "--add-exports",
    +                    "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
    +                    ConsoleTest.class.getName(),
    +                    testName);
             OutputAnalyzer output = ProcessTools.executeProcess(builder, input);
     
             output.waitFor();
    @@ -98,16 +106,18 @@ public class JLineConsoleProviderTest {
     
         public static class ConsoleTest {
             public static void main(String... args) {
    +            // directly instantiate JLine JdkConsole, simulating isTTY=true
    +            var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
                 switch (args[0]) {
                     case "testCorrectOutputReadLine" ->
    -                    System.console().readLine("%%s");
    +                    impl.readLine(null, "%%s");
                     case "testCorrectOutputReadPassword" ->
    -                    System.console().readPassword("%%s");
    +                    impl.readPassword(null, "%%s");
                     case "readAndPrint" ->
    -                    System.out.println("'" + System.console().readLine() + "'");
    +                    System.out.println("'" + impl.readLine() + "'");
                     case "readAndPrint2" -> {
    -                    System.out.println("1: '" +System.console().readLine() + "'");
    -                    System.out.println("2: '" + System.console().readLine() + "'");
    +                    System.out.println("1: '" + impl.readLine() + "'");
    +                    System.out.println("2: '" + impl.readLine() + "'");
                     }
                     default -> throw new UnsupportedOperationException(args[0]);
                 }
    diff --git a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    index acf0c848b43..a7533796b7c 100644
    --- a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    +++ b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    @@ -23,15 +23,19 @@
     
     /**
      * @test
    - * @bug 8333086 8344706
    + * @bug 8333086 8344706 8361613
      * @summary Verify the JLine backend is not initialized for simple printing.
    - * @enablePreview
    - * @modules jdk.internal.le/jdk.internal.org.jline.reader
    + * @modules java.base/jdk.internal.io
    + *          jdk.internal.le/jdk.internal.org.jline
    + *          jdk.internal.le/jdk.internal.org.jline.reader
      *          jdk.internal.le/jdk.internal.org.jline.terminal
      * @library /test/lib
      * @run main LazyJdkConsoleProvider
      */
     
    +import java.nio.charset.StandardCharsets;
    +
    +import jdk.internal.org.jline.JdkConsoleProviderImpl;
     import jdk.internal.org.jline.reader.LineReader;
     import jdk.internal.org.jline.terminal.Terminal;
     
    @@ -41,19 +45,18 @@ import jdk.test.lib.process.ProcessTools;
     public class LazyJdkConsoleProvider {
     
         public static void main(String... args) throws Throwable {
    +        // directly instantiate JLine JdkConsole, simulating isTTY=true
             switch (args.length > 0 ? args[0] : "default") {
                 case "write" -> {
    -                System.console().printf("Hello!\n");
    -                System.console().printf("Hello!");
    -                System.console().format("\nHello!\n");
    -                System.console().flush();
    -                IO.println("Hello!");
    -                IO.print("Hello!");
    -            }
    -            case "read" -> System.console().readLine("Hello!");
    -            case "IO-read" -> {
    -                IO.readln("Hello!");
    +                var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
    +                impl.println("Hello!\n");
    +                impl.println("Hello!");
    +                impl.format(null, "\nHello!\n");
    +                impl.flush();
                 }
    +            case "read" -> new JdkConsoleProviderImpl()
    +                .console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8)
    +                .readLine(null, "Hello!");
                 case "default" -> {
                     new LazyJdkConsoleProvider().runTest();
                 }
    @@ -64,14 +67,15 @@ public class LazyJdkConsoleProvider {
             record TestCase(String testKey, String expected, String notExpected) {}
             TestCase[] testCases = new TestCase[] {
                 new TestCase("write", null, Terminal.class.getName()),
    -            new TestCase("read", LineReader.class.getName(), null),
    -            new TestCase("IO-read", null, Terminal.class.getName())
    +            new TestCase("read", LineReader.class.getName(), null)
             };
             for (TestCase tc : testCases) {
                 ProcessBuilder builder =
    -                    ProcessTools.createTestJavaProcessBuilder("--enable-preview",
    -                                                              "-verbose:class",
    -                                                              "-Djdk.console=jdk.internal.le",
    +                    ProcessTools.createTestJavaProcessBuilder("-verbose:class",
    +                                                              "--add-exports",
    +                                                              "java.base/jdk.internal.io=ALL-UNNAMED",
    +                                                              "--add-exports",
    +                                                              "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
                                                                   LazyJdkConsoleProvider.class.getName(),
                                                                   tc.testKey());
                 OutputAnalyzer output = ProcessTools.executeProcess(builder, "");
    diff --git a/test/jdk/jdk/internal/jline/RedirectedStdOut.java b/test/jdk/jdk/internal/jline/RedirectedStdOut.java
    deleted file mode 100644
    index 71419f96c73..00000000000
    --- a/test/jdk/jdk/internal/jline/RedirectedStdOut.java
    +++ /dev/null
    @@ -1,181 +0,0 @@
    -/*
    - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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.
    - *
    - * 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.
    - *
    - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    - * or visit www.oracle.com if you need additional information or have any
    - * questions.
    - */
    -
    -/**
    - * @test
    - * @bug 8330998 8351435
    - * @summary Verify that even if the stdout is redirected java.io.Console will
    - *          use it for writing.
    - * @modules jdk.internal.le
    - * @library /test/lib
    - * @run main RedirectedStdOut runRedirectAllTest
    - * @run main/othervm --enable-native-access=ALL-UNNAMED RedirectedStdOut runRedirectOutOnly
    - */
    -
    -import java.io.ByteArrayOutputStream;
    -import java.io.PrintStream;
    -import java.lang.foreign.Arena;
    -import java.lang.foreign.FunctionDescriptor;
    -import java.lang.foreign.Linker;
    -import java.lang.foreign.MemorySegment;
    -import java.lang.foreign.SymbolLookup;
    -import java.lang.foreign.ValueLayout;
    -import java.lang.invoke.MethodHandle;
    -import java.nio.file.Files;
    -import java.nio.file.Path;
    -import java.util.Objects;
    -import java.util.Optional;
    -
    -import jdk.test.lib.process.OutputAnalyzer;
    -import jdk.test.lib.process.ProcessTools;
    -
    -public class RedirectedStdOut {
    -    private static final String OUTPUT = "Hello!";
    -
    -    public static void main(String... args) throws Throwable {
    -        RedirectedStdOut.class.getDeclaredMethod(args[0])
    -                              .invoke(new RedirectedStdOut());
    -    }
    -
    -    //verify the case where neither stdin/out/err is attached to a terminal,
    -    //this test is weaker, but more reliable:
    -    void runRedirectAllTest() throws Exception {
    -        ProcessBuilder builder =
    -                ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
    -        OutputAnalyzer output = ProcessTools.executeProcess(builder);
    -
    -        output.waitFor();
    -
    -        if (output.getExitValue() != 0) {
    -            throw new AssertionError("Unexpected return value: " + output.getExitValue() +
    -                                     ", actualOut: " + output.getStdout() +
    -                                     ", actualErr: " + output.getStderr());
    -        }
    -
    -        String expectedOut = OUTPUT;
    -        String actualOut = output.getStdout();
    -
    -        if (!Objects.equals(expectedOut, actualOut)) {
    -            throw new AssertionError("Unexpected stdout content. " +
    -                                     "Expected: '" + expectedOut + "'" +
    -                                     ", got: '" + actualOut + "'");
    -        }
    -
    -        String expectedErr = "";
    -        String actualErr = output.getStderr();
    -
    -        if (!Objects.equals(expectedErr, actualErr)) {
    -            throw new AssertionError("Unexpected stderr content. " +
    -                                     "Expected: '" + expectedErr + "'" +
    -                                     ", got: '" + actualErr + "'");
    -        }
    -    }
    -
    -    //verify the case where stdin is attached to a terminal,
    -    //this test allocates pty, and it might be skipped, if the appropriate
    -    //native functions cannot be found
    -    //it also leaves the VM in a broken state (with a pty attached), and so
    -    //should run in a separate VM instance
    -    void runRedirectOutOnly() throws Throwable {
    -        Path stdout = Path.of(".", "stdout.txt").toAbsolutePath();
    -
    -        Files.deleteIfExists(stdout);
    -
    -        Linker linker = Linker.nativeLinker();
    -        SymbolLookup stdlib = linker.defaultLookup();
    -        MemorySegment parent = Arena.global().allocate(ValueLayout.ADDRESS);
    -        MemorySegment child = Arena.global().allocate(ValueLayout.ADDRESS);
    -        Optional openptyAddress = stdlib.find("openpty");
    -
    -        if (openptyAddress.isEmpty()) {
    -            System.out.println("Cannot lookup openpty.");
    -            //does not have forkpty, ignore
    -            return ;
    -        }
    -
    -        Optional loginttyAddress = stdlib.find("login_tty");
    -
    -        if (loginttyAddress.isEmpty()) {
    -            System.out.println("Cannot lookup login_tty.");
    -            //does not have forkpty, ignore
    -            return ;
    -        }
    -
    -        FunctionDescriptor openttyDescriptor =
    -                FunctionDescriptor.of(ValueLayout.JAVA_INT,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS);
    -        MethodHandle forkpty = linker.downcallHandle(openptyAddress.get(),
    -                                                     openttyDescriptor);
    -        int res = (int) forkpty.invoke(parent,
    -                                       child,
    -                                       MemorySegment.NULL,
    -                                       MemorySegment.NULL,
    -                                       MemorySegment.NULL);
    -
    -        if (res != 0) {
    -            throw new AssertionError();
    -        }
    -
    -        //set the current VM's in/out to the terminal:
    -        FunctionDescriptor loginttyDescriptor =
    -                FunctionDescriptor.of(ValueLayout.JAVA_INT,
    -                                      ValueLayout.JAVA_INT);
    -        MethodHandle logintty = linker.downcallHandle(loginttyAddress.get(),
    -                                                      loginttyDescriptor);
    -        logintty.invoke(child.get(ValueLayout.JAVA_INT, 0));
    -
    -        //createTestJavaProcessBuilder logs to (current process') System.out, but
    -        //that may not work since the redirect. Setting System.out to a scratch value:
    -        System.setOut(new PrintStream(new ByteArrayOutputStream()));
    -
    -        ProcessBuilder builder =
    -            ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
    -
    -        builder.inheritIO();
    -        builder.redirectOutput(stdout.toFile());
    -
    -        OutputAnalyzer output = ProcessTools.executeProcess(builder);
    -
    -        output.waitFor();
    -
    -        String expectedOut = OUTPUT;
    -        String actualOut = Files.readString(stdout);
    -
    -        if (!Objects.equals(expectedOut, actualOut)) {
    -            throw new AssertionError("Unexpected stdout content. " +
    -                                     "Expected: '" + expectedOut + "'" +
    -                                     ", got: '" + actualOut + "'");
    -        }
    -    }
    -
    -    public static class ConsoleTest {
    -        public static void main(String... args) {
    -            System.console().printf(OUTPUT);
    -            System.exit(0);
    -        }
    -    }
    -}
    
    From c01b4fc348fff37c502d38ab3bb3385a5a8cff9a Mon Sep 17 00:00:00 2001
    From: Ioi Lam 
    Date: Fri, 22 Aug 2025 20:41:21 +0000
    Subject: [PATCH 193/471] 8365814: Consolidate has_been_archived() and
     has_been_buffered() in ArchiveBuilder
    
    Reviewed-by: kvn, coleenp
    ---
     src/hotspot/share/cds/archiveBuilder.cpp    | 30 ++++++++++++++-------
     src/hotspot/share/cds/archiveBuilder.hpp    |  7 +++--
     src/hotspot/share/cds/archiveHeapWriter.cpp |  2 +-
     src/hotspot/share/cds/archiveUtils.cpp      |  3 +--
     4 files changed, 26 insertions(+), 16 deletions(-)
    
    diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
    index 7f8c7787152..1d054561c76 100644
    --- a/src/hotspot/share/cds/archiveBuilder.cpp
    +++ b/src/hotspot/share/cds/archiveBuilder.cpp
    @@ -748,17 +748,29 @@ void ArchiveBuilder::mark_and_relocate_to_buffered_addr(address* ptr_location) {
     
     bool ArchiveBuilder::has_been_archived(address src_addr) const {
       SourceObjInfo* p = _src_obj_table.get(src_addr);
    -  return (p != nullptr);
    -}
    -
    -bool ArchiveBuilder::has_been_buffered(address src_addr) const {
    -  if (RegeneratedClasses::has_been_regenerated(src_addr) ||
    -      _src_obj_table.get(src_addr) == nullptr ||
    -      get_buffered_addr(src_addr) == nullptr) {
    +  if (p == nullptr) {
    +    // This object has never been seen by ArchiveBuilder
         return false;
    -  } else {
    -    return true;
       }
    +  if (p->buffered_addr() == nullptr) {
    +    // ArchiveBuilder has seen this object, but decided not to archive it. So
    +    // Any reference to this object will be modified to nullptr inside the buffer.
    +    assert(p->follow_mode() == set_to_null, "must be");
    +    return false;
    +  }
    +
    +  DEBUG_ONLY({
    +    // This is a class/method that belongs to one of the "original" classes that
    +    // have been regenerated by lambdaFormInvokers.cpp. We must have archived
    +    // the "regenerated" version of it.
    +    if (RegeneratedClasses::has_been_regenerated(src_addr)) {
    +      address regen_obj = RegeneratedClasses::get_regenerated_object(src_addr);
    +      precond(regen_obj != nullptr && regen_obj != src_addr);
    +      assert(has_been_archived(regen_obj), "must be");
    +      assert(get_buffered_addr(src_addr) == get_buffered_addr(regen_obj), "must be");
    +    }});
    +
    +  return true;
     }
     
     address ArchiveBuilder::get_buffered_addr(address src_addr) const {
    diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp
    index 1efd4045a99..39cc1c1eb8c 100644
    --- a/src/hotspot/share/cds/archiveBuilder.hpp
    +++ b/src/hotspot/share/cds/archiveBuilder.hpp
    @@ -180,6 +180,7 @@ private:
           return _buffered_addr;
         }
         MetaspaceObj::Type msotype() const { return _msotype; }
    +    FollowMode follow_mode() const { return _follow_mode; }
       };
     
       class SourceObjList {
    @@ -443,10 +444,8 @@ public:
       }
     
       bool has_been_archived(address src_addr) const;
    -
    -  bool has_been_buffered(address src_addr) const;
    -  template  bool has_been_buffered(T src_addr) const {
    -    return has_been_buffered((address)src_addr);
    +  template  bool has_been_archived(T src_addr) const {
    +    return has_been_archived((address)src_addr);
       }
     
       address get_buffered_addr(address src_addr) const;
    diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
    index b651da8418b..9c55b71a1b2 100644
    --- a/src/hotspot/share/cds/archiveHeapWriter.cpp
    +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
    @@ -764,7 +764,7 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
           native_ptr = RegeneratedClasses::get_regenerated_object(native_ptr);
         }
     
    -    guarantee(ArchiveBuilder::current()->has_been_buffered((address)native_ptr),
    +    guarantee(ArchiveBuilder::current()->has_been_archived((address)native_ptr),
                   "Metadata %p should have been archived", native_ptr);
     
         address buffered_native_ptr = ArchiveBuilder::current()->get_buffered_addr((address)native_ptr);
    diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
    index 9a92c6a8648..3c900cad035 100644
    --- a/src/hotspot/share/cds/archiveUtils.cpp
    +++ b/src/hotspot/share/cds/archiveUtils.cpp
    @@ -383,8 +383,7 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
     }
     
     bool ArchiveUtils::has_aot_initialized_mirror(InstanceKlass* src_ik) {
    -  if (SystemDictionaryShared::is_excluded_class(src_ik)) {
    -    assert(!ArchiveBuilder::current()->has_been_buffered(src_ik), "sanity");
    +  if (!ArchiveBuilder::current()->has_been_archived(src_ik)) {
         return false;
       }
       return ArchiveBuilder::current()->get_buffered_addr(src_ik)->has_aot_initialized_mirror();
    
    From 603526b55b5e9b6dfc9323d2cdc4a0b4d0f88a49 Mon Sep 17 00:00:00 2001
    From: Phil Race 
    Date: Fri, 22 Aug 2025 20:50:34 +0000
    Subject: [PATCH 194/471] 8364768: JDK javax.imageio ImageWriters do not all
     flush the output stream
    
    Reviewed-by: psadhukhan, azvegint
    ---
     .../imageio/plugins/gif/GIFImageWriter.java   |  1 +
     .../imageio/plugins/tiff/TIFFImageWriter.java |  1 +
     test/jdk/javax/imageio/FlushTest.java         | 76 +++++++++++++++++++
     3 files changed, 78 insertions(+)
     create mode 100644 test/jdk/javax/imageio/FlushTest.java
    
    diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    index 9558991b767..e009e33d8a0 100644
    --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    @@ -734,6 +734,7 @@ public class GIFImageWriter extends ImageWriter {
             if (writeTrailer) {
                 writeTrailer();
             }
    +        stream.flush();
         }
     
         /**
    diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    index e2227ee6b48..d56bc89035b 100644
    --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    @@ -2327,6 +2327,7 @@ public class TIFFImageWriter extends ImageWriter {
             if (abortRequested()) {
                 resetPositions();
             }
    +        stream.flush();
         }
     
         private void writeHeader() throws IOException {
    diff --git a/test/jdk/javax/imageio/FlushTest.java b/test/jdk/javax/imageio/FlushTest.java
    new file mode 100644
    index 00000000000..e342880e65f
    --- /dev/null
    +++ b/test/jdk/javax/imageio/FlushTest.java
    @@ -0,0 +1,76 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. 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.
    + *
    + * 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.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/*
    + * @test
    + * @bug 8364768
    + * @summary Tests that the standard plugins flush the stream after writing a complete image.
    + */
    +
    +import static java.awt.Color.WHITE;
    +import java.awt.Graphics2D;
    +import java.awt.image.BufferedImage;
    +import java.io.IOException;
    +import java.io.ByteArrayOutputStream;
    +import javax.imageio.ImageIO;
    +import javax.imageio.ImageWriter;
    +import javax.imageio.stream.FileCacheImageOutputStream;
    +
    +public class FlushTest {
    +
    +    static final int SZ = 1000;
    +    static BufferedImage bi;
    +    static final String[] FORMATS = { "jpg", "png", "gif", "tiff", "bmp", "wbmp" } ;
    +    static boolean failed = false;
    +
    +    public static void main(String[] args) throws IOException {
    +
    +        bi = new BufferedImage(SZ, SZ, BufferedImage.TYPE_BYTE_BINARY);
    +        Graphics2D g2d = bi.createGraphics();
    +        g2d.setPaint(WHITE);
    +        g2d.fillRect(0, 0, SZ, SZ);
    +
    +        for (String f : FORMATS) {
    +            testWrite(f);
    +        }
    +        if (failed) {
    +           throw new RuntimeException("Stream sizes differ.");
    +        }
    +    }
    +
    +    static void testWrite(String fmt) throws IOException {
    +        ImageWriter iw = ImageIO.getImageWritersBySuffix(fmt).next();
    +        System.out.println(iw);
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        FileCacheImageOutputStream fcs = new FileCacheImageOutputStream(baos, null);
    +        iw.setOutput(fcs);
    +        iw.write(bi);
    +        int sz0 = baos.size();
    +        fcs.close();
    +        int sz1 = baos.size();
    +        System.out.println("fmt=" + fmt + " sizes=" + sz0 + ", " + sz1);
    +        if (sz0 != sz1) {
    +           failed = true;
    +        }
    +    }
    +}
    
    From f28f6189721a86b1a6ad0a19cc38192af55eb45a Mon Sep 17 00:00:00 2001
    From: Cesar Soares Lucas 
    Date: Fri, 22 Aug 2025 21:51:21 +0000
    Subject: [PATCH 195/471] 8356289: Shenandoah: Clean up SATB barrier runtime
     entry points
    
    Reviewed-by: kdnilsen, ysr, wkemper
    ---
     .../shenandoahBarrierSetAssembler_aarch64.cpp  |  6 +++---
     .../shenandoahBarrierSetAssembler_ppc.cpp      |  4 ++--
     .../shenandoahBarrierSetAssembler_riscv.cpp    |  6 +++---
     .../shenandoahBarrierSetAssembler_x86.cpp      |  6 +++---
     src/hotspot/share/code/aotCodeCache.cpp        |  2 +-
     .../shenandoah/c2/shenandoahBarrierSetC2.cpp   | 18 ++++++++----------
     .../shenandoah/c2/shenandoahBarrierSetC2.hpp   |  2 +-
     .../share/gc/shenandoah/shenandoahRuntime.cpp  |  8 ++------
     .../share/gc/shenandoah/shenandoahRuntime.hpp  |  1 -
     9 files changed, 23 insertions(+), 30 deletions(-)
    
    diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    index ed321ca4759..200c4217134 100644
    --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    @@ -172,9 +172,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
     
       if (expand_call) {
         assert(pre_val != c_rarg1, "smashed arg");
    -    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       }
     
       __ pop(saved, sp);
    @@ -753,7 +753,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ bind(runtime);
       __ push_call_clobbered_registers();
       __ load_parameter(0, pre_val);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       __ pop_call_clobbered_registers();
       __ bind(done);
     
    diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    index b7156144d8b..1f1bc7622ed 100644
    --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    @@ -311,7 +311,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm
       }
     
       // Invoke runtime.
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, R16_thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
     
       // Restore to-be-preserved registers.
       if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) {
    @@ -966,7 +966,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ push_frame_reg_args(nbytes_save, R11_tmp1);
     
       // Invoke runtime.
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), R0_pre_val, R16_thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), R0_pre_val);
     
       // Restore to-be-preserved registers.
       __ pop_frame();
    diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    index 4c1056e75a5..f1236bc183a 100644
    --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    @@ -172,9 +172,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
       // expand_call should be passed true.
       if (expand_call) {
         assert(pre_val != c_rarg1, "smashed arg");
    -    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       }
     
       __ pop_reg(saved, sp);
    @@ -702,7 +702,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ bind(runtime);
       __ push_call_clobbered_registers();
       __ load_parameter(0, pre_val);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       __ pop_call_clobbered_registers();
       __ bind(done);
     
    diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    index d043c8af68a..9e321391f6c 100644
    --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    @@ -276,9 +276,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
           __ mov(c_rarg1, thread);
         }
         // Already moved pre_val into c_rarg0 above
    -    __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2);
    +    __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), 1);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), c_rarg0, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0);
       }
     
       // save the live input values
    @@ -946,7 +946,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
     
       // load the pre-value
       __ load_parameter(0, rcx);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), rcx, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), rcx);
     
       __ restore_live_registers(true);
     
    diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp
    index df2e9648b84..7e53f493c47 100644
    --- a/src/hotspot/share/code/aotCodeCache.cpp
    +++ b/src/hotspot/share/code/aotCodeCache.cpp
    @@ -1369,7 +1369,7 @@ void AOTCodeAddressTable::init_extrs() {
       SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_pre_entry);
     #endif
     #if INCLUDE_SHENANDOAHGC
    -  SET_ADDRESS(_extrs, ShenandoahRuntime::write_ref_field_pre);
    +  SET_ADDRESS(_extrs, ShenandoahRuntime::write_barrier_pre);
       SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom);
       SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow);
     #endif
    diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    index f12b3dc5fa8..fdfde866cd7 100644
    --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    @@ -250,9 +250,8 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit,
           } __ else_(); {
     
             // logging buffer is full, call the runtime
    -        const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_Type();
    -        __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), "shenandoah_wb_pre",
    -                          pre_val, tls);
    +        const TypeFunc *tf = ShenandoahBarrierSetC2::write_barrier_pre_Type();
    +        __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), "shenandoah_wb_pre", pre_val);
           } __ end_if();  // (!index)
         } __ end_if();  // (pre_val != nullptr)
       } __ end_if();  // (!marking)
    @@ -270,7 +269,7 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit,
     
     bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) {
       return call->is_CallLeaf() &&
    -         call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre);
    +         call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre);
     }
     
     bool ShenandoahBarrierSetC2::is_shenandoah_clone_call(Node* call) {
    @@ -520,11 +519,10 @@ void ShenandoahBarrierSetC2::post_barrier(GraphKit* kit,
     
     #undef __
     
    -const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_Type() {
    -  const Type **fields = TypeTuple::fields(2);
    +const TypeFunc* ShenandoahBarrierSetC2::write_barrier_pre_Type() {
    +  const Type **fields = TypeTuple::fields(1);
       fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
    -  fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread
    -  const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields);
    +  const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
     
       // create result type (range)
       fields = TypeTuple::fields(0);
    @@ -1108,7 +1106,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p
     
     Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const {
       if (is_shenandoah_wb_pre_call(n)) {
    -    uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt();
    +    uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt();
         if (n->req() > cnt) {
           Node* addp = n->in(cnt);
           if (has_only_shenandoah_wb_pre_uses(addp)) {
    @@ -1194,7 +1192,7 @@ bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, ui
           assert (n->is_Call(), "");
           CallNode *call = n->as_Call();
           if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) {
    -        uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt();
    +        uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt();
             if (call->req() > cnt) {
               assert(call->req() == cnt + 1, "only one extra input");
               Node *addp = call->in(cnt);
    diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    index 5bf549203ea..dd9e9bcc1a5 100644
    --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    @@ -103,7 +103,7 @@ public:
     
       ShenandoahBarrierSetC2State* state() const;
     
    -  static const TypeFunc* write_ref_field_pre_Type();
    +  static const TypeFunc* write_barrier_pre_Type();
       static const TypeFunc* clone_barrier_Type();
       static const TypeFunc* load_reference_barrier_Type();
       virtual bool has_load_barrier_nodes() const { return true; }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    index 97ba5012efa..0bee8b4cf42 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    @@ -38,20 +38,16 @@ JRT_LEAF(void, ShenandoahRuntime::arraycopy_barrier_narrow_oop(narrowOop* src, n
       ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length);
     JRT_END
     
    -JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre(oopDesc * orig, JavaThread * thread))
    -  assert(thread == JavaThread::current(), "pre-condition");
    +JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre(oopDesc* orig))
       assert(orig != nullptr, "should be optimized out");
       shenandoah_assert_correct(nullptr, orig);
       // Capture the original value that was in the field reference.
    +  JavaThread* thread = JavaThread::current();
       assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_active(), "Shouldn't be here otherwise");
       SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread);
       ShenandoahBarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig);
     JRT_END
     
    -void ShenandoahRuntime::write_barrier_pre(oopDesc* orig) {
    -  write_ref_field_pre(orig, JavaThread::current());
    -}
    -
     JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong(oopDesc* src, oop* load_addr))
       return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr);
     JRT_END
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    index 0ed8959d95e..f1919095d58 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    @@ -36,7 +36,6 @@ public:
       static void arraycopy_barrier_oop(oop* src, oop* dst, size_t length);
       static void arraycopy_barrier_narrow_oop(narrowOop* src, narrowOop* dst, size_t length);
     
    -  static void write_ref_field_pre(oopDesc* orig, JavaThread* thread);
       static void write_barrier_pre(oopDesc* orig);
     
       static oopDesc* load_reference_barrier_strong(oopDesc* src, oop* load_addr);
    
    From 7b9969dc8f20989497ff617abb45543d182b684d Mon Sep 17 00:00:00 2001
    From: Alexander Matveev 
    Date: Fri, 22 Aug 2025 22:24:39 +0000
    Subject: [PATCH 196/471] 8356218: [macos] Document --app-content
    
    Reviewed-by: asemenyuk
    ---
     .../internal/MacApplicationBuilder.java       | 20 ++++++++++++++++
     .../resources/MacResources.properties         |  2 ++
     .../jdk/jpackage/internal/CLIHelp.java        | 10 ++++++--
     .../resources/HelpResources.properties        | 11 +++++++--
     src/jdk.jpackage/share/man/jpackage.md        |  6 +++++
     .../jdk/jpackage/test/JPackageCommand.java    | 24 +++++++++++++++----
     .../tools/jpackage/share/AppContentTest.java  | 16 ++++++++++++-
     7 files changed, 80 insertions(+), 9 deletions(-)
    
    diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    index fc1dd97d9ab..226bb9e8134 100644
    --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    @@ -26,7 +26,10 @@ package jdk.jpackage.internal;
     
     import java.io.IOException;
     import java.io.UncheckedIOException;
    +import java.nio.file.Files;
     import java.nio.file.Path;
    +import java.util.List;
    +import java.util.Set;
     import java.util.Objects;
     import java.util.Optional;
     import jdk.jpackage.internal.model.Application;
    @@ -95,6 +98,7 @@ final class MacApplicationBuilder {
             }
     
             validateAppVersion(app);
    +        validateAppContentDirs(app);
     
             final var mixin = new MacApplicationMixin.Stub(
                     validatedIcon(),
    @@ -140,6 +144,18 @@ final class MacApplicationBuilder {
             }
         }
     
    +    private static void validateAppContentDirs(Application app) {
    +        for (var contentDir : app.contentDirs()) {
    +            if (!Files.isDirectory(contentDir)) {
    +                Log.info(I18N.format("warning.app.content.is.not.dir",
    +                        contentDir));
    +            } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName().toString())) {
    +                Log.info(I18N.format("warning.non.standard.contents.sub.dir",
    +                        contentDir));
    +            }
    +        }
    +    }
    +
         private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws ConfigException {
             try {
                 final var plistFile = AppImageInfoPListFile.loadFromInfoPList(externalInfoPlistFile);
    @@ -250,4 +266,8 @@ final class MacApplicationBuilder {
         private static final Defaults DEFAULTS = new Defaults("utilities");
     
         private static final int MAX_BUNDLE_NAME_LENGTH = 16;
    +
    +    // List of standard subdirectories of the "Contents" directory
    +    private static final Set CONTENTS_SUB_DIRS = Set.of("MacOS",
    +            "Resources", "Frameworks", "PlugIns", "SharedSupport");
     }
    diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    index 7fada9e4305..c48513c7a51 100644
    --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    @@ -85,3 +85,5 @@ message.codesign.failed.reason.app.content="codesign" failed and additional appl
     message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem.
     warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}.
     warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
    +warning.non.standard.contents.sub.dir=Warning: The file name of the directory "{0}" specified for the --app-content option is not a standard subdirectory name in the "Contents" directory of the application bundle. The result application bundle may fail code signing and/or notarization.
    +warning.app.content.is.not.dir=Warning: The value "{0}" of the --app-content option is not a directory. The result application bundle may fail code signing and/or notarization.
    \ No newline at end of file
    diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    index 1dd2d823f27..7790ebb3ebb 100644
    --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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
    @@ -55,6 +55,7 @@ public class CLIHelp {
                 String pInstallDir;
                 String pAppImageDescription;
                 String pSignSampleUsage;
    +            String pAppContentNote;
                 switch (platform) {
                     case MACOS:
                         types = "{\"app-image\", \"dmg\", \"pkg\"}";
    @@ -66,6 +67,8 @@ public class CLIHelp {
                                 = I18N.getString("MSG_Help_mac_app_image");
                         pSignSampleUsage
                                 = I18N.getString("MSG_Help_mac_sign_sample_usage");
    +                    pAppContentNote
    +                            = I18N.getString("MSG_Help_mac_app_content_note");
                         break;
                     case LINUX:
                         types = "{\"app-image\", \"rpm\", \"deb\"}";
    @@ -76,6 +79,7 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                     case WINDOWS:
                         types = "{\"app-image\", \"exe\", \"msi\"}";
    @@ -86,6 +90,7 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                     default:
                         types = "{\"app-image\", \"exe\", \"msi\", \"rpm\", \"deb\", \"pkg\", \"dmg\"}";
    @@ -99,12 +104,13 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                 }
                 Log.info(MessageFormat.format(I18N.getString("MSG_Help"),
                         File.pathSeparator, types, pLaunchOptions,
                         pInstallOptions, pInstallDir, pAppImageDescription,
    -                    pSignSampleUsage));
    +                    pSignSampleUsage, pAppContentNote));
             }
         }
     }
    diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    index 0f0d9fd5a17..df87a63cb8e 100644
    --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    @@ -1,5 +1,5 @@
     #
    -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
    +# Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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
    @@ -133,7 +133,7 @@ Generic Options:\n\
     \          A comma separated list of paths to files and/or directories\n\
     \          to add to the application payload.\n\
     \          This option can be used more than once.\n\
    -\n\
    +{7}\n\
     \Options for creating the application launcher(s):\n\
     \  --add-launcher =\n\
     \          Name of launcher, and a path to a Properties file that contains\n\
    @@ -334,3 +334,10 @@ MSG_Help_mac_sign_sample_usage=\
     \            --mac-sign [...]\n\
     \        Note: the only additional options that are permitted in this mode are:\n\
     \              the set of additional mac signing options and --verbose\n\
    +
    +MSG_Help_mac_app_content_note=\
    +\          Note: The value should be a directory with the "Resources"\n\
    +\          subdirectory (or any other directory that is valid in the "Contents"\n\
    +\          directory of the application bundle). Otherwise, jpackage may produce\n\
    +\          invalid application bundle which may fail code signing and/or\n\
    +\          notarization.\n\
    diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md
    index e49b04e204e..f78bec9808c 100644
    --- a/src/jdk.jpackage/share/man/jpackage.md
    +++ b/src/jdk.jpackage/share/man/jpackage.md
    @@ -190,6 +190,12 @@ The `jpackage` tool will take as input a Java application and a Java run-time im
     
         This option can be used more than once.
     
    +    macOS note: The value should be a directory with the "Resources"
    +                subdirectory (or any other directory that is valid in the
    +                "Contents" directory of the application bundle). Otherwise,
    +                jpackage may produce invalid application bundle which may fail
    +                code signing and/or notarization.
    +
     ### Options for creating the application launcher(s):
     
     
    diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    index 3a423fd71ca..49f565e27e9 100644
    --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    @@ -46,6 +46,7 @@ import java.util.ListIterator;
     import java.util.Map;
     import java.util.Objects;
     import java.util.Optional;
    +import java.util.OptionalInt;
     import java.util.Set;
     import java.util.function.Consumer;
     import java.util.function.Function;
    @@ -811,11 +812,19 @@ public class JPackageCommand extends CommandArguments {
             return exec;
         }
     
    +    public Executor.Result executeIgnoreExitCode() {
    +        return execute(OptionalInt.empty());
    +    }
    +
         public Executor.Result execute() {
             return execute(0);
         }
     
         public Executor.Result execute(int expectedExitCode) {
    +        return execute(OptionalInt.of(expectedExitCode));
    +    }
    +
    +    private Executor.Result execute(OptionalInt expectedExitCode) {
             verifyMutable();
             executePrerequisiteActions();
     
    @@ -852,7 +861,8 @@ public class JPackageCommand extends CommandArguments {
                 }
             }
     
    -        if (expectedExitCode == 0 && !isImagePackageType()) {
    +        if (expectedExitCode.isPresent() && expectedExitCode.orElseThrow() == 0
    +                && !isImagePackageType()) {
                 ConfigFilesStasher.INSTANCE.accept(this);
             }
     
    @@ -860,11 +870,17 @@ public class JPackageCommand extends CommandArguments {
     
             final var directoriesAssert = new ReadOnlyPathsAssert(copy);
     
    -        Executor.Result result = copy.createExecutor().execute(expectedExitCode);
    +        Executor.Result result;
    +        if (expectedExitCode.isEmpty()) {
    +            result = copy.createExecutor().executeWithoutExitCodeCheck();
    +        } else {
    +            result = copy.createExecutor().execute(expectedExitCode.orElseThrow());
    +        }
     
             directoriesAssert.updateAndAssert();
     
    -        if (expectedExitCode == 0 && isImagePackageType()) {
    +        if (expectedExitCode.isPresent() && expectedExitCode.orElseThrow() == 0
    +                && isImagePackageType()) {
                 ConfigFilesStasher.INSTANCE.accept(this);
             }
     
    @@ -872,7 +888,7 @@ public class JPackageCommand extends CommandArguments {
                 outputValidator.accept(result.getOutput().iterator());
             }
     
    -        if (result.exitCode() == 0) {
    +        if (result.exitCode() == 0 && expectedExitCode.isPresent()) {
                 verifyActions.run();
             }
     
    diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java
    index 15b61763562..edb7e2918da 100644
    --- a/test/jdk/tools/jpackage/share/AppContentTest.java
    +++ b/test/jdk/tools/jpackage/share/AppContentTest.java
    @@ -33,12 +33,12 @@ import jdk.jpackage.test.TKit;
     import jdk.jpackage.test.Annotations.Test;
     import jdk.jpackage.test.Annotations.Parameter;
     import java.util.Arrays;
    -import java.util.Collection;
     import java.util.List;
     import java.util.stream.Stream;
     import jdk.jpackage.internal.util.FileUtils;
     import jdk.jpackage.internal.util.function.ThrowingFunction;
     import jdk.jpackage.test.JPackageCommand;
    +import jdk.jpackage.test.JPackageStringBundle;
     
     
     /**
    @@ -116,6 +116,20 @@ public class AppContentTest {
                 .run();
         }
     
    +    @Test(ifOS = MACOS)
    +    @Parameter({TEST_DIR, "warning.non.standard.contents.sub.dir"})
    +    @Parameter({TEST_DUKE, "warning.app.content.is.not.dir"})
    +    public void testWarnings(String testPath, String warningId) throws Exception {
    +        final var appContentValue = TKit.TEST_SRC_ROOT.resolve(testPath);
    +        final var expectedWarning = JPackageStringBundle.MAIN.cannedFormattedString(
    +                warningId, appContentValue);
    +
    +        JPackageCommand.helloAppImage()
    +            .addArguments("--app-content", appContentValue)
    +            .validateOutput(expectedWarning)
    +            .executeIgnoreExitCode();
    +    }
    +
         private static Path getAppContentRoot(JPackageCommand cmd) {
             Path contentDir = cmd.appLayout().contentDirectory();
             if (copyInResources) {
    
    From 09aad0aea8b9f9fda14c5b18ae67b30ffce817d9 Mon Sep 17 00:00:00 2001
    From: SendaoYan 
    Date: Sat, 23 Aug 2025 02:43:23 +0000
    Subject: [PATCH 197/471] 8365834: Mark java/net/httpclient/ManyRequests.java 
     as intermittent
    
    Reviewed-by: jpai
    ---
     test/jdk/java/net/httpclient/ManyRequests.java | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java
    index 5d698d60ee5..493c2c3a504 100644
    --- a/test/jdk/java/net/httpclient/ManyRequests.java
    +++ b/test/jdk/java/net/httpclient/ManyRequests.java
    @@ -24,6 +24,7 @@
     /*
      * @test
      * @bug 8087112 8180044 8256459
    + * @key intermittent
      * @modules java.net.http
      *          java.logging
      *          jdk.httpserver
    
    From 58e7581527208dfd6dd694793e4790dcad8fc3ef Mon Sep 17 00:00:00 2001
    From: Alan Bateman 
    Date: Sun, 24 Aug 2025 16:22:21 +0000
    Subject: [PATCH 198/471] 8365893:
     test/jdk/java/lang/Thread/virtual/JfrEvents.java failing intermittently
    
    Reviewed-by: jpai
    ---
     test/jdk/java/lang/Thread/virtual/JfrEvents.java | 12 +++++++-----
     1 file changed, 7 insertions(+), 5 deletions(-)
    
    diff --git a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    index 0b0c2ccc7a0..0c967811481 100644
    --- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    +++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    @@ -42,6 +42,7 @@ import java.util.concurrent.ThreadFactory;
     import java.util.concurrent.atomic.AtomicBoolean;
     import java.util.concurrent.locks.LockSupport;
     import java.util.stream.Collectors;
    +import java.util.stream.IntStream;
     import java.util.stream.Stream;
     
     import jdk.jfr.EventType;
    @@ -77,12 +78,13 @@ class JfrEvents {
     
                 // execute 100 tasks, each in their own virtual thread
                 recording.start();
    -            ThreadFactory factory = Thread.ofVirtual().factory();
    -            try (var executor = Executors.newThreadPerTaskExecutor(factory)) {
    -                for (int i = 0; i < 100; i++) {
    -                    executor.submit(() -> { });
    +            try {
    +                List threads = IntStream.range(0, 100)
    +                        .mapToObj(_ -> Thread.startVirtualThread(() -> { }))
    +                        .toList();
    +                for (Thread t : threads) {
    +                    t.join();
                     }
    -                Thread.sleep(1000); // give time for thread end events to be recorded
                 } finally {
                     recording.stop();
                 }
    
    From 15601b4718ed26de6f57e633c4f41f6b0cd90cb0 Mon Sep 17 00:00:00 2001
    From: Ioi Lam 
    Date: Mon, 25 Aug 2025 04:01:00 +0000
    Subject: [PATCH 199/471] 8366029: Do not add -XX:VerifyArchivedFields by
     default to CDS tests
    
    Reviewed-by: kvn
    ---
     .../jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java      | 3 ++-
     test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java         | 4 +---
     test/lib/jdk/test/lib/cds/CDSAppTester.java                   | 2 --
     test/lib/jdk/test/lib/cds/CDSTestUtils.java                   | 1 -
     4 files changed, 3 insertions(+), 7 deletions(-)
    
    diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    index 6267c6bdf33..3c3db7d0397 100644
    --- a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    +++ b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    @@ -120,9 +120,9 @@ public class LotsOfSyntheticClasses {
                 OutputAnalyzer output = TestCommon.createArchive(
                     APP_JAR.toString(),
                     listAppClasses(),
    -                MAIN_CLASS_NAME,
                     // Verification for lots of classes slows down the test.
                     "-XX:+IgnoreUnrecognizedVMOptions",
    +                "-XX:+UnlockDiagnosticVMOptions",
                     "-XX:-VerifyDependencies",
                     "-XX:-VerifyBeforeExit"
                 );
    @@ -134,6 +134,7 @@ public class LotsOfSyntheticClasses {
                 TestCommon.run(
                     // Verification for lots of classes slows down the test.
                     "-XX:+IgnoreUnrecognizedVMOptions",
    +                "-XX:+UnlockDiagnosticVMOptions",
                     "-XX:-VerifyDependencies",
                     "-XX:-VerifyBeforeExit",
                     "-cp", APP_JAR.toString(),
    diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    index 4f2822a5970..5d1e3831d86 100644
    --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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
    @@ -427,8 +427,6 @@ public class TestCommon extends CDSTestUtils {
                 cmd.add(opts.appJar);
             }
     
    -        CDSTestUtils.addVerifyArchivedFields(cmd);
    -
             for (String s : opts.suffix) cmd.add(s);
     
             if (RUN_WITH_JFR) {
    diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java
    index cfe17a0be14..fd244c6acc6 100644
    --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java
    +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java
    @@ -402,8 +402,6 @@ abstract public class CDSAppTester {
         public OutputAnalyzer productionRun(String[] extraVmArgs, String[] extraAppArgs) throws Exception {
             RunMode runMode = RunMode.PRODUCTION;
             String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
    -                                                   "-XX:+UnlockDiagnosticVMOptions",
    -                                                   "-XX:VerifyArchivedFields=2", // make sure archived heap objects are good.
                                                        logToFile(productionRunLog(), "aot", "cds"));
             cmdLine = addCommonVMArgs(runMode, cmdLine);
     
    diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    index be6fddc17aa..56e3baa2e25 100644
    --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    @@ -440,7 +440,6 @@ public class CDSTestUtils {
                     opts.archiveName = getDefaultArchiveName();
                 cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
             }
    -        addVerifyArchivedFields(cmd);
     
             if (opts.useVersion)
                 cmd.add("-version");
    
    From 0b8ae260282dbb1fa1e8ce9d14f06f353327e03c Mon Sep 17 00:00:00 2001
    From: Fredrik Bredberg 
    Date: Mon, 25 Aug 2025 06:47:57 +0000
    Subject: [PATCH 200/471] 8365189: Remove LockingMode related code from arm32
    
    Reviewed-by: aboldtch, coleenp
    ---
     src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp   |   8 +-
     src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp |  94 ++-------
     src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp |  66 +-----
     src/hotspot/cpu/arm/interp_masm_arm.cpp       | 191 +++++-------------
     src/hotspot/cpu/arm/macroAssembler_arm.cpp    |   2 -
     src/hotspot/cpu/arm/sharedRuntime_arm.cpp     |  55 +----
     6 files changed, 74 insertions(+), 342 deletions(-)
    
    diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    index 6a859a5875b..c3b91e8c76f 100644
    --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    @@ -2426,13 +2426,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
       Register hdr = op->hdr_opr()->as_pointer_register();
       Register lock = op->lock_opr()->as_pointer_register();
     
    -  if (LockingMode == LM_MONITOR) {
    -    if (op->info() != nullptr) {
    -      add_debug_info_for_null_check_here(op->info());
    -      __ null_check(obj);
    -    }
    -    __ b(*op->stub()->entry());
    -  } else if (op->code() == lir_lock) {
    +  if (op->code() == lir_lock) {
         assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
         int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry());
         if (op->info() != nullptr) {
    diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    index 195607d5c91..f2b08269750 100644
    --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    @@ -177,18 +177,16 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len,
     }
     
     int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
    -  Label done, fast_lock, fast_lock_done;
       int null_check_offset = 0;
     
       const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level
       assert_different_registers(hdr, obj, disp_hdr, tmp2);
     
       assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
    -  const ByteSize obj_offset = BasicObjectLock::obj_offset();
    -  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
    +  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
     
       // save object being locked into the BasicObjectLock
    -  str(obj, Address(disp_hdr, obj_offset));
    +  str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
     
       null_check_offset = offset();
     
    @@ -199,95 +197,29 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
         b(slow_case, ne);
       }
     
    -  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
    -
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    -
    -    Register t1 = disp_hdr; // Needs saving, probably
    -    Register t2 = hdr;      // blow
    -    Register t3 = Rtemp;    // blow
    -
    -    lightweight_lock(obj /* obj */, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    -    // Success: fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -    // That would be acceptable as ether CAS or slow case path is taken in that case.
    -
    -    // Must be the first instruction here, because implicit null check relies on it
    -    ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
    -
    -    tst(hdr, markWord::unlocked_value);
    -    b(fast_lock, ne);
    -
    -    // Check for recursive locking
    -    // See comments in InterpreterMacroAssembler::lock_object for
    -    // explanations on the fast recursive locking check.
    -    // -1- test low 2 bits
    -    movs(tmp2, AsmOperand(hdr, lsl, 30));
    -    // -2- test (hdr - SP) if the low two bits are 0
    -    sub(tmp2, hdr, SP, eq);
    -    movs(tmp2, AsmOperand(tmp2, lsr, exact_log2(os::vm_page_size())), eq);
    -    // If still 'eq' then recursive locking OK
    -    // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8267042)
    -    str(tmp2, Address(disp_hdr, mark_offset));
    -    b(fast_lock_done, eq);
    -    // else need slow case
    -    b(slow_case);
    -
    -
    -    bind(fast_lock);
    -    // Save previous object header in BasicLock structure and update the header
    -    str(hdr, Address(disp_hdr, mark_offset));
    -
    -    cas_for_lock_acquire(hdr, disp_hdr, obj, tmp2, slow_case);
    -
    -    bind(fast_lock_done);
    -  }
    -  bind(done);
    +  Register t1 = disp_hdr; // Needs saving, probably
    +  Register t2 = hdr;      // blow
    +  Register t3 = Rtemp;    // blow
     
    +  lightweight_lock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    +  // Success: fall through
       return null_check_offset;
     }
     
     void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
       assert_different_registers(hdr, obj, disp_hdr, Rtemp);
    -  Register tmp2 = Rtemp;
     
       assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
    -  const ByteSize obj_offset = BasicObjectLock::obj_offset();
    -  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
    -
    -  Label done;
    -
       assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    +  ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
     
    -    ldr(obj, Address(disp_hdr, obj_offset));
    +  Register t1 = disp_hdr; // Needs saving, probably
    +  Register t2 = hdr;      // blow
    +  Register t3 = Rtemp;    // blow
     
    -    Register t1 = disp_hdr; // Needs saving, probably
    -    Register t2 = hdr;      // blow
    -    Register t3 = Rtemp;    // blow
    -
    -    lightweight_unlock(obj /* object */, t1, t2, t3, 1 /* savemask (save t1) */,
    -                       slow_case);
    -    // Success: Fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    // Load displaced header and object from the lock
    -    ldr(hdr, Address(disp_hdr, mark_offset));
    -    // If hdr is null, we've got recursive locking and there's nothing more to do
    -    cbz(hdr, done);
    -
    -    // load object
    -    ldr(obj, Address(disp_hdr, obj_offset));
    -
    -    // Restore the object header
    -    cas_for_lock_release(disp_hdr, hdr, obj, tmp2, slow_case);
    -  }
    -  bind(done);
    +  lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    +  // Success: fall through
     }
     
     #ifndef PRODUCT
    diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    index 89be6d288ff..2d26b4f9a50 100644
    --- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    @@ -81,7 +81,7 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
       assert(VM_Version::supports_ldrex(), "unsupported, yet?");
       assert_different_registers(Roop, Rbox, Rscratch, Rscratch2);
     
    -  Label fast_lock, done;
    +  Label done;
     
       if (DiagnoseSyncOnValueBasedClasses != 0) {
         load_klass(Rscratch, Roop);
    @@ -90,43 +90,10 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
         b(done, ne);
       }
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    -
    -    lightweight_lock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    -                     1 /* savemask (save t1) */, done);
    -
    -    // Success: set Z
    -    cmp(Roop, Roop);
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    Register Rmark      = Rscratch2;
    -
    -    ldr(Rmark, Address(Roop, oopDesc::mark_offset_in_bytes()));
    -    tst(Rmark, markWord::unlocked_value);
    -    b(fast_lock, ne);
    -
    -    // Check for recursive lock
    -    // See comments in InterpreterMacroAssembler::lock_object for
    -    // explanations on the fast recursive locking check.
    -    // -1- test low 2 bits
    -    movs(Rscratch, AsmOperand(Rmark, lsl, 30));
    -    // -2- test (hdr - SP) if the low two bits are 0
    -    sub(Rscratch, Rmark, SP, eq);
    -    movs(Rscratch, AsmOperand(Rscratch, lsr, exact_log2(os::vm_page_size())), eq);
    -    // If still 'eq' then recursive locking OK
    -    // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8153107)
    -    str(Rscratch, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -    b(done);
    -
    -    bind(fast_lock);
    -    str(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -
    -    bool allow_fallthrough_on_failure = true;
    -    bool one_shot = true;
    -    cas_for_lock_acquire(Rmark, Rbox, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
    -  }
    +  lightweight_lock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    +                   1 /* savemask (save t1) */, done);
     
    +  cmp(Roop, Roop); // Success: set Z
       bind(done);
     
       // At this point flags are set as follows:
    @@ -140,29 +107,12 @@ void C2_MacroAssembler::fast_unlock(Register Roop, Register Rbox, Register Rscra
     
       Label done;
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    +  lightweight_unlock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    +                     1 /* savemask (save t1) */, done);
     
    -    lightweight_unlock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    -                       1 /* savemask (save t1) */, done);
    +  cmp(Roop, Roop); // Success: Set Z
    +  // Fall through
     
    -    cmp(Roop, Roop); // Success: Set Z
    -    // Fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    Register Rmark      = Rscratch2;
    -
    -    // Find the lock address and load the displaced header from the stack.
    -    ldr(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -    // If hdr is null, we've got recursive locking and there's nothing more to do
    -    cmp(Rmark, 0);
    -    b(done, eq);
    -
    -    // Restore the object header
    -    bool allow_fallthrough_on_failure = true;
    -    bool one_shot = true;
    -    cas_for_lock_release(Rbox, Rmark, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
    -  }
       bind(done);
     
       // At this point flags are set as follows:
    diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    index e9e6187a6d1..3f9130309e9 100644
    --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp
    +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    @@ -888,105 +888,30 @@ void InterpreterMacroAssembler::set_do_not_unlock_if_synchronized(bool flag, Reg
     void InterpreterMacroAssembler::lock_object(Register Rlock) {
       assert(Rlock == R1, "the second argument");
     
    -  if (LockingMode == LM_MONITOR) {
    -    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    -  } else {
    -    Label done;
    +  const Register Robj = R2;
    +  const Register Rmark = R3;
    +  assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
     
    -    const Register Robj = R2;
    -    const Register Rmark = R3;
    -    assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
    +  Label done, slow_case;
     
    -    const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    -    const int lock_offset = in_bytes(BasicObjectLock::lock_offset());
    -    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
    +  // Load object pointer
    +  ldr(Robj, Address(Rlock, BasicObjectLock::obj_offset()));
     
    -    Label already_locked, slow_case;
    -
    -    // Load object pointer
    -    ldr(Robj, Address(Rlock, obj_offset));
    -
    -    if (DiagnoseSyncOnValueBasedClasses != 0) {
    -      load_klass(R0, Robj);
    -      ldrb(R0, Address(R0, Klass::misc_flags_offset()));
    -      tst(R0, KlassFlags::_misc_is_value_based_class);
    -      b(slow_case, ne);
    -    }
    -
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      lightweight_lock(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case);
    -      b(done);
    -    } else if (LockingMode == LM_LEGACY) {
    -      // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -      // That would be acceptable as ether CAS or slow case path is taken in that case.
    -      // Exception to that is if the object is locked by the calling thread, then the recursive test will pass (guaranteed as
    -      // loads are satisfied from a store queue if performed on the same processor).
    -
    -      assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
    -      ldr(Rmark, Address(Robj, oopDesc::mark_offset_in_bytes()));
    -
    -      // Test if object is already locked
    -      tst(Rmark, markWord::unlocked_value);
    -      b(already_locked, eq);
    -
    -      // Save old object->mark() into BasicLock's displaced header
    -      str(Rmark, Address(Rlock, mark_offset));
    -
    -      cas_for_lock_acquire(Rmark, Rlock, Robj, Rtemp, slow_case);
    -
    -      b(done);
    -
    -      // If we got here that means the object is locked by ether calling thread or another thread.
    -      bind(already_locked);
    -      // Handling of locked objects: recursive locks and slow case.
    -
    -      // Fast check for recursive lock.
    -      //
    -      // Can apply the optimization only if this is a stack lock
    -      // allocated in this thread. For efficiency, we can focus on
    -      // recently allocated stack locks (instead of reading the stack
    -      // base and checking whether 'mark' points inside the current
    -      // thread stack):
    -      //  1) (mark & 3) == 0
    -      //  2) SP <= mark < SP + os::pagesize()
    -      //
    -      // Warning: SP + os::pagesize can overflow the stack base. We must
    -      // neither apply the optimization for an inflated lock allocated
    -      // just above the thread stack (this is why condition 1 matters)
    -      // nor apply the optimization if the stack lock is inside the stack
    -      // of another thread. The latter is avoided even in case of overflow
    -      // because we have guard pages at the end of all stacks. Hence, if
    -      // we go over the stack base and hit the stack of another thread,
    -      // this should not be in a writeable area that could contain a
    -      // stack lock allocated by that thread. As a consequence, a stack
    -      // lock less than page size away from SP is guaranteed to be
    -      // owned by the current thread.
    -      //
    -      // Note: assuming SP is aligned, we can check the low bits of
    -      // (mark-SP) instead of the low bits of mark. In that case,
    -      // assuming page size is a power of 2, we can merge the two
    -      // conditions into a single test:
    -      // => ((mark - SP) & (3 - os::pagesize())) == 0
    -
    -      // (3 - os::pagesize()) cannot be encoded as an ARM immediate operand.
    -      // Check independently the low bits and the distance to SP.
    -      // -1- test low 2 bits
    -      movs(R0, AsmOperand(Rmark, lsl, 30));
    -      // -2- test (mark - SP) if the low two bits are 0
    -      sub(R0, Rmark, SP, eq);
    -      movs(R0, AsmOperand(R0, lsr, exact_log2(os::vm_page_size())), eq);
    -      // If still 'eq' then recursive locking OK: store 0 into lock record
    -      str(R0, Address(Rlock, mark_offset), eq);
    -
    -      b(done, eq);
    -    }
    -
    -    bind(slow_case);
    -
    -    // Call the runtime routine for slow case
    -    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    -    bind(done);
    +  if (DiagnoseSyncOnValueBasedClasses != 0) {
    +    load_klass(R0, Robj);
    +    ldrb(R0, Address(R0, Klass::misc_flags_offset()));
    +    tst(R0, KlassFlags::_misc_is_value_based_class);
    +    b(slow_case, ne);
       }
    +
    +  lightweight_lock(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case);
    +  b(done);
    +
    +  bind(slow_case);
    +
    +  // Call the runtime routine for slow case
    +  call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    +  bind(done);
     }
     
     // Unlocks an object. Used in monitorexit bytecode and remove_activation.
    @@ -997,65 +922,39 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
     void InterpreterMacroAssembler::unlock_object(Register Rlock) {
       assert(Rlock == R0, "the first argument");
     
    -  if (LockingMode == LM_MONITOR) {
    -    call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
    -  } else {
    -    Label done, slow_case;
    +  Label done, slow_case;
     
    -    const Register Robj = R2;
    -    const Register Rmark = R3;
    -    assert_different_registers(Robj, Rmark, Rlock, Rtemp);
    +  const Register Robj = R2;
    +  const Register Rmark = R3;
    +  assert_different_registers(Robj, Rmark, Rlock, Rtemp);
     
    -    const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    -    const int lock_offset = in_bytes(BasicObjectLock::lock_offset());
    -    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
    +  const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    +  const Register Rzero = zero_register(Rtemp);
     
    -    const Register Rzero = zero_register(Rtemp);
    +  // Load oop into Robj
    +  ldr(Robj, Address(Rlock, obj_offset));
     
    -    // Load oop into Robj
    -    ldr(Robj, Address(Rlock, obj_offset));
    +  // Free entry
    +  str(Rzero, Address(Rlock, obj_offset));
     
    -    // Free entry
    -    str(Rzero, Address(Rlock, obj_offset));
    +  // Check for non-symmetric locking. This is allowed by the spec and the interpreter
    +  // must handle it.
    +  ldr(Rtemp, Address(Rthread, JavaThread::lock_stack_top_offset()));
    +  sub(Rtemp, Rtemp, oopSize);
    +  ldr(Rtemp, Address(Rthread, Rtemp));
    +  cmpoop(Rtemp, Robj);
    +  b(slow_case, ne);
     
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    +  lightweight_unlock(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */,
    +                     1 /* savemask (save t1) */, slow_case);
    +  b(done);
     
    -      // Check for non-symmetric locking. This is allowed by the spec and the interpreter
    -      // must handle it.
    -      ldr(Rtemp, Address(Rthread, JavaThread::lock_stack_top_offset()));
    -      sub(Rtemp, Rtemp, oopSize);
    -      ldr(Rtemp, Address(Rthread, Rtemp));
    -      cmpoop(Rtemp, Robj);
    -      b(slow_case, ne);
    +  bind(slow_case);
    +  // Call the runtime routine for slow case.
    +  str(Robj, Address(Rlock, obj_offset)); // restore obj
    +  call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
     
    -      lightweight_unlock(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */,
    -                         1 /* savemask (save t1) */, slow_case);
    -
    -      b(done);
    -
    -    } else if (LockingMode == LM_LEGACY) {
    -
    -      // Load the old header from BasicLock structure
    -      ldr(Rmark, Address(Rlock, mark_offset));
    -
    -      // Test for recursion (zero mark in BasicLock)
    -      cbz(Rmark, done);
    -
    -      bool allow_fallthrough_on_failure = true;
    -
    -      cas_for_lock_release(Rlock, Rmark, Robj, Rtemp, slow_case, allow_fallthrough_on_failure);
    -
    -      b(done, eq);
    -
    -    }
    -    bind(slow_case);
    -
    -    // Call the runtime routine for slow case.
    -    str(Robj, Address(Rlock, obj_offset)); // restore obj
    -    call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
    -
    -    bind(done);
    -  }
    +  bind(done);
     }
     
     // Test ImethodDataPtr.  If it is null, continue at the specified label
    diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    index 3dcde7d898d..e101e5631d9 100644
    --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    @@ -1758,7 +1758,6 @@ void MacroAssembler::read_polling_page(Register dest, relocInfo::relocType rtype
     //  - Success: fallthrough
     //  - Error:   break to slow, Z cleared.
     void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) {
    -  assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
       assert_different_registers(obj, t1, t2, t3);
     
     #ifdef ASSERT
    @@ -1816,7 +1815,6 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Re
     //  - Success: fallthrough
     //  - Error:   break to slow, Z cleared.
     void MacroAssembler::lightweight_unlock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) {
    -  assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
       assert_different_registers(obj, t1, t2, t3);
     
     #ifdef ASSERT
    diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    index 9519c923e22..dcf631525ab 100644
    --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    @@ -1139,41 +1139,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
         // Remember the handle for the unlocking code
         __ mov(sync_handle, R1);
     
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      log_trace(fastlock)("SharedRuntime lock fast");
    -      __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    -                          0x7 /* savemask */, slow_lock);
    +    log_trace(fastlock)("SharedRuntime lock fast");
    +    __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    +                        0x7 /* savemask */, slow_lock);
           // Fall through to lock_done
    -    } else if (LockingMode == LM_LEGACY) {
    -      const Register mark = tmp;
    -      // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -      // That would be acceptable as either CAS or slow case path is taken in that case
    -
    -      __ ldr(mark, Address(sync_obj, oopDesc::mark_offset_in_bytes()));
    -      __ sub(disp_hdr, FP, lock_slot_fp_offset);
    -      __ tst(mark, markWord::unlocked_value);
    -      __ b(fast_lock, ne);
    -
    -      // Check for recursive lock
    -      // See comments in InterpreterMacroAssembler::lock_object for
    -      // explanations on the fast recursive locking check.
    -      // Check independently the low bits and the distance to SP
    -      // -1- test low 2 bits
    -      __ movs(Rtemp, AsmOperand(mark, lsl, 30));
    -      // -2- test (hdr - SP) if the low two bits are 0
    -      __ sub(Rtemp, mark, SP, eq);
    -      __ movs(Rtemp, AsmOperand(Rtemp, lsr, exact_log2(os::vm_page_size())), eq);
    -      // If still 'eq' then recursive locking OK
    -      // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8267042)
    -      __ str(Rtemp, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -      __ b(lock_done, eq);
    -      __ b(slow_lock);
    -
    -      __ bind(fast_lock);
    -      __ str(mark, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -
    -      __ cas_for_lock_acquire(mark, disp_hdr, sync_obj, Rtemp, slow_lock);
    -    }
         __ bind(lock_done);
       }
     
    @@ -1226,21 +1195,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
     
       Label slow_unlock, unlock_done;
       if (method->is_synchronized()) {
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      log_trace(fastlock)("SharedRuntime unlock fast");
    -      __ lightweight_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    -                            7 /* savemask */, slow_unlock);
    -      // Fall through
    -    } else if (LockingMode == LM_LEGACY) {
    -      // See C1_MacroAssembler::unlock_object() for more comments
    -      __ ldr(sync_obj, Address(sync_handle));
    +    log_trace(fastlock)("SharedRuntime unlock fast");
    +    __ lightweight_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    +                          7 /* savemask */, slow_unlock);
    +    // Fall through
     
    -      // See C1_MacroAssembler::unlock_object() for more comments
    -      __ ldr(R2, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -      __ cbz(R2, unlock_done);
    -
    -      __ cas_for_lock_release(disp_hdr, R2, sync_obj, Rtemp, slow_unlock);
    -    }
         __ bind(unlock_done);
       }
     
    
    From 1f0dfdbccac4d23c00cab5663324c965141e1b23 Mon Sep 17 00:00:00 2001
    From: Marc Chevalier 
    Date: Mon, 25 Aug 2025 06:51:28 +0000
    Subject: [PATCH 201/471] 8360561: PhaseIdealLoop::create_new_if_for_predicate
     hits "must be a uct if pattern" assert
    
    Reviewed-by: mhaessig, thartmann, qamai
    ---
     src/hotspot/share/opto/subnode.cpp            | 26 +++++++
     .../igvn/CmpDisjointButNonOrderedRanges.java  | 73 +++++++++++++++++++
     .../igvn/CmpDisjointButNonOrderedRanges2.java | 68 +++++++++++++++++
     .../CmpDisjointButNonOrderedRangesLong.java   | 61 ++++++++++++++++
     4 files changed, 228 insertions(+)
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    
    diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp
    index 5f1af09463f..9c6c7498dd0 100644
    --- a/src/hotspot/share/opto/subnode.cpp
    +++ b/src/hotspot/share/opto/subnode.cpp
    @@ -694,6 +694,11 @@ const Type *CmpINode::sub( const Type *t1, const Type *t2 ) const {
         return TypeInt::CC_LE;
       else if( r0->_lo == r1->_hi ) // Range is never low?
         return TypeInt::CC_GE;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
       return TypeInt::CC;           // else use worst case results
     }
     
    @@ -798,6 +803,12 @@ const Type *CmpUNode::sub( const Type *t1, const Type *t2 ) const {
       // looks at the structure of the node in any other case.)
       if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check())
         return TypeInt::CC_LT;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;                   // else use worst case results
     }
     
    @@ -939,6 +950,12 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
         return TypeInt::CC_LE;
       else if( r0->_lo == r1->_hi ) // Range is never low?
         return TypeInt::CC_GE;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;           // else use worst case results
     }
     
    @@ -993,6 +1010,11 @@ const Type* CmpULNode::sub(const Type* t1, const Type* t2) const {
         }
       }
     
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;                   // else use worst case results
     }
     
    @@ -1368,6 +1390,10 @@ const Type *BoolTest::cc2logical( const Type *CC ) const {
         if( _test == le ) return TypeInt::ONE;
         if( _test == gt ) return TypeInt::ZERO;
       }
    +  if( CC == TypeInt::CC_NE ) {
    +    if( _test == ne ) return TypeInt::ONE;
    +    if( _test == eq ) return TypeInt::ZERO;
    +  }
     
       return TypeInt::BOOL;
     }
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
    new file mode 100644
    index 00000000000..a8f75b9c8f4
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
    @@ -0,0 +1,73 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. 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.
    + *
    + * 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.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * @test
    + * @bug 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @run main/othervm -Xcomp
    + *                   -XX:CompileCommand=compileonly,compiler.igvn.CmpDisjointButNonOrderedRanges::*
    + *                   compiler.igvn.CmpDisjointButNonOrderedRanges
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRanges
    + */
    +package compiler.igvn;
    +
    +public class CmpDisjointButNonOrderedRanges {
    +    static boolean bFld;
    +
    +    public static void main(String[] strArr) {
    +        test();
    +    }
    +
    +    static void test() {
    +        int x = 7;
    +        int y = 4;
    +        for (int i = 3; i < 12; i++) {
    +            // x = 7 \/ x = -195 => x \in [-195, 7] as a signed value
    +            // but [7, bitwise_cast_uint(-195)] as unsigned
    +            // So 0 is not possible.
    +            if (x != 0) {
    +                A.foo();
    +                // Because A is not loaded, A.foo() traps and this point is not reachable.
    +            }
    +            // x is tighten to be in the meet (so Hotspot's join) of [0, 0] and [7, bitwise_cast_uint(-195)]
    +            // that is bottom (Hotspot's top). Data is dead, control needs to be dead as well.
    +            for (int j = 1; j < 8; j++) {
    +                x = -195;
    +                if (bFld) {
    +                    y += 2;
    +                }
    +            }
    +        }
    +    }
    +
    +    static void foo() {
    +    }
    +}
    +
    +
    +class A {
    +    static void foo() {
    +    }
    +}
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
    new file mode 100644
    index 00000000000..205a7f7d380
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
    @@ -0,0 +1,68 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. 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.
    + *
    + * 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.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * @test
    + * @bug 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @run main/othervm -Xbatch
    + *                   -XX:CompileCommand=compileonly,compiler.igvn.CmpDisjointButNonOrderedRanges2::*
    + *                   -XX:-TieredCompilation
    + *                   -XX:+UnlockExperimentalVMOptions
    + *                   -XX:PerMethodTrapLimit=0
    + *                   compiler.igvn.CmpDisjointButNonOrderedRanges2
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRanges2
    + */
    +package compiler.igvn;
    +
    +public class CmpDisjointButNonOrderedRanges2 {
    +    int array[];
    +
    +    void test() {
    +        int val = 2;
    +        for (int i = 0; i < 10; i++) {
    +            // val = 2 \/ val = -12 => val \in [-12, 2] as a signed value
    +            // but [2, bitwise_cast_uint(-12)] as unsigned
    +            // So 0 is not possible.
    +            if (val != 0) {
    +                return;
    +            }
    +            // val is tighten to be in the meet (so Hotspot's join) of [0, 0] and [2, bitwise_cast_uint(-12)]
    +            // that is bottom (Hotspot's top). Data is dead, control needs to be dead as well.
    +            for (int j = 0; j < 10; j++) {
    +                array[1] = val;
    +                val = -12;
    +            }
    +        }
    +    }
    +
    +    static public void main(String[] args) {
    +        var c = new CmpDisjointButNonOrderedRanges2();
    +        for (int i = 0; i < 1000; ++i) {
    +            c.test();
    +            for (int j = 0; j < 100; ++j) {
    +            }
    +        }
    +    }
    +}
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    new file mode 100644
    index 00000000000..c5ef1640721
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    @@ -0,0 +1,61 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. 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.
    + *
    + * 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.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * @test
    + * @bug 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @library /test/lib /
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRangesLong
    + */
    +package compiler.igvn;
    +
    +import compiler.lib.ir_framework.*;
    +
    +public class CmpDisjointButNonOrderedRangesLong {
    +    static boolean bFld;
    +    static double dFld1;
    +    static double dFld2;
    +
    +    public static void main(String[] strArr) {
    +        TestFramework.run();
    +    }
    +
    +    @Test
    +    @IR(failOn = {IRNode.PHI})
    +    @Warmup(0)
    +    static int test() {
    +        long x = 7;
    +        if (bFld) {
    +            x = -195;
    +        }
    +
    +        dFld1 = dFld2 % 2.5;
    +
    +        if (x == 0) {
    +            return 0;
    +        }
    +        return 1;
    +    }
    +}
    
    From d99fb09a20df2639af23d1083afd14247abb991e Mon Sep 17 00:00:00 2001
    From: Jan Lahoda 
    Date: Mon, 25 Aug 2025 07:15:44 +0000
    Subject: [PATCH 202/471] 8359497: IllegalArgumentException thrown by
     SourceCodeAnalysisImpl.highlights()
    
    Reviewed-by: vromero
    ---
     .../share/classes/jdk/jshell/SourceCodeAnalysisImpl.java  | 7 ++++++-
     test/langtools/jdk/jshell/SnippetHighlightTest.java       | 8 +++++++-
     2 files changed, 13 insertions(+), 2 deletions(-)
    
    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    index 4ee629476db..cb4861651e3 100644
    --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    @@ -66,6 +66,7 @@ import com.sun.tools.javac.parser.Tokens.Token;
     import com.sun.tools.javac.parser.Tokens.TokenKind;
     import com.sun.tools.javac.tree.JCTree;
     import com.sun.tools.javac.util.Context;
    +import com.sun.tools.javac.util.Log;
     import jdk.internal.shellsupport.doc.JavadocHelper;
     import com.sun.tools.javac.util.Name;
     import com.sun.tools.javac.util.Names;
    @@ -139,6 +140,7 @@ import javax.lang.model.type.ExecutableType;
     import javax.lang.model.type.TypeKind;
     import javax.lang.model.util.ElementFilter;
     import javax.lang.model.util.Types;
    +import javax.tools.DiagnosticListener;
     import javax.tools.JavaFileManager.Location;
     import javax.tools.StandardLocation;
     
    @@ -654,7 +656,10 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
                 Trees trees = task.trees();
                 SourcePositions sp = trees.getSourcePositions();
                 List tokens = new ArrayList<>();
    -            Scanner scanner = ScannerFactory.instance(new Context()).newScanner(wrappedCode, false);
    +            Context ctx = new Context();
    +            ctx.put(DiagnosticListener.class, (DiagnosticListener) d -> {});
    +            Scanner scanner = ScannerFactory.instance(ctx).newScanner(wrappedCode, false);
    +            Log.instance(ctx).useSource(cut.getSourceFile());
                 scanner.nextToken();
                 BiConsumer addKeywordForSpan = (spanStart, spanEnd) -> {
                     int start = codeWrap.wrapIndexToSnippetIndex(spanStart);
    diff --git a/test/langtools/jdk/jshell/SnippetHighlightTest.java b/test/langtools/jdk/jshell/SnippetHighlightTest.java
    index 9c59a3d8016..902d4347f74 100644
    --- a/test/langtools/jdk/jshell/SnippetHighlightTest.java
    +++ b/test/langtools/jdk/jshell/SnippetHighlightTest.java
    @@ -23,7 +23,7 @@
     
     /*
      * @test
    - * @bug 8274148 8301580
    + * @bug 8274148 8301580 8359497
      * @summary Check snippet highlighting
      * @library /tools/lib
      * @modules jdk.compiler/com.sun.tools.javac.api
    @@ -114,6 +114,12 @@ public class SnippetHighlightTest extends KullaTesting {
                              "Highlight[start=32, end=38, attributes=[KEYWORD]]");
         }
     
    +    public void testNoCrashOnLexicalErrors() { //JDK-8359497
    +        assertHighlights("""
    +                         "
    +                         """);
    +    }
    +
         private void assertHighlights(String code, String... expected) {
             List completions = computeHighlights(code);
             assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString());
    
    From 7fa501e39874214c9bc7503c0bdb68d090245208 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:42:55 +0000
    Subject: [PATCH 203/471] 8365040: G1: Remove sorting at end of collection set
     selection
    
    Reviewed-by: iwalulya, ayang
    ---
     src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 ------
     1 file changed, 6 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    index 6fbbeb41a82..950ffcbc426 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    @@ -36,7 +36,6 @@
     #include "runtime/orderAccess.hpp"
     #include "utilities/debug.hpp"
     #include "utilities/globalDefinitions.hpp"
    -#include "utilities/quickSort.hpp"
     
     uint G1CollectionSet::groups_cur_length() const {
       assert(_inc_build_state == CSetBuildType::Inactive, "must be");
    @@ -344,10 +343,6 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi
       return remaining_time_ms;
     }
     
    -static int compare_region_idx(const uint a, const uint b) {
    -  return static_cast(a-b);
    -}
    -
     // The current mechanism for evacuating pinned old regions is as below:
     // * pinned regions in the marking collection set candidate list (available during mixed gc) are evacuated like
     //   pinned young regions to avoid the complexity of dealing with pinned regions that are part of a
    @@ -688,7 +683,6 @@ void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_m
       finalize_old_part(time_remaining_ms);
     
       stop_incremental_building();
    -  QuickSort::sort(_regions, _regions_cur_length, compare_region_idx);
     }
     
     bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) {
    
    From 28bd29f3963938f3846e68f33ac3648b2ba101f4 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:43:12 +0000
    Subject: [PATCH 204/471] 8365034: G1: Remove num_groups_selected in
     G1CollectionSet::select_candidates_from_optional_groups as it is unnecessary
    
    Reviewed-by: ayang, iwalulya
    ---
     src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 ++----
     1 file changed, 2 insertions(+), 4 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    index 950ffcbc426..e6177af7f68 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    @@ -599,7 +599,6 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
       assert(_optional_groups.num_regions() > 0,
              "Should only be called when there are optional regions");
     
    -  uint num_groups_selected = 0;
       double total_prediction_ms = 0.0;
       G1CSetCandidateGroupList selected;
       for (G1CSetCandidateGroup* group : _optional_groups) {
    @@ -615,16 +614,15 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
         time_remaining_ms -= predicted_time_ms;
     
         num_regions_selected += group->length();
    -    num_groups_selected++;
     
         add_group_to_collection_set(group);
         selected.append(group);
       }
     
       log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups",
    -                            num_regions_selected, num_groups_selected);
    +                            num_regions_selected, selected.length());
       // Remove selected groups from candidate list.
    -  if (num_groups_selected > 0) {
    +  if (selected.length() > 0) {
         _optional_groups.remove(&selected);
         candidates()->remove(&selected);
       }
    
    From 57434c73eac9bd6557b09d4a057e3a2a18f382b4 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:44:20 +0000
    Subject: [PATCH 205/471] 8365976: G1: Full gc should mark nmethods on stack
    
    Reviewed-by: ayang, iwalulya
    ---
     src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 +
     src/hotspot/share/gc/g1/g1FullCollector.cpp | 2 --
     2 files changed, 1 insertion(+), 2 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    index bf512cfa19d..65d863f43ee 100644
    --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    @@ -800,6 +800,7 @@ void G1CollectedHeap::prepare_for_mutator_after_full_collection(size_t allocatio
     
       // Rebuild the code root lists for each region
       rebuild_code_roots();
    +  finish_codecache_marking_cycle();
     
       start_new_collection_set();
       _allocator->init_mutator_alloc_regions();
    diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp
    index 579413768d1..70cded3220a 100644
    --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp
    +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp
    @@ -224,8 +224,6 @@ void G1FullCollector::collect() {
       }
     
       phase5_reset_metadata();
    -
    -  G1CollectedHeap::finish_codecache_marking_cycle();
     }
     
     void G1FullCollector::complete_collection(size_t allocation_word_size) {
    
    From 5cc86738411c36378b89d8f4932a54b3089cf22e Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Paul=20H=C3=BCbner?= 
    Date: Mon, 25 Aug 2025 09:13:35 +0000
    Subject: [PATCH 206/471] 8365765: thread.inline.hpp includes the wrong primary
     header file
    
    Reviewed-by: stefank, ayang, jwaters
    ---
     src/hotspot/share/runtime/thread.inline.hpp | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp
    index 756a4702159..98148d485d8 100644
    --- a/src/hotspot/share/runtime/thread.inline.hpp
    +++ b/src/hotspot/share/runtime/thread.inline.hpp
    @@ -26,7 +26,7 @@
     #ifndef SHARE_RUNTIME_THREAD_INLINE_HPP
     #define SHARE_RUNTIME_THREAD_INLINE_HPP
     
    -#include "runtime/javaThread.hpp"
    +#include "runtime/thread.hpp"
     
     #include "gc/shared/tlab_globals.hpp"
     #include "runtime/atomic.hpp"
    
    From 45726a1f8b8f76586037867a32b82f8ab9b96937 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 10:18:36 +0000
    Subject: [PATCH 207/471] 8365052: G1: Remove G1CollectionSet::groups()
     accessors
    
    Reviewed-by: ayang, kbarrett
    ---
     src/hotspot/share/gc/g1/g1CollectionSet.cpp        | 2 +-
     src/hotspot/share/gc/g1/g1CollectionSet.hpp        | 3 ---
     src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp | 2 +-
     3 files changed, 2 insertions(+), 5 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    index e6177af7f68..72033a1ce9a 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    @@ -105,7 +105,7 @@ void G1CollectionSet::abandon_all_candidates() {
     }
     
     void G1CollectionSet::prepare_for_scan () {
    -  groups()->prepare_for_scan();
    +  _groups.prepare_for_scan();
     }
     
     void G1CollectionSet::add_old_region(G1HeapRegion* hr) {
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
    index 7038cd4e677..4cdfd4b93dd 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp
    @@ -233,9 +233,6 @@ public:
       G1CollectionSetCandidates* candidates() { return &_candidates; }
       const G1CollectionSetCandidates* candidates() const { return &_candidates; }
     
    -  G1CSetCandidateGroupList* groups() { return &_groups; }
    -  const G1CSetCandidateGroupList* groups() const { return &_groups; }
    -
       void prepare_for_scan();
     
       void init_region_lengths(uint eden_cset_region_length,
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
    index 0f166cdf9ff..56fe9bbcc88 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp
    @@ -41,7 +41,7 @@ inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVis
       uint cur_pos = start_pos;
       uint count = 0;
       do {
    -    G1HeapRegionRemSet::iterate_for_merge(groups()->at(offset + cur_pos)->card_set(), cl);
    +    G1HeapRegionRemSet::iterate_for_merge(_groups.at(offset + cur_pos)->card_set(), cl);
         cur_pos++;
         count++;
         if (cur_pos == length) {
    
    From d24449f696c86bca53cca8a77cc3c4eb58a73ced Mon Sep 17 00:00:00 2001
    From: Erik Gahlin 
    Date: Mon, 25 Aug 2025 15:10:50 +0000
    Subject: [PATCH 208/471] 8365815: JFR: Update metadata.xml with 'jfr query'
     examples
    
    Reviewed-by: mgronlun
    ---
     .../build/tools/jfr/GenerateJfrFiles.java     |  6 +++--
     src/hotspot/share/jfr/metadata/metadata.xml   | 27 +++++++++++++++++--
     2 files changed, 29 insertions(+), 4 deletions(-)
    
    diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
    index 09f3a9f5e3f..939f3193820 100644
    --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
    +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java
    @@ -922,8 +922,10 @@ public class GenerateJfrFiles {
             }
             out.write("  using JfrEvent::commit; // else commit() is hidden by overloaded versions in this class");
    -        printConstructor2(out, event, empty);
    -        printCommitMethod(out, event, empty);
    +        if (!event.fields.isEmpty()) {
    +            printConstructor2(out, event, empty);
    +            printCommitMethod(out, event, empty);
    +        }
             if (!empty) {
                 printVerify(out, event.fields);
             }
    diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml
    index 42d99e2477d..060a78f13e7 100644
    --- a/src/hotspot/share/jfr/metadata/metadata.xml
    +++ b/src/hotspot/share/jfr/metadata/metadata.xml
    @@ -40,16 +40,39 @@
              event.commit();
            }
     
    +       void baz(char* text) {
    +         EventText event;
    +         event.set_text(text);
    +         event.commit();
    +       }
    +
            $ make images
            $ java -XX:StartFlightRecording:settings=none,filename=dump.jfr ...
    +       $ jfr view Text dump.jfr
    +       Time     Event Thread                             Text
    +       ======== ======================================== ==========================
    +       21:54:29 Attach Listener                          hello
    +       21:54:29 Attach Listener                          world
            ...
    -       $ jfr print dump.jfr
    +       $ jfr query 'SELECT text, COUNT(text) FROM Text GROUP BY text ORDER BY text ASC' dump.jfr
    +
    +       Text                              Count
    +       =================== ===================
    +       hello                               622
    +       world                                37
    +
    +       $ jfr query 'SELECT COUNT(duration), AVG(duration), MEDIAN(duration), P90(duration),
    +                    P99(duration), P999(duration) FROM Duration' dump.jfr
    +
    +       The 'jfr query' command is only available in debug builds, but recordings with internal
    +       events can be generated by product builds.
     
            Programmatic access:
            try (var rf = new RecordingFile(Path.of("dump.jfr"))) {
                while (rf.hasMoreEvents()) {
                    RecordedEvent e = rf.readEvent();
    -               System.out.println(e.getName() + " " + e.getDuration());
    +               EventType et = e.getEventType();
    +               System.out.println(et.getName() + " " + e.getDuration() + " " + e.getValue("text"));
                }
            };
       !-->
    
    From 040cc7aee03e82e70bcbfcd2dde5cd4b35faeabd Mon Sep 17 00:00:00 2001
    From: Phil Race 
    Date: Mon, 25 Aug 2025 17:01:43 +0000
    Subject: [PATCH 209/471] 8365292: Remove
     javax.imageio.spi.ServiceRegistry.finalize() 8359391: Remove ThreadGroup
     sandboxing from javax.imageio
    
    Reviewed-by: serb, jdv, azvegint
    ---
     .../javax/imageio/spi/IIORegistry.java        |  17 +--
     .../javax/imageio/spi/ServiceRegistry.java    |  38 ++---
     test/jdk/javax/imageio/AppContextTest.java    | 141 ------------------
     3 files changed, 12 insertions(+), 184 deletions(-)
     delete mode 100644 test/jdk/javax/imageio/AppContextTest.java
    
    diff --git a/src/java.desktop/share/classes/javax/imageio/spi/IIORegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/IIORegistry.java
    index 5286464617a..4f8ae8f2d1e 100644
    --- a/src/java.desktop/share/classes/javax/imageio/spi/IIORegistry.java
    +++ b/src/java.desktop/share/classes/javax/imageio/spi/IIORegistry.java
    @@ -44,7 +44,6 @@ import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
     import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
     import com.sun.imageio.plugins.tiff.TIFFImageReaderSpi;
     import com.sun.imageio.plugins.tiff.TIFFImageWriterSpi;
    -import sun.awt.AppContext;
     import java.util.List;
     import java.util.ServiceLoader;
     import java.util.ServiceConfigurationError;
    @@ -105,25 +104,15 @@ public final class IIORegistry extends ServiceRegistry {
             registerApplicationClasspathSpis();
         }
     
    +    private static final IIORegistry registry = new IIORegistry();
    +
         /**
          * Returns the default {@code IIORegistry} instance used by
          * the Image I/O API.  This instance should be used for all
          * registry functions.
    -     *
    -     * 

    Each {@code ThreadGroup} will receive its own instance. - * - * @return the default registry for the current - * {@code ThreadGroup}. + * @return the default registry for the Image I/O API */ public static IIORegistry getDefaultInstance() { - AppContext context = AppContext.getAppContext(); - IIORegistry registry = - (IIORegistry)context.get(IIORegistry.class); - if (registry == null) { - // Create an instance for this AppContext - registry = new IIORegistry(); - context.put(IIORegistry.class, registry); - } return registry; } diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java index 3f82cb3d9f7..be9f40e13df 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java @@ -78,7 +78,7 @@ import java.util.ServiceLoader; * proxy for the heavyweight service. * *

    An application may customize the contents of a registry as it - * sees fit, so long as it has the appropriate runtime permission. + * sees fit. * *

    For information on how to create and deploy service providers, * refer to the documentation on {@link java.util.ServiceLoader ServiceLoader} @@ -283,8 +283,7 @@ public class ServiceRegistry { * {@code onRegistration} method will be called once for each * category it is registered under. Its * {@code onDeregistration} method will be called each time - * it is deregistered from a category or when the registry is - * finalized. + * it is deregistered from a category. * * @param provider the service provider object to be registered. * @@ -313,8 +312,7 @@ public class ServiceRegistry { * {@code onRegistration} method will be called once for each * category it is registered under. Its * {@code onDeregistration} method will be called each time - * it is deregistered from a category or when the registry is - * finalized. + * it is deregistered from a category. * * @param providers an Iterator containing service provider * objects to be registered. @@ -660,6 +658,12 @@ public class ServiceRegistry { /** * Deregisters all currently registered service providers from all * categories. + *

    + * If an application creates a new {@code ServiceRegistry} instance and registers providers, + * and at some point no longer needs the instance, it should call this method to ensure + * that all providers which are instances of {@link RegisterableService} + * receive a {@link RegisterableService#onDeregistration(ServiceRegistry, Class)} call back, + * before allowing the instance to be garbage collected. */ public void deregisterAll() { for (SubRegistry reg : categoryMap.values()) { @@ -667,26 +671,6 @@ public class ServiceRegistry { } } - /** - * Finalizes this object prior to garbage collection. The - * {@code deregisterAll} method is called to deregister all - * currently registered service providers. This method should not - * be called from application code. - * - * @throws Throwable if an error occurs during superclass - * finalization. - * - * @deprecated Finalization has been deprecated for removal. See - * {@link java.lang.Object#finalize} for background information and details - * about migration options. - */ - @Deprecated(since="9", forRemoval=true) - @SuppressWarnings("removal") - public void finalize() throws Throwable { - deregisterAll(); - super.finalize(); - } - /** * Checks whether the provided class is one of the allowed * ImageIO service provider classes. If it is, returns normally. @@ -821,10 +805,6 @@ class SubRegistry { poset.clear(); } - @SuppressWarnings("removal") - public synchronized void finalize() { - clear(); - } } diff --git a/test/jdk/javax/imageio/AppContextTest.java b/test/jdk/javax/imageio/AppContextTest.java deleted file mode 100644 index 1132f652d03..00000000000 --- a/test/jdk/javax/imageio/AppContextTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4421190 - * @summary Tests that Image I/O statics may be referenced properly from - * multiple AppContexts, as would be the case for multiple Applets in a - * single VM. Each AppContext should get its own copy of the registry - * and the caching parameters in the ImageIO class. - * @modules java.desktop/sun.awt - */ - -import java.io.File; -import java.io.IOException; - -import javax.imageio.ImageIO; -import javax.imageio.spi.IIORegistry; - -import sun.awt.SunToolkit; - -class TestThread extends Thread { - - IIORegistry registry; - boolean useCache; - File cacheDirectory; - boolean cacheSettingsOK = false; - String threadName; - - boolean gotCrosstalk = false; - - public TestThread(ThreadGroup tg, - boolean useCache, File cacheDirectory, - String threadName) { - super(tg, threadName); - this.useCache = useCache; - this.cacheDirectory = cacheDirectory; - this.threadName = threadName; - } - - public void run() { -// System.out.println("Thread " + threadName + " in thread group " + -// getThreadGroup().getName()); - - // Create a new AppContext as though we were an applet - SunToolkit.createNewAppContext(); - - // Get default registry and store reference - this.registry = IIORegistry.getDefaultInstance(); - - for (int i = 0; i < 10; i++) { -// System.out.println(threadName + -// ": setting cache parameters to " + -// useCache + ", " + cacheDirectory); - ImageIO.setUseCache(useCache); - ImageIO.setCacheDirectory(cacheDirectory); - - try { - sleep(1000L); - } catch (InterruptedException e) { - } - -// System.out.println(threadName + ": reading cache parameters"); - boolean newUseCache = ImageIO.getUseCache(); - File newCacheDirectory = ImageIO.getCacheDirectory(); - if (newUseCache != useCache || - newCacheDirectory != cacheDirectory) { -// System.out.println(threadName + ": got " + -// newUseCache + ", " + -// newCacheDirectory); -// System.out.println(threadName + ": crosstalk encountered!"); - gotCrosstalk = true; - } - } - } - - public IIORegistry getRegistry() { - return registry; - } - - public boolean gotCrosstalk() { - return gotCrosstalk; - } -} - -public class AppContextTest { - - public AppContextTest() { - ThreadGroup tg0 = new ThreadGroup("ThreadGroup0"); - ThreadGroup tg1 = new ThreadGroup("ThreadGroup1"); - - TestThread t0 = - new TestThread(tg0, false, null, "TestThread 0"); - TestThread t1 = - new TestThread(tg1, true, new File("."), "TestThread 1"); - - t0.start(); - t1.start(); - - try { - t0.join(); - } catch (InterruptedException ie0) { - } - try { - t1.join(); - } catch (InterruptedException ie1) { - } - - if (t0.gotCrosstalk() || t1.gotCrosstalk()) { - throw new RuntimeException("ImageIO methods had crosstalk!"); - } - - if (t0.getRegistry() == t1.getRegistry()) { - throw new RuntimeException("ThreadGroups had same IIORegistry!"); - } - } - - public static void main(String[] args) throws IOException { - new AppContextTest(); - } -} From 63faa50428cef70d6e031189b0f95bd18d06d2e3 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 25 Aug 2025 19:32:03 +0000 Subject: [PATCH 210/471] 8365291: Remove finalize() method from sun/awt/X11InputMethodBase.java Reviewed-by: tr, azvegint --- .../unix/classes/sun/awt/X11InputMethodBase.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java b/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java index 32067b6b6cb..674b909d213 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java +++ b/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java @@ -172,13 +172,6 @@ public abstract class X11InputMethodBase extends InputMethodAdapter { } } - @Override - @SuppressWarnings("removal") - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } - /** * Invokes openIM() that invokes XOpenIM() if it's not opened yet. * @return true if openXIM() is successful or it's already been opened. From 1a7ac16d239cc1c244955a32baa8f5b32367790d Mon Sep 17 00:00:00 2001 From: Paul Hohensee Date: Mon, 25 Aug 2025 19:34:43 +0000 Subject: [PATCH 211/471] 8364382: Remove sun/tools/jstat/jstatLineCountsX.sh from ProblemList on linux-ppc64le and aix due to JDK-8248691 Reviewed-by: eastigeevich, cjplummer, mbaesken --- test/jdk/ProblemList.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 02eef5888e0..eb2666e67fe 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -750,11 +750,6 @@ java/util/zip/CloseInflaterDeflaterTest.java 8339216 linux-s390x sun/tools/jstatd/TestJstatdRmiPort.java 8251259,8293577 generic-all -sun/tools/jstat/jstatLineCounts1.sh 8248691,8268211 linux-ppc64le,aix-ppc64,linux-aarch64 -sun/tools/jstat/jstatLineCounts2.sh 8248691,8268211 linux-ppc64le,aix-ppc64,linux-aarch64 -sun/tools/jstat/jstatLineCounts3.sh 8248691,8268211 linux-ppc64le,aix-ppc64,linux-aarch64 -sun/tools/jstat/jstatLineCounts4.sh 8248691,8268211 linux-ppc64le,aix-ppc64,linux-aarch64 - ############################################################################ # jdk_other From a62942424858178ce99cd5df0e4d484620b1631d Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 26 Aug 2025 01:13:56 +0000 Subject: [PATCH 212/471] 8365579: ml64.exe is not the right assembler for Windows aarch64 Reviewed-by: jwaters, ihse, erikj --- make/autoconf/flags-other.m4 | 8 ++++++-- make/autoconf/toolchain.m4 | 7 +++++-- make/common/native/CompileFile.gmk | 8 +++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/make/autoconf/flags-other.m4 b/make/autoconf/flags-other.m4 index f0fa82489df..9d41cf04791 100644 --- a/make/autoconf/flags-other.m4 +++ b/make/autoconf/flags-other.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -115,7 +115,11 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS], # Force preprocessor to run, just to make sure BASIC_ASFLAGS="-x assembler-with-cpp" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - BASIC_ASFLAGS="-nologo -c" + if test "x$OPENJDK_TARGET_CPU" = xaarch64; then + BASIC_ASFLAGS="-nologo" + else + BASIC_ASFLAGS="-nologo -c" + fi fi AC_SUBST(BASIC_ASFLAGS) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index b7a01074686..f3ef44d382b 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -655,8 +655,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_CORE], if test "x$TOOLCHAIN_TYPE" != xmicrosoft; then AS="$CC -c" else - if test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then - # On 64 bit windows, the assembler is "ml64.exe" + if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then + # On Windows aarch64, the assembler is "armasm64.exe" + UTIL_LOOKUP_TOOLCHAIN_PROGS(AS, armasm64) + elif test "x$OPENJDK_TARGET_CPU_BITS" = "x64"; then + # On Windows x64, the assembler is "ml64.exe" UTIL_LOOKUP_TOOLCHAIN_PROGS(AS, ml64) else # otherwise, the assembler is "ml.exe" diff --git a/make/common/native/CompileFile.gmk b/make/common/native/CompileFile.gmk index 9c3d39d6edf..39b5f34a4c5 100644 --- a/make/common/native/CompileFile.gmk +++ b/make/common/native/CompileFile.gmk @@ -155,6 +155,12 @@ define CreateCompiledNativeFileBody endif $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h + else ifeq ($(TOOLCHAIN_TYPE), microsoft) + ifeq ($(OPENJDK_TARGET_CPU), aarch64) + $1_NON_ASM_EXTENSION_FLAG := + else + $1_NON_ASM_EXTENSION_FLAG := "-Ta" + endif endif else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) # Compile as a C++ or Objective-C++ file @@ -236,7 +242,7 @@ define CreateCompiledNativeFileBody # For assembler calls just create empty dependency lists $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ $$($1_COMPILER) $$($1_FLAGS) \ - $(CC_OUT_OPTION)$$($1_OBJ) -Ta $$($1_SRC_FILE))) \ + $(CC_OUT_OPTION)$$($1_OBJ) $$($1_NON_ASM_EXTENSION_FLAG) $$($1_SRC_FILE))) \ | $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \ $(ECHO) > $$($1_DEPS_FILE) ; \ $(ECHO) > $$($1_DEPS_TARGETS_FILE) From 21efd25c111726a00630e6ee9b316102f5ae41fb Mon Sep 17 00:00:00 2001 From: Ravi Gupta Date: Tue, 26 Aug 2025 02:51:22 +0000 Subject: [PATCH 213/471] 8361067: Test ExtraButtonDrag.java requires frame.dispose in finally block Reviewed-by: abhiscxk, dnguyen, mvs, prr --- .../ExtraButtonDrag.java | 206 ++++++++++-------- 1 file changed, 121 insertions(+), 85 deletions(-) diff --git a/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java b/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java index 3f8eeb17b38..e3b227a0054 100644 --- a/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java +++ b/test/jdk/java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -22,110 +22,120 @@ */ /* - @test - @key headful - @bug 6315717 - @summary verifies that drag events are coming for every button if the property is set to true - @author Andrei Dmitriev : area=awt.mouse - @run main ExtraButtonDrag + * @test + * @key headful + * @bug 6315717 + * @summary Verifies that the mouse drag events received for every button if the property is set to true + * @run main ExtraButtonDrag */ -//events from standard should also come +import java.awt.AWTException; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; -import java.awt.*; -import java.awt.event.*; +public class ExtraButtonDrag { -public class ExtraButtonDrag extends Frame { - static String tk = Toolkit.getDefaultToolkit().getClass().getName(); - static Robot robot; - static int [] buttonsPressed; - static int [] buttonsReleased; - static int [] buttonsClicked; - volatile static boolean dragged = false; - volatile static boolean moved = false; + private static Frame frame; + private static Robot robot; + private static volatile boolean dragged = false; + private static volatile boolean moved = false; + private static volatile Point centerFrame; + private static volatile Point outboundsFrame; + private static final String OS_NAME = System.getProperty("os.name"); + private static MouseAdapter mAdapter = new MouseAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + dragged = true; + } - public ExtraButtonDrag(){ - super("ExtraButtonDrag"); - } + @Override + public void mouseMoved(MouseEvent e) { + moved = true; + } + }; - public static void main(String []s){ - Frame frame = new ExtraButtonDrag(); - - MouseAdapter ma = new MouseAdapter() { - public void mouseDragged(MouseEvent e) { - System.out.println("Dragged "+e);// +" : "+ e.getButton() + " : " +e.getButtonState(e.getButton())); - dragged = true; - } - public void mouseMoved(MouseEvent e) { - System.out.println("Moved "+e); - moved = true; - } - public void mousePressed(MouseEvent e) { - System.out.println(">>> "+e); - } - public void mouseReleased(MouseEvent e) { - System.out.println(">>> "+e); - } - - }; - - frame.addMouseMotionListener(ma); - frame.addMouseListener(ma); + public static void initializeGUI() { + frame = new Frame("ExtraButtonDrag"); + frame.addMouseMotionListener(mAdapter); + frame.addMouseListener(mAdapter); frame.setSize(300, 300); + frame.setLocationRelativeTo(null); frame.setVisible(true); + } - int [] buttonMask = new int [MouseInfo.getNumberOfButtons()]; //InputEvent.getButtonMasks(); + public static void doTest() + throws InvocationTargetException, InterruptedException { - for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++){ - buttonMask[i] = InputEvent.getMaskForButton(i+1); - // System.out.println("TEST: "+tmp[i]); + int[] buttonMask = new int[MouseInfo.getNumberOfButtons()]; + + for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++) { + buttonMask[i] = InputEvent.getMaskForButton(i + 1); } - try { - robot = new Robot(); - robot.delay(1000); - Point centerFrame = new Point(frame.getLocationOnScreen().x + frame.getWidth()/2, frame.getLocationOnScreen().y + frame.getHeight()/2); - Point outboundsFrame = new Point(frame.getLocationOnScreen().x + frame.getWidth()*3/2, frame.getLocationOnScreen().y + frame.getHeight()/2); + EventQueue.invokeAndWait(() -> { + Point location = frame.getLocationOnScreen(); + Dimension size = frame.getSize(); + centerFrame = new Point(location.x + size.width / 2, + location.y + size.height / 2); + outboundsFrame = new Point(location.x + size.width * 3 / 2, + location.y + size.height / 2); + }); - System.out.println("areExtraMouseButtonsEnabled() == " + Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled() ); + System.out.println("areExtraMouseButtonsEnabled() == " + + Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()); - for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++){ - System.out.println("button to drag = " +(i+1) + " : value passed to robot = " +buttonMask[i]); + for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++) { + System.out.println("button to drag = " + (i + 1) + + " : value passed to robot = " + buttonMask[i]); - try { - dragMouse(buttonMask[i], centerFrame.x, centerFrame.y, outboundsFrame.x, outboundsFrame.y); - } catch (IllegalArgumentException e){ - throw new RuntimeException("Test failed. Exception occured.", e); + try { + dragMouse(buttonMask[i], centerFrame.x, centerFrame.y, + outboundsFrame.x, outboundsFrame.y); + } catch (IllegalArgumentException e) { + throw new RuntimeException("Test failed. Exception occured.", + e); + } + + // this is a choice-case for X protocol issue: native events from + // extra buttons doesn't contain + // the correct state so it's unable to decide if there is a drag or + // move. By default we send MOVED event. + // XToolkit: extra buttons should report MOVED events only + // WToolkit: extra buttons should report DRAGGED events only + if (i > 2) { // extra buttons only + if (OS_NAME.equals("Linux")) { + if (!moved || dragged) { + throw new RuntimeException("Test failed." + OS_NAME + + " Button = " + (i + 1) + " moved = " + moved + + " : dragged = " + dragged); + } + } else { // WToolkit + if (moved || !dragged) { + throw new RuntimeException("Test failed." + OS_NAME + + " Button = " + (i + 1) + " moved = " + moved + + " : dragged = " + dragged); + } } - - robot.delay(500); - //this is a choice-case for X protocol issue: native events from extra buttons doesn't contain - // the correct state so it's unable to decide if there is a drag or move. By default we send MOVED event. - //XToolkit: extra buttons should report MOVED events only - //WToolkit: extra buttons should report DRAGGED events only - if (i > 2){ //extra buttons only - if (tk.equals("sun.awt.X11.XToolkit")) { - if (!moved || dragged) { - throw new RuntimeException("Test failed."+ tk +" Button = " +(i+1) + " moved = "+moved +" : dragged = " +dragged); - } - } else { //WToolkit - if (moved || !dragged) { - throw new RuntimeException("Test failed."+ tk +" Button = " +(i+1) + " moved = "+moved +" : dragged = " +dragged); - } - } - } else { - if (moved || !dragged){ - throw new RuntimeException("Test failed. Button = " +(i+1) + " not dragged."); - } + } else { + if (moved || !dragged) { + throw new RuntimeException( + "Test failed. Button = " + (i + 1) + " not dragged."); } } - } catch (Exception e){ - throw new RuntimeException("", e); } } - public static void dragMouse(int button, int x0, int y0, int x1, int y1){ + public static void dragMouse(int button, int x0, int y0, int x1, int y1) { int curX = x0; int curY = y0; int dx = x0 < x1 ? 1 : -1; @@ -138,12 +148,12 @@ public class ExtraButtonDrag extends Frame { robot.mousePress(button); - while (curX != x1){ + while (curX != x1) { curX += dx; robot.mouseMove(curX, curY); robot.delay(5); } - while (curY != y1 ){ + while (curY != y1) { curY += dy; robot.mouseMove(curX, curY); robot.delay(5); @@ -151,4 +161,30 @@ public class ExtraButtonDrag extends Frame { robot.mouseRelease(button); } + public static void main(String[] s) + throws InvocationTargetException, InterruptedException, AWTException { + try { + robot = new Robot(); + robot.setAutoDelay(10); + robot.setAutoWaitForIdle(true); + + EventQueue.invokeAndWait(ExtraButtonDrag::initializeGUI); + robot.waitForIdle(); + robot.delay(100); + + doTest(); + + System.out.println("Test Passed"); + } finally { + EventQueue.invokeAndWait(ExtraButtonDrag::disposeFrame); + } + } + + public static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + } From e5077660c4e66decc9291b09cb2efaf2f5ae982f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 26 Aug 2025 02:53:44 +0000 Subject: [PATCH 214/471] 8361610: Avoid wasted work in ImageIcon(Image) for setting description Reviewed-by: kizune, aivanov --- .../share/classes/javax/swing/ImageIcon.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/src/java.desktop/share/classes/javax/swing/ImageIcon.java index 2bae31ba31f..f53a02a405f 100644 --- a/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -209,8 +209,10 @@ public class ImageIcon implements Icon, Serializable, Accessible { * @param description a brief textual description of the image */ public ImageIcon(Image image, String description) { - this(image); + this.image = image; this.description = description; + + loadImage(image); } /** @@ -222,12 +224,17 @@ public class ImageIcon implements Icon, Serializable, Accessible { * @see java.awt.Image#getProperty */ public ImageIcon (Image image) { - this.image = image; - Object o = image.getProperty("comment", imageObserver); - if (o instanceof String) { - description = (String) o; - } - loadImage(image); + this(image, getImageComment(image)); + } + + /** + * @return the {@code "comment"} property of the image + * if the value of the property is a sting} + * @param image the image to get the {@code "comment"} property + */ + private static String getImageComment(Image image) { + Object o = image.getProperty("comment", null); + return (o instanceof String) ? (String) o : null; } /** From 0f7c0e956e278458e3d875bbda174e3b9e143135 Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Tue, 26 Aug 2025 03:56:35 +0000 Subject: [PATCH 215/471] 8302057: Wrong BeanProperty description for JTable.setShowGrid Reviewed-by: aivanov, serb, azvegint, prr, psadhukhan --- src/java.desktop/share/classes/javax/swing/JTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index 653466318a7..e9ae9d82166 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -1164,7 +1164,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #setShowHorizontalLines */ @BeanProperty(description - = "The color used to draw the grid lines.") + = "Whether grid lines are drawn around the cells.") public void setShowGrid(boolean showGrid) { setShowHorizontalLines(showGrid); setShowVerticalLines(showGrid); From e7d2a52d35e8ad5afa5d26f4c0bb1bf46a1bf0c7 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 26 Aug 2025 05:09:05 +0000 Subject: [PATCH 216/471] 8344333: Spurious System.err.flush() in LWCToolkit.java Reviewed-by: psadhukhan --- .../macosx/classes/sun/lwawt/macosx/LWCToolkit.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 5047a50303b..14ad9621bbd 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -141,8 +141,6 @@ public final class LWCToolkit extends LWToolkit { private static CInputMethodDescriptor sInputMethodDescriptor; static { - System.err.flush(); - ResourceBundle platformResources = null; try { platformResources = ResourceBundle.getBundle("sun.awt.resources.awtosx"); From 98e64cffff24ec8b8abeb7afd121e58bc53ed034 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 26 Aug 2025 05:29:16 +0000 Subject: [PATCH 217/471] 8159055: Clarify handling of null and invalid image data for ImageIcon constructors and setImage method Reviewed-by: aivanov, prr, abhiscxk, kizune, serb --- .../share/classes/javax/swing/ImageIcon.java | 15 ++ .../javax/swing/ImageIcon/ImageIconTest.java | 150 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 test/jdk/javax/swing/ImageIcon/ImageIconTest.java diff --git a/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/src/java.desktop/share/classes/javax/swing/ImageIcon.java index f53a02a405f..aaaa2dfd4a4 100644 --- a/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -63,6 +63,14 @@ import sun.awt.AppContext; * of the image. * *

    + * If the image source parameter to a constructor or method is non-null, + * but does not reference valid accessible image data, + * no exceptions will be thrown but no image will be rendered + * even though {@link #getImage()} will return a non-null value, + * as the image will have no dimensions + * and {@link #getImageLoadStatus()} will report {@code MediaTracker.ERRORED}. + * + *

    * For further information and examples of using image icons, see * How to Use Icons * in The Java Tutorial. @@ -178,6 +186,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * of the image. * @param location the URL for the image * @param description a brief textual description of the image + * @throws NullPointerException if {@code location} is {@code null} * @see #ImageIcon(String) */ public ImageIcon(URL location, String description) { @@ -197,6 +206,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * The icon's description is initialized to be * a string representation of the URL. * @param location the URL for the image + * @throws NullPointerException if {@code location} is {@code null} * @see #getDescription */ public ImageIcon (URL location) { @@ -207,6 +217,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * Creates an ImageIcon from the image. * @param image the image * @param description a brief textual description of the image + * @throws NullPointerException if {@code image} is {@code null} */ public ImageIcon(Image image, String description) { this.image = image; @@ -220,6 +231,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * If the image has a "comment" property that is a string, * then the string is used as the description of this icon. * @param image the image + * @throws NullPointerException if {@code image} is {@code null} * @see #getDescription * @see java.awt.Image#getProperty */ @@ -248,6 +260,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * @param imageData an array of pixels in an image format supported * by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG * @param description a brief textual description of the image + * @throws NullPointerException if {@code imageData} is {@code null} * @see java.awt.Toolkit#createImage */ public ImageIcon (byte[] imageData, String description) { @@ -271,6 +284,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { * * @param imageData an array of pixels in an image format supported by * the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG + * @throws NullPointerException if {@code imageData} is {@code null} * @see java.awt.Toolkit#createImage * @see #getDescription * @see java.awt.Image#getProperty @@ -375,6 +389,7 @@ public class ImageIcon implements Icon, Serializable, Accessible { /** * Sets the image displayed by this icon. * @param image the image + * @throws NullPointerException if {@code image} is {@code null} */ public void setImage(Image image) { this.image = image; diff --git a/test/jdk/javax/swing/ImageIcon/ImageIconTest.java b/test/jdk/javax/swing/ImageIcon/ImageIconTest.java new file mode 100644 index 00000000000..ac9b2b7da67 --- /dev/null +++ b/test/jdk/javax/swing/ImageIcon/ImageIconTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8159055 + * @summary Verifies null parameter and invalid data handling of + * ImageIcon constructors and setImage method + * @run main ImageIconTest + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.net.URI; +import java.net.URL; +import java.util.Random; +import java.awt.Image; +import java.awt.Toolkit; +import javax.swing.ImageIcon; + +public class ImageIconTest { + + static enum ArgType { FILE, URL, BYTE_ARRAY, IMAGE, SET_IMAGE }; + static enum ArgVal { NULL, INVALID_DATA }; + + public static void main(String[] args) throws Exception { + + String imgName = "invalid.gif"; + byte[] invalidData = new byte[100]; + new Random().nextBytes(invalidData); + try (FileOutputStream fos = new FileOutputStream(imgName)) { + fos.write(invalidData); + } + File file = new File(imgName); + file.deleteOnExit(); + + for (ArgType a : ArgType.values()) { + for (final ArgVal v : ArgVal.values()) { + System.out.println("Testing for ArgType " + a + " for case " + v); + boolean expected = true; + boolean passed = false; + try { + switch (a) { + + case FILE : + + expected = false; + String s = (v == ArgVal.NULL) ? null : imgName; + new ImageIcon(s); + passed = true; // no exception expected for this case + break; + + case URL : + + if (v == ArgVal.NULL) { + + new ImageIcon((URL)null); + + } else if (v == ArgVal.INVALID_DATA) { + expected = false; + new ImageIcon(new URI("file://" + imgName).toURL()); + passed = true; // no exception expected for this case + + } + break; + + case BYTE_ARRAY : + + if (v == ArgVal.NULL) { + + byte[] bytes = null; + new ImageIcon(bytes); + + } else if (v == ArgVal.INVALID_DATA) { + expected = false; + + new ImageIcon(invalidData); + + passed = true; // no exception expected for this case + } + break; + + case IMAGE : + + if (v == ArgVal.NULL) { + + new ImageIcon((Image)null); + + } else if (v == ArgVal.INVALID_DATA) { + expected = false; + + new ImageIcon((Image)Toolkit.getDefaultToolkit().createImage(imgName)); + + passed = true; // no exception expected for this case + } + break; + + case SET_IMAGE : + + ImageIcon ii = new ImageIcon(); + + if (v == ArgVal.NULL) { + + ii.setImage((Image) null); + + } else if (v == ArgVal.INVALID_DATA) { + expected = false; + + ii.setImage((Image)Toolkit.getDefaultToolkit().createImage(imgName)); + + passed = true; // no exception expected for this case + } + break; + } + } catch (NullPointerException e) { + if (expected) { + passed = true; + } + } + if (expected && !passed) { + throw new RuntimeException("Did not receive expected exception for : " + a); + } + if (!expected && !passed) { + throw new RuntimeException("Received unexpected exception for : " + a); + } + } + } + + } +} From e5ec464120bec50ab111ee32dfb930f26150b109 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 26 Aug 2025 06:13:33 +0000 Subject: [PATCH 218/471] 8365442: [asan] runtime/ErrorHandling/CreateCoredumpOnCrash.java fails Reviewed-by: jsjolen --- .../jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 76ea10d77cb..2fb42e230a5 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -30,6 +30,7 @@ * jdk.internal.jvmstat/sun.jvmstat.monitor * @run driver CreateCoredumpOnCrash * @requires vm.flagless + * @requires !vm.asan */ import jdk.test.lib.process.ProcessTools; From deec6aa76dffaa80f3c01e72377913cd22f96672 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 26 Aug 2025 06:37:48 +0000 Subject: [PATCH 219/471] 8365394: Stylesheet must not load fonts on --no-fonts output Reviewed-by: hannesw --- .../doclets/formats/html/HtmlDoclet.java | 48 ++++++++++++++----- .../doclets/toolkit/util/DocFile.java | 32 ++++++++++--- .../javadoc/doclet/testFonts/TestFonts.java | 4 ++ .../doclet/testStylesheet/TestStylesheet.java | 1 + 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index d00d7b1becf..24fc8e6b2de 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -317,10 +317,11 @@ public class HtmlDoclet extends AbstractDoclet { copyResource(DocPaths.HIGHLIGHT_JS, DocPaths.SCRIPT_FILES.resolve(DocPaths.HIGHLIGHT_JS), true); } - // If a stylesheet file is not specified, copy the default stylesheet - // and replace newline with platform-specific newline. + // If a stylesheet file is not specified, copy the default stylesheet, + // replace newline with platform-specific newline, + // and remove the reference to fonts if --no-fonts is used. if (options.stylesheetFile().isEmpty()) { - copyResource(DocPaths.STYLESHEET, DocPaths.RESOURCE_FILES.resolve(DocPaths.STYLESHEET), true); + copyStylesheet(options); } copyResource(DocPaths.SCRIPT_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SCRIPT_JS), true); copyResource(DocPaths.LEFT_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.LEFT_SVG), true); @@ -463,18 +464,13 @@ public class HtmlDoclet extends AbstractDoclet { private void copyResource(DocPath sourcePath, DocPath targetPath, boolean replaceNewLine) throws DocletException { - DocPath resourcePath = DocPaths.RESOURCES.resolve(sourcePath); - // Resolve resources against doclets.formats.html package - URL resourceURL = HtmlConfiguration.class.getResource(resourcePath.getPath()); - if (resourceURL == null) { - throw new ResourceIOException(sourcePath, new FileNotFoundException(resourcePath.getPath())); - } + ReadableResource resource = resolveResource(sourcePath); DocFile f = DocFile.createFileForOutput(configuration, targetPath); if (sourcePath.getPath().toLowerCase(Locale.ROOT).endsWith(".template")) { - f.copyResource(resourcePath, resourceURL, configuration.docResources); + f.copyResource(resource.path(), resource.url(), configuration.docResources); } else { - f.copyResource(resourcePath, resourceURL, replaceNewLine); + f.copyResource(resource.path(), resource.url(), replaceNewLine); } } @@ -503,6 +499,23 @@ public class HtmlDoclet extends AbstractDoclet { } } + private void copyStylesheet(HtmlOptions options) throws DocletException { + ReadableResource resource = resolveResource(DocPaths.STYLESHEET); + var targetPath = DocPaths.RESOURCE_FILES.resolve(DocPaths.STYLESHEET); + DocFile f = DocFile.createFileForOutput(configuration, targetPath); + + if (options.noFonts()) { + f.copyResource(resource.path(), resource.url(), line -> { + if (line.startsWith("@import url('fonts")) { + return null; // remove the line + } + return line; + }); + } else { + f.copyResource(resource.path(), resource.url(), true); + } + } + private void copyFile(String filename, DocPath targetPath) throws DocFileIOException { if (filename.isEmpty()) { return; @@ -519,4 +532,17 @@ public class HtmlDoclet extends AbstractDoclet { fromfile.getPath(), path.getPath()); toFile.copyFile(fromfile); } + + private ReadableResource resolveResource(DocPath sourcePath) throws ResourceIOException { + DocPath resolvedPath = DocPaths.RESOURCES.resolve(sourcePath); + // Resolve resources against doclets.formats.html package + URL resourceURL = HtmlConfiguration.class.getResource(resolvedPath.getPath()); + if (resourceURL == null) { + throw new ResourceIOException(sourcePath, new FileNotFoundException(resolvedPath.getPath())); + } + return new ReadableResource(resolvedPath, resourceURL); + } + + private record ReadableResource(DocPath path, URL url) { + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java index 1c69e6156e2..26e9635b9db 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java @@ -35,6 +35,7 @@ import java.io.Writer; import java.net.URL; import java.nio.file.Path; import java.util.MissingResourceException; +import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -188,7 +189,7 @@ public abstract class DocFile { */ public void copyResource(DocPath resource, URL url, boolean replaceNewLine) throws DocFileIOException, ResourceIOException { - copyResource(resource, url, replaceNewLine, null); + copyResource(resource, url, replaceNewLine, UnaryOperator.identity()); } /** @@ -202,11 +203,27 @@ public abstract class DocFile { * @throws ResourceIOException if there is a problem while reading the resource */ public void copyResource(DocPath resource, URL url, Resources resources) throws DocFileIOException, ResourceIOException { - copyResource(resource, url, true, resources); + copyResource(resource, url, resources == null ? UnaryOperator.identity() : line -> localize(line, resources)); } - private void copyResource(DocPath resource, URL url, boolean replaceNewLine, Resources resources) - throws DocFileIOException, ResourceIOException { + /** + * Copy the contents of a resource file to this file while transforming and filtering its lines. + * + * @param resource the path of the resource + * @param url the URL of the resource + * @param lineTransformer the transforming function that is called for each line; may return + * {@code null} to remove a line. + * + * @throws DocFileIOException if there is a problem while writing the copy + * @throws ResourceIOException if there is a problem while reading the resource + */ + public void copyResource(DocPath resource, URL url, UnaryOperator lineTransformer) + throws DocFileIOException, ResourceIOException { + copyResource(resource, url, true, lineTransformer); + } + + private void copyResource(DocPath resource, URL url, boolean replaceNewLine, UnaryOperator lineTransformer) + throws ResourceIOException, DocFileIOException { try { InputStream in = url.openStream(); @@ -216,8 +233,11 @@ public abstract class DocFile { try (Writer writer = openWriter()) { String line; while ((line = readResourceLine(resource, reader)) != null) { - write(this, writer, resources == null ? line : localize(line, resources)); - write(this, writer, PLATFORM_LINE_SEPARATOR); + String transformedLine = lineTransformer.apply(line); + if (transformedLine != null) { + write(this, writer, transformedLine); + write(this, writer, PLATFORM_LINE_SEPARATOR); + } } } catch (IOException e) { throw new DocFileIOException(this, DocFileIOException.Mode.WRITE, e); diff --git a/test/langtools/jdk/javadoc/doclet/testFonts/TestFonts.java b/test/langtools/jdk/javadoc/doclet/testFonts/TestFonts.java index 56b2bbfb786..647ae9d8cdd 100644 --- a/test/langtools/jdk/javadoc/doclet/testFonts/TestFonts.java +++ b/test/langtools/jdk/javadoc/doclet/testFonts/TestFonts.java @@ -64,6 +64,8 @@ public class TestFonts extends JavadocTester { javadoc("-d", base.resolve("out").toString(), src.resolve("Dummy.java").toString()); checkExit(Exit.OK); + checkOutput("resource-files/stylesheet.css", true, + "@import url('fonts/dejavu.css');"); checkOutput("resource-files/fonts/dejavu.css", true, """ /* DejaVu fonts v2.37 */""", @@ -115,6 +117,8 @@ public class TestFonts extends JavadocTester { "resource-files/link.svg", "resource-files/stylesheet.css", "resource-files/x.svg"); + checkOutput("resource-files/stylesheet.css", false, + "@import url('fonts/dejavu.css');"); checkFiles(false, "resource-files/fonts"); } } diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 87ff58e1395..44651c16f5e 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -55,6 +55,7 @@ public class TestStylesheet extends JavadocTester { @Test public void test(Path base) { + setUseDefaultOptions(false); javadoc("-d", base.resolve("out").toString(), "-sourcepath", testSrc, "pkg"); From e38c6f9827c15777361dd1c7ce420f020f5de313 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 26 Aug 2025 06:57:44 +0000 Subject: [PATCH 220/471] 8365656: [ubsan] G1CSetCandidateGroup::liveness() reports division by 0 Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp | 1 + src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 2118bf997a7..ccb52922c09 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -59,6 +59,7 @@ void G1CSetCandidateGroup::calculate_efficiency() { } double G1CSetCandidateGroup::liveness_percent() const { + assert(length() > 0, "must be"); size_t capacity = length() * G1HeapRegion::GrainBytes; return ((capacity - _reclaimable_bytes) * 100.0) / capacity; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 237704c12a8..f37ede6940e 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -3121,8 +3121,8 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSet G1PPRL_TYPE_H_FORMAT, group->group_id(), group->length(), - group->gc_efficiency(), - group->liveness_percent(), + group->length() > 0 ? group->gc_efficiency() : 0.0, + group->length() > 0 ? group->liveness_percent() : 0.0, group->card_set()->mem_size(), type); _total_remset_bytes += group->card_set()->mem_size(); From 5013d69d96e5052972bc04c78a060fd9296518e2 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 26 Aug 2025 07:05:02 +0000 Subject: [PATCH 221/471] 8365633: Incorrect info is reported on hybrid CPU Reviewed-by: kvn, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 10 ++++++++-- src/hotspot/cpu/x86/vm_version_x86.hpp | 7 +++++-- .../share/classes/jdk/vm/ci/amd64/AMD64.java | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index b81c200c440..266fe5abb99 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1099,8 +1099,12 @@ void VM_Version::get_processor_features() { } stringStream ss(2048); - ss.print("(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x", - cores_per_cpu(), threads_per_core(), + if (supports_hybrid()) { + ss.print("(hybrid)"); + } else { + ss.print("(%u cores per cpu, %u threads per core)", cores_per_cpu(), threads_per_core()); + } + ss.print(" family %d model %d stepping %d microcode 0x%x", cpu_family(), _model, _stepping, os::cpu_microcode_revision()); ss.print(", "); int features_offset = (int)ss.size(); @@ -3043,6 +3047,8 @@ VM_Version::VM_Features VM_Version::CpuidInfo::feature_flags() const { if (is_intel()) { if (sef_cpuid7_edx.bits.serialize != 0) vm_features.set_feature(CPU_SERIALIZE); + if (sef_cpuid7_edx.bits.hybrid != 0) + vm_features.set_feature(CPU_HYBRID); if (_cpuid_info.sef_cpuid7_edx.bits.avx512_fp16 != 0) vm_features.set_feature(CPU_AVX512_FP16); } diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 6ee9f95fdf5..573d4ed27dc 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -276,7 +276,8 @@ class VM_Version : public Abstract_VM_Version { fast_short_rep_mov : 1, : 9, serialize : 1, - : 5, + hybrid: 1, + : 4, cet_ibt : 1, : 2, avx512_fp16 : 1, @@ -444,7 +445,8 @@ protected: decl(SHA512, "sha512", 61) /* SHA512 instructions*/ \ decl(AVX512_FP16, "avx512_fp16", 62) /* AVX512 FP16 ISA support*/ \ decl(AVX10_1, "avx10_1", 63) /* AVX10 512 bit vector ISA Version 1 support*/ \ - decl(AVX10_2, "avx10_2", 64) /* AVX10 512 bit vector ISA Version 2 support*/ + decl(AVX10_2, "avx10_2", 64) /* AVX10 512 bit vector ISA Version 2 support*/ \ + decl(HYBRID, "hybrid", 65) /* Hybrid architecture */ #define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (bit), CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) @@ -877,6 +879,7 @@ public: static bool supports_avx512_fp16() { return _features.supports_feature(CPU_AVX512_FP16); } static bool supports_hv() { return _features.supports_feature(CPU_HV); } static bool supports_serialize() { return _features.supports_feature(CPU_SERIALIZE); } + static bool supports_hybrid() { return _features.supports_feature(CPU_HYBRID); } static bool supports_f16c() { return _features.supports_feature(CPU_F16C); } static bool supports_pku() { return _features.supports_feature(CPU_PKU); } static bool supports_ospke() { return _features.supports_feature(CPU_OSPKE); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index dbb27c7d7ec..273ada6f4bc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -287,7 +287,8 @@ public class AMD64 extends Architecture { SHA512, AVX512_FP16, AVX10_1, - AVX10_2 + AVX10_2, + HYBRID } private final EnumSet features; From 68abf76e90d9a0608d84ba827a7b09d2f517fe6f Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Tue, 26 Aug 2025 07:08:45 +0000 Subject: [PATCH 222/471] 8366105: Update link to the external RuleBasedBreakIterator documentation Reviewed-by: naoto, jlu, iris --- .../share/classes/sun/text/RuleBasedBreakIterator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java index c648fb40875..d2ed0efb29e 100644 --- a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java +++ b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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 @@ -210,7 +210,7 @@ import sun.text.SupplementaryCharacterData; * * *

    For a more complete explanation, see http://www.ibm.com/java/education/boundaries/boundaries.html. + * href="https://icu-project.org/docs/papers/text_boundary_analysis_in_java/">Text Boundary Analysis in Java by Richard Gillam. *   For examples, see the resource data (which is annotated).

    * * @author Richard Gillam From 2ae3ea2ad93b83deec1922159d80b94da0397357 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Tue, 26 Aug 2025 08:35:52 +0000 Subject: [PATCH 223/471] 8366035: Simplify CPUTimeCounters::publish_gc_total_cpu_time Reviewed-by: ayang, kbarrett --- src/hotspot/share/runtime/cpuTimeCounters.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/runtime/cpuTimeCounters.cpp b/src/hotspot/share/runtime/cpuTimeCounters.cpp index 5b2e76fed7f..0248db8fec3 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.cpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.cpp @@ -75,15 +75,9 @@ void CPUTimeCounters::inc_gc_total_cpu_time(jlong diff) { void CPUTimeCounters::publish_gc_total_cpu_time() { CPUTimeCounters* instance = CPUTimeCounters::get_instance(); - // Ensure that we are only incrementing atomically by using Atomic::cmpxchg - // to set the value to zero after we obtain the new CPU time difference. - jlong old_value; - jlong fetched_value = Atomic::load(&(instance->_gc_total_cpu_time_diff)); + // Atomically fetch the current _gc_total_cpu_time_diff and reset it to zero. jlong new_value = 0; - do { - old_value = fetched_value; - fetched_value = Atomic::cmpxchg(&(instance->_gc_total_cpu_time_diff), old_value, new_value); - } while (old_value != fetched_value); + jlong fetched_value = Atomic::xchg(&(instance->_gc_total_cpu_time_diff), new_value); get_counter(CPUTimeGroups::CPUTimeType::gc_total)->inc(fetched_value); } From 3641c32c11aa3768ce986d5dcd5393b74f776228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 26 Aug 2025 08:55:08 +0000 Subject: [PATCH 224/471] 8365994: ZGC: Incorrect type signature in ZMappedCache comparator Reviewed-by: cnorrbin, aboldtch --- src/hotspot/share/gc/z/zMappedCache.cpp | 11 ++++------- src/hotspot/share/gc/z/zMappedCache.hpp | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/z/zMappedCache.cpp b/src/hotspot/share/gc/z/zMappedCache.cpp index 173adfbc010..ad02d265e93 100644 --- a/src/hotspot/share/gc/z/zMappedCache.cpp +++ b/src/hotspot/share/gc/z/zMappedCache.cpp @@ -118,14 +118,11 @@ static ZMappedCacheEntry* create_entry(const ZVirtualMemory& vmem) { return entry; } -int ZMappedCache::EntryCompare::cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { +bool ZMappedCache::EntryCompare::cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { const ZVirtualMemory vmem_a = ZMappedCacheEntry::cast_to_entry(a)->vmem(); const ZVirtualMemory vmem_b = ZMappedCacheEntry::cast_to_entry(b)->vmem(); - if (vmem_a.end() < vmem_b.start()) { return -1; } - if (vmem_b.end() < vmem_a.start()) { return 1; } - - return 0; // Overlapping + return vmem_a.end() < vmem_b.start(); } int ZMappedCache::EntryCompare::cmp(zoffset key, const IntrusiveRBNode* node) { @@ -171,12 +168,12 @@ void ZMappedCache::Tree::insert(TreeNode* node, const TreeCursor& cursor) { // Insert in tree TreeImpl::insert_at_cursor(node, cursor); - if (_left_most == nullptr || EntryCompare::cmp(node, _left_most) < 0) { + if (_left_most == nullptr || EntryCompare::cmp(node, _left_most)) { // Keep track of left most node _left_most = node; } - if (_right_most == nullptr || EntryCompare::cmp(_right_most, node) < 0) { + if (_right_most == nullptr || EntryCompare::cmp(_right_most, node)) { // Keep track of right most node _right_most = node; } diff --git a/src/hotspot/share/gc/z/zMappedCache.hpp b/src/hotspot/share/gc/z/zMappedCache.hpp index cf1ddbc7289..28f37de0de1 100644 --- a/src/hotspot/share/gc/z/zMappedCache.hpp +++ b/src/hotspot/share/gc/z/zMappedCache.hpp @@ -41,7 +41,7 @@ class ZMappedCache { private: struct EntryCompare { static int cmp(zoffset a, const IntrusiveRBNode* b); - static int cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b); + static bool cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b); }; struct ZSizeClassListNode { From 28602f3d3ec15b5241a33a46ce43349e6300395d Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 26 Aug 2025 09:54:41 +0000 Subject: [PATCH 225/471] 8365206: RISC-V: compiler/c2/irTests/TestFloat16ScalarOperations.java is failing on riscv64 Reviewed-by: fyang, rehn, dzhang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 15 +- .../cpu/riscv/macroAssembler_riscv.cpp | 56 ++++++ .../cpu/riscv/macroAssembler_riscv.hpp | 3 + src/hotspot/cpu/riscv/riscv.ad | 4 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 12 +- .../float16/Binary16ConversionNaN_2.java | 178 ++++++++++++++++++ 6 files changed, 242 insertions(+), 26 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN_2.java diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index e91af885d78..0420d83ac41 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2161,18 +2161,7 @@ static void float_to_float16_slow_path(C2_MacroAssembler& masm, C2GeneralStub(); __ bind(stub.entry()); - __ fmv_x_w(dst, src); - - // preserve the payloads of non-canonical NaNs. - __ srai(dst, dst, 13); - // preserve the sign bit. - __ srai(tmp, dst, 13); - __ slli(tmp, tmp, 10); - __ mv(t0, 0x3ff); - __ orr(tmp, tmp, t0); - - // get the result by merging sign bit and payloads of preserved non-canonical NaNs. - __ andr(dst, dst, tmp); + __ float_to_float16_NaN(dst, src, t0, tmp); __ j(stub.continuation()); #undef __ @@ -2180,7 +2169,7 @@ static void float_to_float16_slow_path(C2_MacroAssembler& masm, C2GeneralStub(dst, src, xtmp, 130, float_to_float16_slow_path); + auto stub = C2CodeStub::make(dst, src, xtmp, 64, float_to_float16_slow_path); // On riscv, NaN needs a special process as fcvt does not work in that case. diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 453538e4a5a..b4d286cabbf 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5954,6 +5954,62 @@ void MacroAssembler::java_round_double(Register dst, FloatRegister src, FloatReg bind(done); } +// Helper routine processing the slow path of NaN when converting float to float16 +void MacroAssembler::float_to_float16_NaN(Register dst, FloatRegister src, + Register tmp1, Register tmp2) { + fmv_x_w(dst, src); + + // Float (32 bits) + // Bit: 31 30 to 23 22 to 0 + // +---+------------------+-----------------------------+ + // | S | Exponent | Mantissa (Fraction) | + // +---+------------------+-----------------------------+ + // 1 bit 8 bits 23 bits + // + // Float (16 bits) + // Bit: 15 14 to 10 9 to 0 + // +---+----------------+------------------+ + // | S | Exponent | Mantissa | + // +---+----------------+------------------+ + // 1 bit 5 bits 10 bits + const int fp_sign_bits = 1; + const int fp32_bits = 32; + const int fp32_exponent_bits = 8; + const int fp32_mantissa_1st_part_bits = 10; + const int fp32_mantissa_2nd_part_bits = 9; + const int fp32_mantissa_3rd_part_bits = 4; + const int fp16_exponent_bits = 5; + const int fp16_mantissa_bits = 10; + + // preserve the sign bit and exponent, clear mantissa. + srai(tmp2, dst, fp32_bits - fp_sign_bits - fp16_exponent_bits); + slli(tmp2, tmp2, fp16_mantissa_bits); + + // Preserve high order bit of float NaN in the + // binary16 result NaN (tenth bit); OR in remaining + // bits into lower 9 bits of binary 16 significand. + // | (doppel & 0x007f_e000) >> 13 // 10 bits + // | (doppel & 0x0000_1ff0) >> 4 // 9 bits + // | (doppel & 0x0000_000f)); // 4 bits + // + // Check j.l.Float.floatToFloat16 for more information. + // 10 bits + int left_shift = fp_sign_bits + fp32_exponent_bits + 32; + int right_shift = left_shift + fp32_mantissa_2nd_part_bits + fp32_mantissa_3rd_part_bits; + slli(tmp1, dst, left_shift); + srli(tmp1, tmp1, right_shift); + orr(tmp2, tmp2, tmp1); + // 9 bits + left_shift += fp32_mantissa_1st_part_bits; + right_shift = left_shift + fp32_mantissa_3rd_part_bits; + slli(tmp1, dst, left_shift); + srli(tmp1, tmp1, right_shift); + orr(tmp2, tmp2, tmp1); + // 4 bits + andi(tmp1, dst, 0xf); + orr(dst, tmp2, tmp1); +} + #define FCVT_SAFE(FLOATCVT, FLOATSIG) \ void MacroAssembler::FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) { \ Label done; \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 17f113cc819..13b70d5dbd7 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1431,6 +1431,9 @@ public: void java_round_float(Register dst, FloatRegister src, FloatRegister ftmp); void java_round_double(Register dst, FloatRegister src, FloatRegister ftmp); + // Helper routine processing the slow path of NaN when converting float to float16 + void float_to_float16_NaN(Register dst, FloatRegister src, Register tmp1, Register tmp2); + // vector load/store unit-stride instructions void vlex_v(VectorRegister vd, Register base, Assembler::SEW sew, VectorMask vm = unmasked) { switch (sew) { diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 7d204007898..e02d781972b 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -8554,7 +8554,7 @@ instruct convF2HF_reg_reg(iRegINoSp dst, fRegF src, fRegF ftmp, iRegINoSp xtmp) instruct reinterpretS2HF(fRegF dst, iRegI src) %{ match(Set dst (ReinterpretS2HF src)); - format %{ "fmv.h.x $dst, $src" %} + format %{ "fmv.h.x $dst, $src\t# reinterpretS2HF" %} ins_encode %{ __ fmv_h_x($dst$$FloatRegister, $src$$Register); %} @@ -8574,7 +8574,7 @@ instruct convF2HFAndS2HF(fRegF dst, fRegF src) instruct reinterpretHF2S(iRegINoSp dst, fRegF src) %{ match(Set dst (ReinterpretHF2S src)); - format %{ "fmv.x.h $dst, $src" %} + format %{ "fmv.x.h $dst, $src\t# reinterpretHF2S" %} ins_encode %{ __ fmv_x_h($dst$$Register, $src$$FloatRegister); %} diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index fbcb939f59d..7db426327ee 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -6357,18 +6357,8 @@ class StubGenerator: public StubCodeGenerator { __ ret(); __ bind(NaN_SLOW); - __ fmv_x_w(dst, src); - // preserve the payloads of non-canonical NaNs. - __ srai(dst, dst, 13); - // preserve the sign bit. - __ srai(t1, dst, 13); - __ slli(t1, t1, 10); - __ mv(t0, 0x3ff); - __ orr(t1, t1, t0); - - // get the result by merging sign bit and payloads of preserved non-canonical NaNs. - __ andr(dst, dst, t1); + __ float_to_float16_NaN(dst, src, t0, t1); __ ret(); return entry; diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN_2.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN_2.java new file mode 100644 index 00000000000..b1170227542 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN_2.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Rivos Inc. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8365206 + * @summary Verify NaN sign and significand bits are preserved across conversions, + * float -> float16 -> float + * @requires (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @requires vm.compMode != "Xcomp" + * @library /test/lib / + * + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xmixed -XX:-BackgroundCompilation -XX:-UseOnStackReplacement + * -XX:CompileThresholdScaling=1000.0 Binary16ConversionNaN_2 + */ + +/* + * The behavior tested below is an implementation property not + * required by the specification. It would be acceptable for this + * information to not be preserved (as long as a NaN is returned) if, + * say, a intrinsified version using native hardware instructions + * behaved differently. + * + * If that is the case, this test should be modified to disable + * intrinsics or to otherwise not run on platforms with an differently + * behaving intrinsic. + */ + +import compiler.whitebox.CompilerWhiteBoxTest; +import jdk.test.whitebox.WhiteBox; +import java.lang.reflect.Method; +import java.util.Random; + +public class Binary16ConversionNaN_2 { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + /* + * Put all 16-bit NaN values through a conversion loop and make + * sure the significand, sign, and exponent are all preserved. + */ + public static void main(String... argv) throws NoSuchMethodException { + int errors = 0; + final int NAN_EXPONENT = 0x7f80_0000; + final int SIGN_BIT = 0x8000_0000; + + // First, run with Interpreter only to collect "gold" data. + // Glags -Xmixed -XX:CompileThresholdScaling=1000.0 are used + // to prevent compilation during this phase. + float[] pVal = new float[1024]; + float[] pRes = new float[1024]; + float[] nVal = new float[1024]; + float[] nRes = new float[1024]; + + Random rand = new Random(); + + // A NaN has a nonzero significand + for (int i = 1; i <= 0x3ff; i++) { + int shift = rand.nextInt(13+1); + int binaryNaN = (NAN_EXPONENT | (i << shift)); + assert isNaN(binaryNaN); + // the payloads of non-canonical NaNs are preserved. + float f1 = Float.intBitsToFloat(binaryNaN); + float f2 = testRoundTrip(f1); + errors += verify(f1, f2); + pVal[i] = f1; + pRes[i] = f2; + + int binaryNegNaN = (SIGN_BIT | binaryNaN); + float f3 = Float.intBitsToFloat(binaryNegNaN); + float f4 = testRoundTrip(f3); + errors += verify(f3, f4); + nVal[i] = f3; + nRes[i] = f4; + } + if (errors > 0) { // Exit if Interpreter failed + throw new RuntimeException(errors + " errors"); + } + + Method test_method = Binary16ConversionNaN_2.class.getDeclaredMethod("testRoundTrip", float.class); + + // Compile with C1 and compare results + WHITE_BOX.enqueueMethodForCompilation(test_method, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE); + if (!WHITE_BOX.isMethodCompiled(test_method)) { + throw new RuntimeException("test is not compiled by C1"); + } + for (int i = 1; i <= 0x3ff; i++) { + float f1 = testRoundTrip(pVal[i]); + errors += verifyCompiler(pRes[i], f1, "C1"); + float f2 = testRoundTrip(nVal[i]); + errors += verifyCompiler(nRes[i], f2, "C1"); + } + + WHITE_BOX.deoptimizeMethod(test_method); + + // Compile with C2 and compare results + WHITE_BOX.enqueueMethodForCompilation(test_method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + if (!WHITE_BOX.isMethodCompiled(test_method)) { + throw new RuntimeException("test is not compiled by C2"); + } + for (int i = 1; i <= 0x3ff; i++) { + float f1 = testRoundTrip(pVal[i]); + errors += verifyCompiler(pRes[i], f1, "C2"); + float f2 = testRoundTrip(nVal[i]); + errors += verifyCompiler(nRes[i], f2, "C2"); + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } + + private static boolean isNaN(int binary) { + return ((binary & 0x7f80_0000) == 0x7f80_0000) // Max exponent and... + && ((binary & 0x007f_ffff) != 0 ); // significand nonzero. + } + + private static float testRoundTrip(float f) { + short s = Float.floatToFloat16(f); + return Float.float16ToFloat(s); + } + + private static int verify(float f1, float f2) { + int errors = 0; + int i1 = Float.floatToRawIntBits(f1); + int i2 = Float.floatToRawIntBits(f2); + assert Float.isNaN(f1); + if (!Float.isNaN(f2) || + ((i1 & 0x8000_0000) != (i2 & 0x8000_0000))) { + errors++; + System.out.println("Roundtrip failure on NaN value " + + Integer.toHexString(i1) + + "\t got back " + Integer.toHexString(i2)); + } + return errors; + } + + private static int verifyCompiler(float f1, float f2, String name) { + int errors = 0; + int i1 = Float.floatToRawIntBits(f1); + int i2 = Float.floatToRawIntBits(f2); + assert Float.isNaN(f1); + if (!Float.isNaN(f2) || + ((i1 & 0x8000_0000) != (i2 & 0x8000_0000))) { + errors++; + System.out.println("Roundtrip failure on NaN value " + + Integer.toHexString(i1) + + "\t got back " + Integer.toHexString(i2) + + "\t from " + name + " code"); + } + return errors; + } +} From 22d3a6dd34a14994c7210365a5b982c9e65f5892 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 26 Aug 2025 11:55:01 +0000 Subject: [PATCH 226/471] 8366128: jdk/jdk/nio/zipfs/TestPosix.java::testJarFile uses wrong file Reviewed-by: alanb --- test/jdk/jdk/nio/zipfs/TestPosix.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index ff6f9c4920f..526acca8a9e 100644 --- a/test/jdk/jdk/nio/zipfs/TestPosix.java +++ b/test/jdk/jdk/nio/zipfs/TestPosix.java @@ -60,7 +60,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -/** +/* * @test * @bug 8213031 8273935 8324635 * @summary Test POSIX ZIP file operations. @@ -756,7 +756,7 @@ public class TestPosix { delTree(UNZIP_DIR); Files.createDirectory(UNZIP_DIR); File targetDir = UNZIP_DIR.toFile(); - try (JarFile jf = new JarFile(ZIP_FILE.toFile())) { + try (JarFile jf = new JarFile(JAR_FILE.toFile())) { Enumeration zenum = jf.entries(); while (zenum.hasMoreElements()) { JarEntry ze = zenum.nextElement(); From aae13af04bda541a80f74adff5dbf65f44c8271a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Tue, 26 Aug 2025 13:24:05 +0000 Subject: [PATCH 227/471] 8365909: [REDO] Add a compilation timeout flag to catch long running compilations Co-authored-by: Dean Long Reviewed-by: chagedorn, dlong --- .../os/linux/compilerThreadTimeout_linux.cpp | 128 ++++++++++++++++++ .../os/linux/compilerThreadTimeout_linux.hpp | 51 +++++++ src/hotspot/os/linux/globals_linux.hpp | 5 + src/hotspot/share/compiler/compileBroker.cpp | 6 + src/hotspot/share/compiler/compilerThread.cpp | 2 + src/hotspot/share/compiler/compilerThread.hpp | 33 ++++- .../arguments/TestCompileTaskTimeout.java | 55 ++++++++ .../jtreg/runtime/signal/TestSigalrm.java | 4 +- 8 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp create mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp new file mode 100644 index 00000000000..7ee741ff011 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" +#include "compilerThreadTimeout_linux.hpp" +#include "oops/method.hpp" +#include "runtime/osThread.hpp" +#include "signals_posix.hpp" +#include "utilities/globalDefinitions.hpp" + +#include + +#ifdef ASSERT +void compiler_signal_handler(int signo, siginfo_t* info, void* context) { + CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context); +} + +void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) { + switch (signo) { + case TIMEOUT_SIGNAL: { + CompileTask* task = CompilerThread::current()->task(); + const int SIZE = 512; + char method_name_buf[SIZE]; + task->method()->name_and_sig_as_C_string(method_name_buf, SIZE); + assert(false, "compile task %d (%s) timed out after %zd ms", + task->compile_id(), method_name_buf, CompileTaskTimeout); + } + default: { + assert(false, "unexpected signal %d", signo); + } + } +} +#endif // ASSERT + +void CompilerThreadTimeoutLinux::arm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC; + const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC; + const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; + const struct itimerspec its {.it_interval = ts, .it_value = ts}; + + // Start the timer. + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +void CompilerThreadTimeoutLinux::disarm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + // Reset the timer by setting it to zero. + const struct itimerspec its { + .it_interval = {.tv_sec = 0, .tv_nsec=0}, + .it_value = {.tv_sec = 0, .tv_nsec=0} + }; + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +bool CompilerThreadTimeoutLinux::init_timeout() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return true; + } + + JavaThread* thread = JavaThread::current(); + + // Create a POSIX timer sending SIGALRM to this thread only. + sigevent_t sev; + sev.sigev_value.sival_ptr = nullptr; + sev.sigev_signo = TIMEOUT_SIGNAL; + sev.sigev_notify = SIGEV_THREAD_ID; +#ifdef MUSL_LIBC + sev.sigev_notify_thread_id = thread->osthread()->thread_id(); +#else + sev._sigev_un._tid = thread->osthread()->thread_id(); +#endif // MUSL_LIBC + clockid_t clock; + int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock); + if (err != 0) { + return false; + } + err = timer_create(clock, &sev, &_timer); + if (err != 0) { + return false; + } + + // Install the signal handler and check that we do not have a conflicting handler. + struct sigaction sigact, sigact_old; + err = PosixSignals::install_sigaction_signal_handler(&sigact, + &sigact_old, + TIMEOUT_SIGNAL, + (sa_sigaction_t)::compiler_signal_handler); + if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction && + sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) { + return false; + } +#endif // ASSERT + return true; +} diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp new file mode 100644 index 00000000000..2dc6fa7b9c9 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP +#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP + +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" +#include "utilities/macros.hpp" + +#include +#include + +class CompilerThreadTimeoutLinux : public CHeapObj { +#ifdef ASSERT + public: + static const int TIMEOUT_SIGNAL = SIGALRM; + void compiler_signal_handler(int signo, siginfo_t* info, void* context); + private: + timer_t _timer; +#endif // ASSERT + public: + CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {}; + + bool init_timeout(); + void arm(); + void disarm(); +}; + +#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 542e034f59f..90e1e5e5f3f 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -89,6 +89,11 @@ product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \ "Print an annotated memory map at exit") \ \ + develop(intx, CompileTaskTimeout, 0, \ + "Set the timeout for compile tasks' CPU time in milliseconds."\ + " 0 = no timeout (default)") \ + range(0,1000000) \ + \ // end of RUNTIME_OS_FLAGS // diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 804345d95c5..177b8b1c161 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -218,6 +218,7 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); CompileLog* log = thread->log(); + thread->timeout()->arm(); if (log != nullptr && !task->is_unloaded()) task->log_task_start(log); } @@ -228,6 +229,7 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (log != nullptr && !task->is_unloaded()) task->log_task_done(log); thread->set_task(nullptr); thread->set_env(nullptr); + thread->timeout()->disarm(); if (task->is_blocking()) { bool free_task = false; { @@ -1926,6 +1928,10 @@ void CompileBroker::compiler_thread_loop() { log->end_elem(); } + if (!thread->init_compilation_timeout()) { + return; + } + // If compiler thread/runtime initialization fails, exit the compiler thread if (!init_compiler_runtime()) { return; diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 4034e63bc10..7cf494aad56 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -40,6 +40,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, _can_call_java = false; _compiler = nullptr; _arena_stat = nullptr; + _timeout = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -49,6 +50,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; + delete _timeout; // arenastat should have been deleted at the end of the compilation assert(_arena_stat == nullptr, "Should be null"); } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index e20e3017d1f..e4641780a12 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,7 +25,14 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" #include "runtime/javaThread.hpp" +#include "utilities/macros.hpp" + +#ifdef LINUX +#include "compilerThreadTimeout_linux.hpp" +#endif //LINUX class AbstractCompiler; class ArenaStatCounter; @@ -38,10 +45,27 @@ class CompileQueue; class CompilerCounters; class IdealGraphPrinter; +#ifndef LINUX +class CompilerThreadTimeoutGeneric : public CHeapObj { + public: + CompilerThreadTimeoutGeneric() {}; + void arm() {}; + void disarm() {}; + bool init_timeout() { return true; }; +}; +#endif // !LINUX + // A thread used for Compilation. class CompilerThread : public JavaThread { friend class VMStructs; JVMCI_ONLY(friend class CompilerThreadCanCallJava;) + +#ifdef LINUX + typedef CompilerThreadTimeoutLinux Timeout; +#else // LINUX + typedef CompilerThreadTimeoutGeneric Timeout; +#endif // LINUX + private: CompilerCounters* _counters; @@ -57,6 +81,7 @@ class CompilerThread : public JavaThread { ArenaStatCounter* _arena_stat; + Timeout* _timeout; public: static CompilerThread* current() { @@ -113,7 +138,13 @@ class CompilerThread : public JavaThread { public: IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; } void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; } -#endif +#endif // !PRODUCT + + Timeout* timeout() const { return _timeout; }; + bool init_compilation_timeout() { + _timeout = new Timeout(); + return _timeout->init_timeout(); + }; // Get/set the thread's current task CompileTask* task() { return _task; } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java new file mode 100644 index 00000000000..141522744f4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.arguments; + +/* + * @test TestCompileTaskTimeout + * @bug 8308094 8365909 + * @requires vm.debug & vm.flagless & os.name == "Linux" + * @summary Check functionality of CompileTaskTimeout + * @library /test/lib + * @run driver compiler.arguments.TestCompileTaskTimeout + */ + +import jdk.test.lib.process.ProcessTools; + +public class TestCompileTaskTimeout { + + public static void main(String[] args) throws Throwable { + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") + .shouldHaveExitValue(0); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java index b9a3c3e5060..2e485a46cf9 100644 --- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java +++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test - * @requires os.family != "windows" & os.family != "aix" + * @requires os.family != "windows" & os.family != "aix" & vm.flagless * * @summary converted from VM testbase runtime/signal/sigalrm01. * VM testbase keywords: [signal, runtime, linux, macosx] From 173dedfb241af21f07035625d63ec72b07bb4035 Mon Sep 17 00:00:00 2001 From: Johny Jose Date: Tue, 26 Aug 2025 13:53:34 +0000 Subject: [PATCH 228/471] 8366131: ProblemList java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java Reviewed-by: alanb, jpai, smarks --- test/jdk/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index eb2666e67fe..1193ea45ba7 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -617,7 +617,7 @@ java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-al java/rmi/registry/readTest/CodebaseTest.java 8173324 windows-all java/rmi/registry/multipleRegistries/MultipleRegistries.java 8268182 macosx-all - +java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 8365398 generic-all java/rmi/Naming/DefaultRegistryPort.java 8005619 windows-all java/rmi/Naming/legalRegistryNames/LegalRegistryNames.java 8005619 windows-all From caaef3a04ce1a9a8c80d9aade96de43416ab058e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 26 Aug 2025 15:00:20 +0000 Subject: [PATCH 229/471] 8350920: Allow inherited member summaries to be viewed inline Reviewed-by: liach, nbenalla --- .../formats/html/AbstractMemberWriter.java | 133 ++++++++++++++---- .../html/AnnotationTypeMemberWriter.java | 10 -- .../formats/html/ConstructorWriter.java | 6 - .../formats/html/EnumConstantWriter.java | 8 -- .../doclets/formats/html/FieldWriter.java | 26 ++-- .../doclets/formats/html/HtmlDoclet.java | 1 + .../doclets/formats/html/MethodWriter.java | 16 ++- .../formats/html/NestedClassWriter.java | 26 ++-- .../doclets/formats/html/PropertyWriter.java | 16 ++- .../internal/doclets/formats/html/Table.java | 9 +- .../doclets/formats/html/resources/down.svg | 12 ++ .../doclets/formats/html/resources/right.svg | 2 +- .../formats/html/resources/script.js.template | 44 ++++-- .../formats/html/resources/stylesheet.css | 56 ++++++-- .../formats/html/taglets/IndexTaglet.java | 13 +- .../formats/html/taglets/SpecTaglet.java | 33 +---- .../doclets/toolkit/CommentUtils.java | 4 + .../toolkit/resources/doclets.properties | 1 + .../doclets/toolkit/util/DocPaths.java | 3 + .../jdk/javadoc/internal/html/Content.java | 7 + .../javadoc/internal/html/ContentBuilder.java | 9 ++ .../jdk/javadoc/internal/html/HtmlTree.java | 10 ++ .../jdk/javadoc/internal/html/RawHtml.java | 5 + .../TestDuplicateMethods.java | 2 +- .../doclet/testHiddenTag/TestHiddenTag.java | 2 +- .../doclet/testInterface/TestInterface.java | 39 ++++- .../javadoc/doclet/testJavaFX/TestJavaFX.java | 26 +++- .../TestOverrideMethods.java | 111 +++++++++++++-- .../doclet/testStylesheet/TestStylesheet.java | 2 +- .../doclet/testUnexported/TestUnexported.java | 8 +- .../jdk/javadoc/tool/api/basic/APITest.java | 1 + 31 files changed, 481 insertions(+), 160 deletions(-) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/down.svg diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index 5c7bb7f3b37..e2e286d5856 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -28,7 +28,9 @@ package jdk.javadoc.internal.doclets.formats.html; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -45,6 +47,7 @@ import javax.lang.model.type.TypeMirror; import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; @@ -52,6 +55,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -206,16 +210,18 @@ public abstract class AbstractMemberWriter { public void buildSummary(Content target) { var summaryTreeList = new ArrayList(); - - buildMainSummary(summaryTreeList); + var inheritedTocEntries = new LinkedHashMap(); + var ownMemberCount = buildMainSummary(summaryTreeList); + var inheritedSummaries = 0; var showInherited = switch (kind) { case FIELDS, METHODS, NESTED_CLASSES, PROPERTIES -> true; case ANNOTATION_TYPE_MEMBER, ANNOTATION_TYPE_MEMBER_OPTIONAL, ANNOTATION_TYPE_MEMBER_REQUIRED, CONSTRUCTORS, ENUM_CONSTANTS -> false; }; - if (showInherited) - buildInheritedSummary(summaryTreeList); + if (showInherited) { + inheritedSummaries = buildInheritedSummary(summaryTreeList, inheritedTocEntries); + } if (!summaryTreeList.isEmpty()) { Content member = getMemberSummaryHeader(target); @@ -223,6 +229,12 @@ public abstract class AbstractMemberWriter { buildSummary(target, member); writer.tableOfContents.addLink(HtmlIds.forMemberSummary(kind), getSummaryLabel(), TableOfContents.Level.FIRST); + + // Omit TOC entries for inherited members unless there's a substantial number of own members. + if (!inheritedTocEntries.isEmpty() && ownMemberCount > 8 && inheritedSummaries > 0) { + inheritedTocEntries.forEach((key, value) + -> writer.tableOfContents.addLink(key, value, TableOfContents.Level.SECOND)); + } } } @@ -230,40 +242,61 @@ public abstract class AbstractMemberWriter { * Builds the main summary table for the members of this kind. * * @param summaryTreeList the list of contents to which the documentation will be added + * @return the number of documented members */ - private void buildMainSummary(List summaryTreeList) { + private int buildMainSummary(List summaryTreeList) { Set members = asSortedSet(visibleMemberTable.getVisibleMembers(kind)); if (!members.isEmpty()) { var pHelper = writer.getPropertyHelper(); + var table = getSummaryTable(); for (Element member : members) { - final Element property = pHelper.getPropertyElement(member); - if (property != null && member instanceof ExecutableElement ee) { - configuration.cmtUtils.updatePropertyMethodComment(ee, property); - } - if (utils.isMethod(member)) { - var docFinder = utils.docFinder(); - Optional> r = docFinder.search((ExecutableElement) member, (m -> { - var firstSentenceTrees = utils.getFirstSentenceTrees(m); - Optional> optional = firstSentenceTrees.isEmpty() ? Optional.empty() : Optional.of(firstSentenceTrees); - return DocFinder.Result.fromOptional(optional); - })).toOptional(); - // The fact that we use `member` for possibly unrelated tags is suspicious - addMemberSummary(typeElement, member, r.orElse(List.of())); - } else { - addMemberSummary(typeElement, member, utils.getFirstSentenceTrees(member)); - } + addMemberSummaryTableRow(typeElement, member, table, pHelper); } summaryTreeList.add(getSummaryTable(typeElement)); } + return members.size(); + } + + /** + * Adds the summary table row for a member. + * @param enclosingType the enclosing type of the member + * @param member the member + * @param table the summary table + * @param propertyHelper property helper to patch doctree + */ + private void addMemberSummaryTableRow(TypeElement enclosingType, Element member, Table table, + PropertyUtils.PropertyHelper propertyHelper) { + final Element property = propertyHelper.getPropertyElement(member); + if (property != null && member instanceof ExecutableElement ee) { + configuration.cmtUtils.updatePropertyMethodComment(ee, property); + } + + if (utils.isMethod(member)) { + var docFinder = utils.docFinder(); + Optional> r = docFinder.search((ExecutableElement) member, (m -> { + var firstSentenceTrees = utils.getFirstSentenceTrees(m); + Optional> optional = firstSentenceTrees.isEmpty() + ? Optional.empty() : Optional.of(firstSentenceTrees); + return DocFinder.Result.fromOptional(optional); + })).toOptional(); + // The fact that we use `member` for possibly unrelated tags is suspicious + addMemberSummary(enclosingType, member, r.orElse(List.of()), table); + } else { + addMemberSummary(enclosingType, member, utils.getFirstSentenceTrees(member), table); + } } /** * Builds the inherited member summary for the members of this kind. * * @param targets the list of contents to which the documentation will be added + * @param tocEntries map of TOC entries for added summaries + * @return the number of added summary lists, excluding methods from java.lang.Object */ - private void buildInheritedSummary(List targets) { + private int buildInheritedSummary(List targets, Map tocEntries) { var inheritedMembersFromMap = asSortedSet(visibleMemberTable.getAllVisibleMembers(kind)); + // Avoid showing TOC entry if it's just methods inherited from java.lang.Object + var summaryCount = kind == METHODS && utils.isClass(typeElement) ? -1 : 0; for (TypeElement inheritedClass : visibleMemberTable.getVisibleTypeElements()) { if (!utils.isVisible(inheritedClass)) { @@ -284,9 +317,27 @@ public abstract class AbstractMemberWriter { Content links = getInheritedSummaryLinks(); addSummaryFootNote(inheritedClass, inheritedMembers, links); inheritedHeader.add(links); + + if (utils.isIncluded(inheritedClass)) { + var pHelper = writer.getPropertyHelper(); + Table table = createInheritedSummaryTable(inheritedClass); + + for (Element member : inheritedMembers) { + addMemberSummaryTableRow(inheritedClass, member, table, pHelper); + } + + inheritedHeader.add(table); + } targets.add(inheritedHeader); + + summaryCount++; + var label = new ContentBuilder(); + addInheritedSummaryLabel(inheritedClass, label); + tocEntries.put(getInheritedSummaryId(inheritedClass), label.stripTags()); } } + + return summaryCount; } private void addSummaryFootNote(TypeElement inheritedClass, Iterable inheritedMembers, @@ -328,6 +379,7 @@ public abstract class AbstractMemberWriter { * @return the member summary header */ public abstract Content getMemberSummaryHeader(Content content); + /** * Adds the given summary to the list of summaries. * @@ -383,13 +435,37 @@ public abstract class AbstractMemberWriter { */ protected abstract Table createSummaryTable(); + /** + * Creates a summary table for members of the kind supported by this writer inherited + * from {@code typeElement}. + * + * @param typeElement the superclass or interface + * @return a summary table + */ + protected Table createInheritedSummaryTable(TypeElement typeElement) { + throw new UnsupportedOperationException("Inherited summary not supported for " + kind); + } + + /** + * Creates an id for a summary table for members of the kind supported by this writer + * inherited from {@code typeElement}. + * + * @param typeElement the superclass or interface + * @return the id for the summary table + */ + protected HtmlId getInheritedSummaryId(TypeElement typeElement) { + throw new UnsupportedOperationException("Inherited summary not supported for " + kind); + } + /** * Adds inherited summary label for the member. * * @param typeElement the type element to which to link to * @param content the content to which the inherited summary label will be added */ - public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content content); + public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { + throw new UnsupportedOperationException("Inherited summary not supported for " + kind); + } /** * Adds the summary type for the member. @@ -428,8 +504,9 @@ public abstract class AbstractMemberWriter { * @param member the member to be documented * @param target the content to which the inherited summary link will be added */ - protected abstract void addInheritedSummaryLink(TypeElement typeElement, - Element member, Content target); + protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content target) { + throw new UnsupportedOperationException("Inherited summary not supported for " + kind); + } /** * Returns a link for summary (deprecated, preview) pages. @@ -616,11 +693,7 @@ public abstract class AbstractMemberWriter { * @param firstSentenceTrees the tags for the sentence being documented */ public void addMemberSummary(TypeElement tElement, Element member, - List firstSentenceTrees) { - if (tElement != typeElement) { - throw new IllegalStateException(getClass() + ": " + tElement + ", " + typeElement); - } - var table = getSummaryTable(); + List firstSentenceTrees, Table table) { List rowContents = new ArrayList<>(); Content summaryType = new ContentBuilder(); addSummaryType(member, summaryType); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java index 18ab23aa294..1568812da66 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java @@ -284,10 +284,6 @@ public class AnnotationTypeMemberWriter extends AbstractMemberWriter { .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); } - @Override - public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { - } - @Override protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { @@ -297,12 +293,6 @@ public class AnnotationTypeMemberWriter extends AbstractMemberWriter { content.add(code); } - @Override - protected void addInheritedSummaryLink(TypeElement typeElement, - Element member, Content target) { - //Not applicable. - } - @Override protected void addSummaryType(Element member, Content content) { addModifiersAndType(member, getType(member), content); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index c2145c1791a..d8d01a4e6ad 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -30,7 +30,6 @@ import java.util.List; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; @@ -40,7 +39,6 @@ import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; import jdk.javadoc.internal.html.HtmlStyle; -import jdk.javadoc.internal.html.HtmlTag; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -293,10 +291,6 @@ public class ConstructorWriter extends AbstractExecutableMemberWriter { .setColumnStyles(bodyRowStyles); } - @Override - public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { - } - @Override protected void addSummaryType(Element member, Content content) { if (threeColumnSummary()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java index 81c4f1ed87c..56c703e2aef 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java @@ -213,10 +213,6 @@ public class EnumConstantWriter extends AbstractMemberWriter { .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); } - @Override - public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { - } - @Override protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { @@ -226,10 +222,6 @@ public class EnumConstantWriter extends AbstractMemberWriter { content.add(code); } - @Override - protected void addInheritedSummaryLink(TypeElement typeElement, Element member, Content target) { - } - @Override protected void addSummaryType(Element member, Content content) { //Not applicable. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java index e3eed570f41..e44d06e1565 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java @@ -25,9 +25,6 @@ package jdk.javadoc.internal.doclets.formats.html; -import java.util.Arrays; -import java.util.List; - import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -38,7 +35,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; -import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -219,13 +216,19 @@ public class FieldWriter extends AbstractMemberWriter { @Override protected Table createSummaryTable() { - List bodyRowStyles = Arrays.asList(HtmlStyles.colFirst, HtmlStyles.colSecond, - HtmlStyles.colLast); - return new Table(HtmlStyles.summaryTable) .setCaption(contents.fields) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(bodyRowStyles); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, + HtmlStyles.colLast); + } + + @Override + protected Table createInheritedSummaryTable(TypeElement typeElement) { + return new Table(HtmlStyles.summaryTable) + .setHeader(getSummaryTableHeader(null)) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast) + .setRenderTabs(false); } @Override @@ -243,7 +246,7 @@ public class FieldWriter extends AbstractMemberWriter { } var labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, label); - labelHeading.setId(htmlIds.forInheritedFields(typeElement)); + labelHeading.setId(getInheritedSummaryId(typeElement)); labelHeading.add(Entity.NO_BREAK_SPACE); labelHeading.add(classLink); content.add(labelHeading); @@ -269,6 +272,11 @@ public class FieldWriter extends AbstractMemberWriter { addModifiersAndType(member, utils.asInstantiatedFieldType(typeElement, (VariableElement)member), content); } + @Override + protected HtmlId getInheritedSummaryId(TypeElement typeElement) { + return htmlIds.forInheritedFields(typeElement); + } + @Override protected Content getSummaryLink(Element member) { String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName(); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index 24fc8e6b2de..f364702ca12 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -324,6 +324,7 @@ public class HtmlDoclet extends AbstractDoclet { copyStylesheet(options); } copyResource(DocPaths.SCRIPT_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SCRIPT_JS), true); + copyResource(DocPaths.DOWN_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.DOWN_SVG), true); copyResource(DocPaths.LEFT_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.LEFT_SVG), true); copyResource(DocPaths.RIGHT_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.RIGHT_SVG), true); copyResource(DocPaths.CLIPBOARD_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.CLIPBOARD_SVG), true); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java index 2bab8cf6c47..3bc5b7617b0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java @@ -43,6 +43,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -302,6 +303,14 @@ public class MethodWriter extends AbstractExecutableMemberWriter { e -> utils.isDeprecated(e) || utils.isDeprecated(typeElement)); } + @Override + protected Table createInheritedSummaryTable(TypeElement typeElement) { + return new Table(HtmlStyles.summaryTable) + .setHeader(getSummaryTableHeader(null)) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast) + .setRenderTabs(false); + } + @Override public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { Content classLink = getMemberSummaryLinkOrFQN(typeElement, VisibleMemberTable.Kind.METHODS); @@ -317,12 +326,17 @@ public class MethodWriter extends AbstractExecutableMemberWriter { } var labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, label); - labelHeading.setId(htmlIds.forInheritedMethods(typeElement)); + labelHeading.setId(getInheritedSummaryId(typeElement)); labelHeading.add(Entity.NO_BREAK_SPACE); labelHeading.add(classLink); content.add(labelHeading); } + @Override + protected HtmlId getInheritedSummaryId(TypeElement typeElement) { + return htmlIds.forInheritedMethods(typeElement); + } + @Override protected void addSummaryType(Element member, Content content) { ExecutableElement meth = (ExecutableElement)member; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java index 8368172430e..1847ddf979f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java @@ -25,9 +25,6 @@ package jdk.javadoc.internal.doclets.formats.html; -import java.util.Arrays; -import java.util.List; - import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; @@ -36,7 +33,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; -import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -94,13 +91,19 @@ public class NestedClassWriter extends AbstractMemberWriter { @Override protected Table createSummaryTable() { - List bodyRowStyles = Arrays.asList(HtmlStyles.colFirst, HtmlStyles.colSecond, - HtmlStyles.colLast); - return new Table(HtmlStyles.summaryTable) .setCaption(contents.getContent("doclet.Nested_Classes")) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(bodyRowStyles); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, + HtmlStyles.colLast); + } + + @Override + protected Table createInheritedSummaryTable(TypeElement typeElement) { + return new Table(HtmlStyles.summaryTable) + .setHeader(getSummaryTableHeader(typeElement)) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast) + .setRenderTabs(false); } @Override @@ -117,12 +120,17 @@ public class NestedClassWriter extends AbstractMemberWriter { : resources.getText("doclet.Nested_Classes_Interfaces_Inherited_From_Class")); } var labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, label); - labelHeading.setId(htmlIds.forInheritedClasses(typeElement)); + labelHeading.setId(getInheritedSummaryId(typeElement)); labelHeading.add(Entity.NO_BREAK_SPACE); labelHeading.add(classLink); content.add(labelHeading); } + @Override + protected HtmlId getInheritedSummaryId(TypeElement typeElement) { + return htmlIds.forInheritedClasses(typeElement); + } + @Override protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java index 8146689016d..3a29712daff 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java @@ -42,6 +42,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -255,6 +256,14 @@ public class PropertyWriter extends AbstractMemberWriter { .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); } + @Override + protected Table createInheritedSummaryTable(TypeElement typeElement) { + return new Table(HtmlStyles.summaryTable) + .setHeader(getSummaryTableHeader(null)) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast) + .setRenderTabs(false); + } + @Override public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { Content classLink = getMemberSummaryLinkOrFQN(typeElement, VisibleMemberTable.Kind.PROPERTIES); @@ -270,12 +279,17 @@ public class PropertyWriter extends AbstractMemberWriter { } var labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, label) - .setId(htmlIds.forInheritedProperties(typeElement)) + .setId(getInheritedSummaryId(typeElement)) .add(Entity.NO_BREAK_SPACE) .add(classLink); content.add(labelHeading); } + @Override + protected HtmlId getInheritedSummaryId(TypeElement typeElement) { + return htmlIds.forInheritedProperties(typeElement); + } + @Override protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index 572d489057e..37edd800328 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -376,10 +376,13 @@ public class Table extends Content { } var table = HtmlTree.DIV(tableStyle).addStyle(gridStyle); - if ((tabs == null || occurringTabs.size() == 1) && renderTabs) { - if (tabs == null) { + if (tabs == null || (occurringTabs.size() == 1 && renderTabs)) { + // Render table with static content. Note that a single-tab table is only static + // if it is controlled by local tabs. In a multi-table summary page, it still + // must be able to show/hide its content depending on page-level controls. + if (caption != null) { main.add(caption); - } else { + } else if (tabs != null) { main.add(getCaption(occurringTabs.iterator().next().label())); } table.add(getTableBody()); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/down.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/down.svg new file mode 100644 index 00000000000..3d1b8746429 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/down.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/right.svg b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/right.svg index 4b54939c31b..138204f2ee7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/right.svg +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/right.svg @@ -9,4 +9,4 @@ - + \ No newline at end of file diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index a32c44b8043..b275323b2f5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -20,6 +20,7 @@ var activeTableTab = "active-table-tab"; const linkIcon = "##REPLACE:doclet.Link_icon##"; const linkToSection = "##REPLACE:doclet.Link_to_section##"; +const toggleMemberListing = "##REPLACE:doclet.Toggle_member_listing##"; if (typeof hljs !== "undefined") { try { @@ -508,27 +509,44 @@ document.addEventListener("DOMContentLoaded", function(e) { || (hdr.querySelector("a") && hdr.querySelector("a").getAttribute("id")); if (id) { var template = document.createElement('template'); - template.innerHTML =" " + linkIcon +""; + template.innerHTML =" "
+                    + linkIcon + ""; hdr.append(...template.content.childNodes); } }); + document.querySelectorAll("div.inherited-list:has( > div.summary-table) > h3").forEach(h => { + const button = document.createElement("button"); + const p = h.parentElement; + button.addEventListener("click", e => { + toggleStyle(p.classList, p.classList.contains("expanded"), "collapsed", "expanded"); + }); + button.addEventListener("keydown", e => { + if (e.key === " " || e.key === "Enter") { + toggleStyle(p.classList, p.classList.contains("expanded"), "collapsed", "expanded"); + e.preventDefault(); + } + }); + button.setAttribute("aria-label", toggleMemberListing); + h.insertAdjacentElement("afterbegin", button); + }); var sections; var scrollTimeout; var prevHash; function initSectionData() { bodyHeight = document.body.offsetHeight; - sections = [{ id: "", top: 0 }].concat(Array.from(main.querySelectorAll( - "section[id], h2[id], h2 a[id], h3[id], h3 a[id], div[id]")) - .filter((e) => { - return sidebar.querySelector("a[href=\"#" + encodeURI(e.getAttribute("id")) + "\"]") !== null - }).map((e) => { - return { - id: e.getAttribute("id"), - top: e.offsetTop - }; - })); + sections = [{ id: "", top: 0 }].concat( + Array.from(main.querySelectorAll("section[id], h2[id], h2 a[id], h3[id], h3 a[id], div[id]")) + .filter((e) => { + var id = encodeURI(e.getAttribute("id")); + return sidebar.querySelector("a[href=\"#" + id + "\"]") !== null + }).map((e) => { + return { + id: e.getAttribute("id"), + top: e.offsetTop + }; + }) + ); } function setScrollTimeout() { if (scrollTimeout) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 778ee5f03b3..d61283dc677 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -155,7 +155,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img { + div.main-grid img, + .inherited-list h3 > button { filter: invert(100%) brightness(160%); } } @@ -208,7 +209,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img { + div.main-grid img, + .inherited-list h3 > button { filter: invert(100%) brightness(160%); } } @@ -257,7 +259,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img { + div.main-grid img, + .inherited-list h3 > button { filter: none; } } @@ -881,17 +884,18 @@ ul.preview-feature-list input { } .caption span { background-color: var(--navbar-background-color); - padding:5px 12px 7px 12px; - height:16px; + padding:4.5px 12px; + height:19px; color:var(--navbar-text-color); display:inline-block; } .inherited-list h3 { background-color: var(--subnav-background-color); - padding:6px 12px 7px 12px; - height:17px; + padding:5px 5px 6px 12px; + height:18px; width: fit-content; max-width: 93%; + font-size: 0.99em; } /* Background required for captions with links */ .class-use-page .caption span, @@ -907,6 +911,12 @@ ul.preview-feature-list input { .inherited-list h3 a:visited { color:var(--subnav-link-color); } +.caption a:hover, +.caption a:active, +.inherited-list.expanded h3 a:hover, +.inherited-list.expanded h3 a:active { + color: var(--link-color-active); +} div.table-tabs { padding: 8px 0 0 1px; white-space: nowrap; @@ -995,7 +1005,7 @@ div.checkboxes > label > input { .summary-table > div, .details-table > div { font-size: var(--nav-font-size); line-height: 1.6; - padding: 8px 3px 3px 7px; + padding: 8px 5px 3px 7px; overflow: auto hidden; } .summary-table > div.table-header, .details-table > div.table-header { @@ -1515,6 +1525,27 @@ section[class$="-details"] .detail > div { margin: 20px 0; background-color:var(--detail-background-color); } +.inherited-list h3 > button { + cursor: pointer; + color: var(--subnav-link-color); + position: relative; + background-color: transparent; + background-image:url("right.svg"); + background-repeat: no-repeat; + background-size: 12px; + background-position:3px 6px; + border:none; + width: 1.3em; + height: 1.6em; + vertical-align: middle; + top: -2px; +} +.inherited-list h3:has(button) { + padding-left: 2px; +} +.inherited-list.expanded h3 > button { + background-image: url("down.svg"); +} .inherited-list > code { padding: 8px; display: block; @@ -1522,6 +1553,15 @@ section[class$="-details"] .detail > div { border-radius: 0; line-height: var(--code-line-height); } +.inherited-list > div { + display: none; +} +.inherited-list.expanded > code { + display: none; +} +.inherited-list.expanded > div { + display: grid; +} .vertical-separator { padding: 0 5px; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java index 9e7c9acc7bb..a7e5e7fed34 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -60,15 +60,10 @@ public class IndexTaglet extends BaseTaglet { } tagText = utils.normalizeWhitespace(tagText); - Content desc = tagletWriter.htmlWriter.commentTagsToContent(element, indexTree.getDescription(), context.within(indexTree)); - String descText = utils.normalizeWhitespace(extractText(desc)); + Content desc = tagletWriter.htmlWriter.commentTagsToContent(element, indexTree.getDescription(), + context.within(indexTree)); + String descText = utils.normalizeWhitespace(desc.stripTags().toString()); return tagletWriter.createAnchorAndSearchIndex(element, tagText, descText, tag); } - - // ugly but simple; - // alternatives would be to walk the Content's tree structure, or to add new functionality to Content - private String extractText(Content c) { - return c.toString().replaceAll("<[^>]+>", ""); - } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java index 82d37cfad8a..078b2b5206b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java @@ -46,11 +46,8 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; -import jdk.javadoc.internal.html.Entity; import jdk.javadoc.internal.html.HtmlTree; -import jdk.javadoc.internal.html.RawHtml; import jdk.javadoc.internal.html.Text; -import jdk.javadoc.internal.html.TextBuilder; /** * A taglet that represents the {@code @spec} tag. @@ -123,35 +120,7 @@ public class SpecTaglet extends BaseTaglet implements InheritableTaglet { List specTreeLabel = specTree.getTitle(); Content label = htmlWriter.commentTagsToContent(holder, specTreeLabel, tagletWriter.context.isFirstSentence); return getExternalSpecContent(holder, specTree, specTreeURL, - utils.normalizeWhitespace(textOf(label)), label); - } - - // this is here, for now, but might be a useful addition elsewhere, - // perhaps as a method on Content - private String textOf(Content c) { - return appendText(new StringBuilder(), c).toString(); - } - - private StringBuilder appendText(StringBuilder sb, Content c) { - if (c instanceof ContentBuilder cb) { - appendText(sb, cb.getContents()); - } else if (c instanceof HtmlTree ht) { - appendText(sb, ht.getContents()); - } else if (c instanceof RawHtml rh) { - sb.append(rh.toString().replaceAll("<[^>]*>", "")); - } else if (c instanceof TextBuilder tb) { - sb.append(tb.toString()); - } else if (c instanceof Text t) { - sb.append(t.toString()); - } else if (c instanceof Entity e) { - sb.append(e.toString()); - } - return sb; - } - - private StringBuilder appendText(StringBuilder sb, List contents) { - contents.forEach(c -> appendText(sb, c)); - return sb; + utils.normalizeWhitespace(label.stripTags().toString()), label); } Content getExternalSpecContent(Element holder, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java index b123e6f2556..f415a673345 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java @@ -361,6 +361,10 @@ public class CommentUtils { */ public void updatePropertyMethodComment(ExecutableElement member, Element property) { + // Check if member was already processed + if (dcInfoMap.containsKey(member)) { + return; + } final String memberName = member.getSimpleName().toString(); final boolean isSetter = memberName.startsWith("set"); final boolean isGetter = memberName.startsWith("get") || memberName.startsWith("is"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 4b02a720c78..138a8fd0040 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -74,6 +74,7 @@ doclet.JavaScript_in_option=option {0} contains JavaScript.\n\ Use --allow-script-in-comments to allow use of JavaScript. doclet.Link_icon=Link icon doclet.Link_to_section=Link to this section +doclet.Toggle_member_listing=Toggle between short and detailed list view doclet.Packages=Packages doclet.All_Packages=All Packages doclet.Modules=Modules diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java index 7bc4da60419..dbe91585aff 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocPaths.java @@ -106,6 +106,9 @@ public class DocPaths { /** The name of the copy-to-clipboard icon file. */ public static final DocPath CLIPBOARD_SVG = DocPath.create("copy.svg"); + /** The name of the downwards pointing angle icon. */ + public static final DocPath DOWN_SVG = DocPath.create("down.svg"); + /** The name of the left pointing angle icon. */ public static final DocPath LEFT_SVG = DocPath.create("left.svg"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java index 63142f83011..f582dbdc76a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java @@ -142,6 +142,13 @@ public abstract class Content { return 0; } + /** + * {@return the plain text of this content with HTML tags removed} + */ + public Content stripTags() { + return this; + } + /** * {@return true if the content is "phrasing content"} * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java index 358b1591dfc..abcd8e199bb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java @@ -105,6 +105,15 @@ public class ContentBuilder extends Content { return n; } + @Override + public Content stripTags() { + var text = new ContentBuilder(); + for (Content c : contents) { + text.add(c.stripTags()); + } + return text; + } + @Override public boolean isPhrasingContent() { return contents.stream().allMatch(Content::isPhrasingContent); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java index f53a71a6999..20af3013405 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java @@ -178,6 +178,7 @@ public class HtmlTree extends Content { */ @Override public HtmlTree add(Content content) { + Objects.requireNonNull(content, "Content must not be null"); if (content instanceof ContentBuilder cb) { cb.contents.forEach(this::add); } else if (!content.isDiscardable()) { @@ -279,6 +280,15 @@ public class HtmlTree extends Content { return n; } + @Override + public Content stripTags() { + var text = new ContentBuilder(); + for (Content c : content) { + text.add(c.stripTags()); + } + return text; + } + /* * The sets of ASCII URI characters to be left unencoded. * See "Uniform Resource Identifier (URI): Generic Syntax" diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java index 1c9f60f69e8..38be7799c4e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java @@ -157,6 +157,11 @@ public class RawHtml extends Content { return true; } + @Override + public Content stripTags() { + return Text.of(rawHtmlContent.replaceAll("<[^>]*>", "")); + } + @Override public String toString() { return rawHtmlContent; diff --git a/test/langtools/jdk/javadoc/doclet/testDuplicateMethodsWarn/TestDuplicateMethods.java b/test/langtools/jdk/javadoc/doclet/testDuplicateMethodsWarn/TestDuplicateMethods.java index 7e191290f8a..933138e9c6f 100644 --- a/test/langtools/jdk/javadoc/doclet/testDuplicateMethodsWarn/TestDuplicateMethods.java +++ b/test/langtools/jdk/javadoc/doclet/testDuplicateMethodsWarn/TestDuplicateMethods.java @@ -214,7 +214,7 @@ public class TestDuplicateMethods extends JavadocTester { """

    Methods inherited from class PubJ

    - testJ
    + testJ """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java b/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java index 88d2788e8da..f9378e624ba 100644 --- a/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java +++ b/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java @@ -77,7 +77,7 @@ public class TestHiddenTag extends JavadocTester { g1">A A.VisibleInner, A.Visible\ - InnerExtendsInvisibleInner
    + InnerExtendsInvisibleInner """); checkOutput("pkg1/A.VisibleInner.html", false, diff --git a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java index 3b6d2fee06d..6cabc68f7e9 100644 --- a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java +++ b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test * @bug 4682448 4947464 5029946 8025633 8026567 8035473 8139101 8175200 - 8186332 8186703 8182765 8187288 8261976 8303349 8319988 + 8186332 8186703 8182765 8187288 8261976 8303349 8319988 8350920 * @summary Verify that the public modifier does not show up in the * documentation for public methods, as recommended by the JLS. * If A implements I and B extends A, B should be in the list of @@ -211,7 +211,40 @@ public class TestInterface extends JavadocTester { OfDouble, Spliter\ ator.OfInt<Integer>, Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>"""); + code> +
    +
    Modifier and Type
    +
    Interface
    +
    Description
    +
    static interface 
    + +
     
    +
    static interface 
    + +
     
    +
    static interface 
    + +
     
    +
    + + """); checkOutput("pkg2/Spliterator.html", true, """
    Nested Classes
    diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index e5d8e5309bc..4fa89ee0ead 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -25,7 +25,7 @@ * @test * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 * 8167967 8172528 8175200 8178830 8182257 8186332 8182765 8025091 - * 8203791 8184205 8249633 8261976 + * 8203791 8184205 8249633 8261976 8350920 * @summary Test of the JavaFX doclet features. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -241,7 +241,29 @@ public class TestJavaFX extends JavadocTester { """

    Properties inherited from class&\ nbsp;C

    - paused, rate"""); + paused, rate +
    +
    Type
    +
    Property
    +
    Description
    + + +
    +
    Defines if paused.
    +
    + + +
    +
    Defines the direction/speed at which the Timeline is expected to + be played.
    +
    +
    + + """); checkOutput("pkg1/D.html", false, "shouldNotAppear"); } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java index 8a4aa614cd2..8a151407d61 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8157000 8192850 8182765 8223607 8261976 8281376 8313204 8345777 + * @bug 8157000 8192850 8182765 8223607 8261976 8281376 8313204 8345777 8350920 * @summary test the behavior of --override-methods option * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -85,6 +85,17 @@ public class TestOverrideMethods extends JavadocTester { "K", "V", + // Check summary table for inherited nested classes + "summary-table three-column-summary", + "Modifier and Type", + "Class", + "Description", + "class ", + "Classes.P.PN.html", + "Classes.P.PN.html#type-param-K", + "Classes.P.PN.html#type-param-V", + "A nested class in parent", + // Check properties """ Properties declared in class rate""", + // Check summary table for inherited properties + "summary-table three-column-summary", + "Type", + "Property", + "Description", + "Classes.DoubleProperty", + "Classes.P.html#rateProperty", + "rate", + // Check fields """ Fields declared in class field0", + // Check summary table for inherited fields + "summary-table three-column-summary", + "Modifier and Type", + "Field", + "Description", + "int", + "Classes.P.html#field0", + "field0", + // Check method summary "Method Summary", "void", @@ -118,11 +147,23 @@ public class TestOverrideMethods extends JavadocTester { """ Classes.GP.html#m0()" title="m0()">m0""", + // Check summary table for inherited methods + "summary-table three-column-summary", + "Modifier and Type", + "Method", + "Description", + "void", + "Classes.GP.html#m0()", + "m0", + "m0 in grand parent", + // Check methods from java.lang.Object """ - Methods declared in class java.lang.Object""", - """ - clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait""", +

    Methods declared in clas\ + s java.lang.Object

    + clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString,\ + wait, wait, wait + """, // Check method details for override """ @@ -190,6 +231,21 @@ public class TestOverrideMethods extends JavadocTester { "#m7()\">m7()" ); + checkOrder("pkg5/Classes.P.html", + // Check table of contents for inherited members + """ +
  • Nested Class Summary
  • +
  • Property Summary
  • +
  • Field Summary
  • +
  • Constructor Summary
  • +
  • Method Summary +
      +
    1. Method\ + s declared in class Classes.GP
    2. +
    3. Metho\ + ds declared in class java.lang.Object
    4. +
    """); + // Tests for interfaces // Make sure the static methods in the super interface @@ -391,8 +447,32 @@ public class TestOverrideMethods extends JavadocTester {

    Methods declared in class <\ a href="Base.html#method-summary" title="class in pkg6">Base

    m1, m3, m9 - """); + le="m3()">m3, m9
    +
    +
    Modifier and Type
    +
    Method
    +
    Description
    +
    java.lang.Object
    +
    m1()
    +
    +
    This is Base::m1.
    +
    + +
    m3()
    +
    +
    This is Base::m3.
    +
    +
    abstract java.lang.Object
    +
    m9()
    +
    +
    This is Base::m9.
    +
    +
    + """); } @Test @@ -415,7 +495,22 @@ public class TestOverrideMethods extends JavadocTester { erface AnnotatedBase m1"""); + , int[])">m1
    +
    +
    Modifier and Type
    +
    Method
    +
    Description
    +
    java.lang.Iterable<java.lang\ + .String>
    +
    m1(java.lang.Class<\ + ? extends java.lang.CharSequence> p1, + int[] p2)
    +
    +
    This is AnnotatedBase::m1.
    +
    +
    + """); checkOutput("pkg7/AnnotatedSub2.html", true, """ diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 44651c16f5e..d63220f5c4b 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -87,7 +87,7 @@ public class TestStylesheet extends JavadocTester { .summary-table > div, .details-table > div { font-size: var(--nav-font-size); line-height: 1.6; - padding: 8px 3px 3px 7px; + padding: 8px 5px 3px 7px; overflow: auto hidden; }""", "@import url('fonts/dejavu.css');", diff --git a/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java b/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java index 798a034ae13..c12ae597ce8 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java +++ b/test/langtools/jdk/javadoc/doclet/testUnexported/TestUnexported.java @@ -258,13 +258,13 @@ public class TestUnexported extends JavadocTester {

    Methods inherit\ ed from class InternalClass

    - p + p """, """

    Methods inh\ erited from interface InternalInterface

    - m + m """); checkOrder("mb/pb/B.html", @@ -286,13 +286,13 @@ public class TestUnexported extends JavadocTester {

    Methods inherit\ ed from class InternalClass

    - p + p """, """

    Methods inh\ erited from interface InternalInterface

    - m + m """); } diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index 5db718cd810..e4e3c6baa87 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -205,6 +205,7 @@ class APITest { "pkg/package-summary.html", "pkg/package-tree.html", "resource-files/copy.svg", + "resource-files/down.svg", "resource-files/glass.svg", "resource-files/jquery-ui.min.css", "resource-files/left.svg", From 6a480ad07a64dc291c5e46e024febedc857f5e1a Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 26 Aug 2025 16:58:54 +0000 Subject: [PATCH 230/471] 8366126: Feedback on two errors in JSR 400 Reviewed-by: hchao, wetmore --- .../share/classes/java/security/spec/EncodedKeySpec.java | 1 - .../share/classes/java/security/spec/PKCS8EncodedKeySpec.java | 1 - .../share/classes/java/security/spec/X509EncodedKeySpec.java | 1 - 3 files changed, 3 deletions(-) diff --git a/src/java.base/share/classes/java/security/spec/EncodedKeySpec.java b/src/java.base/share/classes/java/security/spec/EncodedKeySpec.java index e9838efdaf1..5c1a4f79f81 100644 --- a/src/java.base/share/classes/java/security/spec/EncodedKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/EncodedKeySpec.java @@ -79,7 +79,6 @@ public abstract class EncodedKeySpec implements KeySpec { * * Java Security Standard Algorithm Names Specification * for information about standard asymmetric key algorithm names. - * @spec security/standard-names.html Java Security Standard Algorithm Names * @throws NullPointerException if {@code encodedKey} * or {@code algorithm} is null. * @throws IllegalArgumentException if {@code algorithm} is diff --git a/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java b/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java index 917b15e06b6..0518e6ed272 100644 --- a/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java @@ -101,7 +101,6 @@ public non-sealed class PKCS8EncodedKeySpec extends EncodedKeySpec implements * * Java Security Standard Algorithm Names Specification * for information about standard asymmetric key algorithm names. - * @spec security/standard-names.html Java Security Standard Algorithm Names * @throws NullPointerException if {@code encodedKey} * or {@code algorithm} is null. * @throws IllegalArgumentException if {@code algorithm} is diff --git a/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java b/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java index e8b6e599676..6d0f105e64f 100644 --- a/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java @@ -80,7 +80,6 @@ public non-sealed class X509EncodedKeySpec extends EncodedKeySpec implements * * Java Security Standard Algorithm Names Specification * for information about standard asymmetric key algorithm names. - * @spec security/standard-names.html Java Security Standard Algorithm Names * @throws NullPointerException if {@code encodedKey} * or {@code algorithm} is null. * @throws IllegalArgumentException if {@code algorithm} is From 2b44ed70707175f87ba962d8a6ce6bbc2c8737bf Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 26 Aug 2025 17:42:27 +0000 Subject: [PATCH 231/471] 8365807: (fs) Two-arg UnixFileAttributes.getIfExists should not use exception for control flow Reviewed-by: alanb --- .../sun/nio/fs/UnixFileAttributes.java | 35 ++++++------------- .../sun/nio/fs/UnixNativeDispatcher.java | 24 +++++++++---- .../native/libnio/fs/UnixNativeDispatcher.c | 16 ++++----- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 48dc4c07d0d..55661ff12a3 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -83,18 +83,8 @@ class UnixFileAttributes // get the UnixFileAttributes for a given file. // Returns null if the file does not exist. - static UnixFileAttributes getIfExists(UnixPath path) - throws UnixException - { - UnixFileAttributes attrs = new UnixFileAttributes(); - int errno = UnixNativeDispatcher.stat2(path, attrs); - if (errno == 0) { - return attrs; - } else if (errno == UnixConstants.ENOENT) { - return null; - } else { - throw new UnixException(errno); - } + static UnixFileAttributes getIfExists(UnixPath path) throws UnixException { + return getIfExists(path, true); } // get the UnixFileAttributes for a given file, optionally following links. @@ -104,17 +94,14 @@ class UnixFileAttributes { UnixFileAttributes attrs = new UnixFileAttributes(); int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW; - try { - UnixNativeDispatcher.fstatat(UnixConstants.AT_FDCWD, - path.asByteArray(), flag, attrs); - } catch (UnixException x) { - if (x.errno() == UnixConstants.ENOENT) - return null; - - throw x; - } - - return attrs; + int errno = UnixNativeDispatcher.fstatat2(UnixConstants.AT_FDCWD, + path, flag, attrs); + if (errno == 0) + return attrs; + else if (errno == UnixConstants.ENOENT) + return null; + else + throw new UnixException(errno); } // get the UnixFileAttributes for an open file @@ -130,7 +117,7 @@ class UnixFileAttributes { UnixFileAttributes attrs = new UnixFileAttributes(); int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW; - UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs); + UnixNativeDispatcher.fstatat(dfd, path, flag, attrs); return attrs; } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index 09611f23298..77dc1851478 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -256,15 +256,15 @@ class UnixNativeDispatcher { } } } + private static native int stat0(long pathAddress, UnixFileAttributes attrs); + // Variant of stat() returning errno instead of throwing UnixException static int stat2(UnixPath path, UnixFileAttributes attrs) { try (NativeBuffer buffer = copyToNativeBuffer(path)) { return stat0(buffer.address(), attrs); } } - private static native int stat0(long pathAddress, UnixFileAttributes attrs); - /** * lstat(const char* path, struct stat* buf) */ @@ -288,15 +288,25 @@ class UnixNativeDispatcher { /** * fstatat(int filedes,const char* path, struct stat* buf, int flag) */ - static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs) + static void fstatat(int dfd, UnixPath path, int flag, UnixFileAttributes attrs) throws UnixException { - try (NativeBuffer buffer = NativeBuffers.asNativeBuffer(path)) { - fstatat0(dfd, buffer.address(), flag, attrs); + try (NativeBuffer buffer = copyToNativeBuffer(path)) { + int errno = fstatat0(dfd, buffer.address(), flag, attrs); + if (errno != 0) { + throw new UnixException(errno); + } + } + } + private static native int fstatat0(int dfd, long pathAddress, int flag, + UnixFileAttributes attrs); + + // Variant of fstatat() returning errno instead of throwing UnixException + static int fstatat2(int dfd, UnixPath path, int flag, UnixFileAttributes attrs) { + try (NativeBuffer buffer = copyToNativeBuffer(path)) { + return fstatat0(dfd, buffer.address(), flag, attrs); } } - private static native void fstatat0(int dfd, long pathAddress, int flag, - UnixFileAttributes attrs) throws UnixException; /** * chown(const char* path, uid_t owner, gid_t group) diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 5f81241b7dd..60ccdfc45fc 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -741,7 +741,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstat0(JNIEnv* env, jclass this, jint fd, } } -JNIEXPORT void JNICALL +JNIEXPORT jint JNICALL Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, jlong pathAddress, jint flag, jobject attrs) { @@ -761,23 +761,23 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd RESTARTABLE(statx_wrapper((int)dfd, path, flags, mask, &statx_buf), err); if (err == 0) { copy_statx_attributes(env, &statx_buf, attrs); + return 0; } else { - throwUnixException(env, errno); + return errno; } - // statx was available, so return now - return; } #endif if (my_fstatat_func == NULL) { JNU_ThrowInternalError(env, "should not reach here"); - return; + return ENOTSUP; } RESTARTABLE((*my_fstatat_func)((int)dfd, path, &buf, (int)flag), err); - if (err == -1) { - throwUnixException(env, errno); - } else { + if (err == 0) { copy_stat_attributes(env, &buf, attrs); + return 0; + } else { + return errno; } } From c203e7093e9b8c52cdf4ae249ab27d16d6a2c623 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 26 Aug 2025 18:37:22 +0000 Subject: [PATCH 232/471] 8366037: Remove oopDesc::mark_addr() Reviewed-by: shade, stefank, tschatzl --- src/hotspot/share/gc/g1/g1OopClosures.inline.hpp | 6 +++--- .../share/gc/parallel/psPromotionManager.inline.hpp | 4 ++-- src/hotspot/share/oops/oop.hpp | 4 +++- src/hotspot/share/oops/oop.inline.hpp | 7 +++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 8d84f144f02..c0c67fda949 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -50,8 +50,8 @@ inline void G1ScanClosureBase::prefetch_and_push(T* p, const oop obj) { // stall. We'll try to prefetch the object (for write, given that // we might need to install the forwarding reference) and we'll // get back to it when pop it from the queue - Prefetch::write(obj->mark_addr(), 0); - Prefetch::read(obj->mark_addr(), (HeapWordSize*2)); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); + Prefetch::read(obj->base_addr(), oopDesc::mark_offset_in_bytes() + (HeapWordSize*2)); // slightly paranoid test; I'm trying to catch potential // problems before we go into push_on_queue to know where the diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 4946b0fde82..451a7dae189 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. 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 @@ -61,7 +61,7 @@ inline void PSPromotionManager::claim_or_forward_depth(T* p) { if (PSScavenge::is_obj_in_young(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?"); - Prefetch::write(obj->mark_addr(), 0); + Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); push_depth(ScannerTask(p)); } } diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 02f87da2937..3ec0ce5764a 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -65,9 +65,11 @@ class oopDesc { // Must be trivial; see verifying static assert after the class. oopDesc() = default; + inline void* base_addr(); + inline const void* base_addr() const; + inline markWord mark() const; inline markWord mark_acquire() const; - inline markWord* mark_addr() const; inline void set_mark(markWord m); static inline void set_mark(HeapWord* mem, markWord m); diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 4ca1bfce472..16c444a43f8 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -47,6 +47,9 @@ // Implementation of all inlined member functions defined in oop.hpp // We need a separate file to avoid circular references +void* oopDesc::base_addr() { return this; } +const void* oopDesc::base_addr() const { return this; } + markWord oopDesc::mark() const { return Atomic::load(&_mark); } @@ -55,10 +58,6 @@ markWord oopDesc::mark_acquire() const { return Atomic::load_acquire(&_mark); } -markWord* oopDesc::mark_addr() const { - return (markWord*) &_mark; -} - void oopDesc::set_mark(markWord m) { Atomic::store(&_mark, m); } From c75534517729b903b63263cf64dc2ff841e3dcb1 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 26 Aug 2025 18:54:16 +0000 Subject: [PATCH 233/471] 8365197: javax.imageio.stream MemoryCache based streams no longer need a disposer. Reviewed-by: psadhukhan, jdv, serb --- .../stream/MemoryCacheImageInputStream.java | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java index 1799254c59a..0630e19e98c 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -27,8 +27,6 @@ package javax.imageio.stream; import java.io.InputStream; import java.io.IOException; -import sun.java2d.Disposer; -import sun.java2d.DisposerRecord; /** * An implementation of {@code ImageInputStream} that gets its @@ -48,12 +46,6 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { private MemoryCache cache = new MemoryCache(); - /** The referent to be registered with the Disposer. */ - private final Object disposerReferent = new Object(); - - /** The DisposerRecord that resets the underlying MemoryCache. */ - private final DisposerRecord disposerRecord; - /** * Constructs a {@code MemoryCacheImageInputStream} that will read * from a given {@code InputStream}. @@ -68,9 +60,6 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { throw new IllegalArgumentException("stream == null!"); } this.stream = stream; - - disposerRecord = new StreamDisposerRecord(cache); - Disposer.addRecord(disposerReferent, disposerRecord); } public int read() throws IOException { @@ -165,23 +154,8 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { */ public void close() throws IOException { super.close(); - disposerRecord.dispose(); // this resets the MemoryCache stream = null; + cache.reset(); cache = null; } - - private static class StreamDisposerRecord implements DisposerRecord { - private MemoryCache cache; - - public StreamDisposerRecord(MemoryCache cache) { - this.cache = cache; - } - - public synchronized void dispose() { - if (cache != null) { - cache.reset(); - cache = null; - } - } - } } From b426151a33158637eb04c07a5133d95cbb8bf04c Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 26 Aug 2025 20:54:27 +0000 Subject: [PATCH 234/471] 8365885: Clean up constant pool reflection native code Reviewed-by: iklam, alanb --- src/hotspot/share/include/jvm.h | 36 ++++----- src/hotspot/share/prims/jvm.cpp | 36 ++++----- .../jdk/internal/reflect/ConstantPool.java | 78 ++++++++++--------- .../share/native/libjava/ConstantPool.c | 74 +++++++++--------- .../constantPool/ConstantPoolTest.java | 33 +++++--- .../constantPool/ConstantPoolTestDummy.jasm | 8 +- 6 files changed, 140 insertions(+), 125 deletions(-) diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 4d39537e5a1..2f0958bcac4 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -644,58 +644,58 @@ JNIEXPORT jobject JNICALL JVM_GetClassConstantPool(JNIEnv *env, jclass cls); JNIEXPORT jint JNICALL JVM_ConstantPoolGetSize -(JNIEnv *env, jobject unused, jobject jcpool); +(JNIEnv *env, jobject jcpool); JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jclass JNICALL JVM_ConstantPoolGetClassAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetClassRefIndexAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetMethodAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobject JNICALL JVM_ConstantPoolGetFieldAtIfLoaded -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetMemberRefInfoAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetNameAndTypeRefIndexAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jobjectArray JNICALL JVM_ConstantPoolGetNameAndTypeRefInfoAt -(JNIEnv *env, jobject obj, jobject unused, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jint JNICALL JVM_ConstantPoolGetIntAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jlong JNICALL JVM_ConstantPoolGetLongAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jfloat JNICALL JVM_ConstantPoolGetFloatAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jdouble JNICALL JVM_ConstantPoolGetDoubleAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jstring JNICALL JVM_ConstantPoolGetStringAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jstring JNICALL JVM_ConstantPoolGetUTF8At -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); JNIEXPORT jbyte JNICALL JVM_ConstantPoolGetTagAt -(JNIEnv *env, jobject unused, jobject jcpool, jint index); +(JNIEnv *env, jobject jcpool, jint index); /* * Parameter reflection diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 098bd729c0b..abec3bc59b6 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1927,7 +1927,7 @@ JVM_ENTRY(jobject, JVM_GetClassConstantPool(JNIEnv *env, jclass cls)) JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused)) +JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); return cp->length(); @@ -1935,7 +1935,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetSize(JNIEnv *env, jobject obj, jobject unused JVM_END -JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -1948,7 +1948,7 @@ JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -1992,7 +1992,7 @@ static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bo return JNIHandles::make_local(THREAD, method); } -JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2002,7 +2002,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2037,7 +2037,7 @@ static jobject get_field_at_helper(constantPoolHandle cp, jint index, bool force return JNIHandles::make_local(THREAD, field); } -JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jobject unusedl, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2047,7 +2047,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2057,7 +2057,7 @@ JVM_ENTRY(jobject, JVM_ConstantPoolGetFieldAtIfLoaded(JNIEnv *env, jobject obj, } JVM_END -JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2082,7 +2082,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2095,7 +2095,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetClassRefIndexAt(JNIEnv *env, jobject obj, job } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2108,7 +2108,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetNameAndTypeRefIndexAt(JNIEnv *env, jobject ob } JVM_END -JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2129,7 +2129,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, job } JVM_END -JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); @@ -2141,7 +2141,7 @@ JVM_ENTRY(jint, JVM_ConstantPoolGetIntAt(JNIEnv *env, jobject obj, jobject unuse } JVM_END -JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0L)); @@ -2153,7 +2153,7 @@ JVM_ENTRY(jlong, JVM_ConstantPoolGetLongAt(JNIEnv *env, jobject obj, jobject unu } JVM_END -JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0f)); @@ -2165,7 +2165,7 @@ JVM_ENTRY(jfloat, JVM_ConstantPoolGetFloatAt(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_(0.0)); @@ -2177,7 +2177,7 @@ JVM_ENTRY(jdouble, JVM_ConstantPoolGetDoubleAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_NULL); @@ -2190,7 +2190,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject } JVM_END -JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jint index)) { JvmtiVMObjectAllocEventCollector oam; constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); @@ -2205,7 +2205,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject u } JVM_END -JVM_ENTRY(jbyte, JVM_ConstantPoolGetTagAt(JNIEnv *env, jobject obj, jobject unused, jint index)) +JVM_ENTRY(jbyte, JVM_ConstantPoolGetTagAt(JNIEnv *env, jobject obj, jint index)) { constantPoolHandle cp = constantPoolHandle(THREAD, reflect_ConstantPool::get_cp(JNIHandles::resolve_non_null(obj))); bounds_check(cp, index, CHECK_0); diff --git a/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java b/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java index a43034126e4..d56ecff5e36 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -34,41 +34,41 @@ import java.util.Set; public class ConstantPool { // Number of entries in this constant pool (= maximum valid constant pool index) - public int getSize() { return getSize0 (constantPoolOop); } - public Class getClassAt (int index) { return getClassAt0 (constantPoolOop, index); } - public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (constantPoolOop, index); } + public int getSize() { return getSize0 (); } + public Class getClassAt (int index) { return getClassAt0 (index); } + public Class getClassAtIfLoaded (int index) { return getClassAtIfLoaded0 (index); } // Returns a class reference index for a method or a field. public int getClassRefIndexAt(int index) { - return getClassRefIndexAt0(constantPoolOop, index); + return getClassRefIndexAt0(index); } // Returns either a Method or Constructor. // Static initializers are returned as Method objects. - public Member getMethodAt (int index) { return getMethodAt0 (constantPoolOop, index); } - public Member getMethodAtIfLoaded(int index) { return getMethodAtIfLoaded0(constantPoolOop, index); } - public Field getFieldAt (int index) { return getFieldAt0 (constantPoolOop, index); } - public Field getFieldAtIfLoaded (int index) { return getFieldAtIfLoaded0 (constantPoolOop, index); } + public Member getMethodAt (int index) { return getMethodAt0 (index); } + public Member getMethodAtIfLoaded(int index) { return getMethodAtIfLoaded0(index); } + public Field getFieldAt (int index) { return getFieldAt0 (index); } + public Field getFieldAtIfLoaded (int index) { return getFieldAtIfLoaded0 (index); } // Fetches the class name, member (field, method or interface // method) name, and type descriptor as an array of three Strings - public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (constantPoolOop, index); } + public String[] getMemberRefInfoAt (int index) { return getMemberRefInfoAt0 (index); } // Returns a name and type reference index for a method, a field or an invokedynamic. public int getNameAndTypeRefIndexAt(int index) { - return getNameAndTypeRefIndexAt0(constantPoolOop, index); + return getNameAndTypeRefIndexAt0(index); } // Fetches the name and type from name_and_type index as an array of two Strings public String[] getNameAndTypeRefInfoAt(int index) { - return getNameAndTypeRefInfoAt0(constantPoolOop, index); + return getNameAndTypeRefInfoAt0(index); } - public int getIntAt (int index) { return getIntAt0 (constantPoolOop, index); } - public long getLongAt (int index) { return getLongAt0 (constantPoolOop, index); } - public float getFloatAt (int index) { return getFloatAt0 (constantPoolOop, index); } - public double getDoubleAt (int index) { return getDoubleAt0 (constantPoolOop, index); } - public String getStringAt (int index) { return getStringAt0 (constantPoolOop, index); } - public String getUTF8At (int index) { return getUTF8At0 (constantPoolOop, index); } + public int getIntAt (int index) { return getIntAt0 (index); } + public long getLongAt (int index) { return getLongAt0 (index); } + public float getFloatAt (int index) { return getFloatAt0 (index); } + public double getDoubleAt (int index) { return getDoubleAt0 (index); } + public String getStringAt (int index) { return getStringAt0 (index); } + public String getUTF8At (int index) { return getUTF8At0 (index); } public Tag getTagAt(int index) { - return Tag.valueOf(getTagAt0(constantPoolOop, index)); + return Tag.valueOf(getTagAt0(index)); } - public static enum Tag { + public enum Tag { UTF8(1), INTEGER(3), FLOAT(4), @@ -82,7 +82,9 @@ public class ConstantPool { NAMEANDTYPE(12), METHODHANDLE(15), METHODTYPE(16), + DYNAMIC(17), INVOKEDYNAMIC(18), + // For index after long/double and 0 INVALID(0); private final int tagCode; @@ -111,22 +113,22 @@ public class ConstantPool { // HotSpot-internal constant pool object (set by the VM, name known to the VM) private Object constantPoolOop; - private native int getSize0 (Object constantPoolOop); - private native Class getClassAt0 (Object constantPoolOop, int index); - private native Class getClassAtIfLoaded0 (Object constantPoolOop, int index); - private native int getClassRefIndexAt0 (Object constantPoolOop, int index); - private native Member getMethodAt0 (Object constantPoolOop, int index); - private native Member getMethodAtIfLoaded0(Object constantPoolOop, int index); - private native Field getFieldAt0 (Object constantPoolOop, int index); - private native Field getFieldAtIfLoaded0 (Object constantPoolOop, int index); - private native String[] getMemberRefInfoAt0 (Object constantPoolOop, int index); - private native int getNameAndTypeRefIndexAt0(Object constantPoolOop, int index); - private native String[] getNameAndTypeRefInfoAt0(Object constantPoolOop, int index); - private native int getIntAt0 (Object constantPoolOop, int index); - private native long getLongAt0 (Object constantPoolOop, int index); - private native float getFloatAt0 (Object constantPoolOop, int index); - private native double getDoubleAt0 (Object constantPoolOop, int index); - private native String getStringAt0 (Object constantPoolOop, int index); - private native String getUTF8At0 (Object constantPoolOop, int index); - private native byte getTagAt0 (Object constantPoolOop, int index); + private native int getSize0 (); + private native Class getClassAt0 (int index); + private native Class getClassAtIfLoaded0 (int index); + private native int getClassRefIndexAt0 (int index); + private native Member getMethodAt0 (int index); + private native Member getMethodAtIfLoaded0(int index); + private native Field getFieldAt0 (int index); + private native Field getFieldAtIfLoaded0 (int index); + private native String[] getMemberRefInfoAt0 (int index); + private native int getNameAndTypeRefIndexAt0(int index); + private native String[] getNameAndTypeRefInfoAt0(int index); + private native int getIntAt0 (int index); + private native long getLongAt0 (int index); + private native float getFloatAt0 (int index); + private native double getDoubleAt0 (int index); + private native String getStringAt0 (int index); + private native String getUTF8At0 (int index); + private native byte getTagAt0 (int index); } diff --git a/src/java.base/share/native/libjava/ConstantPool.c b/src/java.base/share/native/libjava/ConstantPool.c index 3fb7b74e518..2fea25c728a 100644 --- a/src/java.base/share/native/libjava/ConstantPool.c +++ b/src/java.base/share/native/libjava/ConstantPool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -27,110 +27,110 @@ #include "jdk_internal_reflect_ConstantPool.h" JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getSize0 -(JNIEnv *env, jobject unused, jobject jcpool) +(JNIEnv *env, jobject jcpool) { - return JVM_ConstantPoolGetSize(env, unused, jcpool); + return JVM_ConstantPoolGetSize(env, jcpool); } JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassAt(env, jcpool, index); } JNIEXPORT jclass JNICALL Java_jdk_internal_reflect_ConstantPool_getClassAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassAtIfLoaded(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getClassRefIndexAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetClassRefIndexAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetClassRefIndexAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMethodAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetMethodAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getMethodAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMethodAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetMethodAtIfLoaded(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFieldAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetFieldAt(env, jcpool, index); } JNIEXPORT jobject JNICALL Java_jdk_internal_reflect_ConstantPool_getFieldAtIfLoaded0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFieldAtIfLoaded(env, unused, jcpool, index); + return JVM_ConstantPoolGetFieldAtIfLoaded(env, jcpool, index); } JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getMemberRefInfoAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetMemberRefInfoAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetMemberRefInfoAt(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefIndexAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetNameAndTypeRefIndexAt(env, jcpool, index); } JNIEXPORT jobjectArray JNICALL Java_jdk_internal_reflect_ConstantPool_getNameAndTypeRefInfoAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetNameAndTypeRefInfoAt(env, jcpool, index); } JNIEXPORT jint JNICALL Java_jdk_internal_reflect_ConstantPool_getIntAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetIntAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetIntAt(env, jcpool, index); } JNIEXPORT jlong JNICALL Java_jdk_internal_reflect_ConstantPool_getLongAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetLongAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetLongAt(env, jcpool, index); } JNIEXPORT jfloat JNICALL Java_jdk_internal_reflect_ConstantPool_getFloatAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetFloatAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetFloatAt(env, jcpool, index); } JNIEXPORT jdouble JNICALL Java_jdk_internal_reflect_ConstantPool_getDoubleAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetDoubleAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetDoubleAt(env, jcpool, index); } JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getStringAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetStringAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetStringAt(env, jcpool, index); } JNIEXPORT jstring JNICALL Java_jdk_internal_reflect_ConstantPool_getUTF8At0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetUTF8At(env, unused, jcpool, index); + return JVM_ConstantPoolGetUTF8At(env, jcpool, index); } JNIEXPORT jbyte JNICALL Java_jdk_internal_reflect_ConstantPool_getTagAt0 -(JNIEnv *env, jobject unused, jobject jcpool, jint index) +(JNIEnv *env, jobject jcpool, jint index) { - return JVM_ConstantPoolGetTagAt(env, unused, jcpool, index); + return JVM_ConstantPoolGetTagAt(env, jcpool, index); } diff --git a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java index 903a08e56df..f53b6cf0032 100644 --- a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java +++ b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -29,16 +29,21 @@ * java.base/jdk.internal.reflect * @library /test/lib * @compile ConstantPoolTestDummy.jasm - * @run main jdk.internal.reflect.constantPool.ConstantPoolTest + * @compile ConstantPoolTest.java + * @run junit ConstantPoolTest */ -package jdk.internal.reflect.constantPool; - +import java.lang.classfile.ClassFile; import java.util.HashMap; import java.util.Map; import jdk.internal.access.SharedSecrets; import jdk.internal.reflect.ConstantPool; import jdk.test.lib.Asserts; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConstantPoolTest { @@ -46,13 +51,23 @@ public class ConstantPoolTest { private static final ConstantPool CP = SharedSecrets.getJavaLangAccess() .getConstantPool(TEST_CLASS); - public static void main(String[] s) { - for (TestCase testCase : TestCase.values()) { - testCase.test(); - } + @ParameterizedTest + @EnumSource(TestCase.class) + void runTestCases(TestCase testCase) { + testCase.test(); } - public static enum TestCase { + @Test + void testSize() throws Throwable { + byte[] data; + try (var in = ConstantPoolTest.class.getResourceAsStream("/ConstantPoolTestDummy.class")) { + data = in.readAllBytes(); + } + var testClass = ClassFile.of().parse(data); + assertEquals(testClass.constantPool().size(), CP.getSize()); + } + + public enum TestCase { GET_TAG_AT { { referenceMap.put(1, ConstantPool.Tag.METHODREF); diff --git a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm index 3884f1644ff..03934b930e0 100644 --- a/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm +++ b/test/jdk/jdk/internal/reflect/constantPool/ConstantPoolTestDummy.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -21,8 +21,6 @@ * questions. */ -package jdk/internal/reflect/constantPool; - super public #2; //class ConstantPoolTestDummy version 52:0 { @@ -41,7 +39,7 @@ const #7 = Asciz "LineNumberTable"; const #8 = Asciz "SourceFile"; const #9 = Asciz "ConstantPoolTestDummy.java"; const #10 = NameAndType #4:#5; // "":"()V" -const #11 = Asciz "jdk/internal/reflect/constantPool/ConstantPoolTestDummy"; +const #11 = Asciz "ConstantPoolTestDummy"; const #12 = Asciz "java/lang/Object"; const #13 = long 6l; const #15 = int 1; @@ -76,7 +74,7 @@ const #44 = Asciz "Lookup"; const #45 = class #47; // java/lang/invoke/MethodHandles const #46 = Asciz "java/lang/invoke/MethodHandles$Lookup"; const #47 = Asciz "java/lang/invoke/MethodHandles"; -const #48 = Field #2.#49; // jdk/internal/reflect/constantPool/ConstantPoolTestDummy.myField:"I" +const #48 = Field #2.#49; // ConstantPoolTestDummy.myField:"I" const #49 = NameAndType #50:#51; // myField:"I" const #50 = Asciz "myField"; const #51 = Asciz "I"; From 23670fd41895ccc38931f836d218ff7392a6065a Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:49:57 +0000 Subject: [PATCH 235/471] 8363972: Lenient parsing of minus sign pattern in DecimalFormat/CompactNumberFormat Reviewed-by: jlu, rriggs --- .../build/tools/cldrconverter/Bundle.java | 1 + .../tools/cldrconverter/LDMLParseHandler.java | 28 ++ .../java/text/CompactNumberFormat.java | 24 +- .../classes/java/text/DecimalFormat.java | 71 ++++- .../java/text/DecimalFormatSymbols.java | 54 +++- .../share/classes/java/text/NumberFormat.java | 6 +- .../TestCompactNumber.java | 9 +- .../NumberFormat/LenientMinusSignTest.java | 251 ++++++++++++++++++ 8 files changed, 406 insertions(+), 38 deletions(-) create mode 100644 test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index cbef22d91c0..c4aaa28193a 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -79,6 +79,7 @@ class Bundle { "NumberElements/nan", "NumberElements/currencyDecimal", "NumberElements/currencyGroup", + "NumberElements/lenientMinusSigns", }; private static final String[] TIME_PATTERN_KEYS = { diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 6d5dde0d181..98c0605f8b7 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -844,6 +844,26 @@ class LDMLParseHandler extends AbstractLDMLHandler { }); break; + // Lenient parsing + case "parseLenients": + if ("lenient".equals(attributes.getValue("level"))) { + pushKeyContainer(qName, attributes, attributes.getValue("scope")); + } else { + pushIgnoredContainer(qName); + } + break; + + case "parseLenient": + // Use only the lenient minus sign for now + if (currentContainer instanceof KeyContainer kc + && kc.getKey().equals("number") + && attributes.getValue("sample").equals("-")) { + pushStringEntry(qName, attributes, currentNumberingSystem + "NumberElements/lenientMinusSigns"); + } else { + pushIgnoredContainer(qName); + } + break; + default: // treat anything else as a container pushContainer(qName, attributes); @@ -1150,6 +1170,14 @@ class LDMLParseHandler extends AbstractLDMLHandler { currentStyle = ""; putIfEntry(); break; + case "parseLenient": + if (currentContainer instanceof StringEntry se) { + // Convert to a simple concatenation of lenient minuses + // e.g. "[\--﹣ ‐‑ ‒ – −⁻₋ ➖]" -> "--﹣‐‑‒–−⁻₋➖" for the root locale + put(se.getKey(), se.getValue().replaceAll("[\\[\\]\\\\ ]", "")); + } + break; + default: putIfEntry(); } diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index fae11cbdba1..7163b2dd63b 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -147,7 +147,7 @@ import java.util.stream.Collectors; * a compact pattern. This special pattern can appear explicitly for any specific * range, or considered as a default pattern for an empty string. * - *

    Negative Subpatterns

    + *

    Negative Subpatterns

    * A compact pattern contains a positive and negative subpattern * separated by a subpattern boundary character {@code ';'}, * for example, {@code "0K;-0K"}. Each subpattern has a prefix, @@ -159,7 +159,10 @@ import java.util.stream.Collectors; * the negative prefix and suffix. The number of minimum integer digits, * and other characteristics are all the same as the positive pattern. * That means that {@code "0K;-00K"} produces precisely the same behavior - * as {@code "0K;-0K"}. + * as {@code "0K;-0K"}. In {@link NumberFormat##leniency lenient parsing} + * mode, loose matching of the minus sign pattern is enabled, following the + * LDML’s + * loose matching specification. * *

    Escaping Special Characters

    * Many characters in a compact pattern are taken literally, they are matched @@ -1585,6 +1588,9 @@ public final class CompactNumberFormat extends NumberFormat { * and are not digits that occur within the numerical portion * *

    + * When lenient, the minus sign in the {@link ##negative_subpatterns + * negative subpatterns} is loosely matched against lenient minus sign characters. + *

    * The subclass returned depends on the value of * {@link #isParseBigDecimal}. *

      @@ -1693,14 +1699,12 @@ public final class CompactNumberFormat extends NumberFormat { // Given text does not match the non empty valid compact prefixes // check with the default prefixes if (!gotPositive && !gotNegative) { - if (text.regionMatches(pos.index, defaultPosPrefix, 0, - defaultPosPrefix.length())) { + if (decimalFormat.matchAffix(text, position, defaultPosPrefix)) { // Matches the default positive prefix matchedPosPrefix = defaultPosPrefix; gotPositive = true; } - if (text.regionMatches(pos.index, defaultNegPrefix, 0, - defaultNegPrefix.length())) { + if (decimalFormat.matchAffix(text, position, defaultNegPrefix)) { // Matches the default negative prefix matchedNegPrefix = defaultNegPrefix; gotNegative = true; @@ -1924,7 +1928,7 @@ public final class CompactNumberFormat extends NumberFormat { if (!affix.isEmpty() && !affix.equals(defaultAffix)) { // Look ahead only for the longer match than the previous match if (matchedAffix.length() < affix.length()) { - return text.regionMatches(position, affix, 0, affix.length()); + return decimalFormat.matchAffix(text, position, affix); } } return false; @@ -2026,8 +2030,7 @@ public final class CompactNumberFormat extends NumberFormat { if (!gotPos && !gotNeg) { String positiveSuffix = defaultDecimalFormat.getPositiveSuffix(); String negativeSuffix = defaultDecimalFormat.getNegativeSuffix(); - boolean containsPosSuffix = text.regionMatches(position, - positiveSuffix, 0, positiveSuffix.length()); + boolean containsPosSuffix = decimalFormat.matchAffix(text, position, positiveSuffix); boolean endsWithPosSuffix = containsPosSuffix && text.length() == position + positiveSuffix.length(); if (parseStrict ? endsWithPosSuffix : containsPosSuffix) { @@ -2035,8 +2038,7 @@ public final class CompactNumberFormat extends NumberFormat { matchedPosSuffix = positiveSuffix; gotPos = true; } - boolean containsNegSuffix = text.regionMatches(position, - negativeSuffix, 0, negativeSuffix.length()); + boolean containsNegSuffix = decimalFormat.matchAffix(text, position, negativeSuffix); boolean endsWithNegSuffix = containsNegSuffix && text.length() == position + negativeSuffix.length(); if (parseStrict ? endsWithNegSuffix : containsNegSuffix) { diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 50bb1e01336..aa881aecc8a 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -296,7 +296,7 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * #setMaximumIntegerDigits(int)} can be used to manually adjust the maximum * integer digits. * - *

      Negative Subpatterns

      + *

      Negative Subpatterns

      * A {@code DecimalFormat} pattern contains a positive and negative * subpattern, for example, {@code "#,##0.00;(#,##0.00)"}. Each * subpattern has a prefix, numeric part, and suffix. The negative subpattern @@ -307,7 +307,11 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * serves only to specify the negative prefix and suffix; the number of digits, * minimal digits, and other characteristics are all the same as the positive * pattern. That means that {@code "#,##0.0#;(#)"} produces precisely - * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}. + * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}. In + * {@link NumberFormat##leniency lenient parsing} mode, loose matching of the + * minus sign pattern is enabled, following the LDML’s + * + * loose matching specification. * *

      The prefixes, suffixes, and various symbols used for infinity, digits, * grouping separators, decimal separators, etc. may be set to arbitrary @@ -2189,6 +2193,9 @@ public class DecimalFormat extends NumberFormat { * and are not digits that occur within the numerical portion *

    *

    + * When lenient, the minus sign in the {@link ##negative_subpatterns + * negative subpatterns} is loosely matched against lenient minus sign characters. + *

    * The subclass returned depends on the value of {@link #isParseBigDecimal} * as well as on the string being parsed. *

      @@ -2385,10 +2392,8 @@ public class DecimalFormat extends NumberFormat { boolean gotPositive, gotNegative; // check for positivePrefix; take longest - gotPositive = text.regionMatches(position, positivePrefix, 0, - positivePrefix.length()); - gotNegative = text.regionMatches(position, negativePrefix, 0, - negativePrefix.length()); + gotPositive = matchAffix(text, position, positivePrefix); + gotNegative = matchAffix(text, position, negativePrefix); if (gotPositive && gotNegative) { if (positivePrefix.length() > negativePrefix.length()) { @@ -2424,15 +2429,13 @@ public class DecimalFormat extends NumberFormat { // When lenient, text only needs to contain the suffix. if (!isExponent) { if (gotPositive) { - boolean containsPosSuffix = - text.regionMatches(position, positiveSuffix, 0, positiveSuffix.length()); + boolean containsPosSuffix = matchAffix(text, position, positiveSuffix); boolean endsWithPosSuffix = containsPosSuffix && text.length() == position + positiveSuffix.length(); gotPositive = parseStrict ? endsWithPosSuffix : containsPosSuffix; } if (gotNegative) { - boolean containsNegSuffix = - text.regionMatches(position, negativeSuffix, 0, negativeSuffix.length()); + boolean containsNegSuffix = matchAffix(text, position, negativeSuffix); boolean endsWithNegSuffix = containsNegSuffix && text.length() == position + negativeSuffix.length(); gotNegative = parseStrict ? endsWithNegSuffix : containsNegSuffix; @@ -3501,6 +3504,54 @@ public class DecimalFormat extends NumberFormat { if (needQuote) buffer.append('\''); } + /** + * {@return true if the text matches the affix} + * In lenient mode, lenient minus signs also match the hyphen-minus + * (U+002D). Package-private access, as this is called from + * CompactNumberFormat. + * + * Note: Minus signs in the supplementary character range or normalization + * equivalents are not matched, as they may alter the affix length. + */ + boolean matchAffix(String text, int position, String affix) { + var alen = affix.length(); + var tlen = text.length(); + + if (alen == 0) { + // always match with an empty affix, as affix is optional + return true; + } + if (position >= tlen) { + return false; + } + if (parseStrict) { + return text.regionMatches(position, affix, 0, alen); + } + + var lms = symbols.getLenientMinusSigns(); + int i = 0; + int limit = Math.min(tlen, position + alen); + for (; position + i < limit; i++) { + char t = text.charAt(position + i); + char a = affix.charAt(i); + int tIndex = lms.indexOf(t); + int aIndex = lms.indexOf(a); + // Non LMS. Match direct + if (tIndex < 0 && aIndex < 0) { + if (t != a) { + return false; + } + } else { + // By here, at least one LMS. Ensure both LMS. + if (tIndex < 0 || aIndex < 0) { + return false; + } + } + } + // Return true if entire affix was matched + return i == alen; + } + /** * Implementation of producing a pattern. This method returns a positive and * negative (if needed), pattern string in the form of : Prefix (optional) diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index da20af60662..dfb344f26a7 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -718,6 +718,17 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { this.minusSign = findNonFormatChar(minusSignText, '-'); } + /** + * {@return the lenient minus signs} Multiple lenient minus signs + * are concatenated to form the returned string. Each codepoint + * in the string is a valid minus sign pattern. If there are no + * lenient minus signs defined in this locale, {@code minusSignText} + * is returned. + */ + String getLenientMinusSigns() { + return lenientMinusSigns; + } + //------------------------------------------------------------ // END Package Private methods ... to be made public later //------------------------------------------------------------ @@ -818,18 +829,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private void initialize(Locale locale) { this.locale = locale; - // check for region override - Locale override = locale.getUnicodeLocaleType("nu") == null ? - CalendarDataUtility.findRegionOverride(locale) : - locale; - - // get resource bundle data - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); - // Avoid potential recursions - if (!(adapter instanceof ResourceBundleBasedAdapter)) { - adapter = LocaleProviderAdapter.getResourceBundleBased(); - } - Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); + Object[] data = loadNumberData(locale); String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0); @@ -854,11 +854,30 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { monetaryGroupingSeparator = numberElements.length < 13 || numberElements[12].isEmpty() ? groupingSeparator : numberElements[12].charAt(0); + // Lenient minus signs + lenientMinusSigns = numberElements.length < 14 ? minusSignText : numberElements[13]; + // maybe filled with previously cached values, or null. intlCurrencySymbol = (String) data[1]; currencySymbol = (String) data[2]; } + private Object[] loadNumberData(Locale locale) { + // check for region override + Locale override = locale.getUnicodeLocaleType("nu") == null ? + CalendarDataUtility.findRegionOverride(locale) : + locale; + + // get resource bundle data + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); + // Avoid potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + + return adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); + } + /** * Obtains non-format single character from String */ @@ -995,6 +1014,14 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { } currencyInitialized = true; } + + if (loadNumberData(locale) instanceof Object[] d && + d[0] instanceof String[] numberElements && + numberElements.length >= 14) { + lenientMinusSigns = numberElements[13]; + } else { + lenientMinusSigns = minusSignText; + } } /** @@ -1174,6 +1201,9 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { private transient Currency currency; private transient volatile boolean currencyInitialized; + // Lenient minus. No need to be set by applications + private transient String lenientMinusSigns; + /** * Cached hash code. */ diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 0f4da56de0c..759ed7ae5ea 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -195,7 +195,11 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * Lenient parsing should be used when attempting to parse a number * out of a String that contains non-numerical or non-format related values. * For example, using a {@link Locale#US} currency format to parse the number - * {@code 1000} out of the String "$1,000.00 was paid". + * {@code 1000} out of the String "$1,000.00 was paid". Lenient parsing also + * allows loose matching of characters in the source text. For example, an + * implementation of the {@code NumberFormat} class may allow matching "−" + * (U+2212 MINUS SIGN) to the "-" (U+002D HYPHEN-MINUS) pattern character + * when used as a negative prefix. *

      * Strict parsing should be used when attempting to ensure a String adheres exactly * to a locale's conventions, and can thus serve to validate input. For example, successfully diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index 16de2247779..e9972f62f3e 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 + * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 8363972 * @summary Checks the functioning of compact number format * @modules jdk.localedata * @run testng/othervm TestCompactNumber @@ -462,6 +462,8 @@ public class TestCompactNumber { {FORMAT_SE_SHORT, "12345679,89\u00a0bn", 1.2345679890000001E19, Double.class}, {FORMAT_SE_SHORT, "\u2212999", -999L, Long.class}, {FORMAT_SE_SHORT, "\u22128\u00a0mn", -8000000L, Long.class}, + // lenient parsing. Hyphen-minus should match the localized minus sign + {FORMAT_SE_SHORT, "-8\u00a0mn", -8000000L, Long.class}, {FORMAT_SE_SHORT, "\u22128\u00a0dt", -8000L, Long.class}, {FORMAT_SE_SHORT, "\u221212345679\u00a0bn", -1.2345679E19, Double.class}, {FORMAT_SE_SHORT, "\u221212345679,89\u00a0bn", -1.2345679890000001E19, Double.class}, @@ -503,8 +505,7 @@ public class TestCompactNumber { {FORMAT_EN_US_SHORT, "K12,347", null}, // Invalid prefix for ja_JP {FORMAT_JA_JP_SHORT, "\u4E071", null}, - // Localized minus sign should be used - {FORMAT_SE_SHORT, "-8\u00a0mn", null},}; + }; } @DataProvider(name = "invalidParse") diff --git a/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java b/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java new file mode 100644 index 00000000000..251cac7c9cb --- /dev/null +++ b/test/jdk/java/text/Format/NumberFormat/LenientMinusSignTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8363972 + * @summary Unit tests for lenient minus parsing + * @modules jdk.localedata + * java.base/java.text:+open + * @run junit LenientMinusSignTest + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.invoke.MethodHandles; +import java.text.CompactNumberFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class LenientMinusSignTest { + private static final Locale FINNISH = Locale.of("fi"); + private static final DecimalFormatSymbols DFS = + new DecimalFormatSymbols(Locale.ROOT); + private static final String MINUS_PATTERN = "\u002D"; + + // "parseLenient" data from CLDR v47. These data are subject to change + private static Stream minus() { + return Stream.of( + MINUS_PATTERN, // "-" Hyphen-Minus + "\uFF0D", // "-" Fullwidth Hyphen-Minus + "\uFE63", // "﹣" Small Hyphen-Minus + "\u2010", // "‐" Hyphen + "\u2011", // "‑" Non-Breaking Hyphen + "\u2012", // "‒" Figure Dash + "\u2013", // "–" En Dash + "\u2212", // "−" Minus Sign + "\u207B", // "⁻" Superscript Minus + "\u208B", // "₋" Subscript Minus + "\u2796" // "➖" Heavy Minus Sign + ); + } + + @Test + void testFinnishMinus() throws ParseException { + // originally reported in JDK-8189097 + // Should not throw a ParseException + assertEquals(NumberFormat.getInstance(FINNISH).parse(MINUS_PATTERN + "1,5"), -1.5); + } + + @Test + void testFinnishMinusStrict() { + // Should throw a ParseException + var nf = NumberFormat.getInstance(FINNISH); + nf.setStrict(true); + assertThrows(ParseException.class, () -> nf.parse(MINUS_PATTERN + "1,5")); + } + + @Test + void testReadObject() throws IOException, ClassNotFoundException, ParseException { + // check if deserialized NF works with lenient minus. Using the Finnish example + var nf = NumberFormat.getInstance(FINNISH); + NumberFormat nfDeser; + byte[] serialized; + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos)) { + out.writeObject(nf); + out.flush(); + serialized = bos.toByteArray(); + } + try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized); + ObjectInputStream in = new ObjectInputStream(bis)) { + nfDeser = (NumberFormat) in.readObject(); + } + assertEquals(nfDeser.parse(MINUS_PATTERN + "1,5"), -1.5); + } + + // White box test. modifies the private `lenientMinusSigns` field in the DFS + @Test + void testSupplementary() throws IllegalAccessException, NoSuchFieldException, ParseException { + var dfs = new DecimalFormatSymbols(Locale.ROOT); + MethodHandles.privateLookupIn(DecimalFormatSymbols.class, MethodHandles.lookup()) + .findVarHandle(DecimalFormatSymbols.class, "lenientMinusSigns", String.class) + .set(dfs, "-🙂"); + // Direct match. Should succeed + var df = new DecimalFormat("#.#;🙂#.#", dfs); + assertEquals(df.parse("🙂1.5"), -1.5); + + // Fail if the lengths of negative prefixes differ + assertThrows(ParseException.class, () -> df.parse("-1.5")); + var df2= new DecimalFormat("#.#;-#.#", dfs); + assertThrows(ParseException.class, () -> df2.parse("🙂1.5")); + } + + @Nested + class DecimalFormatTest { + private static final String PREFIX = "+#;-#"; + private static final String SUFFIX = "#+;#-"; + private static final String LONG_PREFIX = "pos#;-neg#"; + private static final String LONG_SUFFIX = "#pos;#neg-"; + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientPrefix(String sign) throws ParseException { + var df = new DecimalFormat(PREFIX, DFS); + df.setStrict(false); + assertEquals(MINUS_PATTERN + "1", df.format(df.parse(sign + "1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientSuffix(String sign) throws ParseException { + var df = new DecimalFormat(SUFFIX, DFS); + df.setStrict(false); + assertEquals("1" + MINUS_PATTERN, df.format(df.parse("1" + sign))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictPrefix(String sign) throws ParseException { + var df = new DecimalFormat(PREFIX, DFS); + df.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals(MINUS_PATTERN + "1", df.format(df.parse(sign + "1"))); + } else { + assertThrows(ParseException.class, () -> df.parse(sign + "1")); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictSuffix(String sign) throws ParseException { + var df = new DecimalFormat(SUFFIX, DFS); + df.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals("1" + MINUS_PATTERN, df.format(df.parse("1" + sign))); + } else { + assertThrows(ParseException.class, () -> df.parse("1" + sign)); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongPrefix(String sign) throws ParseException { + var df = new DecimalFormat(LONG_PREFIX, DFS); + assertEquals(MINUS_PATTERN + "neg1", df.format(df.parse(sign + "neg1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongSuffix(String sign) throws ParseException { + var df = new DecimalFormat(LONG_SUFFIX, DFS); + assertEquals("1neg" + MINUS_PATTERN, df.format(df.parse("1neg" + sign))); + } + } + + @Nested + class CompactNumberFormatTest { + private static final String[] PREFIX = {"+0;-0"}; + private static final String[] SUFFIX = {"0+;0-"}; + private static final String[] LONG_PREFIX = {"pos0;-neg0"}; + private static final String[] LONG_SUFFIX = {"0pos;0neg-"}; + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, PREFIX); + cnf.setStrict(false); + assertEquals(MINUS_PATTERN + "1", cnf.format(cnf.parse(sign + "1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLenientSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, SUFFIX); + cnf.setStrict(false); + assertEquals("1" + MINUS_PATTERN, cnf.format(cnf.parse("1" + sign))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, PREFIX); + cnf.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals(MINUS_PATTERN + "1", cnf.format(cnf.parse(sign + "1"))); + } else { + assertThrows(ParseException.class, () -> cnf.parse(sign + "1")); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testStrictSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, SUFFIX); + cnf.setStrict(true); + if (sign.equals(MINUS_PATTERN)) { + assertEquals("1" + MINUS_PATTERN, cnf.format(cnf.parse("1" + sign))); + } else { + assertThrows(ParseException.class, () -> cnf.parse("1" + sign)); + } + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongPrefix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, LONG_PREFIX); + assertEquals(MINUS_PATTERN + "neg1", cnf.format(cnf.parse(sign + "neg1"))); + } + + @ParameterizedTest + @MethodSource("LenientMinusSignTest#minus") + public void testLongSuffix(String sign) throws ParseException { + var cnf = new CompactNumberFormat("0", DFS, LONG_SUFFIX); + assertEquals("1neg" + MINUS_PATTERN, cnf.format(cnf.parse( "1neg" + sign))); + } + } +} From 69645fd4ba5c0a7e20727f5d85d87cefc40e8c70 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:51:32 +0000 Subject: [PATCH 236/471] 8361972: Clarify the condition of System.console() about standard input/output Reviewed-by: smarks, jlu, joehw --- .../share/classes/java/io/Console.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 838334a0901..2878de79718 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -38,20 +38,20 @@ import sun.nio.cs.UTF_8; * Methods to access the character-based console device, if any, associated * with the current Java virtual machine. * - *

      Whether a virtual machine has a console is dependent upon the + *

      Whether a virtual machine's console exists is dependent upon the * underlying platform and also upon the manner in which the virtual * machine is invoked. If the virtual machine is started from an * interactive command line without redirecting the standard input and - * output streams then its console will exist and will typically be + * output streams, then its console will generally exist and will be * connected to the keyboard and display from which the virtual machine - * was launched. If the virtual machine is started automatically, for - * example by a background job scheduler, then it may not - * have a console. + * was launched. If the standard input or standard output have been + * redirected (for example, to a file or to a pipe), or if the virtual + * machine was started from a background job scheduler, the console + * will not exist. *

      - * If this virtual machine has a console then it is represented by a - * unique instance of this class which can be obtained by invoking the - * {@link java.lang.System#console()} method. If no console device is - * available then an invocation of that method will return {@code null}. + * If the console exists, then it is represented by a unique instance of this + * class which can be obtained by invoking the {@link System#console()} method. + * If the console does not exist, that method will return {@code null}. *

      * Read and write operations are synchronized to guarantee the atomic * completion of critical operations; therefore invoking methods @@ -535,18 +535,14 @@ public sealed class Console implements Flushable permits ProxyingConsole { /** * {@return {@code true} if the {@code Console} instance is a terminal} *

      - * This method returns {@code true} if the console device, associated with the current - * Java virtual machine, is a terminal, typically an interactive command line - * connected to a keyboard and display. - * - * @implNote The default implementation returns the value equivalent to calling - * {@code isatty(stdin/stdout)} on POSIX platforms, or whether standard in/out file - * descriptors are character devices or not on Windows. + * This method always returns {@code true}, since {@link System#console()} + * provides a {@code Console} instance only when both standard input and + * output are unredirected, that is, when running in an interactive terminal. * * @since 22 */ public boolean isTerminal() { - return istty; + return true; } private static UnsupportedOperationException newUnsupportedOperationException() { From 1ff73cb2ec41612d316921e852f29e7fa4dc9109 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 26 Aug 2025 21:51:53 +0000 Subject: [PATCH 237/471] 8364752: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss Reviewed-by: rriggs, vyazici, scolebourne --- .../java/time/format/DateTimeFormatter.java | 8 ++- .../time/format/DateTimeFormatterBuilder.java | 11 ++-- .../java/time/test/java/time/TestInstant.java | 61 ++++++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 7127e277294..108f1e1eef8 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -1199,8 +1199,10 @@ public final class DateTimeFormatter { * When formatting, the instant will always be suffixed by 'Z' to indicate UTC. * The second-of-minute is always output. * The nano-of-second outputs zero, three, six or nine digits as necessary. - * When parsing, the behaviour of {@link DateTimeFormatterBuilder#appendOffsetId()} - * will be used to parse the offset, converting the instant to UTC as necessary. + * When parsing, the lenient mode behavior of + * {@link DateTimeFormatterBuilder#appendOffset(String, String) + * appendOffset("+HH", "Z")} will be used to parse the offset, + * converting the instant to UTC as necessary. * The time to at least the seconds field is required. * Fractional seconds from zero to nine are parsed. * The localized decimal style is not used. diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index f5eeeec563c..43a79cd85ee 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -894,8 +894,10 @@ public final class DateTimeFormatterBuilder { * {@link DateTimeFormatter#parsedLeapSecond()} for full details. *

      * When formatting, the instant will always be suffixed by 'Z' to indicate UTC. - * When parsing, the behaviour of {@link DateTimeFormatterBuilder#appendOffsetId()} - * will be used to parse the offset, converting the instant to UTC as necessary. + * When parsing, the lenient mode behaviour of + * {@link DateTimeFormatterBuilder#appendOffset(String, String) + * appendOffset("+HH", "Z")} will be used to parse the offset, + * converting the instant to UTC as necessary. *

      * An alternative to this method is to format/parse the instant as a single * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}. @@ -956,7 +958,7 @@ public final class DateTimeFormatterBuilder { * Appends the zone offset, such as '+01:00', to the formatter. *

      * This appends an instruction to format/parse the offset ID to the builder. - * This is equivalent to calling {@code appendOffset("+HH:mm:ss", "Z")}. + * This is equivalent to calling {@code appendOffset("+HH:MM:ss", "Z")}. * See {@link #appendOffset(String, String)} for details on formatting * and parsing. * @@ -3887,7 +3889,8 @@ public final class DateTimeFormatterBuilder { .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true) - .appendOffsetId() + .parseLenient() + .appendOffset("+HH", "Z") .toFormatter().toPrinterParser(false); DateTimeParseContext newContext = context.copy(); int pos = parser.parse(newContext, text, position); diff --git a/test/jdk/java/time/test/java/time/TestInstant.java b/test/jdk/java/time/test/java/time/TestInstant.java index 1879334cb2a..8dbd951bde1 100644 --- a/test/jdk/java/time/test/java/time/TestInstant.java +++ b/test/jdk/java/time/test/java/time/TestInstant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -61,6 +61,9 @@ package test.java.time; import java.time.Duration; import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import org.testng.annotations.Test; @@ -70,7 +73,7 @@ import static org.testng.Assert.assertThrows; /** * Test Instant. - * @bug 8273369 8331202 + * @bug 8273369 8331202 8364752 */ @Test public class TestInstant extends AbstractTest { @@ -151,4 +154,58 @@ public class TestInstant extends AbstractTest { Instant.now().until(null); }); } + + @DataProvider + private Object[][] valid_instants() { + var I1 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02")).toInstant(); + var I2 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02:02")).toInstant(); + var I3 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("+02:02:02")).toInstant(); + var I4 = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.of("Z")).toInstant(); + return new Object[][] { + {"2017-01-01T00:00:00.000+02", I1}, + {"2017-01-01T00:00:00.000+0200", I1}, + {"2017-01-01T00:00:00.000+02:00", I1}, + {"2017-01-01T00:00:00.000+020000", I1}, + {"2017-01-01T00:00:00.000+02:00:00", I1}, + + {"2017-01-01T00:00:00.000+0202", I2}, + {"2017-01-01T00:00:00.000+02:02", I2}, + + {"2017-01-01T00:00:00.000+020202", I3}, + {"2017-01-01T00:00:00.000+02:02:02", I3}, + + {"2017-01-01T00:00:00.000Z", I4}, + }; + } + + @Test(dataProvider = "valid_instants") + public void test_parse_valid(String instant, Instant expected) { + assertEquals(Instant.parse(instant), expected); + } + + @DataProvider + private Object[][] invalid_instants() { + return new Object[][] { + {"2017-01-01T00:00:00.000"}, + {"2017-01-01T00:00:00.000+0"}, + {"2017-01-01T00:00:00.000+0:"}, + {"2017-01-01T00:00:00.000+02:"}, + {"2017-01-01T00:00:00.000+020"}, + {"2017-01-01T00:00:00.000+02:0"}, + {"2017-01-01T00:00:00.000+02:0:"}, + {"2017-01-01T00:00:00.000+02:00:"}, + {"2017-01-01T00:00:00.000+02:000"}, + {"2017-01-01T00:00:00.000+02:00:0"}, + {"2017-01-01T00:00:00.000+02:00:0:"}, + {"2017-01-01T00:00:00.000+0200000"}, + {"2017-01-01T00:00:00.000+02:00:000"}, + {"2017-01-01T00:00:00.000+02:00:00:"}, + {"2017-01-01T00:00:00.000UTC"}, + }; + } + + @Test(dataProvider = "invalid_instants") + public void test_parse_invalid(String instant) { + assertThrows(DateTimeParseException.class, () -> Instant.parse(instant)); + } } From 82289f6559cc083ee306b3175fef3ae9f87d6b1c Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 26 Aug 2025 22:30:32 +0000 Subject: [PATCH 238/471] 8365611: Use lookup table for JfrEventThrottler Reviewed-by: mgronlun --- .../recorder/service/jfrEventThrottler.cpp | 104 ++++++++++-------- .../recorder/service/jfrEventThrottler.hpp | 6 +- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp index f660a01c04c..787b2d7456b 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp @@ -25,7 +25,10 @@ #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/utilities/jfrSpinlockHelper.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" constexpr static const JfrSamplerParams _disabled_params = { 0, // sample points per window @@ -34,9 +37,44 @@ constexpr static const JfrSamplerParams _disabled_params = { false // reconfigure }; -static JfrEventThrottler* _disabled_cpu_time_sample_throttler = nullptr; -static JfrEventThrottler* _object_allocation_throttler = nullptr; -static JfrEventThrottler* _safepoint_latency_throttler = nullptr; +constexpr static const JfrEventId throttleble_events[] = { + JfrCPUTimeSampleEvent, JfrObjectAllocationSampleEvent, JfrSafepointLatencyEvent +}; +constexpr static int num_throttled_events = sizeof(throttleble_events) / sizeof(throttleble_events[0]); + +// Throttler-by-ID lookup table +class ThrottlerLookupTable { + static constexpr int max = (int)LAST_EVENT_ID; + STATIC_ASSERT(max < 1000); // should this ever get unreasonably large, we rethink this table. + JfrEventThrottler* _table[max]; +public: + ThrottlerLookupTable() { memset(_table, 0, sizeof(_table)); } + + bool initialize() { + for (int i = 0; i < num_throttled_events; i++) { + const JfrEventId id = throttleble_events[i]; + JfrEventThrottler* p = JfrEventThrottler::create_throttler(id); + _table[(int)id] = p; + if (p == nullptr) { + return false; + } + } + return true; + } + + void destroy() { + for (int i = 0; i < max; i++) { + delete _table[i]; + _table[i] = nullptr; + } + } + + JfrEventThrottler* at(JfrEventId id) const { + return _table[(int)id]; + } +}; + +static ThrottlerLookupTable _throttler_table; JfrEventThrottler::JfrEventThrottler(JfrEventId event_id) : JfrAdaptiveSampler(), @@ -49,58 +87,36 @@ JfrEventThrottler::JfrEventThrottler(JfrEventId event_id) : _update(false) {} bool JfrEventThrottler::create() { - assert(_disabled_cpu_time_sample_throttler == nullptr, "invariant"); - _disabled_cpu_time_sample_throttler = new JfrEventThrottler(JfrCPUTimeSampleEvent); - _disabled_cpu_time_sample_throttler->_disabled = true; - assert(_object_allocation_throttler == nullptr, "invariant"); - _object_allocation_throttler = new JfrEventThrottler(JfrObjectAllocationSampleEvent); - if (_object_allocation_throttler == nullptr || !_object_allocation_throttler->initialize()) { - return false; + bool rc = _throttler_table.initialize(); + if (rc) { + _throttler_table.at(JfrCPUTimeSampleEvent)->_disabled = true; // CPU time sampler disabled } - assert(_safepoint_latency_throttler == nullptr, "invariant"); - _safepoint_latency_throttler = new JfrEventThrottler(JfrSafepointLatencyEvent); - return _safepoint_latency_throttler != nullptr && _safepoint_latency_throttler->initialize(); + return rc; } void JfrEventThrottler::destroy() { - delete _disabled_cpu_time_sample_throttler; - _disabled_cpu_time_sample_throttler = nullptr; - delete _object_allocation_throttler; - _object_allocation_throttler = nullptr; - delete _safepoint_latency_throttler; - _safepoint_latency_throttler = nullptr; + _throttler_table.destroy(); } -// There is currently only two throttler instances, one for the jdk.ObjectAllocationSample event -// and another for the SamplingLatency event. -// When introducing many more throttlers, consider adding a lookup map keyed by event id. JfrEventThrottler* JfrEventThrottler::for_event(JfrEventId event_id) { - assert(_disabled_cpu_time_sample_throttler != nullptr, "Disabled CPU time throttler has not been properly initialized"); - assert(_object_allocation_throttler != nullptr, "ObjectAllocation throttler has not been properly initialized"); - assert(_safepoint_latency_throttler != nullptr, "SafepointLatency throttler has not been properly initialized"); - assert(event_id == JfrObjectAllocationSampleEvent || event_id == JfrSafepointLatencyEvent || event_id == JfrCPUTimeSampleEvent, "Event type has an unconfigured throttler"); - if (event_id == JfrObjectAllocationSampleEvent) { - return _object_allocation_throttler; - } - if (event_id == JfrSafepointLatencyEvent) { - return _safepoint_latency_throttler; - } - if (event_id == JfrCPUTimeSampleEvent) { - return _disabled_cpu_time_sample_throttler; - } - return nullptr; + JfrEventThrottler* const throttler = _throttler_table.at(event_id); + assert(throttler != nullptr, "Event type %d has an unconfigured throttler", (int)event_id); + return throttler; } void JfrEventThrottler::configure(JfrEventId event_id, int64_t sample_size, int64_t period_ms) { - if (event_id == JfrObjectAllocationSampleEvent) { - assert(_object_allocation_throttler != nullptr, "ObjectAllocation throttler has not been properly initialized"); - _object_allocation_throttler->configure(sample_size, period_ms); - return; - } - if (event_id == JfrSafepointLatencyEvent) { - assert(_safepoint_latency_throttler != nullptr, "SafepointLatency throttler has not been properly initialized"); - _safepoint_latency_throttler->configure(sample_size, period_ms); + JfrEventThrottler* const throttler = _throttler_table.at(event_id); + assert(throttler != nullptr, "Event type %d has an unconfigured throttler", (int)event_id); + throttler->configure(sample_size, period_ms); +} + +JfrEventThrottler* JfrEventThrottler::create_throttler(JfrEventId id) { + JfrEventThrottler* p = new JfrEventThrottler(id); + if (p != nullptr && p->initialize() == false) { + delete p; + p = nullptr; } + return p; } /* diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp index be6f8127205..d6e123ecbe6 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Datadog, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,8 +29,11 @@ #include "jfr/support/jfrAdaptiveSampler.hpp" #include "jfrfiles/jfrEventIds.hpp" +class ThrottlerLookupTable; + class JfrEventThrottler : public JfrAdaptiveSampler { friend class JfrRecorder; + friend class ThrottlerLookupTable; private: JfrSamplerParams _last_params; int64_t _sample_size; @@ -43,6 +46,7 @@ class JfrEventThrottler : public JfrAdaptiveSampler { static bool create(); static void destroy(); JfrEventThrottler(JfrEventId event_id); + static JfrEventThrottler* create_throttler(JfrEventId event_id); void configure(int64_t event_sample_size, int64_t period_ms); const JfrSamplerParams& update_params(const JfrSamplerWindow* expired); From 1aca920f5987399dbd114fd5e62b26b363363e64 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Tue, 26 Aug 2025 23:57:20 +0000 Subject: [PATCH 239/471] 8365673: Incorrect number of cores are reported on Ryzen CPU Reviewed-by: dholmes, kvn --- src/hotspot/cpu/x86/vm_version_x86.cpp | 5 ++++- src/hotspot/cpu/x86/vm_version_x86.hpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 266fe5abb99..1c9f8ed2e40 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -3148,7 +3148,10 @@ uint VM_Version::cores_per_cpu() { result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); } } else if (is_amd_family()) { - result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1); + result = _cpuid_info.ext_cpuid8_ecx.bits.threads_per_cpu + 1; + if (cpu_family() >= 0x17) { // Zen or later + result /= _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1; + } } else if (is_zx()) { bool supports_topology = supports_processor_topology(); if (supports_topology) { diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 573d4ed27dc..54b3a93d64b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -199,8 +199,8 @@ class VM_Version : public Abstract_VM_Version { union ExtCpuid8Ecx { uint32_t value; struct { - uint32_t cores_per_cpu : 8, - : 24; + uint32_t threads_per_cpu : 8, + : 24; } bits; }; From 0d543293045d0037791774a1414ef279a1f6768b Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 27 Aug 2025 02:15:02 +0000 Subject: [PATCH 240/471] 8366127: RISC-V: compiler/intrinsics/TestVerifyIntrinsicChecks.java fails when running without RVV Reviewed-by: fyang, fjiang --- .../jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java index 392ca35e2fd..c482a73affd 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestVerifyIntrinsicChecks.java @@ -34,6 +34,7 @@ * @comment `vm.debug == true` is required since `VerifyIntrinsicChecks` is a * development flag * @requires vm.debug == true & vm.flavor == "server" & !vm.graal.enabled + * @requires (os.arch != "riscv64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*")) * @run main/othervm compiler.intrinsics.TestVerifyIntrinsicChecks verify */ From aaff9dec241e4d8eebefd6beaf287582621f315c Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 27 Aug 2025 04:27:43 +0000 Subject: [PATCH 241/471] 8362566: Use -Xlog:aot+map to print contents of existing AOT cache Reviewed-by: vlivanov, kvn --- src/hotspot/share/cds/aotMapLogger.cpp | 930 ++++++++++++++++++ src/hotspot/share/cds/aotMapLogger.hpp | 126 +++ src/hotspot/share/cds/archiveBuilder.cpp | 424 +------- src/hotspot/share/cds/archiveBuilder.hpp | 10 +- src/hotspot/share/cds/archiveHeapWriter.cpp | 59 +- src/hotspot/share/cds/archiveHeapWriter.hpp | 4 +- src/hotspot/share/cds/cdsConfig.cpp | 3 + src/hotspot/share/cds/metaspaceShared.cpp | 28 +- .../classfile/systemDictionaryShared.cpp | 6 + .../classfile/systemDictionaryShared.hpp | 3 + src/hotspot/share/oops/cpCache.hpp | 1 + src/hotspot/share/oops/objArrayOop.hpp | 3 +- .../hotspot/jtreg/runtime/cds/CDSMapTest.java | 40 +- .../cds/appcds/aotCache/AOTMapTest.java | 139 +++ 14 files changed, 1313 insertions(+), 463 deletions(-) create mode 100644 src/hotspot/share/cds/aotMapLogger.cpp create mode 100644 src/hotspot/share/cds/aotMapLogger.hpp create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp new file mode 100644 index 00000000000..712901a71ca --- /dev/null +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotMapLogger.hpp" +#include "cds/archiveHeapWriter.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/filemap.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "classfile/vmClasses.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/metaspaceClosure.hpp" +#include "memory/resourceArea.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/globals_extension.hpp" +#include "utilities/growableArray.hpp" + +bool AOTMapLogger::_is_logging_at_bootstrap; +bool AOTMapLogger::_is_runtime_logging; +intx AOTMapLogger::_buffer_to_requested_delta; +intx AOTMapLogger::_requested_to_mapped_metadata_delta; +size_t AOTMapLogger::_num_root_segments; +size_t AOTMapLogger::_num_obj_arrays_logged; +GrowableArrayCHeap* AOTMapLogger::_roots; +ArchiveHeapInfo* AOTMapLogger::_dumptime_heap_info; + +class AOTMapLogger::RequestedMetadataAddr { + address _raw_addr; + +public: + RequestedMetadataAddr(address raw_addr) : _raw_addr(raw_addr) {} + + address raw_addr() const { return _raw_addr; } + + Klass* to_real_klass() const { + if (_raw_addr == nullptr) { + return nullptr; + } + + if (_is_runtime_logging) { + return (Klass*)(_raw_addr + _requested_to_mapped_metadata_delta); + } else { + ArchiveBuilder* builder = ArchiveBuilder::current(); + address buffered_addr = builder->requested_to_buffered(_raw_addr); + address klass = builder->get_source_addr(buffered_addr); + return (Klass*)klass; + } + } +}; // AOTMapLogger::RequestedMetadataAddr + +void AOTMapLogger::ergo_initialize() { + if (!CDSConfig::is_dumping_archive() && CDSConfig::is_using_archive() && log_is_enabled(Info, aot, map)) { + _is_logging_at_bootstrap = true; + if (FLAG_IS_DEFAULT(ArchiveRelocationMode)) { + FLAG_SET_ERGO(ArchiveRelocationMode, 0); + } else if (ArchiveRelocationMode != 0) { + log_warning(aot, map)("Addresses in the AOT map may be incorrect for -XX:ArchiveRelocationMode=%d.", ArchiveRelocationMode); + } + } +} + +void AOTMapLogger::dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo, + ArchiveHeapInfo* heap_info, + char* bitmap, size_t bitmap_size_in_bytes) { + _is_runtime_logging = false; + _buffer_to_requested_delta = ArchiveBuilder::current()->buffer_to_requested_delta(); + _num_root_segments = mapinfo->heap_root_segments().count(); + _dumptime_heap_info = heap_info; + + log_file_header(mapinfo); + + DumpRegion* rw_region = &builder->_rw_region; + DumpRegion* ro_region = &builder->_ro_region; + + dumptime_log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs); + dumptime_log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs); + + address bitmap_end = address(bitmap + bitmap_size_in_bytes); + log_region_range("bitmap", address(bitmap), bitmap_end, nullptr); + log_as_hex((address)bitmap, bitmap_end, nullptr); + +#if INCLUDE_CDS_JAVA_HEAP + if (heap_info->is_used()) { + dumptime_log_heap_region(heap_info); + } +#endif + + log_info(aot, map)("[End of AOT cache map]"); +} + +// This class is used to find the location and type of all the +// archived metaspace objects. +class AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs : public UniqueMetaspaceClosure { + GrowableArrayCHeap _objs; + + static int compare_objs_by_addr(ArchivedObjInfo* a, ArchivedObjInfo* b) { + intx diff = a->_src_addr - b->_src_addr; + if (diff < 0) { + return -1; + } else if (diff == 0) { + return 0; + } else { + return 1; + } + } + +public: + GrowableArrayCHeap* objs() { return &_objs; } + + virtual bool do_unique_ref(Ref* ref, bool read_only) { + ArchivedObjInfo info; + info._src_addr = ref->obj(); + info._buffered_addr = ref->obj(); + info._requested_addr = ref->obj(); + info._bytes = ref->size() * BytesPerWord; + info._type = ref->msotype(); + _objs.append(info); + + return true; // keep iterating + } + + void finish() { + UniqueMetaspaceClosure::finish(); + _objs.sort(compare_objs_by_addr); + } +}; // AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs + +void AOTMapLogger::runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo) { + _is_runtime_logging = true; + _requested_to_mapped_metadata_delta = static_mapinfo->relocation_delta(); + + ResourceMark rm; + RuntimeGatherArchivedMetaspaceObjs gatherer; + + if (log_is_enabled(Debug, aot, map)) { + // The metaspace objects in the AOT cache are stored as a stream of bytes. For space + // saving, we don't store a complete index that tells us where one object ends and + // another object starts. There's also no type information. + // + // However, we can rebuild our index by iterating over all the objects using + // MetaspaceClosure, starting from the dictionary of Klasses in SystemDictionaryShared. + GrowableArray klasses; + SystemDictionaryShared::get_all_archived_classes(/*is_static*/true, &klasses); + if (dynamic_mapinfo != nullptr) { + SystemDictionaryShared::get_all_archived_classes(/*is_static*/false, &klasses); + } + + for (int i = 0; i < klasses.length(); i++) { + gatherer.push(klasses.adr_at(i)); + } + gatherer.finish(); + } + + runtime_log(static_mapinfo, gatherer.objs()); + if (dynamic_mapinfo != nullptr) { + runtime_log(dynamic_mapinfo, gatherer.objs()); + } +} + +void AOTMapLogger::runtime_log(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { + log_file_header(mapinfo); + + runtime_log_metaspace_regions(mapinfo, objs); + +#if INCLUDE_CDS_JAVA_HEAP + if (mapinfo->has_heap_region() && CDSConfig::is_loading_heap()) { + _num_root_segments = mapinfo->heap_root_segments().count(); + runtime_log_heap_region(mapinfo); + } +#endif + + log_info(aot, map)("[End of map]"); +} + +void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* region, + const ArchiveBuilder::SourceObjList* src_objs) { + address region_base = address(region->base()); + address region_top = address(region->top()); + log_region_range(name, region_base, region_top, region_base + _buffer_to_requested_delta); + if (log_is_enabled(Debug, aot, map)) { + GrowableArrayCHeap objs; + for (int i = 0; i < src_objs->objs()->length(); i++) { + ArchiveBuilder::SourceObjInfo* src_info = src_objs->at(i); + ArchivedObjInfo info; + info._src_addr = src_info->source_addr(); + info._buffered_addr = src_info->buffered_addr(); + info._requested_addr = info._buffered_addr + _buffer_to_requested_delta; + info._bytes = src_info->size_in_bytes(); + info._type = src_info->msotype(); + objs.append(info); + } + + log_metaspace_objects_impl(address(region->base()), address(region->end()), &objs, 0, objs.length()); + } +} + +void AOTMapLogger::runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { + FileMapRegion* rw = mapinfo->region_at(MetaspaceShared::rw); + FileMapRegion* ro = mapinfo->region_at(MetaspaceShared::ro); + + address rw_base = address(rw->mapped_base()); + address rw_end = address(rw->mapped_end()); + address ro_base = address(ro->mapped_base()); + address ro_end = address(ro->mapped_end()); + + int first_rw_index = -1; + int first_ro_index = -1; + int last_ro_index = -1; + + if (log_is_enabled(Debug, aot, map)) { + int i = 0; + for (; i < objs->length(); i++) { + address p = objs->at(i)._src_addr; + if (p < rw_base) { + // We are printing the dynamic archive but found an object in the static archive + precond(!mapinfo->is_static()); + continue; + } + if (first_rw_index < 0) { + first_rw_index = i; + continue; + } + if (p < ro_base) { + continue; + } + if (first_ro_index < 0) { + first_ro_index = i; + continue; + } + if (p < ro_end) { + continue; + } else { + last_ro_index = i; + break; + } + } + } + + if (last_ro_index < 0) { + last_ro_index = objs->length(); + } + + log_region_range("rw", rw_base, rw_end, rw_base - _requested_to_mapped_metadata_delta); + if (log_is_enabled(Debug, aot, map)) { + log_metaspace_objects_impl(rw_base, rw_end, objs, first_rw_index, first_ro_index); + } + + log_region_range("ro", ro_base, ro_end, ro_base - _requested_to_mapped_metadata_delta); + if (log_is_enabled(Debug, aot, map)) { + log_metaspace_objects_impl(ro_base, ro_end, objs, first_ro_index, last_ro_index); + } +} + +void AOTMapLogger::log_file_header(FileMapInfo* mapinfo) { + const char* type; + if (mapinfo->is_static()) { + if (CDSConfig::new_aot_flags_used()) { + type = "AOT cache"; + } else { + type = "Static CDS archive"; + } + } else { + type = "Dynamic CDS archive"; + } + + log_info(aot, map)("%s map for %s", type, mapinfo->full_path()); + + address header = address(mapinfo->header()); + address header_end = header + mapinfo->header()->header_size(); + + log_region_range("header", header, header_end, nullptr); + LogStreamHandle(Info, aot, map) lsh; + mapinfo->print(&lsh); + log_as_hex(header, header_end, nullptr); +} + +// Log information about a region, whose address at dump time is [base .. top). At +// runtime, this region will be mapped to requested_base. requested_base is nullptr if this +// region will be mapped at os-selected addresses (such as the bitmap region), or will +// be accessed with os::read (the header). +void AOTMapLogger::log_region_range(const char* name, address base, address top, address requested_base) { + size_t size = top - base; + base = requested_base; + if (requested_base == nullptr) { + top = (address)size; + } else { + top = requested_base + size; + } + log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", + name, p2i(base), p2i(top), size); +} + +#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d" + +void AOTMapLogger::log_metaspace_objects_impl(address region_base, address region_end, GrowableArrayCHeap* objs, + int start_idx, int end_idx) { + address last_obj_base = region_base; + address last_obj_end = region_base; + Thread* current = Thread::current(); + + for (int i = start_idx; i < end_idx; i++) { + ArchivedObjInfo& info = objs->at(i); + address src = info._src_addr; + address buffered_addr = info._buffered_addr; + address requested_addr = info._requested_addr; + int bytes = info._bytes; + MetaspaceObj::Type type = info._type; + const char* type_name = MetaspaceObj::type_name(type); + + log_as_hex(last_obj_base, buffered_addr, last_obj_base + _buffer_to_requested_delta); + + switch (type) { + case MetaspaceObj::ClassType: + log_klass((Klass*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstantPoolType: + log_constant_pool((ConstantPool*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstantPoolCacheType: + log_constant_pool_cache((ConstantPoolCache*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::ConstMethodType: + log_const_method((ConstMethod*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::MethodType: + log_method((Method*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::SymbolType: + log_symbol((Symbol*)src, requested_addr, type_name, bytes, current); + break; + default: + log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes); + break; + } + + last_obj_base = buffered_addr; + last_obj_end = buffered_addr + bytes; + } + + log_as_hex(last_obj_base, last_obj_end, last_obj_base + _buffer_to_requested_delta); + if (last_obj_end < region_end) { + log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes", + p2i(last_obj_end + _buffer_to_requested_delta), + size_t(region_end - last_obj_end)); + log_as_hex(last_obj_end, region_end, last_obj_end + _buffer_to_requested_delta); + } +} + +void AOTMapLogger::log_constant_pool(ConstantPool* cp, address requested_addr, + const char* type_name, int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + cp->pool_holder()->external_name()); +} + +void AOTMapLogger::log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr, + const char* type_name, int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + cpc->constant_pool()->pool_holder()->external_name()); +} + +void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, cm->method()->external_name()); +} + +void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, k->external_name()); +} + +void AOTMapLogger::log_method(Method* m, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, m->external_name()); +} + +void AOTMapLogger::log_symbol(Symbol* s, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, + s->as_quoted_ascii()); +} + +#undef _LOG_PREFIX + +// Log all the data [base...top). Pretend that the base address +// will be mapped to requested_base at run-time. +void AOTMapLogger::log_as_hex(address base, address top, address requested_base, bool is_heap) { + assert(top >= base, "must be"); + + LogStreamHandle(Trace, aot, map) lsh; + if (lsh.is_enabled()) { + int unitsize = sizeof(address); + if (is_heap && UseCompressedOops) { + // This makes the compressed oop pointers easier to read, but + // longs and doubles will be split into two words. + unitsize = sizeof(narrowOop); + } + os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); + } +} + +#if INCLUDE_CDS_JAVA_HEAP +// FakeOop (and subclasses FakeMirror, FakeString, FakeObjArray, FakeTypeArray) are used to traverse +// and print the (image of) heap objects stored in the AOT cache. These objects are different than regular oops: +// - They do not reside inside the range of the heap. +// - For +UseCompressedOops: pointers may use a different narrowOop encoding: see FakeOop::read_oop_at(narrowOop*) +// - For -UseCompressedOops: pointers are not direct: see FakeOop::read_oop_at(oop*) +// +// Hence, in general, we cannot use regular oop API (such as oopDesc::obj_field()) on these objects. There +// are a few rare case where regular oop API work, but these are all guarded with the raw_oop() method and +// should be used with care. +class AOTMapLogger::FakeOop { + static int _requested_shift; + static intx _buffer_to_requested_delta; + static address _buffer_start; + static address _buffer_end; + static uint64_t _buffer_start_narrow_oop; // The encoded narrow oop for the objects at _buffer_start + + address _buffer_addr; + + static void assert_range(address buffer_addr) { + assert(_buffer_start <= buffer_addr && buffer_addr < _buffer_end, "range check"); + } + + address* field_addr(int field_offset) { + return (address*)(_buffer_addr + field_offset); + } + +protected: + RequestedMetadataAddr metadata_field(int field_offset) { + return RequestedMetadataAddr(*(address*)(field_addr(field_offset))); + } + + // Return an "oop" pointer so we can use APIs that accept regular oops. This + // must be used with care, as only a limited number of APIs can work with oops that + // live outside of the range of the heap. + oop raw_oop() { return cast_to_oop(_buffer_addr); } + +public: + static void init_globals(address requested_base, address requested_start, int requested_shift, + address buffer_start, address buffer_end) { + _requested_shift = requested_shift; + _buffer_to_requested_delta = requested_start - buffer_start; + _buffer_start = buffer_start; + _buffer_end = buffer_end; + + precond(requested_start >= requested_base); + if (UseCompressedOops) { + _buffer_start_narrow_oop = (uint64_t)(pointer_delta(requested_start, requested_base, 1)) >> _requested_shift; + assert(_buffer_start_narrow_oop < 0xffffffff, "sanity"); + } else { + _buffer_start_narrow_oop = 0xdeadbeed; + } + } + + FakeOop() : _buffer_addr(nullptr) {} + + FakeOop(address buffer_addr) : _buffer_addr(buffer_addr) { + if (_buffer_addr != nullptr) { + assert_range(_buffer_addr); + } + } + + FakeMirror& as_mirror(); + FakeObjArray& as_obj_array(); + FakeString& as_string(); + FakeTypeArray& as_type_array(); + + RequestedMetadataAddr klass() { + address rk = (address)real_klass(); + if (_is_runtime_logging) { + return RequestedMetadataAddr(rk - _requested_to_mapped_metadata_delta); + } else { + ArchiveBuilder* builder = ArchiveBuilder::current(); + return builder->to_requested(builder->get_buffered_addr(rk)); + } + } + + Klass* real_klass() { + assert(UseCompressedClassPointers, "heap archiving requires UseCompressedClassPointers"); + if (_is_runtime_logging) { + return raw_oop()->klass(); + } else { + return ArchiveHeapWriter::real_klass_of_buffered_oop(_buffer_addr); + } + } + + // in heap words + size_t size() { + if (_is_runtime_logging) { + return raw_oop()->size_given_klass(real_klass()); + } else { + return ArchiveHeapWriter::size_of_buffered_oop(_buffer_addr); + } + } + + bool is_array() { return real_klass()->is_array_klass(); } + bool is_null() { return _buffer_addr == nullptr; } + + int array_length() { + precond(is_array()); + return arrayOop(raw_oop())->length(); + } + + address requested_addr() { + return _buffer_addr + _buffer_to_requested_delta; + } + + uint32_t as_narrow_oop_value() { + precond(UseCompressedOops); + if (_buffer_addr == nullptr) { + return 0; + } + uint64_t pd = (uint64_t)(pointer_delta(_buffer_addr, _buffer_start, 1)); + return checked_cast(_buffer_start_narrow_oop + (pd >> _requested_shift)); + } + + FakeOop read_oop_at(narrowOop* addr) { // +UseCompressedOops + uint64_t n = (uint64_t)(*addr); + if (n == 0) { + return FakeOop(nullptr); + } else { + precond(n >= _buffer_start_narrow_oop); + address value = _buffer_start + ((n - _buffer_start_narrow_oop) << _requested_shift); + return FakeOop(value); + } + } + + FakeOop read_oop_at(oop* addr) { // -UseCompressedOops + address requested_value = cast_from_oop

      (*addr); + if (requested_value == nullptr) { + return FakeOop(nullptr); + } else { + return FakeOop(requested_value - _buffer_to_requested_delta); + } + } + + FakeOop obj_field(int field_offset) { + if (UseCompressedOops) { + return read_oop_at(raw_oop()->field_addr(field_offset)); + } else { + return read_oop_at(raw_oop()->field_addr(field_offset)); + } + } + + void print_non_oop_field(outputStream* st, fieldDescriptor* fd) { + // fd->print_on_for() works for non-oop fields in fake oops + precond(fd->field_type() != T_ARRAY && fd->field_type() != T_OBJECT); + fd->print_on_for(st, raw_oop()); + } +}; // AOTMapLogger::FakeOop + +class AOTMapLogger::FakeMirror : public AOTMapLogger::FakeOop { +public: + void print_class_signature_on(outputStream* st); + + Klass* real_mirrored_klass() { + RequestedMetadataAddr mirrored_klass = metadata_field(java_lang_Class::klass_offset()); + return mirrored_klass.to_real_klass(); + } + + int static_oop_field_count() { + return java_lang_Class::static_oop_field_count(raw_oop()); + } +}; // AOTMapLogger::FakeMirror + +class AOTMapLogger::FakeObjArray : public AOTMapLogger::FakeOop { + objArrayOop raw_objArrayOop() { + return (objArrayOop)raw_oop(); + } + +public: + int length() { + return raw_objArrayOop()->length(); + } + FakeOop obj_at(int i) { + if (UseCompressedOops) { + return read_oop_at(raw_objArrayOop()->obj_at_addr(i)); + } else { + return read_oop_at(raw_objArrayOop()->obj_at_addr(i)); + } + } +}; // AOTMapLogger::FakeObjArray + +class AOTMapLogger::FakeString : public AOTMapLogger::FakeOop { +public: + bool is_latin1() { + jbyte coder = raw_oop()->byte_field(java_lang_String::coder_offset()); + assert(CompactStrings || coder == java_lang_String::CODER_UTF16, "Must be UTF16 without CompactStrings"); + return coder == java_lang_String::CODER_LATIN1; + } + + FakeTypeArray value(); + + int length(); + void print_on(outputStream* st, int max_length = MaxStringPrintSize); +}; // AOTMapLogger::FakeString + +class AOTMapLogger::FakeTypeArray : public AOTMapLogger::FakeOop { + typeArrayOop raw_typeArrayOop() { + return (typeArrayOop)raw_oop(); + } + +public: + void print_elements_on(outputStream* st) { + TypeArrayKlass::cast(real_klass())->oop_print_elements_on(raw_typeArrayOop(), st); + } + + int length() { return raw_typeArrayOop()->length(); } + jbyte byte_at(int i) { return raw_typeArrayOop()->byte_at(i); } + jchar char_at(int i) { return raw_typeArrayOop()->char_at(i); } +}; // AOTMapLogger::FakeTypeArray + +AOTMapLogger::FakeMirror& AOTMapLogger::FakeOop::as_mirror() { + precond(real_klass() == vmClasses::Class_klass()); + return (FakeMirror&)*this; +} + +AOTMapLogger::FakeObjArray& AOTMapLogger::FakeOop::as_obj_array() { + precond(real_klass()->is_objArray_klass()); + return (FakeObjArray&)*this; +} + +AOTMapLogger::FakeTypeArray& AOTMapLogger::FakeOop::as_type_array() { + precond(real_klass()->is_typeArray_klass()); + return (FakeTypeArray&)*this; +} + +AOTMapLogger::FakeString& AOTMapLogger::FakeOop::as_string() { + precond(real_klass() == vmClasses::String_klass()); + return (FakeString&)*this; +} + +void AOTMapLogger::FakeMirror::print_class_signature_on(outputStream* st) { + ResourceMark rm; + RequestedMetadataAddr requested_klass = metadata_field(java_lang_Class::klass_offset()); + Klass* real_klass = requested_klass.to_real_klass(); + + if (real_klass == nullptr) { + // This is a primitive mirror (Java expressions of int.class, long.class, void.class, etc); + RequestedMetadataAddr requested_array_klass = metadata_field(java_lang_Class::array_klass_offset()); + Klass* real_array_klass = requested_array_klass.to_real_klass(); + if (real_array_klass == nullptr) { + st->print(" V"); // The special mirror for void.class that doesn't have any representation in C++ + } else { + precond(real_array_klass->is_typeArray_klass()); + st->print(" %c", real_array_klass->name()->char_at(1)); + } + } else { + const char* class_name = real_klass->name()->as_C_string(); + if (real_klass->is_instance_klass()) { + st->print(" L%s;", class_name); + } else { + st->print(" %s", class_name); + } + if (real_klass->has_aot_initialized_mirror()) { + st->print(" (aot-inited)"); + } + } +} + +AOTMapLogger::FakeTypeArray AOTMapLogger::FakeString::value() { + return obj_field(java_lang_String::value_offset()).as_type_array(); +} + +int AOTMapLogger::FakeString::length() { + FakeTypeArray v = value(); + if (v.is_null()) { + return 0; + } + int arr_length = v.length(); + if (!is_latin1()) { + assert((arr_length & 1) == 0, "should be even for UTF16 string"); + arr_length >>= 1; // convert number of bytes to number of elements + } + return arr_length; +} + +void AOTMapLogger::FakeString::print_on(outputStream* st, int max_length) { + FakeTypeArray v = value(); + int length = this->length(); + bool is_latin1 = this->is_latin1(); + bool abridge = length > max_length; + + st->print("\""); + for (int index = 0; index < length; index++) { + // If we need to abridge and we've printed half the allowed characters + // then jump to the tail of the string. + if (abridge && index >= max_length / 2) { + st->print(" ... (%d characters ommitted) ... ", length - 2 * (max_length / 2)); + index = length - (max_length / 2); + abridge = false; // only do this once + } + jchar c = (!is_latin1) ? v.char_at(index) : + ((jchar) v.byte_at(index)) & 0xff; + if (c < ' ') { + st->print("\\x%02X", c); // print control characters e.g. \x0A + } else { + st->print("%c", c); + } + } + st->print("\""); + + if (length > max_length) { + st->print(" (abridged) "); + } +} + +class AOTMapLogger::ArchivedFieldPrinter : public FieldClosure { + FakeOop _fake_oop; + outputStream* _st; +public: + ArchivedFieldPrinter(FakeOop fake_oop, outputStream* st) : _fake_oop(fake_oop), _st(st) {} + + void do_field(fieldDescriptor* fd) { + _st->print(" - "); + BasicType ft = fd->field_type(); + switch (ft) { + case T_ARRAY: + case T_OBJECT: + { + fd->print_on(_st); // print just the name and offset + FakeOop field_value = _fake_oop.obj_field(fd->offset()); + print_oop_info_cr(_st, field_value); + } + break; + default: + _fake_oop.print_non_oop_field(_st, fd); // name, offset, value + _st->cr(); + } + } +}; // AOTMapLogger::ArchivedFieldPrinter + +int AOTMapLogger::FakeOop::_requested_shift; +intx AOTMapLogger::FakeOop::_buffer_to_requested_delta; +address AOTMapLogger::FakeOop::_buffer_start; +address AOTMapLogger::FakeOop::_buffer_end; +uint64_t AOTMapLogger::FakeOop::_buffer_start_narrow_oop; + +void AOTMapLogger::dumptime_log_heap_region(ArchiveHeapInfo* heap_info) { + MemRegion r = heap_info->buffer_region(); + address buffer_start = address(r.start()); // start of the current oop inside the buffer + address buffer_end = address(r.end()); + + address requested_base = UseCompressedOops ? (address)CompressedOops::base() : (address)ArchiveHeapWriter::NOCOOPS_REQUESTED_BASE; + address requested_start = UseCompressedOops ? ArchiveHeapWriter::buffered_addr_to_requested_addr(buffer_start) : requested_base; + int requested_shift = CompressedOops::shift(); + + FakeOop::init_globals(requested_base, requested_start, requested_shift, buffer_start, buffer_end); + + log_region_range("heap", buffer_start, buffer_end, requested_start); + log_oops(buffer_start, buffer_end); +} + +void AOTMapLogger::runtime_log_heap_region(FileMapInfo* mapinfo) { + ResourceMark rm; + int heap_region_index = MetaspaceShared::hp; + FileMapRegion* r = mapinfo->region_at(heap_region_index); + size_t alignment = ObjectAlignmentInBytes; + + // Allocate a buffer and read the image of the archived heap region. This buffer is outside + // of the real Java heap, so we must use FakeOop to access the contents of the archived heap objects. + char* buffer = resource_allocate_bytes(r->used() + alignment); + address buffer_start = (address)align_up(buffer, alignment); + address buffer_end = buffer_start + r->used(); + if (!mapinfo->read_region(heap_region_index, (char*)buffer_start, r->used(), /* do_commit = */ false)) { + log_error(aot)("Cannot read heap region; AOT map logging of heap objects failed"); + return; + } + + address requested_base = UseCompressedOops ? (address)mapinfo->narrow_oop_base() : mapinfo->heap_region_requested_address(); + address requested_start = requested_base + r->mapping_offset(); + int requested_shift = mapinfo->narrow_oop_shift(); + + FakeOop::init_globals(requested_base, requested_start, requested_shift, buffer_start, buffer_end); + + log_region_range("heap", buffer_start, buffer_end, requested_start); + log_oops(buffer_start, buffer_end); +} + +void AOTMapLogger::log_oops(address buffer_start, address buffer_end) { + LogStreamHandle(Debug, aot, map) st; + if (!st.is_enabled()) { + return; + } + + _roots = new GrowableArrayCHeap(); + _num_obj_arrays_logged = 0; + + for (address fop = buffer_start; fop < buffer_end; ) { + FakeOop fake_oop(fop); + st.print(PTR_FORMAT ": @@ Object ", p2i(fake_oop.requested_addr())); + print_oop_info_cr(&st, fake_oop, /*print_requested_addr=*/false); + + LogStreamHandle(Trace, aot, map, oops) trace_st; + if (trace_st.is_enabled()) { + print_oop_details(fake_oop, &trace_st); + } + + address next_fop = fop + fake_oop.size() * BytesPerWord; + log_as_hex(fop, next_fop, fake_oop.requested_addr(), /*is_heap=*/true); + + fop = next_fop; + } + + delete _roots; +} + +void AOTMapLogger::print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_requested_addr) { + if (fake_oop.is_null()) { + st->print_cr("null"); + } else { + ResourceMark rm; + Klass* real_klass = fake_oop.real_klass(); + address requested_addr = fake_oop.requested_addr(); + if (print_requested_addr) { + st->print(PTR_FORMAT " ", p2i(requested_addr)); + } + if (UseCompressedOops) { + st->print("(0x%08x) ", fake_oop.as_narrow_oop_value()); + } + if (fake_oop.is_array()) { + int array_len = fake_oop.array_length(); + st->print_cr("%s length: %d", real_klass->external_name(), array_len); + } else { + st->print("%s", real_klass->external_name()); + + if (real_klass == vmClasses::String_klass()) { + st->print(" "); + fake_oop.as_string().print_on(st); + } else if (real_klass == vmClasses::Class_klass()) { + fake_oop.as_mirror().print_class_signature_on(st); + } + + st->cr(); + } + } +} + +// Print the fields of instanceOops, or the elements of arrayOops +void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) { + Klass* real_klass = fake_oop.real_klass(); + + st->print(" - klass: "); + real_klass->print_value_on(st); + st->print(" " PTR_FORMAT, p2i(fake_oop.klass().raw_addr())); + st->cr(); + + if (real_klass->is_typeArray_klass()) { + fake_oop.as_type_array().print_elements_on(st); + } else if (real_klass->is_objArray_klass()) { + FakeObjArray fake_obj_array = fake_oop.as_obj_array(); + bool is_logging_root_segment = _num_obj_arrays_logged < _num_root_segments; + + for (int i = 0; i < fake_obj_array.length(); i++) { + FakeOop elm = fake_obj_array.obj_at(i); + if (is_logging_root_segment) { + st->print(" root[%4d]: ", _roots->length()); + _roots->append(elm); + } else { + st->print(" -%4d: ", i); + } + print_oop_info_cr(st, elm); + } + _num_obj_arrays_logged ++; + } else { + st->print_cr(" - fields (%zu words):", fake_oop.size()); + + ArchivedFieldPrinter print_field(fake_oop, st); + InstanceKlass::cast(real_klass)->print_nonstatic_fields(&print_field); + + if (real_klass == vmClasses::Class_klass()) { + FakeMirror fake_mirror = fake_oop.as_mirror(); + + st->print(" - signature: "); + fake_mirror.print_class_signature_on(st); + st->cr(); + + Klass* real_mirrored_klass = fake_mirror.real_mirrored_klass(); + if (real_mirrored_klass != nullptr && real_mirrored_klass->is_instance_klass()) { + InstanceKlass* real_mirrored_ik = InstanceKlass::cast(real_mirrored_klass); + + ConstantPoolCache* cp_cache = real_mirrored_ik->constants()->cache(); + if (!_is_runtime_logging) { + cp_cache = ArchiveBuilder::current()->get_buffered_addr(cp_cache); + } + int rr_root_index = cp_cache->archived_references_index(); + st->print(" - resolved_references: "); + if (rr_root_index >= 0) { + FakeOop resolved_references = _roots->at(rr_root_index); + print_oop_info_cr(st, resolved_references); + } else { + st->print("null"); + } + + st->print_cr("- ---- static fields (%d):", fake_mirror.static_oop_field_count()); + real_mirrored_ik->do_local_static_fields(&print_field); + } + } + } +} +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp new file mode 100644 index 00000000000..9cd67fb7ff6 --- /dev/null +++ b/src/hotspot/share/cds/aotMapLogger.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CDS_AOTMAPLOGGER_HPP +#define SHARE_CDS_AOTMAPLOGGER_HPP + +#include "cds/archiveBuilder.hpp" +#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" + +class ArchiveHeapInfo; +class DumpRegion; +class FileMapInfo; +class outputStream; + +// Write detailed info to a mapfile to analyze contents of the AOT cache/CDS archive. +// -Xlog:aot+map* can be used both when creating an AOT cache, or when using an AOT cache. +// +// Creating cache: +// java -XX:AOTCacheOutput=app.aot -Xlog:aot+map*=trace -cp app.jar App +// +// Using cache: +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace -cp app.jar App +// +// You can also print the map of a cache without executing the application by using the +// --version flag: +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace --version +// +// Because the output can be large, it's best to save it to a file +// java -XX:AOTCache=app.aot -Xlog:aot+map*=trace:file=aot.map:none:filesize=0 --version +class AOTMapLogger : AllStatic { + struct ArchivedObjInfo { + address _src_addr; + address _buffered_addr; + address _requested_addr; + int _bytes; + MetaspaceObj::Type _type; + }; + + // FakeOop and subtypes + class FakeOop; + class FakeMirror; + class FakeObjArray; + class FakeString; + class FakeTypeArray; + + class RequestedMetadataAddr; + class RuntimeGatherArchivedMetaspaceObjs; + + static bool _is_logging_at_bootstrap; + static bool _is_runtime_logging; + static size_t _num_root_segments; + static size_t _num_obj_arrays_logged; + static GrowableArrayCHeap* _roots; + static ArchiveHeapInfo* _dumptime_heap_info; + + static intx _buffer_to_requested_delta; + static intx _requested_to_mapped_metadata_delta; + + static void runtime_log(FileMapInfo* mapinfo, GrowableArrayCHeap* objs); + static void runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs); + static void dumptime_log_metaspace_region(const char* name, DumpRegion* region, + const ArchiveBuilder::SourceObjList* src_objs); + + // Common code for dumptime/runtime + static void log_file_header(FileMapInfo* mapinfo); + static void log_region_range(const char* name, address base, address top, address requested_base); + static void log_metaspace_objects_impl(address region_base, address region_end, + GrowableArrayCHeap* objs, int start_idx, int end_idx); + static void log_as_hex(address base, address top, address requested_base, bool is_heap = false); + + // Metaspace object: type-specific logging + static void log_constant_pool(ConstantPool* cp, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr, + const char* type_name, int bytes, Thread* current); + static void log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current); + + +#if INCLUDE_CDS_JAVA_HEAP + static void dumptime_log_heap_region(ArchiveHeapInfo* heap_info); + static void runtime_log_heap_region(FileMapInfo* mapinfo); + + static void print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_requested_addr = true); + static void print_oop_details(FakeOop fake_oop, outputStream* st); + static void log_oops(address buf_start, address buf_end); + class ArchivedFieldPrinter; // to be replaced by ArchivedFieldPrinter2 +#endif + +public: + static void ergo_initialize(); + static bool is_logging_at_bootstrap() { return _is_logging_at_bootstrap; } + + static void dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo, + ArchiveHeapInfo* heap_info, + char* bitmap, size_t bitmap_size_in_bytes); + static void runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo); +}; + +#endif // SHARE_CDS_AOTMAPLOGGER_HPP diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 1d054561c76..1c807776e3c 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassLinker.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" @@ -46,7 +47,6 @@ #include "interpreter/abstractInterpreter.hpp" #include "jvm.h" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "memory/allStatic.hpp" #include "memory/memoryReserver.hpp" #include "memory/memRegion.hpp" @@ -60,7 +60,6 @@ #include "oops/oopHandle.inline.hpp" #include "oops/trainingData.hpp" #include "runtime/arguments.hpp" -#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/globals_extension.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -1188,424 +1187,6 @@ void ArchiveBuilder::relocate_to_requested() { } } -// Write detailed info to a mapfile to analyze contents of the archive. -// static dump: -// java -Xshare:dump -Xlog:cds+map=trace:file=cds.map:none:filesize=0 -// dynamic dump: -// java -cp MyApp.jar -XX:ArchiveClassesAtExit=MyApp.jsa \ -// -Xlog:cds+map=trace:file=cds.map:none:filesize=0 MyApp -// -// We need to do some address translation because the buffers used at dump time may be mapped to -// a different location at runtime. At dump time, the buffers may be at arbitrary locations -// picked by the OS. At runtime, we try to map at a fixed location (SharedBaseAddress). For -// consistency, we log everything using runtime addresses. -class ArchiveBuilder::CDSMapLogger : AllStatic { - static intx buffer_to_runtime_delta() { - // Translate the buffers used by the RW/RO regions to their eventual (requested) locations - // at runtime. - return ArchiveBuilder::current()->buffer_to_requested_delta(); - } - - // rw/ro regions only - static void log_metaspace_region(const char* name, DumpRegion* region, - const ArchiveBuilder::SourceObjList* src_objs) { - address region_base = address(region->base()); - address region_top = address(region->top()); - log_region(name, region_base, region_top, region_base + buffer_to_runtime_delta()); - log_metaspace_objects(region, src_objs); - } - -#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d" - - static void log_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* current) { - ResourceMark rm(current); - log_debug(aot, map)(_LOG_PREFIX " %s", - p2i(runtime_dest), type_name, bytes, k->external_name()); - } - static void log_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* current) { - ResourceMark rm(current); - log_debug(aot, map)(_LOG_PREFIX " %s", - p2i(runtime_dest), type_name, bytes, m->external_name()); - } - - // rw/ro regions only - static void log_metaspace_objects(DumpRegion* region, const ArchiveBuilder::SourceObjList* src_objs) { - address last_obj_base = address(region->base()); - address last_obj_end = address(region->base()); - address region_end = address(region->end()); - Thread* current = Thread::current(); - for (int i = 0; i < src_objs->objs()->length(); i++) { - SourceObjInfo* src_info = src_objs->at(i); - address src = src_info->source_addr(); - address dest = src_info->buffered_addr(); - log_as_hex(last_obj_base, dest, last_obj_base + buffer_to_runtime_delta()); - address runtime_dest = dest + buffer_to_runtime_delta(); - int bytes = src_info->size_in_bytes(); - - MetaspaceObj::Type type = src_info->msotype(); - const char* type_name = MetaspaceObj::type_name(type); - - switch (type) { - case MetaspaceObj::ClassType: - log_klass((Klass*)src, runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstantPoolType: - log_klass(((ConstantPool*)src)->pool_holder(), - runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstantPoolCacheType: - log_klass(((ConstantPoolCache*)src)->constant_pool()->pool_holder(), - runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::MethodType: - log_method((Method*)src, runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::ConstMethodType: - log_method(((ConstMethod*)src)->method(), runtime_dest, type_name, bytes, current); - break; - case MetaspaceObj::SymbolType: - { - ResourceMark rm(current); - Symbol* s = (Symbol*)src; - log_debug(aot, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, - s->as_quoted_ascii()); - } - break; - default: - log_debug(aot, map)(_LOG_PREFIX, p2i(runtime_dest), type_name, bytes); - break; - } - - last_obj_base = dest; - last_obj_end = dest + bytes; - } - - log_as_hex(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta()); - if (last_obj_end < region_end) { - log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes", - p2i(last_obj_end + buffer_to_runtime_delta()), - size_t(region_end - last_obj_end)); - log_as_hex(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta()); - } - } - -#undef _LOG_PREFIX - - // Log information about a region, whose address at dump time is [base .. top). At - // runtime, this region will be mapped to requested_base. requested_base is nullptr if this - // region will be mapped at os-selected addresses (such as the bitmap region), or will - // be accessed with os::read (the header). - // - // Note: across -Xshare:dump runs, base may be different, but requested_base should - // be the same as the archive contents should be deterministic. - static void log_region(const char* name, address base, address top, address requested_base) { - size_t size = top - base; - base = requested_base; - if (requested_base == nullptr) { - top = (address)size; - } else { - top = requested_base + size; - } - log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", - name, p2i(base), p2i(top), size); - } - -#if INCLUDE_CDS_JAVA_HEAP - static void log_heap_region(ArchiveHeapInfo* heap_info) { - MemRegion r = heap_info->buffer_region(); - address start = address(r.start()); // start of the current oop inside the buffer - address end = address(r.end()); - log_region("heap", start, end, ArchiveHeapWriter::buffered_addr_to_requested_addr(start)); - - LogStreamHandle(Info, aot, map) st; - - HeapRootSegments segments = heap_info->heap_root_segments(); - assert(segments.base_offset() == 0, "Sanity"); - - for (size_t seg_idx = 0; seg_idx < segments.count(); seg_idx++) { - address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start); - st.print_cr(PTR_FORMAT ": Heap roots segment [%d]", - p2i(requested_start), segments.size_in_elems(seg_idx)); - start += segments.size_in_bytes(seg_idx); - } - log_heap_roots(); - - while (start < end) { - size_t byte_size; - oop source_oop = ArchiveHeapWriter::buffered_addr_to_source_obj(start); - address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start); - st.print(PTR_FORMAT ": @@ Object ", p2i(requested_start)); - - if (source_oop != nullptr) { - // This is a regular oop that got archived. - // Don't print the requested addr again as we have just printed it at the beginning of the line. - // Example: - // 0x00000007ffd27938: @@ Object (0xfffa4f27) java.util.HashMap - print_oop_info_cr(&st, source_oop, /*print_requested_addr=*/false); - byte_size = source_oop->size() * BytesPerWord; - } else if ((byte_size = ArchiveHeapWriter::get_filler_size_at(start)) > 0) { - // We have a filler oop, which also does not exist in BufferOffsetToSourceObjectTable. - // Example: - // 0x00000007ffc3ffd8: @@ Object filler 40 bytes - st.print_cr("filler %zu bytes", byte_size); - } else { - ShouldNotReachHere(); - } - - address oop_end = start + byte_size; - log_as_hex(start, oop_end, requested_start, /*is_heap=*/true); - - if (source_oop != nullptr) { - log_oop_details(heap_info, source_oop, /*buffered_addr=*/start); - } - start = oop_end; - } - } - - // ArchivedFieldPrinter is used to print the fields of archived objects. We can't - // use _source_obj->print_on(), because we want to print the oop fields - // in _source_obj with their requested addresses using print_oop_info_cr(). - class ArchivedFieldPrinter : public FieldClosure { - ArchiveHeapInfo* _heap_info; - outputStream* _st; - oop _source_obj; - address _buffered_addr; - public: - ArchivedFieldPrinter(ArchiveHeapInfo* heap_info, outputStream* st, oop src_obj, address buffered_addr) : - _heap_info(heap_info), _st(st), _source_obj(src_obj), _buffered_addr(buffered_addr) {} - - void do_field(fieldDescriptor* fd) { - _st->print(" - "); - BasicType ft = fd->field_type(); - switch (ft) { - case T_ARRAY: - case T_OBJECT: - { - fd->print_on(_st); // print just the name and offset - oop obj = _source_obj->obj_field(fd->offset()); - if (java_lang_Class::is_instance(obj)) { - obj = HeapShared::scratch_java_mirror(obj); - } - print_oop_info_cr(_st, obj); - } - break; - default: - if (ArchiveHeapWriter::is_marked_as_native_pointer(_heap_info, _source_obj, fd->offset())) { - print_as_native_pointer(fd); - } else { - fd->print_on_for(_st, cast_to_oop(_buffered_addr)); // name, offset, value - _st->cr(); - } - } - } - - void print_as_native_pointer(fieldDescriptor* fd) { - LP64_ONLY(assert(fd->field_type() == T_LONG, "must be")); - NOT_LP64 (assert(fd->field_type() == T_INT, "must be")); - - // We have a field that looks like an integer, but it's actually a pointer to a MetaspaceObj. - address source_native_ptr = (address) - LP64_ONLY(_source_obj->long_field(fd->offset())) - NOT_LP64( _source_obj->int_field (fd->offset())); - ArchiveBuilder* builder = ArchiveBuilder::current(); - - // The value of the native pointer at runtime. - address requested_native_ptr = builder->to_requested(builder->get_buffered_addr(source_native_ptr)); - - // The address of _source_obj at runtime - oop requested_obj = ArchiveHeapWriter::source_obj_to_requested_obj(_source_obj); - // The address of this field in the requested space - assert(requested_obj != nullptr, "Attempting to load field from null oop"); - address requested_field_addr = cast_from_oop
      (requested_obj) + fd->offset(); - - fd->print_on(_st); - _st->print_cr(PTR_FORMAT " (marked metadata pointer @" PTR_FORMAT " )", - p2i(requested_native_ptr), p2i(requested_field_addr)); - } - }; - - // Print the fields of instanceOops, or the elements of arrayOops - static void log_oop_details(ArchiveHeapInfo* heap_info, oop source_oop, address buffered_addr) { - LogStreamHandle(Trace, aot, map, oops) st; - if (st.is_enabled()) { - Klass* source_klass = source_oop->klass(); - ArchiveBuilder* builder = ArchiveBuilder::current(); - Klass* requested_klass = builder->to_requested(builder->get_buffered_addr(source_klass)); - - st.print(" - klass: "); - source_klass->print_value_on(&st); - st.print(" " PTR_FORMAT, p2i(requested_klass)); - st.cr(); - - if (source_oop->is_typeArray()) { - TypeArrayKlass::cast(source_klass)->oop_print_elements_on(typeArrayOop(source_oop), &st); - } else if (source_oop->is_objArray()) { - objArrayOop source_obj_array = objArrayOop(source_oop); - for (int i = 0; i < source_obj_array->length(); i++) { - st.print(" -%4d: ", i); - oop obj = source_obj_array->obj_at(i); - if (java_lang_Class::is_instance(obj)) { - obj = HeapShared::scratch_java_mirror(obj); - } - print_oop_info_cr(&st, obj); - } - } else { - st.print_cr(" - fields (%zu words):", source_oop->size()); - ArchivedFieldPrinter print_field(heap_info, &st, source_oop, buffered_addr); - InstanceKlass::cast(source_klass)->print_nonstatic_fields(&print_field); - - if (java_lang_Class::is_instance(source_oop)) { - oop scratch_mirror = source_oop; - st.print(" - signature: "); - print_class_signature_for_mirror(&st, scratch_mirror); - st.cr(); - - Klass* src_klass = java_lang_Class::as_Klass(scratch_mirror); - if (src_klass != nullptr && src_klass->is_instance_klass()) { - oop rr = HeapShared::scratch_resolved_references(InstanceKlass::cast(src_klass)->constants()); - st.print(" - archived_resolved_references: "); - print_oop_info_cr(&st, rr); - - // We need to print the fields in the scratch_mirror, not the original mirror. - // (if a class is not aot-initialized, static fields in its scratch mirror will be cleared). - assert(scratch_mirror == HeapShared::scratch_java_mirror(src_klass->java_mirror()), "sanity"); - st.print_cr("- ---- static fields (%d):", java_lang_Class::static_oop_field_count(scratch_mirror)); - InstanceKlass::cast(src_klass)->do_local_static_fields(&print_field); - } - } - } - } - } - - static void print_class_signature_for_mirror(outputStream* st, oop scratch_mirror) { - assert(java_lang_Class::is_instance(scratch_mirror), "sanity"); - if (java_lang_Class::is_primitive(scratch_mirror)) { - for (int i = T_BOOLEAN; i < T_VOID+1; i++) { - BasicType bt = (BasicType)i; - if (!is_reference_type(bt) && scratch_mirror == HeapShared::scratch_java_mirror(bt)) { - oop orig_mirror = Universe::java_mirror(bt); - java_lang_Class::print_signature(orig_mirror, st); - return; - } - } - ShouldNotReachHere(); - } - java_lang_Class::print_signature(scratch_mirror, st); - } - - static void log_heap_roots() { - LogStreamHandle(Trace, aot, map, oops) st; - if (st.is_enabled()) { - for (int i = 0; i < HeapShared::pending_roots()->length(); i++) { - st.print("roots[%4d]: ", i); - print_oop_info_cr(&st, HeapShared::pending_roots()->at(i)); - } - } - } - - // Example output: - // - The first number is the requested address (if print_requested_addr == true) - // - The second number is the narrowOop version of the requested address (if UseCompressedOops == true) - // 0x00000007ffc7e840 (0xfff8fd08) java.lang.Class Ljava/util/Array; - // 0x00000007ffc000f8 (0xfff8001f) [B length: 11 - static void print_oop_info_cr(outputStream* st, oop source_oop, bool print_requested_addr = true) { - if (source_oop == nullptr) { - st->print_cr("null"); - } else { - ResourceMark rm; - oop requested_obj = ArchiveHeapWriter::source_obj_to_requested_obj(source_oop); - if (print_requested_addr) { - st->print(PTR_FORMAT " ", p2i(requested_obj)); - } - if (UseCompressedOops) { - st->print("(0x%08x) ", CompressedOops::narrow_oop_value(requested_obj)); - } - if (source_oop->is_array()) { - int array_len = arrayOop(source_oop)->length(); - st->print_cr("%s length: %d", source_oop->klass()->external_name(), array_len); - } else { - st->print("%s", source_oop->klass()->external_name()); - - if (java_lang_String::is_instance(source_oop)) { - st->print(" "); - java_lang_String::print(source_oop, st); - } else if (java_lang_Class::is_instance(source_oop)) { - oop scratch_mirror = source_oop; - - st->print(" "); - print_class_signature_for_mirror(st, scratch_mirror); - - Klass* src_klass = java_lang_Class::as_Klass(scratch_mirror); - if (src_klass != nullptr && src_klass->is_instance_klass()) { - InstanceKlass* buffered_klass = - ArchiveBuilder::current()->get_buffered_addr(InstanceKlass::cast(src_klass)); - if (buffered_klass->has_aot_initialized_mirror()) { - st->print(" (aot-inited)"); - } - } - } - st->cr(); - } - } - } -#endif // INCLUDE_CDS_JAVA_HEAP - - // Log all the data [base...top). Pretend that the base address - // will be mapped to requested_base at run-time. - static void log_as_hex(address base, address top, address requested_base, bool is_heap = false) { - assert(top >= base, "must be"); - - LogStreamHandle(Trace, aot, map) lsh; - if (lsh.is_enabled()) { - int unitsize = sizeof(address); - if (is_heap && UseCompressedOops) { - // This makes the compressed oop pointers easier to read, but - // longs and doubles will be split into two words. - unitsize = sizeof(narrowOop); - } - os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base); - } - } - - static void log_header(FileMapInfo* mapinfo) { - LogStreamHandle(Info, aot, map) lsh; - if (lsh.is_enabled()) { - mapinfo->print(&lsh); - } - } - -public: - static void log(ArchiveBuilder* builder, FileMapInfo* mapinfo, - ArchiveHeapInfo* heap_info, - char* bitmap, size_t bitmap_size_in_bytes) { - log_info(aot, map)("%s CDS archive map for %s", CDSConfig::is_dumping_static_archive() ? "Static" : "Dynamic", mapinfo->full_path()); - - address header = address(mapinfo->header()); - address header_end = header + mapinfo->header()->header_size(); - log_region("header", header, header_end, nullptr); - log_header(mapinfo); - log_as_hex(header, header_end, nullptr); - - DumpRegion* rw_region = &builder->_rw_region; - DumpRegion* ro_region = &builder->_ro_region; - - log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs); - log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs); - - address bitmap_end = address(bitmap + bitmap_size_in_bytes); - log_region("bitmap", address(bitmap), bitmap_end, nullptr); - log_as_hex((address)bitmap, bitmap_end, nullptr); - -#if INCLUDE_CDS_JAVA_HEAP - if (heap_info->is_used()) { - log_heap_region(heap_info); - } -#endif - - log_info(aot, map)("[End of CDS archive map]"); - } -}; // end ArchiveBuilder::CDSMapLogger - void ArchiveBuilder::print_stats() { _alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used())); } @@ -1645,8 +1226,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i } if (log_is_enabled(Info, aot, map)) { - CDSMapLogger::log(this, mapinfo, heap_info, - bitmap, bitmap_size_in_bytes); + AOTMapLogger::dumptime_log(this, mapinfo, heap_info, bitmap, bitmap_size_in_bytes); } CDS_JAVA_HEAP_ONLY(HeapShared::destroy_archived_object_cache()); FREE_C_HEAP_ARRAY(char, bitmap); diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 39cc1c1eb8c..170e61beba8 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -93,6 +93,8 @@ constexpr size_t SharedSpaceObjectAlignment = Metaspace::min_allocation_alignmen // buffered_address + _buffer_to_requested_delta == requested_address // class ArchiveBuilder : public StackObj { + friend class AOTMapLogger; + protected: DumpRegion* _current_dump_region; address _buffer_bottom; // for writing the contents of rw/ro regions @@ -202,8 +204,6 @@ private: SourceObjInfo* at(int i) const { return objs()->at(i); } }; - class CDSMapLogger; - static const int INITIAL_TABLE_SIZE = 15889; static const int MAX_TABLE_SIZE = 1000000; @@ -316,6 +316,12 @@ public: return (T)(address(obj) + _buffer_to_requested_delta); } + template T requested_to_buffered(T obj) const { + T b = (T)(address(obj) - _buffer_to_requested_delta); + assert(is_in_buffer_space(b), "must be"); + return b; + } + static intx get_buffer_to_requested_delta() { return current()->buffer_to_requested_delta(); } diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 9c55b71a1b2..c7750c70f1b 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -162,6 +162,44 @@ oop ArchiveHeapWriter::buffered_addr_to_source_obj(address buffered_addr) { } } +Klass* ArchiveHeapWriter::real_klass_of_buffered_oop(address buffered_addr) { + oop p = buffered_addr_to_source_obj(buffered_addr); + if (p != nullptr) { + return p->klass(); + } else if (get_filler_size_at(buffered_addr) > 0) { + return Universe::fillerArrayKlass(); + } else { + // This is one of the root segments + return Universe::objectArrayKlass(); + } +} + +size_t ArchiveHeapWriter::size_of_buffered_oop(address buffered_addr) { + oop p = buffered_addr_to_source_obj(buffered_addr); + if (p != nullptr) { + return p->size(); + } + + size_t nbytes = get_filler_size_at(buffered_addr); + if (nbytes > 0) { + assert((nbytes % BytesPerWord) == 0, "should be aligned"); + return nbytes / BytesPerWord; + } + + address hrs = buffer_bottom(); + for (size_t seg_idx = 0; seg_idx < _heap_root_segments.count(); seg_idx++) { + nbytes = _heap_root_segments.size_in_bytes(seg_idx); + if (hrs == buffered_addr) { + assert((nbytes % BytesPerWord) == 0, "should be aligned"); + return nbytes / BytesPerWord; + } + hrs += nbytes; + } + + ShouldNotReachHere(); + return 0; +} + address ArchiveHeapWriter::buffered_addr_to_requested_addr(address buffered_addr) { return _requested_bottom + buffered_address_to_offset(buffered_addr); } @@ -709,27 +747,6 @@ void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) { } } -// Do we have a jlong/jint field that's actually a pointer to a MetaspaceObj? -bool ArchiveHeapWriter::is_marked_as_native_pointer(ArchiveHeapInfo* heap_info, oop src_obj, int field_offset) { - HeapShared::CachedOopInfo* p = HeapShared::archived_object_cache()->get(src_obj); - assert(p != nullptr, "must be"); - - // requested_field_addr = the address of this field in the requested space - oop requested_obj = requested_obj_from_buffer_offset(p->buffer_offset()); - Metadata** requested_field_addr = (Metadata**)(cast_from_oop
      (requested_obj) + field_offset); - assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check"); - - BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom; - // Leading zeros have been removed so some addresses may not be in the ptrmap - size_t start_pos = FileMapInfo::current_info()->heap_ptrmap_start_pos(); - if (idx < start_pos) { - return false; - } else { - idx -= start_pos; - } - return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true); -} - void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) { int num_non_null_ptrs = 0; Metadata** bottom = (Metadata**) _requested_bottom; diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index f8f55a745ee..18e647912f1 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -236,11 +236,11 @@ public: static size_t get_filler_size_at(address buffered_addr); static void mark_native_pointer(oop src_obj, int offset); - static bool is_marked_as_native_pointer(ArchiveHeapInfo* heap_info, oop src_obj, int field_offset); static oop source_obj_to_requested_obj(oop src_obj); static oop buffered_addr_to_source_obj(address buffered_addr); static address buffered_addr_to_requested_addr(address buffered_addr); - + static Klass* real_klass_of_buffered_oop(address buffered_addr); + static size_t size_of_buffered_oop(address buffered_addr); }; #endif // INCLUDE_CDS_JAVA_HEAP #endif // SHARE_CDS_ARCHIVEHEAPWRITER_HPP diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 51899490a12..6922b66d7cd 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" @@ -104,6 +105,8 @@ void CDSConfig::ergo_initialize() { if (!is_dumping_heap()) { _is_dumping_full_module_graph = false; } + + AOTMapLogger::ergo_initialize(); } const char* CDSConfig::default_archive_path() { diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 5c55dea52c8..4d8f2b50017 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -29,6 +29,7 @@ #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMapLogger.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -325,6 +326,24 @@ void MetaspaceShared::initialize_for_static_dump() { // Called by universe_post_init() void MetaspaceShared::post_initialize(TRAPS) { if (CDSConfig::is_using_archive()) { + FileMapInfo *static_mapinfo = FileMapInfo::current_info(); + FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); + + if (AOTMapLogger::is_logging_at_bootstrap()) { + // The map logging needs to be done here, as it requires some stubs on Windows, + // which are not generated until the end of init_globals(). + AOTMapLogger::runtime_log(static_mapinfo, dynamic_mapinfo); + } + + // Close any open file descriptors. However, mmap'ed pages will remain in memory. + static_mapinfo->close(); + static_mapinfo->unmap_region(MetaspaceShared::bm); + + if (dynamic_mapinfo != nullptr) { + dynamic_mapinfo->close(); + dynamic_mapinfo->unmap_region(MetaspaceShared::bm); + } + int size = AOTClassLocationConfig::runtime()->length(); if (size > 0) { CDSProtectionDomain::allocate_shared_data_arrays(size, CHECK); @@ -1954,6 +1973,7 @@ class CountSharedSymbols : public SymbolClosure { void MetaspaceShared::initialize_shared_spaces() { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); + FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); // Verify various attributes of the archive, plus initialize the // shared string/symbol tables. @@ -1969,19 +1989,11 @@ void MetaspaceShared::initialize_shared_spaces() { Universe::load_archived_object_instances(); AOTCodeCache::initialize(); - // Close the mapinfo file - static_mapinfo->close(); - - static_mapinfo->unmap_region(MetaspaceShared::bm); - - FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); if (dynamic_mapinfo != nullptr) { intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data(); ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress); ArchiveBuilder::serialize_dynamic_archivable_items(&rc); DynamicArchive::setup_array_klasses(); - dynamic_mapinfo->close(); - dynamic_mapinfo->unmap_region(MetaspaceShared::bm); } LogStreamHandle(Info, aot) lsh; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 1845c28d819..1be7a6db662 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1179,6 +1179,12 @@ const char* SystemDictionaryShared::loader_type_for_shared_class(Klass* k) { } } +void SystemDictionaryShared::get_all_archived_classes(bool is_static_archive, GrowableArray* classes) { + get_archive(is_static_archive)->_builtin_dictionary.iterate([&] (const RunTimeClassInfo* record) { + classes->append(record->klass()); + }); +} + class SharedDictionaryPrinter : StackObj { outputStream* _st; int _index; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 5f6dd055fd6..e3c22ee11a0 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -115,6 +115,8 @@ class DumpTimeSharedClassTable; class RunTimeClassInfo; class RunTimeSharedDictionary; +template class GrowableArray; + class SharedClassLoadingMark { private: Thread* THREAD; @@ -269,6 +271,7 @@ public: bool is_static_archive = true); static void serialize_vm_classes(class SerializeClosure* soc); static const char* loader_type_for_shared_class(Klass* k); + static void get_all_archived_classes(bool is_static_archive, GrowableArray* classes); static void print() { return print_on(tty); } static void print_on(outputStream* st) NOT_CDS_RETURN; static void print_shared_archive(outputStream* st, bool is_static = true) NOT_CDS_RETURN; diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 83af4b88e32..e9e4f9a40e5 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -111,6 +111,7 @@ class ConstantPoolCache: public MetaspaceObj { oop archived_references() NOT_CDS_JAVA_HEAP_RETURN_(nullptr); void clear_archived_references() NOT_CDS_JAVA_HEAP_RETURN; + CDS_JAVA_HEAP_ONLY(int archived_references_index() { return _archived_references_index; }) inline objArrayOop resolved_references(); void set_resolved_references(OopHandle s) { _resolved_references = s; } diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 8e39b897018..0539171f1ab 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -44,6 +44,7 @@ class objArrayOopDesc : public arrayOopDesc { friend class Continuation; template friend class RawOopWriter; + friend class AOTMapLogger; template T* obj_at_addr(int index) const; diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java index 5a5978a8633..c93b16c68b8 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java @@ -25,6 +25,7 @@ * @test * @bug 8308903 * @summary Test the contents of -Xlog:aot+map + * @requires vm.flagless * @requires vm.cds * @library /test/lib * @run driver CDSMapTest @@ -33,6 +34,8 @@ import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import java.util.ArrayList; public class CDSMapTest { @@ -46,34 +49,57 @@ public class CDSMapTest { } public static void doTest(boolean compressed) throws Exception { - ArrayList dumpArgs = new ArrayList<>(); + ArrayList vmArgs = new ArrayList<>(); // Use the same heap size as make/Images.gmk - dumpArgs.add("-Xmx128M"); + vmArgs.add("-Xmx128M"); if (Platform.is64bit()) { // These options are available only on 64-bit. String sign = (compressed) ? "+" : "-"; - dumpArgs.add("-XX:" + sign + "UseCompressedOops"); + vmArgs.add("-XX:" + sign + "UseCompressedOops"); } - dump(dumpArgs); + String archiveFile = dump(vmArgs); + exec(vmArgs, archiveFile); + } static int id = 0; - static void dump(ArrayList args, String... more) throws Exception { + + // Create a map file when creating the archive + static String dump(ArrayList args) throws Exception { String logName = "SharedArchiveFile" + (id++); String archiveName = logName + ".jsa"; String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) .addPrefix("-Xlog:cds=debug") + // filesize=0 ensures that a large map file not broken up in multiple files. .addPrefix("-Xlog:aot+map=debug,aot+map+oops=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) - .addSuffix(args) - .addSuffix(more); + .addSuffix(args); CDSTestUtils.createArchiveAndCheck(opts); CDSMapReader.MapFile mapFile = CDSMapReader.read(mapName); CDSMapReader.validate(mapFile); + + return archiveName; + } + + // Create a map file when using the archive + static void exec(ArrayList vmArgs, String archiveFile) throws Exception { + String mapName = archiveFile + ".exec.map"; + vmArgs.add("-XX:SharedArchiveFile=" + archiveFile); + vmArgs.add("-Xlog:cds=debug"); + vmArgs.add("-Xshare:on"); + vmArgs.add("-Xlog:aot+map=debug,aot+map+oops=trace:file=" + mapName + ":none:filesize=0"); + vmArgs.add("--version"); + String[] cmdLine = vmArgs.toArray(new String[vmArgs.size()]); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(cmdLine); + OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "exec"); + out.shouldHaveExitValue(0); + + CDSMapReader.MapFile mapFile = CDSMapReader.read(mapName); + CDSMapReader.validate(mapFile); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java new file mode 100644 index 00000000000..f544b5653b7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=aot + * @bug 8362566 + * @summary Test the contents of -Xlog:aot+map with AOT workflow + * @requires vm.flagless + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/hotspot/jtreg/runtime/cds + * @build AOTMapTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar AOTMapTestApp + * @run driver AOTMapTest AOT --two-step-training + */ + +/** + * @test id=dynamic + * @bug 8362566 + * @summary Test the contents of -Xlog:aot+map with AOT workflow + * @requires vm.flagless + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/hotspot/jtreg/runtime/cds + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @build AOTMapTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar AOTMapTestApp + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. AOTMapTest DYNAMIC + */ + + +import java.util.ArrayList; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.Platform; + +public class AOTMapTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "AOTMapTestApp"; + + public static void main(String[] args) throws Exception { + doTest(args, false); + + if (Platform.is64bit()) { + // There's no oop/klass compression on 32-bit. + doTest(args, true); + } + } + + public static void doTest(String[] args, boolean compressed) throws Exception { + Tester tester = new Tester(compressed); + tester.run(args); + + validate(tester.dumpMapFile); + validate(tester.runMapFile); + } + + static void validate(String mapFileName) { + CDSMapReader.MapFile mapFile = CDSMapReader.read(mapFileName); + CDSMapReader.validate(mapFile); + } + + static class Tester extends CDSAppTester { + boolean compressed; + String dumpMapFile; + String runMapFile; + + public Tester(boolean compressed) { + super(mainClass); + this.compressed = compressed; + + dumpMapFile = "test" + (compressed ? "0" : "1") + ".dump.aotmap"; + runMapFile = "test" + (compressed ? "0" : "1") + ".run.aotmap"; + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + ArrayList vmArgs = new ArrayList<>(); + + vmArgs.add("-Xmx128M"); + vmArgs.add("-Xlog:aot=debug"); + + if (Platform.is64bit()) { + // These options are available only on 64-bit. + String sign = (compressed) ? "+" : "-"; + vmArgs.add("-XX:" + sign + "UseCompressedOops"); + } + + // filesize=0 ensures that a large map file not broken up in multiple files. + String logMapPrefix = "-Xlog:aot+map=debug,aot+map+oops=trace:file="; + String logMapSuffix = ":none:filesize=0"; + + if (runMode == RunMode.ASSEMBLY || runMode == RunMode.DUMP_DYNAMIC) { + vmArgs.add(logMapPrefix + dumpMapFile + logMapSuffix); + } else if (runMode == RunMode.PRODUCTION) { + vmArgs.add(logMapPrefix + runMapFile + logMapSuffix); + } + + return vmArgs.toArray(new String[vmArgs.size()]); + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + }; + } + } +} + +class AOTMapTestApp { + public static void main(String[] args) { + System.out.println("Hello AOTMapTestApp"); + } +} From 88c39793670f2d36490530993feb60e138f43a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Wed, 27 Aug 2025 07:55:57 +0000 Subject: [PATCH 242/471] 8365256: RelocIterator should use indexes instead of pointers Reviewed-by: kvn, dlong --- src/hotspot/share/code/codeBlob.cpp | 30 ++++++--------- src/hotspot/share/code/nmethod.cpp | 20 +++++----- src/hotspot/share/code/relocInfo.cpp | 55 +++++++++++++++------------- src/hotspot/share/code/relocInfo.hpp | 28 +++++++------- 4 files changed, 64 insertions(+), 69 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 9ec5478a071..6d34204d074 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -128,7 +128,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size int mutable_data_size) : _oop_maps(nullptr), // will be set by set_oop_maps() call _name(name), - _mutable_data(header_begin() + size), // default value is blob_end() + _mutable_data(nullptr), _size(size), _relocation_size(align_up(cb->total_relocation_size(), oopSize)), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -158,10 +158,8 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } - } else { - // We need unique and valid not null address - assert(_mutable_data == blob_end(), "sanity"); } + assert(_mutable_data != nullptr || _mutable_data_size == 0, "No mutable data => mutable data size is 0"); set_oop_maps(oop_maps); } @@ -170,7 +168,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) : _oop_maps(nullptr), _name(name), - _mutable_data(header_begin() + size), // default value is blob_end() + _mutable_data(nullptr), _size(size), _relocation_size(0), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -184,9 +182,9 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade _kind(kind), _caller_must_gc_arguments(false) { + assert(_mutable_data == nullptr && _mutable_data_size == 0, "invariant"); assert(is_aligned(size, oopSize), "unaligned size"); assert(is_aligned(header_size, oopSize), "unaligned size"); - assert(_mutable_data == blob_end(), "sanity"); } void CodeBlob::restore_mutable_data(address reloc_data) { @@ -197,7 +195,7 @@ void CodeBlob::restore_mutable_data(address reloc_data) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } } else { - _mutable_data = blob_end(); // default value + _mutable_data = nullptr; } if (_relocation_size > 0) { assert(_mutable_data_size > 0, "relocation is part of mutable data section"); @@ -206,17 +204,13 @@ void CodeBlob::restore_mutable_data(address reloc_data) { } void CodeBlob::purge() { - assert(_mutable_data != nullptr, "should never be null"); - if (_mutable_data != blob_end()) { - os::free(_mutable_data); - _mutable_data = blob_end(); // Valid not null address - _mutable_data_size = 0; - _relocation_size = 0; - } - if (_oop_maps != nullptr) { - delete _oop_maps; - _oop_maps = nullptr; - } + os::free(_mutable_data); + _mutable_data = nullptr; + _mutable_data_size = 0; + delete _oop_maps; + _oop_maps = nullptr; + _relocation_size = 0; + NOT_PRODUCT(_asm_remarks.clear()); NOT_PRODUCT(_dbg_strings.clear()); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index b8b3a70bf58..a45ca141455 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1327,8 +1327,8 @@ nmethod::nmethod( "wrong mutable data size: %d != %d + %d", _mutable_data_size, _relocation_size, metadata_size); - // native wrapper does not have read-only data but we need unique not null address - _immutable_data = blob_end(); + // native wrapper does not have read-only data + _immutable_data = nullptr; _immutable_data_size = 0; _nul_chk_table_offset = 0; _handler_table_offset = 0; @@ -1510,8 +1510,7 @@ nmethod::nmethod( assert(immutable_data != nullptr, "required"); _immutable_data = immutable_data; } else { - // We need unique not null address - _immutable_data = blob_end(); + _immutable_data = nullptr; } CHECKED_CAST(_nul_chk_table_offset, uint16_t, (align_up((int)dependencies->size_in_bytes(), oopSize))); CHECKED_CAST(_handler_table_offset, uint16_t, (_nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize))); @@ -2147,15 +2146,14 @@ void nmethod::purge(bool unregister_nmethod) { delete ec; ec = next; } - if (_pc_desc_container != nullptr) { - delete _pc_desc_container; - } + + delete _pc_desc_container; delete[] _compiled_ic_data; - if (_immutable_data != blob_end()) { - os::free(_immutable_data); - _immutable_data = blob_end(); // Valid not null address - } + os::free(_immutable_data); + _immutable_data = nullptr; + _immutable_data_size = 0; + if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 8fc22596d01..fb24844000d 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -116,9 +116,6 @@ void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, re // ---------------------------------------------------------------------------------------------------- // Implementation of RelocIterator -// A static dummy to serve as a safe pointer when there is no relocation info. -static relocInfo dummy_relocInfo = relocInfo(relocInfo::none, 0); - void RelocIterator::initialize(nmethod* nm, address begin, address limit) { initialize_misc(); @@ -130,14 +127,9 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { guarantee(nm != nullptr, "must be able to deduce nmethod from other arguments"); _code = nm; - if (nm->relocation_size() == 0) { - _current = &dummy_relocInfo - 1; - _end = &dummy_relocInfo; - } else { - assert(((nm->relocation_begin() != nullptr) && (nm->relocation_end() != nullptr)), "valid start and end pointer"); - _current = nm->relocation_begin() - 1; - _end = nm->relocation_end(); - } + _base = nm->relocation_begin(); + _current = -1; + _len = nm->relocation_end() - _base; _addr = nm->content_begin(); // Initialize code sections. @@ -156,11 +148,21 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { } +RelocIterator::RelocIterator(relocInfo& ri) { + initialize_misc(); + _base = &ri; + _len = 1; + _current = -1; + _limit = nullptr; + _addr = 0; +} + RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { initialize_misc(); assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)), "valid start and end pointer"); - _current = cs->locs_start() - 1; - _end = cs->locs_end(); + _base = cs->locs_start(); + _len = cs->locs_end() - _base; + _current = -1; _addr = cs->start(); _code = nullptr; // Not cb->blob(); @@ -186,8 +188,9 @@ RelocIterator::RelocIterator(CodeBlob* cb) { } else { _code = nullptr; } - _current = cb->relocation_begin() - 1; - _end = cb->relocation_end(); + _base = cb->relocation_begin(); + _len = cb->relocation_end() - _base; + _current = -1; _addr = cb->content_begin(); _section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin(); @@ -216,7 +219,7 @@ void RelocIterator::set_limits(address begin, address limit) { // the limit affects this next stuff: if (begin != nullptr) { - relocInfo* backup; + int backup; address backup_addr; while (true) { backup = _current; @@ -238,12 +241,12 @@ void RelocIterator::set_limits(address begin, address limit) { // very efficiently (a single extra halfword). Larger chunks of // relocation data need a halfword header to hold their size. void RelocIterator::advance_over_prefix() { - if (_current->is_datalen()) { - _data = (short*) _current->data(); - _datalen = _current->datalen(); + if (current()->is_datalen()) { + _data = (short*) current()->data(); + _datalen = current()->datalen(); _current += _datalen + 1; // skip the embedded data & header } else { - _databuf = _current->immediate(); + _databuf = current()->immediate(); _data = &_databuf; _datalen = 1; _current++; // skip the header @@ -350,9 +353,9 @@ void Relocation::const_verify_data_value(address x) { RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; - relocInfo ri = relocInfo(rtype, 0); - RelocIterator itr; - itr.set_current(ri); + relocInfo ri(rtype, 0); + RelocIterator itr(ri); + itr.next(); itr.reloc(); return itr._rh; } @@ -839,7 +842,7 @@ void RelocIterator::print_current_on(outputStream* st) { return; } st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); + p2i(current()), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), current()->addr_offset()); if (current()->format() != 0) st->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -990,7 +993,7 @@ void RelocIterator::print_current_on(outputStream* st) { void RelocIterator::print_on(outputStream* st) { RelocIterator save_this = (*this); - relocInfo* scan = _current; + relocInfo* scan = current_no_check(); if (!has_current()) scan += 1; // nothing to scan here! bool skip_next = has_current(); @@ -1000,7 +1003,7 @@ void RelocIterator::print_on(outputStream* st) { skip_next = false; st->print(" @" INTPTR_FORMAT ": ", p2i(scan)); - relocInfo* newscan = _current+1; + relocInfo* newscan = current_no_check()+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { st->print("%04x", *(short*)scan & 0xFFFF); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 714a964b28d..58dbf61abbe 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -562,12 +562,13 @@ class RelocIterator : public StackObj { private: address _limit; // stop producing relocations after this _addr - relocInfo* _current; // the current relocation information - relocInfo* _end; // end marker; we're done iterating when _current == _end + relocInfo* _base; // base pointer into relocInfo array + int _current; // current index + int _len; // length nmethod* _code; // compiled method containing _addr address _addr; // instruction to which the relocation applies - short _databuf; // spare buffer for compressed data short* _data; // pointer to the relocation's data + short _databuf; // spare buffer for compressed data short _datalen; // number of halfwords in _data // Base addresses needed to compute targets of section_word_type relocs. @@ -578,15 +579,14 @@ class RelocIterator : public StackObj { _datalen = !b ? -1 : 0; DEBUG_ONLY(_data = nullptr); } - void set_current(relocInfo& ri) { - _current = &ri; - set_has_current(true); - } RelocationHolder _rh; // where the current relocation is allocated - relocInfo* current() const { assert(has_current(), "must have current"); - return _current; } + relocInfo* current_no_check() const { return &_base[_current]; } + relocInfo* current() const { + assert(has_current(), "must have current"); + return current_no_check(); + } void set_limits(address begin, address limit); @@ -597,6 +597,7 @@ class RelocIterator : public StackObj { void initialize(nmethod* nm, address begin, address limit); RelocIterator() { initialize_misc(); } + RelocIterator(relocInfo& ri); public: // constructor @@ -607,25 +608,24 @@ class RelocIterator : public StackObj { // get next reloc info, return !eos bool next() { _current++; - assert(_current <= _end, "must not overrun relocInfo"); - if (_current == _end) { + assert(_current <= _len, "must not overrun relocInfo"); + if (_current == _len) { set_has_current(false); return false; } set_has_current(true); - if (_current->is_prefix()) { + if (current()->is_prefix()) { advance_over_prefix(); assert(!current()->is_prefix(), "only one prefix at a time"); } - _addr += _current->addr_offset(); + _addr += current()->addr_offset(); if (_limit != nullptr && _addr >= _limit) { set_has_current(false); return false; } - return true; } From b39c73696d0421b218e301403d589af5a91b037f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 27 Aug 2025 09:08:13 +0000 Subject: [PATCH 243/471] 8359683: ZGC: NUMA-Aware Relocation Reviewed-by: aboldtch, sjohanss --- src/hotspot/share/gc/z/zArray.hpp | 4 + src/hotspot/share/gc/z/zArray.inline.hpp | 14 ++ src/hotspot/share/gc/z/zForwarding.hpp | 5 +- src/hotspot/share/gc/z/zForwarding.inline.hpp | 7 +- src/hotspot/share/gc/z/zHeap.cpp | 4 +- src/hotspot/share/gc/z/zHeap.hpp | 2 +- src/hotspot/share/gc/z/zHeuristics.cpp | 9 +- src/hotspot/share/gc/z/zObjectAllocator.cpp | 2 +- src/hotspot/share/gc/z/zPage.inline.hpp | 1 + src/hotspot/share/gc/z/zPageAllocator.cpp | 30 ++- src/hotspot/share/gc/z/zPageAllocator.hpp | 3 +- src/hotspot/share/gc/z/zRelocate.cpp | 218 ++++++++++++------ src/hotspot/share/gc/z/zRelocate.hpp | 28 ++- src/hotspot/share/gc/z/zRelocationSet.hpp | 5 +- .../share/gc/z/zRelocationSet.inline.hpp | 10 +- 15 files changed, 244 insertions(+), 98 deletions(-) diff --git a/src/hotspot/share/gc/z/zArray.hpp b/src/hotspot/share/gc/z/zArray.hpp index 1b7e99b3ace..9ef911bb1b5 100644 --- a/src/hotspot/share/gc/z/zArray.hpp +++ b/src/hotspot/share/gc/z/zArray.hpp @@ -91,6 +91,10 @@ public: ZArrayIteratorImpl(const ZArray* array); bool next(T* elem); + + template + bool next_if(T* elem, Function predicate, Args&&... args); + bool next_index(size_t* index); T index_to_elem(size_t index); diff --git a/src/hotspot/share/gc/z/zArray.inline.hpp b/src/hotspot/share/gc/z/zArray.inline.hpp index 547a73ffc0d..bf606a88e68 100644 --- a/src/hotspot/share/gc/z/zArray.inline.hpp +++ b/src/hotspot/share/gc/z/zArray.inline.hpp @@ -161,6 +161,20 @@ inline bool ZArrayIteratorImpl::next(T* elem) { return false; } +template +template +inline bool ZArrayIteratorImpl::next_if(T* elem, Function predicate, Args&&... args) { + size_t index; + while (next_index(&index)) { + if (predicate(index_to_elem(index), args...)) { + *elem = index_to_elem(index); + return true; + } + } + + return false; +} + template inline bool ZArrayIteratorImpl::next_index(size_t* index) { if (Parallel) { diff --git a/src/hotspot/share/gc/z/zForwarding.hpp b/src/hotspot/share/gc/z/zForwarding.hpp index c58c479984f..29b5cf4aabe 100644 --- a/src/hotspot/share/gc/z/zForwarding.hpp +++ b/src/hotspot/share/gc/z/zForwarding.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -59,6 +59,7 @@ private: const size_t _object_alignment_shift; const AttachedArray _entries; ZPage* const _page; + const uint32_t _partition_id; const ZPageAge _from_age; const ZPageAge _to_age; volatile bool _claimed; @@ -108,6 +109,8 @@ public: size_t size() const; size_t object_alignment_shift() const; + uint32_t partition_id() const; + bool is_promotion() const; // Visit from-objects diff --git a/src/hotspot/share/gc/z/zForwarding.inline.hpp b/src/hotspot/share/gc/z/zForwarding.inline.hpp index eb5f4a36161..43558018793 100644 --- a/src/hotspot/share/gc/z/zForwarding.inline.hpp +++ b/src/hotspot/share/gc/z/zForwarding.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -61,6 +61,7 @@ inline ZForwarding::ZForwarding(ZPage* page, ZPageAge to_age, size_t nentries) _object_alignment_shift(page->object_alignment_shift()), _entries(nentries), _page(page), + _partition_id(page->single_partition_id()), _from_age(page->age()), _to_age(to_age), _claimed(false), @@ -102,6 +103,10 @@ inline size_t ZForwarding::object_alignment_shift() const { return _object_alignment_shift; } +inline uint32_t ZForwarding::partition_id() const { + return _partition_id; +} + inline bool ZForwarding::is_promotion() const { return _from_age != ZPageAge::old && _to_age == ZPageAge::old; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index e43336c8ea3..44e5974993e 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -250,8 +250,8 @@ void ZHeap::account_undo_alloc_page(ZPage* page) { p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); } -ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { - ZPage* const page = _page_allocator.alloc_page(type, size, flags, age); +ZPage* ZHeap::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) { + ZPage* const page = _page_allocator.alloc_page(type, size, flags, age, preferred_partition); if (page != nullptr) { // Insert page table entry _page_table.insert(page); diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index f7d606fc260..64ebc253b26 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -108,7 +108,7 @@ public: void mark_flush(Thread* thread); // Page allocation - ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition); void undo_alloc_page(ZPage* page); void free_page(ZPage* page); size_t free_empty_pages(ZGenerationId id, const ZArray* pages); diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index fac5fca080d..ccd31ee1749 100644 --- a/src/hotspot/share/gc/z/zHeuristics.cpp +++ b/src/hotspot/share/gc/z/zHeuristics.cpp @@ -26,6 +26,7 @@ #include "gc/z/zCPU.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHeuristics.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" @@ -58,9 +59,11 @@ void ZHeuristics::set_medium_page_size() { } size_t ZHeuristics::relocation_headroom() { - // Calculate headroom needed to avoid in-place relocation. Each worker will try - // to allocate a small page, and all workers will share a single medium page. - return (ConcGCThreads * ZPageSizeSmall) + ZPageSizeMediumMax; + // Calculate headroom needed to avoid in-place relocation. For each NUMA node, + // each worker will try to allocate a small page, and all workers will share a + // single medium page. + const size_t per_numa_headroom = (ConcGCThreads * ZPageSizeSmall) + ZPageSizeMediumMax; + return per_numa_headroom * ZNUMA::count(); } bool ZHeuristics::use_per_cpu_shared_small_pages() { diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index c6dd0a1a152..63e7f2b4ae9 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -53,7 +53,7 @@ ZPage* const* ZObjectAllocator::PerAge::shared_small_page_addr() const { } ZPage* ZObjectAllocator::PerAge::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags) { - return ZHeap::heap()->alloc_page(type, size, flags, _age); + return ZHeap::heap()->alloc_page(type, size, flags, _age, ZNUMA::id()); } void ZObjectAllocator::PerAge::undo_alloc_page(ZPage* page) { diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index f6c2029ac06..f9a0dbf328d 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -157,6 +157,7 @@ inline const ZVirtualMemory& ZPage::virtual_memory() const { } inline uint32_t ZPage::single_partition_id() const { + assert(!is_multi_partition(), "Don't fetch single partition id if page is multi-partition"); return _single_partition_id; } diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 52d5d775757..ba0ab923e11 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -412,7 +412,7 @@ private: const Ticks _start_timestamp; const uint32_t _young_seqnum; const uint32_t _old_seqnum; - const uint32_t _initiating_numa_id; + const uint32_t _preferred_partition; bool _is_multi_partition; ZSinglePartitionAllocation _single_partition_allocation; ZMultiPartitionAllocation _multi_partition_allocation; @@ -420,7 +420,7 @@ private: ZFuture _stall_result; public: - ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) + ZPageAllocation(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) : _type(type), _requested_size(size), _flags(flags), @@ -428,12 +428,14 @@ public: _start_timestamp(Ticks::now()), _young_seqnum(ZGeneration::young()->seqnum()), _old_seqnum(ZGeneration::old()->seqnum()), - _initiating_numa_id(ZNUMA::id()), + _preferred_partition(preferred_partition), _is_multi_partition(false), _single_partition_allocation(size), _multi_partition_allocation(size), _node(), - _stall_result() {} + _stall_result() { + assert(_preferred_partition < ZNUMA::count(), "Preferred partition out-of-bounds (0 <= %d < %d)", _preferred_partition, ZNUMA::count()); + } void reset_for_retry() { _is_multi_partition = false; @@ -474,8 +476,8 @@ public: return _old_seqnum; } - uint32_t initiating_numa_id() const { - return _initiating_numa_id; + uint32_t preferred_partition() const { + return _preferred_partition; } bool is_multi_partition() const { @@ -1397,10 +1399,10 @@ static void check_out_of_memory_during_initialization() { } } -ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age) { +ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition) { EventZPageAllocation event; - ZPageAllocation allocation(type, size, flags, age); + ZPageAllocation allocation(type, size, flags, age, preferred_partition); // Allocate the page ZPage* const page = alloc_page_inner(&allocation); @@ -1548,7 +1550,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } // Round robin single-partition claiming - const uint32_t start_numa_id = allocation->initiating_numa_id(); + const uint32_t start_numa_id = allocation->preferred_partition(); const uint32_t start_partition = start_numa_id; const uint32_t num_partitions = _partitions.count(); @@ -1560,7 +1562,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } } - if (!is_multi_partition_enabled() || sum_available() < allocation->size()) { + if (!is_multi_partition_allowed(allocation)) { // Multi-partition claiming is not possible return false; } @@ -1578,7 +1580,7 @@ bool ZPageAllocator::claim_capacity(ZPageAllocation* allocation) { } bool ZPageAllocator::claim_capacity_fast_medium(ZPageAllocation* allocation) { - const uint32_t start_node = allocation->initiating_numa_id(); + const uint32_t start_node = allocation->preferred_partition(); const uint32_t numa_nodes = ZNUMA::count(); for (uint32_t i = 0; i < numa_nodes; ++i) { @@ -2191,6 +2193,12 @@ bool ZPageAllocator::is_multi_partition_enabled() const { return _virtual.is_multi_partition_enabled(); } +bool ZPageAllocator::is_multi_partition_allowed(const ZPageAllocation* allocation) const { + return is_multi_partition_enabled() && + allocation->type() == ZPageType::large && + allocation->size() <= sum_available(); +} + const ZPartition& ZPageAllocator::partition_from_partition_id(uint32_t numa_id) const { return _partitions.get(numa_id); } diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index c5d1bedd863..a2f4c94e8d4 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -220,6 +220,7 @@ private: void satisfy_stalled(); bool is_multi_partition_enabled() const; + bool is_multi_partition_allowed(const ZPageAllocation* allocation) const; const ZPartition& partition_from_partition_id(uint32_t partition_id) const; ZPartition& partition_from_partition_id(uint32_t partition_id); @@ -263,7 +264,7 @@ public: ZPageAllocatorStats stats(ZGeneration* generation) const; ZPageAllocatorStats update_and_stats(ZGeneration* generation); - ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age, uint32_t preferred_partition); void safe_destroy_page(ZPage* page); void free_page(ZPage* page); void free_pages(ZGenerationId id, const ZArray* pages); diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 95e22cf4c69..556f413348b 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -32,6 +32,7 @@ #include "gc/z/zHeap.inline.hpp" #include "gc/z/zIndexDistributor.inline.hpp" #include "gc/z/zIterator.inline.hpp" +#include "gc/z/zNUMA.inline.hpp" #include "gc/z/zObjectAllocator.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageAge.inline.hpp" @@ -43,6 +44,7 @@ #include "gc/z/zStringDedup.inline.hpp" #include "gc/z/zTask.hpp" #include "gc/z/zUncoloredRoot.inline.hpp" +#include "gc/z/zValue.inline.hpp" #include "gc/z/zVerify.hpp" #include "gc/z/zWorkers.hpp" #include "prims/jvmtiTagMap.hpp" @@ -304,9 +306,38 @@ void ZRelocateQueue::desynchronize() { _lock.notify_all(); } +ZRelocationTargets::ZRelocationTargets() + : _targets() {} + +ZPage* ZRelocationTargets::get(uint32_t partition_id, ZPageAge age) { + return _targets.get(partition_id)[untype(age) - 1]; +} + +void ZRelocationTargets::set(uint32_t partition_id, ZPageAge age, ZPage* page) { + _targets.get(partition_id)[untype(age) - 1] = page; +} + +template +void ZRelocationTargets::apply_and_clear_targets(Function function) { + ZPerNUMAIterator iter(&_targets); + for (TargetArray* targets; iter.next(&targets);) { + for (size_t i = 0; i < ZNumRelocationAges; i++) { + // Apply function + function((*targets)[i]); + + // Clear target + (*targets)[i] = nullptr; + } + } +} + ZRelocate::ZRelocate(ZGeneration* generation) : _generation(generation), - _queue() {} + _queue(), + _iters(), + _small_targets(), + _medium_targets(), + _shared_medium_targets() {} ZWorkers* ZRelocate::workers() const { return _generation->workers(); @@ -394,12 +425,13 @@ static ZPage* alloc_page(ZForwarding* forwarding) { const ZPageType type = forwarding->type(); const size_t size = forwarding->size(); const ZPageAge age = forwarding->to_age(); + const uint32_t preferred_partition = forwarding->partition_id(); ZAllocationFlags flags; flags.set_non_blocking(); flags.set_gc_relocation(); - return ZHeap::heap()->alloc_page(type, size, flags, age); + return ZHeap::heap()->alloc_page(type, size, flags, age, preferred_partition); } static void retire_target_page(ZGeneration* generation, ZPage* page) { @@ -442,7 +474,7 @@ public: return page; } - void share_target_page(ZPage* page) { + void share_target_page(ZPage* page, uint32_t partition_id) { // Does nothing } @@ -467,34 +499,26 @@ public: class ZRelocateMediumAllocator { private: - ZGeneration* const _generation; - ZConditionLock _lock; - ZPage* _shared[ZNumRelocationAges]; - bool _in_place; - volatile size_t _in_place_count; + ZGeneration* const _generation; + ZConditionLock _lock; + ZRelocationTargets* _shared_targets; + bool _in_place; + volatile size_t _in_place_count; public: - ZRelocateMediumAllocator(ZGeneration* generation) + ZRelocateMediumAllocator(ZGeneration* generation, ZRelocationTargets* shared_targets) : _generation(generation), _lock(), - _shared(), + _shared_targets(shared_targets), _in_place(false), _in_place_count(0) {} ~ZRelocateMediumAllocator() { - for (uint i = 0; i < ZNumRelocationAges; ++i) { - if (_shared[i] != nullptr) { - retire_target_page(_generation, _shared[i]); + _shared_targets->apply_and_clear_targets([&](ZPage* page) { + if (page != nullptr) { + retire_target_page(_generation, page); } - } - } - - ZPage* shared(ZPageAge age) { - return _shared[untype(age - 1)]; - } - - void set_shared(ZPageAge age, ZPage* page) { - _shared[untype(age - 1)] = page; + }); } ZPage* alloc_and_retire_target_page(ZForwarding* forwarding, ZPage* target) { @@ -510,9 +534,10 @@ public: // current target page if another thread shared a page, or allocated // a new page. const ZPageAge to_age = forwarding->to_age(); - if (shared(to_age) == target) { + const uint32_t partition_id = forwarding->partition_id(); + if (_shared_targets->get(partition_id, to_age) == target) { ZPage* const to_page = alloc_page(forwarding); - set_shared(to_age, to_page); + _shared_targets->set(partition_id, to_age, to_page); if (to_page == nullptr) { Atomic::inc(&_in_place_count); _in_place = true; @@ -524,18 +549,18 @@ public: } } - return shared(to_age); + return _shared_targets->get(partition_id, to_age); } - void share_target_page(ZPage* page) { + void share_target_page(ZPage* page, uint32_t partition_id) { const ZPageAge age = page->age(); ZLocker locker(&_lock); assert(_in_place, "Invalid state"); - assert(shared(age) == nullptr, "Invalid state"); + assert(_shared_targets->get(partition_id, age) == nullptr, "Invalid state"); assert(page != nullptr, "Invalid page"); - set_shared(age, page); + _shared_targets->set(partition_id, age, page); _in_place = false; _lock.notify_all(); @@ -563,21 +588,12 @@ class ZRelocateWork : public StackObj { private: Allocator* const _allocator; ZForwarding* _forwarding; - ZPage* _target[ZNumRelocationAges]; + ZRelocationTargets* _targets; ZGeneration* const _generation; size_t _other_promoted; size_t _other_compacted; ZStringDedupContext _string_dedup_context; - - ZPage* target(ZPageAge age) { - return _target[untype(age - 1)]; - } - - void set_target(ZPageAge age, ZPage* page) { - _target[untype(age - 1)] = page; - } - size_t object_alignment() const { return (size_t)1 << _forwarding->object_alignment_shift(); } @@ -591,11 +607,11 @@ private: } } - zaddress try_relocate_object_inner(zaddress from_addr) { + zaddress try_relocate_object_inner(zaddress from_addr, uint32_t partition_id) { ZForwardingCursor cursor; const size_t size = ZUtils::object_size(from_addr); - ZPage* const to_page = target(_forwarding->to_age()); + ZPage* const to_page = _targets->get(partition_id, _forwarding->to_age()); // Lookup forwarding { @@ -806,8 +822,8 @@ private: } } - bool try_relocate_object(zaddress from_addr) { - const zaddress to_addr = try_relocate_object_inner(from_addr); + bool try_relocate_object(zaddress from_addr, uint32_t partition_id) { + const zaddress to_addr = try_relocate_object_inner(from_addr, partition_id); if (is_null(to_addr)) { return false; @@ -888,13 +904,18 @@ private: const zaddress addr = to_zaddress(obj); assert(ZHeap::heap()->is_object_live(addr), "Should be live"); - while (!try_relocate_object(addr)) { - // Allocate a new target page, or if that fails, use the page being - // relocated as the new target, which will cause it to be relocated - // in-place. - const ZPageAge to_age = _forwarding->to_age(); - ZPage* to_page = _allocator->alloc_and_retire_target_page(_forwarding, target(to_age)); - set_target(to_age, to_page); + const ZPageAge to_age = _forwarding->to_age(); + const uint32_t partition_id = _forwarding->partition_id(); + + while (!try_relocate_object(addr, partition_id)) { + // Failed to relocate object, try to allocate a new target page, + // or if that fails, use the page being relocated as the new target, + // which will cause it to be relocated in-place. + ZPage* const target_page = _targets->get(partition_id, to_age); + ZPage* to_page = _allocator->alloc_and_retire_target_page(_forwarding, target_page); + _targets->set(partition_id, to_age, to_page); + + // We got a new page, retry relocation if (to_page != nullptr) { continue; } @@ -903,23 +924,24 @@ private: // the page, or its forwarding table, until it has been released // (relocation completed). to_page = start_in_place_relocation(ZAddress::offset(addr)); - set_target(to_age, to_page); + _targets->set(partition_id, to_age, to_page); } } public: - ZRelocateWork(Allocator* allocator, ZGeneration* generation) + ZRelocateWork(Allocator* allocator, ZRelocationTargets* targets, ZGeneration* generation) : _allocator(allocator), _forwarding(nullptr), - _target(), + _targets(targets), _generation(generation), _other_promoted(0), _other_compacted(0) {} ~ZRelocateWork() { - for (uint i = 0; i < ZNumRelocationAges; ++i) { - _allocator->free_target_page(_target[i]); - } + _targets->apply_and_clear_targets([&](ZPage* page) { + _allocator->free_target_page(page); + }); + // Report statistics on-behalf of non-worker threads _generation->increase_promoted(_other_promoted); _generation->increase_compacted(_other_compacted); @@ -1012,8 +1034,9 @@ public: page->log_msg(" (relocate page done in-place)"); // Different pages when promoting - ZPage* const target_page = target(_forwarding->to_age()); - _allocator->share_target_page(target_page); + const uint32_t target_partition = _forwarding->partition_id(); + ZPage* const target_page = _targets->get(target_partition, _forwarding->to_age()); + _allocator->share_target_page(target_page, target_partition); } else { // Wait for all other threads to call release_page @@ -1057,31 +1080,63 @@ public: class ZRelocateTask : public ZRestartableTask { private: - ZRelocationSetParallelIterator _iter; - ZGeneration* const _generation; - ZRelocateQueue* const _queue; - ZRelocateSmallAllocator _small_allocator; - ZRelocateMediumAllocator _medium_allocator; + ZGeneration* const _generation; + ZRelocateQueue* const _queue; + ZPerNUMA* _iters; + ZPerWorker* _small_targets; + ZPerWorker* _medium_targets; + ZRelocateSmallAllocator _small_allocator; + ZRelocateMediumAllocator _medium_allocator; + const size_t _total_forwardings; + volatile size_t _numa_local_forwardings; public: - ZRelocateTask(ZRelocationSet* relocation_set, ZRelocateQueue* queue) + ZRelocateTask(ZRelocationSet* relocation_set, + ZRelocateQueue* queue, + ZPerNUMA* iters, + ZPerWorker* small_targets, + ZPerWorker* medium_targets, + ZRelocationTargets* shared_medium_targets) : ZRestartableTask("ZRelocateTask"), - _iter(relocation_set), _generation(relocation_set->generation()), _queue(queue), + _iters(iters), + _small_targets(small_targets), + _medium_targets(medium_targets), _small_allocator(_generation), - _medium_allocator(_generation) {} + _medium_allocator(_generation, shared_medium_targets), + _total_forwardings(relocation_set->nforwardings()), + _numa_local_forwardings(0) { + + for (uint32_t i = 0; i < ZNUMA::count(); i++) { + ZRelocationSetParallelIterator* const iter = _iters->addr(i); + + // Destruct the iterator from the previous GC-cycle, which is a temporary + // iterator if this is the first GC-cycle. + iter->~ZRelocationSetParallelIterator(); + + // In-place construct the iterator with the current relocation set + ::new (iter) ZRelocationSetParallelIterator(relocation_set); + } + } ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); // Signal that we're not using the queue anymore. Used mostly for asserts. _queue->deactivate(); + + if (ZNUMA::is_enabled()) { + log_debug(gc, reloc, numa)("Forwardings relocated NUMA-locally: %zu / %zu (%.0f%%)", + _numa_local_forwardings, _total_forwardings, percent_of(_numa_local_forwardings, _total_forwardings)); + } } virtual void work() { - ZRelocateWork small(&_small_allocator, _generation); - ZRelocateWork medium(&_medium_allocator, _generation); + ZRelocateWork small(&_small_allocator, _small_targets->addr(), _generation); + ZRelocateWork medium(&_medium_allocator, _medium_targets->addr(), _generation); + const uint32_t num_nodes = ZNUMA::count(); + uint32_t numa_local_forwardings_worker = 0; const auto do_forwarding = [&](ZForwarding* forwarding) { ZPage* const page = forwarding->page(); @@ -1107,12 +1162,29 @@ public: } }; + const auto check_numa_local = [&](ZForwarding* forwarding, uint32_t numa_id) { + return forwarding->partition_id() == numa_id; + }; + const auto do_forwarding_one_from_iter = [&]() { ZForwarding* forwarding; + const uint32_t start_node = ZNUMA::id(); + uint32_t current_node = start_node; - if (_iter.next(&forwarding)) { - claim_and_do_forwarding(forwarding); - return true; + for (uint32_t i = 0; i < num_nodes; i++) { + if (_iters->get(current_node).next_if(&forwarding, check_numa_local, current_node)) { + claim_and_do_forwarding(forwarding); + + if (current_node == start_node) { + // Track if this forwarding was relocated on the local NUMA node + numa_local_forwardings_worker++; + } + + return true; + } + + // Check next node. + current_node = (current_node + 1) % num_nodes; } return false; @@ -1138,6 +1210,10 @@ public: } } + if (ZNUMA::is_enabled()) { + Atomic::add(&_numa_local_forwardings, numa_local_forwardings_worker, memory_order_relaxed); + } + _queue->leave(); } @@ -1218,7 +1294,7 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { } { - ZRelocateTask relocate_task(relocation_set, &_queue); + ZRelocateTask relocate_task(relocation_set, &_queue, &_iters, &_small_targets, &_medium_targets, &_shared_medium_targets); workers()->run(&relocate_task); } diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 400fc61b055..d0ddf7deecf 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,6 +27,7 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zPageAge.hpp" #include "gc/z/zRelocationSet.hpp" +#include "gc/z/zValue.hpp" class ZForwarding; class ZGeneration; @@ -74,15 +75,34 @@ public: void desynchronize(); }; +class ZRelocationTargets { +private: + using TargetArray = ZPage*[ZNumRelocationAges]; + + ZPerNUMA _targets; + +public: + ZRelocationTargets(); + + ZPage* get(uint32_t partition_id, ZPageAge age); + void set(uint32_t partition_id, ZPageAge age, ZPage* page); + + template + void apply_and_clear_targets(Function function); +}; + class ZRelocate { friend class ZRelocateTask; private: - ZGeneration* const _generation; - ZRelocateQueue _queue; + ZGeneration* const _generation; + ZRelocateQueue _queue; + ZPerNUMA _iters; + ZPerWorker _small_targets; + ZPerWorker _medium_targets; + ZRelocationTargets _shared_medium_targets; ZWorkers* workers() const; - void work(ZRelocationSetParallelIterator* iter); public: ZRelocate(ZGeneration* generation); diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index 2052f3c7bf1..ee1a9447617 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -52,6 +52,8 @@ private: public: ZRelocationSet(ZGeneration* generation); + size_t nforwardings() const; + void install(const ZRelocationSetSelector* selector); void reset(ZPageAllocator* page_allocator); ZGeneration* generation() const; @@ -64,6 +66,7 @@ public: template class ZRelocationSetIteratorImpl : public ZArrayIteratorImpl { public: + ZRelocationSetIteratorImpl(); ZRelocationSetIteratorImpl(ZRelocationSet* relocation_set); }; diff --git a/src/hotspot/share/gc/z/zRelocationSet.inline.hpp b/src/hotspot/share/gc/z/zRelocationSet.inline.hpp index 9c093936d4c..b501021bc26 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.inline.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -28,6 +28,14 @@ #include "gc/z/zArray.inline.hpp" +inline size_t ZRelocationSet::nforwardings() const { + return _nforwardings; +} + +template +inline ZRelocationSetIteratorImpl::ZRelocationSetIteratorImpl() + : ZArrayIteratorImpl(nullptr, 0) {} + template inline ZRelocationSetIteratorImpl::ZRelocationSetIteratorImpl(ZRelocationSet* relocation_set) : ZArrayIteratorImpl(relocation_set->_forwardings, relocation_set->_nforwardings) {} From 0ca38bdc4d503158fda57bbc8bc9adc420628079 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 27 Aug 2025 09:30:48 +0000 Subject: [PATCH 244/471] 8365919: Replace currentTimeMillis with nanoTime in Stresser.java Reviewed-by: tschatzl, phh --- .../vmTestbase/nsk/share/test/Stresser.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java index 83e8baa2836..c2851267911 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java @@ -58,9 +58,12 @@ public class Stresser implements ExecutionController { private String name; private long maxIterations; private long iterations; + + // In nanoseconds private long startTime; - private long finishTime; private long currentTime; + private long stressTime; + private PrintStream defaultOutput = System.out; /* @@ -179,15 +182,15 @@ public class Stresser implements ExecutionController { */ public void printExecutionInfo(PrintStream out) { println(out, "Completed iterations: " + iterations); - println(out, "Execution time: " + (currentTime - startTime) + " seconds"); + println(out, "Execution time: " + (currentTime - startTime) / 1_000_000_000.0 + " seconds"); if (!finished) { println(out, "Execution is not finished yet"); } else if (forceFinish) { println(out, "Execution was forced to finish"); } else if (maxIterations != 0 && iterations >= maxIterations) { println(out, "Execution finished because number of iterations was exceeded: " + iterations + " >= " + maxIterations); - } else if (finishTime != 0 && currentTime >= finishTime) { - println(out, "Execution finished because time was exceeded: " + (currentTime - startTime) + " >= " + (finishTime - startTime)); + } else if (stressTime != 0 && (currentTime - startTime) >= stressTime) { + println(out, "Execution finished because time has exceeded stress time: " + stressTime / 1_000_000_000 + " seconds"); } } @@ -208,13 +211,8 @@ public class Stresser implements ExecutionController { public void start(long stdIterations) { maxIterations = stdIterations * options.getIterationsFactor(); iterations = 0; - long stressTime = options.getTime(); - startTime = System.currentTimeMillis(); - if (stressTime == 0) { - finishTime = 0; - } else { - finishTime = startTime + stressTime * 1000; - } + stressTime = options.getTime() * 1_000_000_000; + startTime = System.nanoTime(); finished = false; forceFinish = false; if (options.isDebugEnabled()) { @@ -232,7 +230,7 @@ public class Stresser implements ExecutionController { * finally {} block. */ public void finish() { - currentTime = System.currentTimeMillis(); + currentTime = System.nanoTime(); finished = true; if (options.isDebugEnabled()) { printExecutionInfo(defaultOutput); @@ -255,10 +253,12 @@ public class Stresser implements ExecutionController { */ public boolean iteration() { ++iterations; + boolean result = continueExecution(); + // Call print at the end to show the most up-to-date info. if (options.isDebugDetailed()) { printExecutionInfo(defaultOutput); } - return continueExecution(); + return result; } /** @@ -267,14 +267,14 @@ public class Stresser implements ExecutionController { * @return true if execution needs to continue */ public boolean continueExecution() { - currentTime = System.currentTimeMillis(); + currentTime = System.nanoTime(); if (startTime == 0) { throw new TestBug("Stresser is not started."); } return !forceFinish && !finished && (maxIterations == 0 || iterations < maxIterations) - && (finishTime == 0 || currentTime < finishTime); + && (stressTime == 0 || (currentTime - startTime) < stressTime); } /** @@ -309,7 +309,7 @@ public class Stresser implements ExecutionController { * @return time */ public long getExecutionTime() { - return System.currentTimeMillis() - startTime; + return (System.nanoTime() - startTime) / 1_000_000; } /** @@ -318,11 +318,11 @@ public class Stresser implements ExecutionController { * @return time */ public long getTimeLeft() { - long current = System.currentTimeMillis(); - if (current >= finishTime) { + long elapsedTime = System.nanoTime() - startTime; + if (elapsedTime >= stressTime) { return 0; } else { - return finishTime - current; + return (stressTime - elapsedTime) / 1_000_000; } } From 19f0755c48e998b5b136ca58ea21eb3b54bc7b33 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 27 Aug 2025 09:41:12 +0000 Subject: [PATCH 245/471] 8365203: defineClass with direct buffer can cause use-after-free Reviewed-by: jpai --- .../share/classes/java/lang/ClassLoader.java | 17 +++- .../defineClass/TestGuardByteBuffer.java | 79 +++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 6082bc53297..511785a5ac8 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -52,6 +52,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.access.SharedSecrets; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.ClassLoaders; @@ -1049,14 +1050,22 @@ public abstract class ClassLoader { protectionDomain = preDefineClass(name, protectionDomain); String source = defineClassSourceLocation(protectionDomain); - Class c = defineClass2(this, name, b, b.position(), len, protectionDomain, source); - postDefineClass(c, protectionDomain); - return c; + + SharedSecrets.getJavaNioAccess().acquireSession(b); + try { + Class c = defineClass2(this, name, b, b.position(), len, protectionDomain, source); + postDefineClass(c, protectionDomain); + return c; + } finally { + SharedSecrets.getJavaNioAccess().releaseSession(b); + } } static native Class defineClass1(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd, String source); + // Warning: Before calling this method, the provided ByteBuffer must be guarded + // via JavaNioAccess::(acquire|release)Session static native Class defineClass2(ClassLoader loader, String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source); diff --git a/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java b/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java new file mode 100644 index 00000000000..6c12004ee4c --- /dev/null +++ b/test/jdk/java/lang/ClassLoader/defineClass/TestGuardByteBuffer.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8365203 + * @summary Tests guarding of ByteBuffers in ClassLoader::defineClass + * @run junit TestGuardByteBuffer + */ + +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.util.HexFormat; + +import static org.junit.jupiter.api.Assertions.*; + +final class TestGuardByteBuffer { + + @Test + void guardCrash() { + final byte[] classBytes = getClassBytes(); // get bytes of a valid class + final var cl = new ClassLoader() { + void tryCrash() { + var arena = Arena.ofConfined(); + var byteBuffer = arena.allocate(classBytes.length).asByteBuffer(); + // Close the arena underneath + arena.close(); + // expected to always fail because the arena + // from which the ByteBuffer was constructed + // has been closed + assertThrows(IllegalStateException.class, + () -> defineClass(null, byteBuffer, null)); + } + }; + for (int i = 0; i < 10_000; i++) { + cl.tryCrash(); + } + } + + private static byte[] getClassBytes() { + // unused. this is here just for reference + final String source = """ + public class NoOp {} + """; + // (externally) compiled content of the above "source", represented as hex + final String classBytesHex = """ + cafebabe00000044000d0a000200030700040c000500060100106a6176612f + 6c616e672f4f626a6563740100063c696e69743e0100032829560700080100 + 044e6f4f70010004436f646501000f4c696e654e756d6265725461626c6501 + 000a536f7572636546696c650100094e6f4f702e6a61766100210007000200 + 0000000001000100050006000100090000001d00010001000000052ab70001 + b100000001000a000000060001000000010001000b00000002000c + """; + + return HexFormat.of().parseHex(classBytesHex.replaceAll("\n", "")); + } + +} From 32df2d17f3c0407ad7e90eacfdc0fd7a65f67551 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 27 Aug 2025 10:15:25 +0000 Subject: [PATCH 246/471] 8365772: RISC-V: correctly prereserve NaN payload when converting from float to float16 in vector way Reviewed-by: fyang, rehn --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 1 + .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 67 +++++++++++++++---- .../TestFloatConversionsVectorNaN.java | 14 ++-- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 3317ccc3b53..c267cb669ac 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1988,6 +1988,7 @@ enum VectorMask { // Vector Narrowing Integer Right Shift Instructions INSN(vnsra_wi, 0b1010111, 0b011, 0b101101); + INSN(vnsrl_wi, 0b1010111, 0b011, 0b101100); #undef INSN diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 0420d83ac41..1bdb7bc2f7c 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2248,41 +2248,80 @@ static void float_to_float16_v_slow_path(C2_MacroAssembler& masm, #define __ masm. VectorRegister dst = stub.data<0>(); VectorRegister src = stub.data<1>(); - VectorRegister tmp = stub.data<2>(); + VectorRegister vtmp = stub.data<2>(); + assert_different_registers(dst, src, vtmp); + __ bind(stub.entry()); + // Active elements (NaNs) are marked in v0 mask register. // mul is already set to mf2 in float_to_float16_v. - // preserve the payloads of non-canonical NaNs. - __ vnsra_wi(dst, src, 13, Assembler::v0_t); + // Float (32 bits) + // Bit: 31 30 to 23 22 to 0 + // +---+------------------+-----------------------------+ + // | S | Exponent | Mantissa (Fraction) | + // +---+------------------+-----------------------------+ + // 1 bit 8 bits 23 bits + // + // Float (16 bits) + // Bit: 15 14 to 10 9 to 0 + // +---+----------------+------------------+ + // | S | Exponent | Mantissa | + // +---+----------------+------------------+ + // 1 bit 5 bits 10 bits + const int fp_sign_bits = 1; + const int fp32_bits = 32; + const int fp32_mantissa_2nd_part_bits = 9; + const int fp32_mantissa_3rd_part_bits = 4; + const int fp16_exponent_bits = 5; + const int fp16_mantissa_bits = 10; - // preserve the sign bit. - __ vnsra_wi(tmp, src, 26, Assembler::v0_t); - __ vsll_vi(tmp, tmp, 10, Assembler::v0_t); - __ mv(t0, 0x3ff); - __ vor_vx(tmp, tmp, t0, Assembler::v0_t); + // preserve the sign bit and exponent, clear mantissa. + __ vnsra_wi(dst, src, fp32_bits - fp_sign_bits - fp16_exponent_bits, Assembler::v0_t); + __ vsll_vi(dst, dst, fp16_mantissa_bits, Assembler::v0_t); - // get the result by merging sign bit and payloads of preserved non-canonical NaNs. - __ vand_vv(dst, dst, tmp, Assembler::v0_t); + // Preserve high order bit of float NaN in the + // binary16 result NaN (tenth bit); OR in remaining + // bits into lower 9 bits of binary 16 significand. + // | (doppel & 0x007f_e000) >> 13 // 10 bits + // | (doppel & 0x0000_1ff0) >> 4 // 9 bits + // | (doppel & 0x0000_000f)); // 4 bits + // + // Check j.l.Float.floatToFloat16 for more information. + // 10 bits + __ vnsrl_wi(vtmp, src, fp32_mantissa_2nd_part_bits + fp32_mantissa_3rd_part_bits, Assembler::v0_t); + __ mv(t0, 0x3ff); // retain first part of mantissa in a float 32 + __ vand_vx(vtmp, vtmp, t0, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); + // 9 bits + __ vnsrl_wi(vtmp, src, fp32_mantissa_3rd_part_bits, Assembler::v0_t); + __ mv(t0, 0x1ff); // retain second part of mantissa in a float 32 + __ vand_vx(vtmp, vtmp, t0, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); + // 4 bits + // Narrow shift is necessary to move data from 32 bits element to 16 bits element in vector register. + __ vnsrl_wi(vtmp, src, 0, Assembler::v0_t); + __ vand_vi(vtmp, vtmp, 0xf, Assembler::v0_t); + __ vor_vv(dst, dst, vtmp, Assembler::v0_t); __ j(stub.continuation()); #undef __ } // j.l.Float.float16ToFloat -void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp, - Register tmp, uint vector_length) { +void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, + VectorRegister vtmp, Register tmp, uint vector_length) { assert_different_registers(dst, src, vtmp); auto stub = C2CodeStub::make - (dst, src, vtmp, 28, float_to_float16_v_slow_path); + (dst, src, vtmp, 56, float_to_float16_v_slow_path); // On riscv, NaN needs a special process as vfncvt_f_f_w does not work in that case. vsetvli_helper(BasicType::T_FLOAT, vector_length, Assembler::m1); // check whether there is a NaN. - // replace v_fclass with vmseq_vv as performance optimization. + // replace v_fclass with vmfne_vv as performance optimization. vmfne_vv(v0, src, src); vcpop_m(t0, v0); diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java index 6f76defa279..dad6e51f2ec 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java @@ -23,6 +23,7 @@ /** * @test + * @key randomness * @bug 8320646 * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs, with NaN * @requires vm.compiler2.enabled @@ -37,9 +38,11 @@ package compiler.vectorization; import java.util.HexFormat; +import java.util.Random; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestFloatConversionsVectorNaN { private static final int ARRLEN = 1024; @@ -79,14 +82,16 @@ public class TestFloatConversionsVectorNaN { @Run(test = {"test_float_float16"}, mode = RunMode.STANDALONE) public void kernel_test_float_float16() { + Random rand = Utils.getRandomInstance(); int errno = 0; finp = new float[ARRLEN]; sout = new short[ARRLEN]; // Setup for (int i = 0; i < ARRLEN; i++) { - if (i%39 == 0) { - int x = 0x7f800000 + ((i/39) << 13); + if (i%3 == 0) { + int shift = rand.nextInt(13+1); + int x = 0x7f800000 + ((i/39) << shift); x = (i%2 == 0) ? x : (x | 0x80000000); finp[i] = Float.intBitsToFloat(x); } else { @@ -128,7 +133,8 @@ public class TestFloatConversionsVectorNaN { static int assertEquals(int idx, float f, short expected, short actual) { HexFormat hf = HexFormat.of(); - String msg = "floatToFloat16 wrong result: idx: " + idx + ", \t" + f + + String msg = "floatToFloat16 wrong result: idx: " + idx + + ", \t" + f + ", hex: " + Integer.toHexString(Float.floatToRawIntBits(f)) + ",\t expected: " + hf.toHexDigits(expected) + ",\t actual: " + hf.toHexDigits(actual); if ((expected & 0x7c00) != 0x7c00) { @@ -167,7 +173,7 @@ public class TestFloatConversionsVectorNaN { // Setup for (int i = 0; i < ARRLEN; i++) { - if (i%39 == 0) { + if (i%3 == 0) { int x = 0x7c00 + i; x = (i%2 == 0) ? x : (x | 0x8000); sinp[i] = (short)x; From 124575b4c2b52328a8efddb40e67057a53b44a04 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 27 Aug 2025 11:45:43 +0000 Subject: [PATCH 247/471] 8359348: G1: Improve cpu usage measurements for heap sizing Reviewed-by: tschatzl, ayang, manc --- src/hotspot/share/gc/g1/g1Analytics.cpp | 39 +++++++++++----- src/hotspot/share/gc/g1/g1Analytics.hpp | 44 ++++++++++++++----- .../share/gc/g1/g1HeapSizingPolicy.cpp | 4 +- src/hotspot/share/gc/g1/g1Policy.cpp | 12 ++++- test/hotspot/gtest/gc/g1/test_g1Analytics.cpp | 4 +- 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Analytics.cpp b/src/hotspot/share/gc/g1/g1Analytics.cpp index 59d1a48cd85..686554ffaa4 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.cpp +++ b/src/hotspot/share/gc/g1/g1Analytics.cpp @@ -28,6 +28,7 @@ #include "gc/shared/gc_globals.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" @@ -73,6 +74,8 @@ G1Analytics::G1Analytics(const G1Predictions* predictor) : _concurrent_mark_cleanup_times_ms(NumPrevPausesForHeuristics), _alloc_rate_ms_seq(TruncatedSeqLength), _prev_collection_pause_end_ms(0.0), + _gc_cpu_time_at_pause_end_ms(), + _concurrent_gc_cpu_time_ms(), _concurrent_refine_rate_ms_seq(TruncatedSeqLength), _dirtied_cards_rate_ms_seq(TruncatedSeqLength), _dirtied_cards_in_thread_buffers_seq(TruncatedSeqLength), @@ -88,8 +91,8 @@ G1Analytics::G1Analytics(const G1Predictions* predictor) : _young_other_cost_per_region_ms_seq(TruncatedSeqLength), _non_young_other_cost_per_region_ms_seq(TruncatedSeqLength), _recent_prev_end_times_for_all_gcs_sec(NumPrevPausesForHeuristics), - _long_term_pause_time_ratio(0.0), - _short_term_pause_time_ratio(0.0) { + _long_term_gc_time_ratio(0.0), + _short_term_gc_time_ratio(0.0) { // Seed sequences with initial values. _recent_prev_end_times_for_all_gcs_sec.add(os::elapsedTime()); @@ -149,6 +152,10 @@ int G1Analytics::num_alloc_rate_ms() const { return _alloc_rate_ms_seq.num(); } +double G1Analytics::gc_cpu_time_ms() const { + return (double)CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_MILLISEC; +} + void G1Analytics::report_concurrent_mark_remark_times_ms(double ms) { _concurrent_mark_remark_times_ms.add(ms); } @@ -157,15 +164,27 @@ void G1Analytics::report_alloc_rate_ms(double alloc_rate) { _alloc_rate_ms_seq.add(alloc_rate); } -void G1Analytics::compute_pause_time_ratios(double end_time_sec, double pause_time_ms) { +void G1Analytics::update_gc_time_ratios(double end_time_sec, double pause_time_ms) { + // This estimates the wall-clock time "lost" by application mutator threads due to concurrent GC + // activity. We do not account for contention on other shared resources such as memory bandwidth and + // caches, therefore underestimate the impact of the concurrent GC activity on mutator threads. + uint num_cpus = (uint)os::active_processor_count(); + double concurrent_gc_impact_time = _concurrent_gc_cpu_time_ms / num_cpus; + + double gc_time_ms = pause_time_ms + concurrent_gc_impact_time; + double long_interval_ms = (end_time_sec - oldest_known_gc_end_time_sec()) * 1000.0; - double gc_pause_time_ms = _recent_gc_times_ms.sum() - _recent_gc_times_ms.oldest() + pause_time_ms; - _long_term_pause_time_ratio = gc_pause_time_ms / long_interval_ms; - _long_term_pause_time_ratio = clamp(_long_term_pause_time_ratio, 0.0, 1.0); + double long_term_gc_time_ms = _recent_gc_times_ms.sum() - _recent_gc_times_ms.oldest() + gc_time_ms; + + _long_term_gc_time_ratio = long_term_gc_time_ms / long_interval_ms; + _long_term_gc_time_ratio = clamp(_long_term_gc_time_ratio, 0.0, 1.0); double short_interval_ms = (end_time_sec - most_recent_gc_end_time_sec()) * 1000.0; - _short_term_pause_time_ratio = pause_time_ms / short_interval_ms; - _short_term_pause_time_ratio = clamp(_short_term_pause_time_ratio, 0.0, 1.0); + + _short_term_gc_time_ratio = gc_time_ms / short_interval_ms; + _short_term_gc_time_ratio = clamp(_short_term_gc_time_ratio, 0.0, 1.0); + + update_recent_gc_times(end_time_sec, gc_time_ms); } void G1Analytics::report_concurrent_refine_rate_ms(double cards_per_ms) { @@ -305,8 +324,8 @@ double G1Analytics::most_recent_gc_end_time_sec() const { } void G1Analytics::update_recent_gc_times(double end_time_sec, - double pause_time_ms) { - _recent_gc_times_ms.add(pause_time_ms); + double gc_time_ms) { + _recent_gc_times_ms.add(gc_time_ms); _recent_prev_end_times_for_all_gcs_sec.add(end_time_sec); } diff --git a/src/hotspot/share/gc/g1/g1Analytics.hpp b/src/hotspot/share/gc/g1/g1Analytics.hpp index 2fd3c78df27..e5e2dd74101 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.hpp +++ b/src/hotspot/share/gc/g1/g1Analytics.hpp @@ -44,7 +44,15 @@ class G1Analytics: public CHeapObj { TruncatedSeq _concurrent_mark_cleanup_times_ms; TruncatedSeq _alloc_rate_ms_seq; - double _prev_collection_pause_end_ms; + double _prev_collection_pause_end_ms; + + // Records the total GC CPU time (in ms) at the end of the last GC pause. + // Used as a baseline to calculate CPU time spent in GC threads between pauses. + double _gc_cpu_time_at_pause_end_ms; + + // CPU time (ms) spent by GC threads between the end of the last pause + // and the start of the current pause; calculated at start of a GC pause. + double _concurrent_gc_cpu_time_ms; TruncatedSeq _concurrent_refine_rate_ms_seq; TruncatedSeq _dirtied_cards_rate_ms_seq; @@ -75,10 +83,10 @@ class G1Analytics: public CHeapObj { // Statistics kept per GC stoppage, pause or full. TruncatedSeq _recent_prev_end_times_for_all_gcs_sec; - // Cached values for long and short term pause time ratios. See - // compute_pause_time_ratios() for how they are computed. - double _long_term_pause_time_ratio; - double _short_term_pause_time_ratio; + // Cached values for long and short term gc time ratios. See + // update_gc_time_ratios() for how they are computed. + double _long_term_gc_time_ratio; + double _short_term_gc_time_ratio; double predict_in_unit_interval(TruncatedSeq const* seq) const; size_t predict_size(TruncatedSeq const* seq) const; @@ -102,12 +110,12 @@ public: return _prev_collection_pause_end_ms; } - double long_term_pause_time_ratio() const { - return _long_term_pause_time_ratio; + double long_term_gc_time_ratio() const { + return _long_term_gc_time_ratio; } - double short_term_pause_time_ratio() const { - return _short_term_pause_time_ratio; + double short_term_gc_time_ratio() const { + return _short_term_gc_time_ratio; } static constexpr uint max_num_of_recorded_pause_times() { @@ -122,6 +130,20 @@ public: _prev_collection_pause_end_ms = ms; } + void set_gc_cpu_time_at_pause_end_ms(double ms) { + _gc_cpu_time_at_pause_end_ms = ms; + } + + double gc_cpu_time_at_pause_end_ms() const { + return _gc_cpu_time_at_pause_end_ms; + } + + void set_concurrent_gc_cpu_time_ms(double ms) { + _concurrent_gc_cpu_time_ms = ms; + } + + double gc_cpu_time_ms() const; + void report_concurrent_mark_remark_times_ms(double ms); void report_concurrent_mark_cleanup_times_ms(double ms); void report_alloc_rate_ms(double alloc_rate); @@ -173,8 +195,8 @@ public: size_t predict_pending_cards(bool for_young_only_phase) const; // Add a new GC of the given duration and end time to the record. - void update_recent_gc_times(double end_time_sec, double elapsed_ms); - void compute_pause_time_ratios(double end_time_sec, double pause_time_ms); + void update_recent_gc_times(double end_time_sec, double gc_time_ms); + void update_gc_time_ratios(double end_time_sec, double pause_time_ms); }; #endif // SHARE_GC_G1_G1ANALYTICS_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index 6f82d7cc284..03a1444f8e6 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -217,8 +217,8 @@ size_t G1HeapSizingPolicy::young_collection_resize_amount(bool& expand, size_t a assert(GCTimeRatio > 0, "must be"); expand = false; - const double long_term_gc_cpu_usage = _analytics->long_term_pause_time_ratio(); - const double short_term_gc_cpu_usage = _analytics->short_term_pause_time_ratio(); + const double long_term_gc_cpu_usage = _analytics->long_term_gc_time_ratio(); + const double short_term_gc_cpu_usage = _analytics->short_term_gc_time_ratio(); double gc_cpu_usage_target = 1.0 / (1.0 + GCTimeRatio); gc_cpu_usage_target = scale_with_heap(gc_cpu_usage_target); diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 53f0a7bf7a6..6141f1056fe 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -664,6 +664,12 @@ bool G1Policy::should_retain_evac_failed_region(uint index) const { void G1Policy::record_pause_start_time() { Ticks now = Ticks::now(); _cur_pause_start_sec = now.seconds(); + + double prev_gc_cpu_pause_end_ms = _analytics->gc_cpu_time_at_pause_end_ms(); + double cur_gc_cpu_time_ms = _analytics->gc_cpu_time_ms(); + + double concurrent_gc_cpu_time_ms = cur_gc_cpu_time_ms - prev_gc_cpu_pause_end_ms; + _analytics->set_concurrent_gc_cpu_time_ms(concurrent_gc_cpu_time_ms); } void G1Policy::record_young_collection_start() { @@ -1346,8 +1352,7 @@ void G1Policy::update_gc_pause_time_ratios(G1GCPauseType gc_type, double start_t double pause_time_sec = end_time_sec - start_time_sec; double pause_time_ms = pause_time_sec * 1000.0; - _analytics->compute_pause_time_ratios(end_time_sec, pause_time_ms); - _analytics->update_recent_gc_times(end_time_sec, pause_time_ms); + _analytics->update_gc_time_ratios(end_time_sec, pause_time_ms); if (gc_type == G1GCPauseType::Cleanup || gc_type == G1GCPauseType::Remark) { _analytics->append_prev_collection_pause_end_ms(pause_time_ms); @@ -1370,6 +1375,9 @@ void G1Policy::record_pause(G1GCPauseType gc_type, } update_time_to_mixed_tracking(gc_type, start, end); + + double elapsed_gc_cpu_time = _analytics->gc_cpu_time_ms(); + _analytics->set_gc_cpu_time_at_pause_end_ms(elapsed_gc_cpu_time); } void G1Policy::update_time_to_mixed_tracking(G1GCPauseType gc_type, diff --git a/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp b/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp index a4947774414..5a75051656c 100644 --- a/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1Analytics.cpp @@ -29,6 +29,6 @@ TEST_VM(G1Analytics, is_initialized) { G1Predictions p(0.888888); // the actual sigma value doesn't matter G1Analytics a(&p); - ASSERT_EQ(a.long_term_pause_time_ratio(), 0.0); - ASSERT_EQ(a.short_term_pause_time_ratio(), 0.0); + ASSERT_EQ(a.long_term_gc_time_ratio(), 0.0); + ASSERT_EQ(a.short_term_gc_time_ratio(), 0.0); } From 1d53ac30f1db88df9a97b63b3ff56d26975d3a57 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 27 Aug 2025 14:25:39 +0000 Subject: [PATCH 248/471] 8366028: MethodType::fromMethodDescriptorString should not throw UnsupportedOperationException for invalid descriptors Reviewed-by: jvernee --- .../sun/invoke/util/BytecodeDescriptor.java | 13 ++++++++--- test/jdk/java/lang/invoke/MethodTypeTest.java | 23 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java index 53fd6322758..76bbff2a610 100644 --- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java +++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -96,8 +96,15 @@ public class BytecodeDescriptor { } } else if (c == '[') { Class t = parseSig(str, i, end, loader); - if (t != null) - t = t.arrayType(); + if (t != null) { + try { + t = t.arrayType(); + } catch (UnsupportedOperationException ex) { + // Bad arrays, such as [V or more than 255 dims + // We have a more informative IAE + return null; + } + } return t; } else { return Wrapper.forBasicType(c).primitiveType(); diff --git a/test/jdk/java/lang/invoke/MethodTypeTest.java b/test/jdk/java/lang/invoke/MethodTypeTest.java index c2ae4e0e84f..70949236066 100644 --- a/test/jdk/java/lang/invoke/MethodTypeTest.java +++ b/test/jdk/java/lang/invoke/MethodTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -22,6 +22,7 @@ */ /* @test + * @bug 8366028 * @summary unit tests for java.lang.invoke.MethodType * @compile MethodTypeTest.java * @run testng/othervm test.java.lang.invoke.MethodTypeTest @@ -35,6 +36,8 @@ import java.lang.reflect.Method; import java.util.*; import org.testng.*; + +import static org.testng.Assert.assertThrows; import static org.testng.AssertJUnit.*; import org.testng.annotations.*; @@ -218,6 +221,24 @@ public class MethodTypeTest { return sb.toString().replace('.', '/'); } + @DataProvider(name = "badMethodDescriptorStrings") + public String[] badMethodDescriptorStrings() { + return new String[] { + "(I)", + "(V)V", + "([V)V", + "(" + "[".repeat(256) + "J)I", + "(java/lang/Object)V", + "()java/lang/Object", + }; + } + + // JDK-8366028 + @Test(dataProvider = "badMethodDescriptorStrings", expectedExceptions = IllegalArgumentException.class) + public void testFromMethodDescriptorStringNegatives(String desc) { + MethodType.fromMethodDescriptorString(desc, null); + } + @Test public void testHasPrimitives() { System.out.println("hasPrimitives"); From 79cea6dd174c22f99b4cafc835e6c843c1b4ec38 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 27 Aug 2025 14:37:39 +0000 Subject: [PATCH 249/471] 8365975: Sort share/memory includes Reviewed-by: shade, ayang, jwaters --- src/hotspot/share/memory/allocation.cpp | 1 - src/hotspot/share/memory/arena.cpp | 1 - src/hotspot/share/memory/classLoaderMetaspace.cpp | 2 +- src/hotspot/share/memory/heapInspection.hpp | 2 +- src/hotspot/share/memory/iterator.inline.hpp | 4 ++-- src/hotspot/share/memory/memRegion.cpp | 1 - src/hotspot/share/memory/metadataFactory.hpp | 1 + src/hotspot/share/memory/metaspace/blockTree.cpp | 2 +- src/hotspot/share/memory/metaspace/metablock.inline.hpp | 5 +++-- src/hotspot/share/memory/metaspace/virtualSpaceList.cpp | 2 +- src/hotspot/share/memory/metaspaceClosure.hpp | 1 + src/hotspot/share/memory/resourceArea.inline.hpp | 1 + test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 13 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 0d99c1bea68..a7c0045eac3 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/arena.hpp" #include "memory/metaspace.hpp" diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index d29861c69bb..db0bb8add21 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -24,7 +24,6 @@ */ #include "compiler/compilationMemoryStatistic.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/arena.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/memory/classLoaderMetaspace.cpp b/src/hotspot/share/memory/classLoaderMetaspace.cpp index efa6adc7a7b..c1ff172071d 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.cpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.cpp @@ -26,7 +26,6 @@ #include "logging/log.hpp" #include "memory/classLoaderMetaspace.hpp" #include "memory/metaspace.hpp" -#include "memory/metaspaceUtils.hpp" #include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/internalStats.hpp" #include "memory/metaspace/metablock.hpp" @@ -38,6 +37,7 @@ #include "memory/metaspace/metaspaceStatistics.hpp" #include "memory/metaspace/runningCounters.hpp" #include "memory/metaspaceTracer.hpp" +#include "memory/metaspaceUtils.hpp" #include "oops/klass.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index ca9a46c9140..58e91217a32 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -27,9 +27,9 @@ #include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" +#include "oops/annotations.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" -#include "oops/annotations.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index 7ed2b9b3faa..498c74fd1d2 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -32,12 +32,12 @@ #include "code/nmethod.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" -#include "oops/klass.hpp" +#include "oops/instanceClassLoaderKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" -#include "oops/instanceClassLoaderKlass.inline.hpp" #include "oops/instanceRefKlass.inline.hpp" #include "oops/instanceStackChunkKlass.inline.hpp" +#include "oops/klass.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/typeArrayKlass.inline.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/memory/memRegion.cpp b/src/hotspot/share/memory/memRegion.cpp index 4391e25aec3..3c481926025 100644 --- a/src/hotspot/share/memory/memRegion.cpp +++ b/src/hotspot/share/memory/memRegion.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/memRegion.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp index 355702f7980..f2542069f04 100644 --- a/src/hotspot/share/memory/metadataFactory.hpp +++ b/src/hotspot/share/memory/metadataFactory.hpp @@ -30,6 +30,7 @@ #include "oops/array.inline.hpp" #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" + #include class MetadataFactory : AllStatic { diff --git a/src/hotspot/share/memory/metaspace/blockTree.cpp b/src/hotspot/share/memory/metaspace/blockTree.cpp index 33237494b50..7ad24353c96 100644 --- a/src/hotspot/share/memory/metaspace/blockTree.cpp +++ b/src/hotspot/share/memory/metaspace/blockTree.cpp @@ -23,8 +23,8 @@ * */ -#include "memory/metaspace/chunklevel.hpp" #include "memory/metaspace/blockTree.hpp" +#include "memory/metaspace/chunklevel.hpp" #include "memory/resourceArea.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/memory/metaspace/metablock.inline.hpp b/src/hotspot/share/memory/metaspace/metablock.inline.hpp index 04eb6c22277..87dceceeb74 100644 --- a/src/hotspot/share/memory/metaspace/metablock.inline.hpp +++ b/src/hotspot/share/memory/metaspace/metablock.inline.hpp @@ -27,10 +27,11 @@ #define SHARE_MEMORY_METASPACE_METABLOCK_INLINE_HPP #include "memory/metaspace/metablock.hpp" -#include "utilities/globalDefinitions.hpp" + #include "utilities/align.hpp" -#include "utilities/ostream.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" class outputStream; diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp index 64a17fcbfa9..c4b112defb4 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp @@ -29,8 +29,8 @@ #include "memory/metaspace/commitLimiter.hpp" #include "memory/metaspace/counters.hpp" #include "memory/metaspace/freeChunkList.hpp" -#include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/metaspaceCommon.hpp" +#include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/virtualSpaceList.hpp" #include "memory/metaspace/virtualSpaceNode.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index c35363eb71f..beb7cdc6318 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -34,6 +34,7 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" + #include // The metadata hierarchy is separate from the oop hierarchy diff --git a/src/hotspot/share/memory/resourceArea.inline.hpp b/src/hotspot/share/memory/resourceArea.inline.hpp index d3e8364773a..cd8890c228d 100644 --- a/src/hotspot/share/memory/resourceArea.inline.hpp +++ b/src/hotspot/share/memory/resourceArea.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_MEMORY_RESOURCEAREA_INLINE_HPP #include "memory/resourceArea.hpp" + #include "nmt/memTracker.hpp" inline char* ResourceArea::allocate_bytes(size_t size, AllocFailType alloc_failmode) { diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 1a304a44944..74da9626bae 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -55,6 +55,7 @@ public class TestIncludesAreSorted { "share/jvmci", "share/libadt", "share/logging", + "share/memory", "share/metaprogramming", "share/oops", "share/opto", From b43c2c663567e59f8b5c84b1b45536078190605b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 27 Aug 2025 14:48:33 +0000 Subject: [PATCH 250/471] 8366225: Linux Alpine (fast)debug build fails after JDK-8365909 Reviewed-by: mbaesken, thartmann --- src/hotspot/os/linux/compilerThreadTimeout_linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp index 7ee741ff011..c19b3e64825 100644 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp @@ -94,7 +94,7 @@ bool CompilerThreadTimeoutLinux::init_timeout() { JavaThread* thread = JavaThread::current(); // Create a POSIX timer sending SIGALRM to this thread only. - sigevent_t sev; + struct sigevent sev; sev.sigev_value.sival_ptr = nullptr; sev.sigev_signo = TIMEOUT_SIGNAL; sev.sigev_notify = SIGEV_THREAD_ID; From f1c0b4ed722bf4cc5f262e804cec26d59ceb6e8b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 27 Aug 2025 15:30:01 +0000 Subject: [PATCH 251/471] 8361495: (fc) Async close of streams connected to uninterruptible FileChannel doesn't throw AsynchronousCloseException in all cases Reviewed-by: alanb --- .../classes/sun/nio/ch/FileChannelImpl.java | 6 +- .../channels/Channels/AsyncCloseStreams.java | 158 ++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 7f37ad36452..a1ddcad94f5 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -178,7 +178,11 @@ public class FileChannelImpl } private void endBlocking(boolean completed) throws AsynchronousCloseException { - if (!uninterruptible) end(completed); + if (!uninterruptible) { + end(completed); + } else if (!completed && !isOpen()) { + throw new AsynchronousCloseException(); + } } // -- Standard channel operations -- diff --git a/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java b/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java new file mode 100644 index 00000000000..053cae0df7e --- /dev/null +++ b/test/jdk/java/nio/channels/Channels/AsyncCloseStreams.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8361495 + * @summary Test for AsynchronousCloseException from uninterruptible FileChannel + * @run junit AsyncCloseStreams + */ + +import java.io.Closeable; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.ClosedChannelException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.concurrent.LinkedTransferQueue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.fail; + +public class AsyncCloseStreams { + private static final Closeable STOP = () -> { }; + + private static Thread startCloseThread(LinkedTransferQueue q) { + return Thread.ofPlatform().start(() -> { + try { + Closeable c; + while((c = q.take()) != STOP) { + try { + c.close(); + } catch (IOException ignored) { + } + } + } catch (InterruptedException ignored) { + } + }); + } + + @Test + public void available() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + + do { + InputStream in = Files.newInputStream(path); + close.offer(in); + int available = 0; + try { + available = in.available(); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + continue; + } catch (Throwable t) { + fail("Unexpected error", t); + } + if (available < 0) { + fail("FAILED: available < 0"); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } + + @Test + public void read() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + byte[] bytes = new byte[100_000]; + Arrays.fill(bytes, (byte)27); + Files.write(path, bytes); + + do { + InputStream in = Files.newInputStream(path); + close.offer(in); + int value = 0; + try { + value = in.read(); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + continue; + } catch (Throwable t) { + fail("Unexpected error", t); + } + if (value < 0) { + fail("FAILED: value < 0"); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } + + @Test + public void write() throws InterruptedException, IOException { + var close = new LinkedTransferQueue(); + Thread closeThread = startCloseThread(close); + + try { + Path path = Files.createTempFile(Path.of("."), "foo", "bar"); + path.toFile().deleteOnExit(); + + do { + OutputStream out = Files.newOutputStream(path); + close.offer(out); + try { + out.write(27); + } catch (AsynchronousCloseException ace) { + System.err.println("AsynchronousCloseException caught"); + break; + } catch (ClosedChannelException ignored) { + } catch (Throwable t) { + fail("Write error", t); + } + } while (true); + } finally { + close.offer(STOP); + closeThread.join(); + } + } +} From bd4c0f4a7da9122527dd25df74797c42deaced3c Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 27 Aug 2025 15:30:17 +0000 Subject: [PATCH 252/471] 8358618: UnsupportedOperationException constructors javadoc is not clear Reviewed-by: liach, aivanov, rriggs --- .../lang/UnsupportedOperationException.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/lang/UnsupportedOperationException.java b/src/java.base/share/classes/java/lang/UnsupportedOperationException.java index 8fd0ede6252..6e42dc43009 100644 --- a/src/java.base/share/classes/java/lang/UnsupportedOperationException.java +++ b/src/java.base/share/classes/java/lang/UnsupportedOperationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -37,14 +37,17 @@ package java.lang; */ public class UnsupportedOperationException extends RuntimeException { /** - * Constructs an UnsupportedOperationException with no detail message. + * Constructs a new {@code UnsupportedOperationException} with {@code null} + * as its detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause(Throwable)}. */ public UnsupportedOperationException() { } /** - * Constructs an UnsupportedOperationException with the specified - * detail message. + * Constructs a new {@code UnsupportedOperationException} with the specified + * detail message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause(Throwable)}. * * @param message the detail message */ @@ -53,8 +56,8 @@ public class UnsupportedOperationException extends RuntimeException { } /** - * Constructs a new exception with the specified detail message and - * cause. + * Constructs a new {@code UnsupportedOperationException} with the specified + * detail message and cause. * *

      Note that the detail message associated with {@code cause} is * not automatically incorporated in this exception's detail @@ -73,8 +76,9 @@ public class UnsupportedOperationException extends RuntimeException { } /** - * Constructs a new exception with the specified cause and a detail - * message of {@code (cause==null ? null : cause.toString())} (which + * Constructs a new {@code UnsupportedOperationException} with the specified + * cause and a detail message of + * {@code (cause==null ? null : cause.toString())} (which * typically contains the class and detail message of {@code cause}). * This constructor is useful for exceptions that are little more than * wrappers for other throwables (for example, {@link From 075ddef831f059cad1639bb6834a0923e725e15f Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 27 Aug 2025 17:49:17 +0000 Subject: [PATCH 253/471] 8364039: Adding implNote to DOMSignContext and DOMValidateContext on JDK-specific properties Reviewed-by: mullan --- .../xml/crypto/dsig/dom/DOMSignContext.java | 6 ++- .../crypto/dsig/dom/DOMValidateContext.java | 38 ++++++++++++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java index 46748166060..566217cbaed 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java @@ -33,6 +33,7 @@ import javax.xml.crypto.dsig.XMLSignContext; import javax.xml.crypto.dsig.XMLSignature; import java.security.Key; import java.security.PrivateKey; +import java.security.Provider; import java.security.SecureRandom; import java.security.Signature; @@ -51,9 +52,12 @@ import org.w3c.dom.Node; * instance to sign two different {@link XMLSignature} objects). * * @implNote - * The JDK implementation supports the following property that can be set + * The JDK implementation supports the following properties that can be set * using the {@link #setProperty setProperty} method. *

        + *
      • org.jcp.xml.dsig.internal.dom.SignatureProvider: value + * must be a {@link Provider}. If specified, the underlying {@code Signature} + * will be instantiated from this provider. *
      • jdk.xmldsig.SecureRandom: value must be a * {@link SecureRandom}. If specified, this object will be * used to initialize the underlying {@code Signature} during signing diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java index 8e63305d177..82e7f0ce24e 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMValidateContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -33,6 +33,8 @@ import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLValidateContext; import java.security.Key; +import java.security.Provider; + import org.w3c.dom.Node; /** @@ -52,18 +54,28 @@ import org.w3c.dom.Node; * instance to validate two different {@link XMLSignature} objects). * * @implNote - * By default, the JDK implementation enables a secure validation mode by - * setting the org.jcp.xml.dsig.secureValidation property to - * Boolean.TRUE (see the {@link #setProperty setProperty} - * method). When enabled, validation of XML signatures are subject to - * stricter checking of algorithms and other constraints as specified by the - * jdk.xml.dsig.secureValidationPolicy security property. - * The mode can be disabled by setting the property to {@code Boolean.FALSE}. - * The mode can also be enabled or disabled by setting the - * {@systemProperty org.jcp.xml.dsig.secureValidation} system property to - * "true" or "false". Any other value for the system property is also treated - * as "false". If the system property is set, it supersedes the - * {@code DOMValidateContext} property value. + * The JDK implementation supports the following properties that can be set + * using the {@link #setProperty setProperty} method. + *
          + *
        • org.jcp.xml.dsig.secureValidation: value must be a + * {@link Boolean}. When enabled, validation of XML signatures are subject + * to stricter checking of algorithms and other constraints as specified by the + * jdk.xml.dsig.secureValidationPolicy security property. + * The default value if not specified is Boolean.TRUE. + * The mode can be disabled by setting the property to {@code Boolean.FALSE}. + * The mode can also be enabled or disabled by setting the + * {@systemProperty org.jcp.xml.dsig.secureValidation} system property to + * "true" or "false". Any other value for the system property is also treated + * as "false". If the system property is set, it supersedes the + * {@code DOMValidateContext} property value. + *
        • org.jcp.xml.dsig.validateManifests: value + * must be a {@link Boolean}. If enabled, the references in manifest + * elements (if exist) are validated during signature validation. + * The default value if not specified is Boolean.FALSE. + *
        • org.jcp.xml.dsig.internal.dom.SignatureProvider: value + * must be a {@link Provider}. If specified, the underlying {@code Signature} + * will be instantiated from this provider. + *
        * * @author Sean Mullan * @author JSR 105 Expert Group From 501e6aed4407d63b000320168dc5d0553ce8a23b Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Thu, 28 Aug 2025 05:02:25 +0000 Subject: [PATCH 254/471] 8366223: ZGC: ZPageAllocator::cleanup_failed_commit_multi_partition is broken Reviewed-by: stefank, jsikstro --- src/hotspot/share/gc/z/zPageAllocator.cpp | 2 +- .../share/gc/z/zPhysicalMemoryManager.cpp | 13 ++- src/hotspot/share/gc/z/z_globals.hpp | 5 + .../hotspot/jtreg/gc/z/TestCommitFailure.java | 104 ++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/gc/z/TestCommitFailure.java diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index ba0ab923e11..d8f653cc7d0 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1941,7 +1941,7 @@ void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAlloca } const size_t committed = allocation->committed_capacity(); - const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); + const ZVirtualMemory non_harvested_vmem = partial_vmem.last_part(allocation->harvested()); const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); diff --git a/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp index 2c2f9988d4b..54477d19a27 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp +++ b/src/hotspot/share/gc/z/zPhysicalMemoryManager.cpp @@ -214,9 +214,20 @@ void ZPhysicalMemoryManager::free(const ZVirtualMemory& vmem, uint32_t numa_id) }); } +static size_t inject_commit_limit(const ZVirtualMemory& vmem) { + // To facilitate easier interoperability with multi partition allocations we + // divide by ZNUMA::count(). Users of ZFailLargerCommits need to be aware of + // this when writing tests. In the future we could probe the VirtualMemoryManager + // and condition this division on whether the vmem is in the multi partition + // address space. + return align_up(MIN2(ZFailLargerCommits / ZNUMA::count(), vmem.size()), ZGranuleSize); +} + size_t ZPhysicalMemoryManager::commit(const ZVirtualMemory& vmem, uint32_t numa_id) { zbacking_index* const pmem = _physical_mappings.addr(vmem.start()); - const size_t size = vmem.size(); + const size_t size = ZFailLargerCommits > 0 + ? inject_commit_limit(vmem) + : vmem.size(); size_t total_committed = 0; diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index d818cf9fc3f..b1a4ae4c898 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -118,6 +118,11 @@ develop(bool, ZVerifyOops, false, \ "Verify accessed oops") \ \ + develop(size_t, ZFailLargerCommits, 0, \ + "Commits larger than ZFailLargerCommits will be truncated, " \ + "used to stress page allocation commit failure paths " \ + "(0: Disabled)") \ + \ develop(uint, ZFakeNUMA, 1, \ "ZFakeNUMA is used to test the internal NUMA memory support " \ "without the need for UseNUMA") \ diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java new file mode 100644 index 00000000000..c1babe7eb83 --- /dev/null +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc.z; + +/* + * @test id=ZFakeNUMA + * @requires vm.gc.Z & vm.debug + * @library / /test/lib + * @summary Test ZGC graceful failure when a commit fails (with ZFakeNUMA) + * @run driver gc.z.TestCommitFailure -XX:ZFakeNUMA=16 + */ + +import jdk.test.lib.process.ProcessTools; + +import static gc.testlibrary.Allocation.blackHole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class TestCommitFailure { + static final int K = 1024; + static final int M = 1024 * K; + + static final int XMS = 128 * M; + static final int XMX = 512 * M; + + static class Test { + static final int LARGE_ALLOC = 256 * M; + static final int SMALL_GARBAGE = 256 * M; + static final int SMALL_LIVE = 128 * M; + + // Allocates at least totalLive bytes of objects and add them to list. + static void allocLive(List list, int totalLive) { + final int largePageAllocationSize = 6 * M; + for (int live = 0; live < totalLive; live += largePageAllocationSize) { + list.add(new byte[largePageAllocationSize - K]); + } + } + + // Allocates at least totalGarbage bytes of garbage large pages. + static void allocGarbage(int totalGarbage) { + final int largePageAllocationSize = 6 * M; + for (int garbage = 0; garbage < totalGarbage; garbage += largePageAllocationSize) { + blackHole(new byte[largePageAllocationSize - K]); + } + } + + public static void main(String[] args) { + final var list = new ArrayList(); + try { + // Fill heap with small live objects + allocLive(list, SMALL_LIVE); + // Fill with small garbage objects + allocGarbage(SMALL_GARBAGE); + // Allocate large objects where commit fails until an OOME is thrown + while (true) { + list.add(new byte[LARGE_ALLOC - K]); + } + } catch (OutOfMemoryError oome) {} + blackHole(list); + } + } + + public static void main(String[] args) throws Exception { + final int xmxInM = XMX / M; + final int xmsInM = XMS / M; + final var arguments = new ArrayList(Arrays.asList(args)); + arguments.addAll(List.of( + "-XX:+UseZGC", + "-Xlog:gc+init", + "-XX:ZFailLargerCommits=" + XMS, + "-Xms" + xmsInM + "M", + "-Xmx" + xmxInM + "M", + Test.class.getName())); + + ProcessTools.executeTestJava(arguments) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("Forced to lower max Java heap size") + .shouldHaveExitValue(0); + } +} From 443b17263876355ef508ae68ddad6c108de29db8 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 28 Aug 2025 05:53:23 +0000 Subject: [PATCH 255/471] 8324751: C2 SuperWord: Aliasing Analysis runtime check Reviewed-by: kvn, mhaessig --- .../share/compiler/compilerDefinitions.cpp | 5 + src/hotspot/share/opto/c2_globals.hpp | 9 + src/hotspot/share/opto/graphKit.cpp | 4 +- src/hotspot/share/opto/loopUnswitch.cpp | 2 + src/hotspot/share/opto/loopnode.cpp | 16 +- src/hotspot/share/opto/mempointer.cpp | 189 ++- src/hotspot/share/opto/mempointer.hpp | 420 +++++- src/hotspot/share/opto/predicates.hpp | 53 +- src/hotspot/share/opto/superword.cpp | 20 +- src/hotspot/share/opto/superword.hpp | 2 + .../share/opto/superwordVTransformBuilder.cpp | 15 +- .../share/opto/traceAutoVectorizationTag.hpp | 1 + src/hotspot/share/opto/vectorization.cpp | 790 +++++++++- src/hotspot/share/opto/vectorization.hpp | 122 +- src/hotspot/share/opto/vtransform.cpp | 242 +++- src/hotspot/share/opto/vtransform.hpp | 115 +- .../TestVectorizationMismatchedAccess.java | 88 +- .../loopopts/superword/TestAliasing.java | 516 +++++++ .../superword/TestAliasingFuzzer.java | 1284 +++++++++++++++++ .../superword/TestCyclicDependency.java | 172 ++- .../superword/TestDependencyOffsets.java | 4 +- .../loopopts/superword/TestMemorySegment.java | 71 +- .../superword/TestMemorySegmentAliasing.java | 914 ++++++++++++ .../superword/TestMemorySegment_8359688.java | 98 ++ .../superword/TestMemorySegment_8360204.java | 90 ++ .../superword/TestMemorySegment_8365982.java | 98 ++ .../loopopts/superword/TestSplitPacks.java | 310 +++- .../runner/LoopArrayIndexComputeTest.java | 105 +- .../bench/vm/compiler/VectorAliasing.java | 308 ++++ 29 files changed, 5812 insertions(+), 251 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index fa894559fef..35201973dfe 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -621,5 +621,10 @@ void CompilerConfig::ergo_initialize() { // blind guess LoopStripMiningIterShortLoop = LoopStripMiningIter / 10; } + if (UseAutoVectorizationSpeculativeAliasingChecks && !LoopMultiversioning && !UseAutoVectorizationPredicate) { + warning("Disabling UseAutoVectorizationSpeculativeAliasingChecks, because neither of the following is enabled:" + " LoopMultiversioning UseAutoVectorizationPredicate"); + UseAutoVectorizationSpeculativeAliasingChecks = false; + } #endif // COMPILER2 } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 3a2d4cbdf96..0a4f231c49b 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -359,6 +359,15 @@ develop(bool, TraceLoopMultiversioning, false, \ "Trace loop multiversioning") \ \ + product(bool, UseAutoVectorizationPredicate, true, DIAGNOSTIC, \ + "Use AutoVectorization predicate (for speculative compilation)") \ + \ + product(bool, UseAutoVectorizationSpeculativeAliasingChecks, true, DIAGNOSTIC, \ + "Allow the use Multiversioning or Predicate to add aliasing" \ + "runtime checks. Runtime checks will only be inserted if either" \ + "LoopMultiversioning or UseAutoVectorizationPredicate are" \ + "enabled.") \ + \ product(bool, AllowVectorizeOnDemand, true, \ "Globally suppress vectorization set in VectorizeMethod") \ \ diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index d65239ab0f8..d4776d9d2f0 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4076,7 +4076,9 @@ void GraphKit::add_parse_predicates(int nargs) { add_parse_predicate(Deoptimization::Reason_profile_predicate, nargs); } } - add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, nargs); + if (UseAutoVectorizationPredicate) { + add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, nargs); + } // Loop Limit Check Predicate should be near the loop. add_parse_predicate(Deoptimization::Reason_loop_limit_check, nargs); } diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index a8d9a5d740b..b40a0492df5 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -481,6 +481,8 @@ void PhaseIdealLoop::do_multiversioning(IdealLoopTree* lpt, Node_List& old_new) // | // slow_path // +// For more descriptions on multiversioning: +// See: PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks IfTrueNode* PhaseIdealLoop::create_new_if_for_multiversion(IfTrueNode* multiversioning_fast_proj) { // Give all nodes in the old sub-graph a name. IfNode* multiversion_if = multiversioning_fast_proj->in(0)->as_If(); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 2c604e6d478..da2252f3d53 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -31,6 +31,7 @@ #include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/arraycopynode.hpp" +#include "opto/c2_globals.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" #include "opto/connode.hpp" @@ -1133,11 +1134,13 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { } } - // We only want to use the auto-vectorization check as a trap once per bci. And - // PhaseIdealLoop::add_parse_predicate only checks trap limits per method, so - // we do a custom check here. - if (!C->too_many_traps(cloned_sfpt->jvms()->method(), cloned_sfpt->jvms()->bci(), Deoptimization::Reason_auto_vectorization_check)) { - add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); + if (UseAutoVectorizationPredicate) { + // We only want to use the auto-vectorization check as a trap once per bci. And + // PhaseIdealLoop::add_parse_predicate only checks trap limits per method, so + // we do a custom check here. + if (!C->too_many_traps(cloned_sfpt->jvms()->method(), cloned_sfpt->jvms()->bci(), Deoptimization::Reason_auto_vectorization_check)) { + add_parse_predicate(Deoptimization::Reason_auto_vectorization_check, inner_head, outer_ilt, cloned_sfpt); + } } add_parse_predicate(Deoptimization::Reason_loop_limit_check, inner_head, outer_ilt, cloned_sfpt); @@ -4642,6 +4645,9 @@ void IdealLoopTree::dump_head() { tty->print(" predicated"); } } + if (UseAutoVectorizationPredicate && predicates.auto_vectorization_check_block()->is_non_empty()) { + tty->print(" auto_vectorization_check_predicate"); + } if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); diff --git a/src/hotspot/share/opto/mempointer.cpp b/src/hotspot/share/opto/mempointer.cpp index 0dadc14a686..a63ba8ef701 100644 --- a/src/hotspot/share/opto/mempointer.cpp +++ b/src/hotspot/share/opto/mempointer.cpp @@ -41,13 +41,22 @@ MemPointer::MemPointer(const MemNode* mem, MemPointer MemPointerParser::parse(MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)) { assert(_worklist.is_empty(), "no prior parsing"); + assert(_raw_summands.is_empty(), "no prior parsing"); assert(_summands.is_empty(), "no prior parsing"); Node* pointer = _mem->in(MemNode::Address); const jint size = _mem->memory_size(); +#ifndef PRODUCT + if (trace.is_trace_parsing()) { + tty->print_cr("MemPointerParser::parse: size=%d", size); + tty->print(" mem: "); _mem->dump(); + tty->print(" pointer: "); pointer->dump(); + } +#endif + // Start with the trivial summand. - _worklist.push(MemPointerSummand(pointer, NoOverflowInt(1))); + _worklist.push(MemPointerRawSummand::make_trivial(pointer)); // Decompose the summands until only terminal summands remain. This effectively // parses the pointer expression recursively. @@ -60,11 +69,71 @@ MemPointer MemPointerParser::parse(MemPointerParserCallback& callback parse_sub_expression(_worklist.pop(), callback); } - // Bail out if there is a constant overflow. - if (_con.is_NaN()) { - return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); - } + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerRawSummand::print_on(tty, _raw_summands); } ) + canonicalize_raw_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerRawSummand::print_on(tty, _raw_summands); } ) + create_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerSummand::print_on(tty, _con, _summands); } ) + canonicalize_summands(); + NOT_PRODUCT( if (trace.is_trace_parsing()) { MemPointerSummand::print_on(tty, _con, _summands); } ) + + return MemPointer::make(pointer, _raw_summands, _con, _summands, size NOT_PRODUCT(COMMA trace)); +} + +void MemPointerParser::canonicalize_raw_summands() { + // We sort by: + // - int group id + // - variable idx + // This means that summands of the same int group with the same variable are consecutive. + // This simplifies the combining of summands below. + _raw_summands.sort(MemPointerRawSummand::cmp_by_int_group_and_variable_idx); + + // Combine summands of the same int group with the same variable, adding up the scales. + int pos_put = 0; + int pos_get = 0; + while (pos_get < _raw_summands.length()) { + const MemPointerRawSummand& summand = _raw_summands.at(pos_get++); + Node* variable = summand.variable(); + NoOverflowInt scaleI = summand.scaleI(); + NoOverflowInt scaleL = summand.scaleL(); + int int_group = summand.int_group(); + // Add up scale of all summands with the same variable. + while (pos_get < _raw_summands.length() && + _raw_summands.at(pos_get).int_group() == int_group && + _raw_summands.at(pos_get).variable() == variable) { + MemPointerRawSummand s = _raw_summands.at(pos_get++); + if (int_group == 0) { + assert(scaleI.is_one() && s.scaleI().is_one(), "no ConvI2L"); + scaleL = scaleL + s.scaleL(); + } else { + assert(scaleL.value() == s.scaleL().value(), "same ConvI2L, same scaleL"); + scaleI = scaleI + s.scaleI(); + } + } + // Keep summands with non-zero scale. + if (!scaleI.is_zero() && !scaleL.is_NaN()) { + _raw_summands.at_put(pos_put++, MemPointerRawSummand(variable, scaleI, scaleL, int_group)); + } + } + _raw_summands.trunc_to(pos_put); +} + +void MemPointerParser::create_summands() { + assert(_con.is_zero(), "no prior parsing"); + assert(_summands.is_empty(), "no prior parsing"); + + for (int i = 0; i < _raw_summands.length(); i++) { + const MemPointerRawSummand& raw_summand = _raw_summands.at(i); + if (raw_summand.is_con()) { + _con = _con + raw_summand.to_con(); + } else { + _summands.push(raw_summand.to_summand()); + } + } +} + +void MemPointerParser::canonicalize_summands() { // Sorting by variable idx means that all summands with the same variable are consecutive. // This simplifies the combining of summands with the same variable below. _summands.sort(MemPointerSummand::cmp_by_variable_idx); @@ -81,38 +150,36 @@ MemPointer MemPointerParser::parse(MemPointerParserCallback& callback MemPointerSummand s = _summands.at(pos_get++); scale = scale + s.scale(); } - // Bail out if scale is NaN. - if (scale.is_NaN()) { - return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); - } // Keep summands with non-zero scale. if (!scale.is_zero()) { _summands.at_put(pos_put++, MemPointerSummand(variable, scale)); } } _summands.trunc_to(pos_put); - - return MemPointer::make(pointer, _summands, _con, size NOT_PRODUCT(COMMA trace)); } // Parse a sub-expression of the pointer, starting at the current summand. We parse the // current node, and see if it can be decomposed into further summands, or if the current // summand is terminal. -void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, MemPointerParserCallback& callback) { +void MemPointerParser::parse_sub_expression(const MemPointerRawSummand& summand, MemPointerParserCallback& callback) { Node* n = summand.variable(); - const NoOverflowInt scale = summand.scale(); + const NoOverflowInt scaleI = summand.scaleI(); + const NoOverflowInt scaleL = summand.scaleL(); + const int int_group = summand.int_group(); const NoOverflowInt one(1); int opc = n->Opcode(); - if (is_safe_to_decompose_op(opc, scale)) { + if (is_safe_to_decompose_op(opc, scaleI * scaleL)) { switch (opc) { case Op_ConI: case Op_ConL: { - // Terminal: add to constant. + // Terminal summand. NoOverflowInt con = (opc == Op_ConI) ? NoOverflowInt(n->get_int()) : NoOverflowInt(n->get_long()); - _con = _con + scale * con; + NoOverflowInt conI = (int_group == 0) ? scaleI : scaleI * con; + NoOverflowInt conL = (int_group == 0) ? scaleL * con : scaleL; + _raw_summands.push(MemPointerRawSummand::make_con(conI, conL, int_group)); return; } case Op_AddP: @@ -122,8 +189,8 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me // Decompose addition. Node* a = n->in((opc == Op_AddP) ? 2 : 1); Node* b = n->in((opc == Op_AddP) ? 3 : 2); - _worklist.push(MemPointerSummand(a, scale)); - _worklist.push(MemPointerSummand(b, scale)); + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, int_group)); + _worklist.push(MemPointerRawSummand(b, scaleI, scaleL, int_group)); callback.callback(n); return; } @@ -134,10 +201,15 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me Node* a = n->in(1); Node* b = n->in(2); - NoOverflowInt sub_scale = NoOverflowInt(-1) * scale; + // int_group x.scaleI x.scaleL y.scaleI y.scaleL + // 2L * (x - y) 0 1 2 1 -2 + // ConvI2L(x - y) 1 1 1 -1 1 - _worklist.push(MemPointerSummand(a, scale)); - _worklist.push(MemPointerSummand(b, sub_scale)); + NoOverflowInt sub_scaleI = (int_group == 0) ? scaleI : scaleI * NoOverflowInt(-1); + NoOverflowInt sub_scaleL = (int_group == 0) ? scaleL * NoOverflowInt(-1) : scaleL; + + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, int_group)); + _worklist.push(MemPointerRawSummand(b, sub_scaleI, sub_scaleL, int_group)); callback.callback(n); return; } @@ -169,10 +241,14 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me break; } - // Accumulate scale. - NoOverflowInt new_scale = scale * factor; + // int_group x.scaleI x.scaleL + // 2L * (4L * x) 0 1 8 + // 2L * ConvI2L(4 * x) 1 4 2 - _worklist.push(MemPointerSummand(variable, new_scale)); + NoOverflowInt mul_scaleI = (int_group == 0) ? scaleI : scaleI * factor; + NoOverflowInt mul_scaleL = (int_group == 0) ? scaleL * factor : scaleL; + + _worklist.push(MemPointerRawSummand(variable, mul_scaleI, mul_scaleL, int_group)); callback.callback(n); return; } @@ -200,7 +276,16 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me { // Decompose: look through. Node* a = n->in(1); - _worklist.push(MemPointerSummand(a, scale)); + + int cast_int_group = int_group; +#ifdef _LP64 + if (opc == Op_ConvI2L) { + assert(int_group == 0, "only find ConvI2L once"); + // We just discovered a new ConvI2L, and this creates a new "int group". + cast_int_group = _next_int_group++; + } +#endif + _worklist.push(MemPointerRawSummand(a, scaleI, scaleL, cast_int_group)); callback.callback(n); return; } @@ -212,7 +297,7 @@ void MemPointerParser::parse_sub_expression(const MemPointerSummand& summand, Me } // Default: we could not parse the "summand" further, i.e. it is terminal. - _summands.push(summand); + _raw_summands.push(summand); } bool MemPointerParser::sub_expression_has_native_base_candidate(Node* start) { @@ -618,3 +703,55 @@ bool MemPointer::never_overlaps_with(const MemPointer& other) const { return is_never_overlap; } +// Examples: +// p1 = MemPointer[size=1, base + i + 16] +// p2 = MemPointer[size=1, base + i + 17] +// -> Always at distance 1 +// -> Can never overlap -> return false +// +// p1 = MemPointer[size=1, base + i + 16] +// p2 = MemPointer[size=1, base + i + 16] +// -> Always at distance 0 +// -> Always have exact overlap -> return true +// +// p1 = MemPointer[size=4, x + y + z + 4L * i + 16] +// p2 = MemPointer[size=4, x + y + z + 4L * i + 56] +// -> Always at distance 40 +// -> Can never overlap -> return false +// +// p1 = MemPointer[size=8, x + y + z + 4L * i + 16] +// p2 = MemPointer[size=8, x + y + z + 4L * i + 20] +// -> Always at distance 4 +// -> Always have partial overlap -> return true +// +// p1 = MemPointer[size=4, base1 + 4L * i1 + 16] +// p2 = MemPointer[size=4, base2 + 4L * i2 + 20] +// -> Have differing summands, distance is unknown +// -> Unknown if overlap at runtime -> return false +bool MemPointer::always_overlaps_with(const MemPointer& other) const { + const MemPointerAliasing aliasing = get_aliasing_with(other NOT_PRODUCT( COMMA _trace )); + + // The aliasing tries to compute: + // distance = other - this + // + // We know that we have an overlap if we can prove: + // this < other + other.size && this + this.size > other + // + // Which we can restate as: + // distance > -other.size && this.size > distance + // + const jint distance_lo = -other.size(); + const jint distance_hi = size(); + bool is_always_overlap = aliasing.is_always_in_distance_range(distance_lo, distance_hi); + +#ifndef PRODUCT + if (_trace.is_trace_overlap()) { + tty->print("Always Overlap: %s, distance_lo: %d, distance_hi: %d, aliasing: ", + is_always_overlap ? "true" : "false", distance_lo, distance_hi); + aliasing.print_on(tty); + tty->cr(); + } +#endif + + return is_always_overlap; +} diff --git a/src/hotspot/share/opto/mempointer.hpp b/src/hotspot/share/opto/mempointer.hpp index 90216a5e2d3..5fe9d78a61e 100644 --- a/src/hotspot/share/opto/mempointer.hpp +++ b/src/hotspot/share/opto/mempointer.hpp @@ -41,6 +41,10 @@ // - alignment -> find an alignment solution for all memops in a vectorized loop // - detect partial overlap -> indicates store-to-load-forwarding failures // +// A more advanced use case of MemPointers is speculative aliasing analysis. If we can prove that +// the MemPointer has a linear form in the loop induction variable (iv), we can formulate runtime +// checks to establish that two MemPointer never overlap for all iterations, i.e. for all iv values. +// // ----------------------------------------------------------------------------------------- // // Intuition and Examples: @@ -158,7 +162,7 @@ // // pointer = SUM(summands) + con // -// Where each summand_i in summands has the form: +// Where each summand_i in summands has the MemPointerSummand form: // // summand_i = scale_i * variable_i // @@ -267,6 +271,10 @@ // the idea of a "safe decomposition", and then prove that all the decompositions we apply // are such "safe decompositions". // +// Even further down, we prove the "MemPointer Linearity Corrolary", where we show that +// (under reasonable restrictions) both the MemPointer and the corresponding pointer +// can be considered linear functions. +// // // Definition: Safe decomposition // Trivial decomposition: @@ -385,7 +393,103 @@ // // This shows that p1 and p2 have a distance greater than the array size, and hence at least one of the two // pointers must be out of bounds. This contradicts our assumption (S1) and we are done. - +// +// +// Having proven the "MemPointer Lemma", we can now derive an interesting corrolary. +// +// With the "Linearity Corrolary" below, we can prove that some MemPointers can be treated as +// linear in some summand variable v over some range r. This is useful when MemPointers are +// used in loops, where v=iv scale_v=scale_iv and the range is the iv range from some initial +// iv value to the last iv value just before the limit. +// For an application, see: VPointer::make_speculative_aliasing_check_with +// +// MemPointer Linearity Corrolary: +// Given: +// (C0) pointer p and its MemPointer mp, which is constructed with safe decompositions. +// (C1) a specific summand "scale_v * v" that occurs in mp. +// (C2) a strided range r = [lo, lo + stride_v, .. hi] for v (lo and hi are inclusive in the range). +// (C3) for all v in this strided range r we know that p is within bounds of its memory object. +// (C4) abs(scale_v * stride_v) < 2^31 +// Required for (S2) in application of MemPointer Lemma below, it is essencial in +// establishing linearity of mp. +// +// Then: +// Both p and mp have a linear form for v in r: +// p(v) = p(lo) - lo * scale_v + v * scale_v (Corrolary P) +// mp(v) = mp(lo) - lo * scale_v + v * scale_v (Corrolary MP) +// +// Note: the calculations are done in long, and hence there can be no int overflow. +// Thus, p(v) and mp(v) can be considered linear functions for v in r. +// +// It can be useful to "anchor" at hi instead of lo: +// p(hi) = p(lo) - lo * scale_v + hi * scale_v +// +// p(v) = p(lo) - lo * scale_v + v * scale_v +// -------------------- +// = p(hi) - hi * scale_v + v * scale_v (Alternative Corrolary P) +// +// +// Proof of "MemPointer Linearity Corrolary": +// We state the form of mp: +// +// mp = summand_rest + scale_v * v + con +// +// We prove the Corrolary by induction over v: +// Base Case: v = lo +// p(lo) = p(lo) - lo * scale_v + lo * scale_v +// mp(lo) = mp(lo) - lo * scale_v + lo * scale_v +// +// Step Case: v0 and v1 in r, v1 = v0 + stride_v +// Assume: +// p(v0) = p(lo) - lo * scale_v + v * scale_v (Induction Hypothesis IH-P) +// mp(v0) = mp(lo) - lo * scale_v + v * scale_v (Induction Hypothesis IH-MP) +// +// We take the form of mp, and further apply SAFE1 decompositions, i.e. long addition, +// subtraction and multiplication: +// mp(v1) = summand_rest + scale_v * v1 + con +// = summand_rest + scale_v * (v0 + stride_v) + con +// = summand_rest + scale_v * v0 + scale_v * stride_v + con +// = mp(v0) + scale_v * stride_v +// +// From this it follows that we can see mp(v0) and mp(v1) as two MemPointer with the +// same summands, and only their constants differ by exactly "scale_v * stride_v": +// mp(v0) = summand_rest + scale_v * v0 + con +// mp(v1) = summand_rest + scale_v * v0 + con + scale_v * stride_v (MP-DIFF) +// +// We continue by applying the Induction Hypothesis IH-MP +// mp(v1) = mp(v0) + scale_v * stride_v +// -------- apply (IH-MP) ------------- +// = mp(lo) - lo * scale_v + v0 * scale_v + scale_v * stride_v +// = mp(lo) - lo * scale_v + (v0 + stride_v) * scale_v +// = mp(lo) - lo * scale_v + v1 * scale_v +// +// This proves the Corrolary MP. +// +// To prove the Corrolary P, we now apply the MemPointer Lemma: +// (S0) Let p(v0) and p(v1) be the pointers corresponding to v0 and v1, and mp(v0) and mp(v1) +// their MemPointer. (C0) provides the safe deconstruction, and reformulation of terms +// happens with long addition, subtraction and multiplication only, and is hence SAFE +// as well. +// (S1) According to (C3), p is in bounds of its memory object for all v in r. Since v0 and +// v1 are in r, it follows that p(v0) and p(v1) are in bounds of the same memory object. +// (S2) The difference of constants of mp(v0) and mp(v1) is exactly "scale_v * stride_v" (MP-DIFF). +// Given (C4), this difference is not too large. +// (S3) All summands of mp0 and mp1 are the same (only the constants differ), given (MP-DIFF). +// +// It follows: +// p(v1) - p(v0) = mp(v1) - mp(v0) +// +// Reformulating and applying (MP-DIFF) and (IH-P): +// p(v1) = p(v0) + mp(v1) - mp(v1) +// apply (MP-DIFF) +// = p(v0) + scale_v * stride_v +// ------------ apply (IH-P) ------------ +// = p(lo) - lo * scale_v + v0 * scale_v + scale_v * stride_v +// = p(lo) - lo * scale_v + (v0 + stride_v) * scale_v +// = p(lo) - lo * scale_v + v1 * scale_v +// +// This proves Corrolary P. +// #ifndef PRODUCT class TraceMemPointer : public StackObj { private: @@ -466,6 +570,13 @@ public: (_distance <= distance_lo || distance_hi <= _distance); } + // Use case: overlap. + // Note: the bounds are exclusive: lo < element < hi + bool is_always_in_distance_range(const jint distance_lo, const jint distance_hi) const { + return _aliasing == AlwaysAtDistance && + (distance_lo < _distance && _distance < distance_hi); + } + #ifndef PRODUCT void print_on(outputStream* st) const { switch(_aliasing) { @@ -540,7 +651,167 @@ public: #ifndef PRODUCT void print_on(outputStream* st) const { _scale.print_on(st); - tty->print(" * [%d %s]", _variable->_idx, _variable->Name()); + st->print(" * [%d %s]", _variable->_idx, _variable->Name()); + } + + static void print_on(outputStream* st, NoOverflowInt con, const GrowableArray& summands) { + st->print("Summands (%d): con(", summands.length()); + con.print_on(st); + st->print(")"); + for (int i = 0; i < summands.length(); i++) { + st->print(" + "); + summands.at(i).print_on(tty); + } + st->cr(); + } +#endif +}; + +// We need two different ways of tracking the summands: +// - MemPointerRawSummand: designed to keep track of the original form of +// the pointer, preserving its overflow behavior. +// - MemPointerSummand: designed to allow simplification of the MemPointer +// form, does not preserve the original form and +// ignores overflow from ConvI2L. +// +// The MemPointerSummand is designed to allow the simplification of +// the MemPointer form as much as possible, to allow aliasing checks +// to be as simple as possible. For example, the C2 IR pointer: +// +// pointer = AddP( +// AddP( +// base, +// LShiftL( +// ConvI2L( +// AddI(AddI(i, LShiftI(j, 2)), con1) +// ), +// 1 +// ) +// ), +// con2 +// ) +// +// and more readable: +// +// pointer = base + 2L * ConvI2L(i + 4 * j + con1) + con2 +// +// is simplified to this MemPointer form, using only MemPointerSummands, +// which ignore the possible overflow in ConvI2L: +// +// pointer = base + 2L * ConvI2L(i) + 8L * ConvI2L(j) + con +// con = 2L * con1 + con2 +// +// This is really convenient, because this way we are able to ignore +// the ConvI2L in the aliasing anaylsis computation, and we can collect +// all constants to a single constant. Even with this simplicication, +// we are able to prove the correctness of the aliasing checks. +// +// However, there is one thing we are not able to do with this simplification: +// we cannot reconstruct the original pointer expression, because the +// simplification ignores overflows that could happen inside the ConvI2L: +// +// 2L * ConvI2L(i + 4 * j + con1) != 2L * ConvI2L(i) + 8L * ConvI2L(j) + 2L * con1 +// +// The MemPointerRawSummand is designed to keep track of the original form +// of the pointer, preserving its overflow behaviour. We observe that the +// only critical point for overflows is at the ConvI2L. Thus, we give each +// ConvI2L a "int group" id > 0, and all raw summands belonging to that ConvI2L +// have that id. This allows us to reconstruct which raw summands need to +// be added together before the ConvI2L. Any raw summands that do not belong +// to a ConvI2L (i.e. the summands with long variables) have "int group" +// id = 0, since they do not belong to any such "int group" and can be +// directly added together. For raw summands belonging to an "int group", +// we need to track the scale inside (scaleI) and outside (scaleL) the +// ConvI2L. With the example from above: +// +// pointer = base + 2L * ConvI2L(i + 4 * j + con1) + con2 +// +// _variable = base _variable = i _variable = j _variable = null _variable = null +// _scaleI = 1 _scaleI = 1 _scaleI = 4 _scaleI = con1 _scaleI = 1 +// _scaleL = 1 _scaleL = 2 _scaleL = 2 _scaleL = 2 _scaleL = con2 +// _int_group = 0 _int_group = 1 _int_group = 1 _int_group = 1 _int_group = 0 +// +// Note: we also need to track constants as separate raw summands. For +// this, we say that a raw summand tracks a constant iff _variable == null, +// and we store the constant value in _scaleI (for int constant) and in +// _scaleL (for long constants). +// +class MemPointerRawSummand : public StackObj { +private: + Node* _variable; + NoOverflowInt _scaleI; + NoOverflowInt _scaleL; + int _int_group; + +public: + MemPointerRawSummand(Node* variable, NoOverflowInt scaleI, NoOverflowInt scaleL, int int_group) : + _variable(variable), _scaleI(scaleI), _scaleL(scaleL), _int_group(int_group) {} + + MemPointerRawSummand() : + MemPointerRawSummand(nullptr, NoOverflowInt::make_NaN(), NoOverflowInt::make_NaN(), -1) {} + + static MemPointerRawSummand make_trivial(Node* variable) { + assert(variable != nullptr, "must have variable"); + return MemPointerRawSummand(variable, NoOverflowInt(1), NoOverflowInt(1), 0); + } + + static MemPointerRawSummand make_con(NoOverflowInt scaleI, NoOverflowInt scaleL, int int_group) { + return MemPointerRawSummand(nullptr, scaleI, scaleL, int_group); + } + + bool is_valid() const { return _int_group >= 0; } + bool is_con() const { assert(is_valid(), ""); return _variable == nullptr; } + Node* variable() const { assert(is_valid(), ""); return _variable; } + NoOverflowInt scaleI() const { assert(is_valid(), ""); return _scaleI; } + NoOverflowInt scaleL() const { assert(is_valid(), ""); return _scaleL; } + int int_group() const { assert(is_valid(), ""); return _int_group; } + + MemPointerSummand to_summand() const { + assert(!is_con(), "must be variable"); + return MemPointerSummand(variable(), scaleL() * scaleI()); + } + + NoOverflowInt to_con() const { + assert(is_con(), "must be constant"); + return scaleL() * scaleI(); + } + + static int cmp_by_int_group_and_variable_idx(MemPointerRawSummand* p1, MemPointerRawSummand* p2) { + int int_group_diff = p1->int_group() - p2->int_group(); + if (int_group_diff != 0) { return int_group_diff; } + + if (p1->is_con()) { + return p2->is_con() ? 0 : 1; + } + if (p2->is_con()) { + return -1; + } + return p1->variable()->_idx - p2->variable()->_idx; + } + +#ifndef PRODUCT + void print_on(outputStream* st) const { + if (!is_valid()) { + st->print(""); + } else { + st->print("<%d: ", _int_group); + _scaleL.print_on(st); + st->print(" * "); + _scaleI.print_on(st); + if (!is_con()) { + st->print(" * [%d %s]", _variable->_idx, _variable->Name()); + } + st->print(">"); + } + } + + static void print_on(outputStream* st, const GrowableArray& summands) { + st->print("Raw Summands (%d): ", summands.length()); + for (int i = 0; i < summands.length(); i++) { + if (i > 0) { st->print(" + "); } + summands.at(i).print_on(tty); + } + st->cr(); } #endif }; @@ -582,10 +853,13 @@ public: // class MemPointer : public StackObj { public: - // We limit the number of summands to 10. This is just a best guess, and not at this - // point supported by evidence. But I think it is reasonable: usually, a pointer - // contains a base pointer (e.g. array pointer or null for native memory) and a few - // variables. It should be rare that we have more than 9 variables. + // We limit the number of summands to 10, and the raw summands to 16. This is just a + // best guess, and not at this point supported by evidence. But I think it is reasonable: + // usually, a pointer contains a base pointer (e.g. array pointer or null for native memory) + // and a few variables. It should be rare that we have more than 9 variables. We need + // a few more raw summands, especially because there can be multiple constants, one + // per ConvI2L "int group". + static const int RAW_SUMMANDS_SIZE = 16; static const int SUMMANDS_SIZE = 10; // A base can be: @@ -637,10 +911,20 @@ public: }; private: + // Raw summands: represent the pointer form exactly, allowing the reconstruction of the + // pointer expression. Overflows inside the "int groups" (i.e. ConvI2L) + // are preserved, and there may be multiple constants. + MemPointerRawSummand _raw_summands[RAW_SUMMANDS_SIZE]; + + // Summands: Simplified form, with only a single constant. Makes aliasing analysis + // much simpler. MemPointerSummand _summands[SUMMANDS_SIZE]; const NoOverflowInt _con; const Base _base; + + // Size in bytes for the referenced memory region: [pointer, pointer + size) const jint _size; + NOT_PRODUCT( const TraceMemPointer& _trace; ) // Default / trivial: pointer = 0 + 1 * pointer @@ -659,6 +943,7 @@ private: // pointer = SUM(SUMMANDS) + con MemPointer(Node* pointer, + const GrowableArray& raw_summands, const GrowableArray& summands, const NoOverflowInt& con, const jint size @@ -670,14 +955,25 @@ private: { assert(!_con.is_NaN(), "non-NaN constant"); assert(summands.length() <= SUMMANDS_SIZE, "summands must fit"); + assert(raw_summands.length() <= RAW_SUMMANDS_SIZE, "raw summands must fit"); #ifdef ASSERT for (int i = 0; i < summands.length(); i++) { const MemPointerSummand& s = summands.at(i); assert(s.variable() != nullptr, "variable cannot be null"); assert(!s.scale().is_NaN(), "non-NaN scale"); } + for (int i = 0; i < raw_summands.length(); i++) { + const MemPointerRawSummand& s = raw_summands.at(i); + assert(!s.scaleI().is_NaN(), "non-NaN scale"); + assert(!s.scaleL().is_NaN(), "non-NaN scale"); + } #endif + // Copy raw summands in the same order. + for (int i = 0; i < raw_summands.length(); i++) { + _raw_summands[i] = raw_summands.at(i); + } + // Put the base in the 0th summand. Node* base = _base.object_or_native_or_null(); int pos = 0; @@ -708,6 +1004,11 @@ private: NOT_PRODUCT(COMMA _trace(old._trace)) { assert(!_con.is_NaN(), "non-NaN constant"); + + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + _raw_summands[i] = old.raw_summands_at(i); + } + for (int i = 0; i < SUMMANDS_SIZE; i++) { _summands[i] = old.summands_at(i); } @@ -733,17 +1034,29 @@ public: } static MemPointer make(Node* pointer, + const GrowableArray& raw_summands, + const NoOverflowInt con, const GrowableArray& summands, - const NoOverflowInt& con, const jint size NOT_PRODUCT(COMMA const TraceMemPointer& trace)) { - if (summands.length() <= SUMMANDS_SIZE) { - return MemPointer(pointer, summands, con, size NOT_PRODUCT(COMMA trace)); + if (raw_summands.length() <= RAW_SUMMANDS_SIZE && + summands.length() <= SUMMANDS_SIZE && + has_no_NaN_in_con_and_summands(con, summands)) { + return MemPointer(pointer, raw_summands, summands, con, size NOT_PRODUCT(COMMA trace)); } else { return MemPointer::make_trivial(pointer, size NOT_PRODUCT(COMMA trace)); } } + static bool has_no_NaN_in_con_and_summands(const NoOverflowInt con, + const GrowableArray& summands) { + if (con.is_NaN()) { return false; } + for (int i = 0; i < summands.length(); i++) { + if (summands.at(i).scale().is_NaN()) { return false; } + } + return true; + } + MemPointer make_with_size(const jint new_size) const { return MemPointer(*this, this->con(), new_size); }; @@ -775,10 +1088,34 @@ public: return _summands[i]; } + const MemPointerRawSummand& raw_summands_at(const uint i) const { + assert(i < RAW_SUMMANDS_SIZE, "in bounds"); + return _raw_summands[i]; + } + const NoOverflowInt con() const { return _con; } const Base& base() const { return _base; } jint size() const { return _size; } + int max_int_group() const { + int n = 0; + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + const MemPointerRawSummand& s = _raw_summands[i]; + if (!s.is_valid()) { continue; } + n = MAX2(n, s.int_group()); + } + return n; + } + + template + void for_each_raw_summand_of_int_group(int int_group, Callback callback) const { + for (int i = 0; i < RAW_SUMMANDS_SIZE; i++) { + const MemPointerRawSummand& s = _raw_summands[i]; + if (!s.is_valid() || s.int_group() != int_group) { continue; } + callback(s); + } + } + static int cmp_summands(const MemPointer& a, const MemPointer& b) { for (int i = 0; i < SUMMANDS_SIZE; i++) { const MemPointerSummand& s_a = a.summands_at(i); @@ -801,6 +1138,7 @@ public: bool is_adjacent_to_and_before(const MemPointer& other) const; bool never_overlaps_with(const MemPointer& other) const; + bool always_overlaps_with(const MemPointer& other) const; #ifndef PRODUCT void print_form_on(outputStream* st) const { @@ -818,13 +1156,54 @@ public: } } - void print_on(outputStream* st, bool end_with_cr = true) const { + void print_on(outputStream* st) const { st->print("MemPointer[size: %2d, base: ", size()); _base.print_on(st); st->print(", form: "); print_form_on(st); st->print("]"); - if (end_with_cr) { st->cr(); } + st->cr(); + + st->print(" raw: "); + + int long_count = 0; + for_each_raw_summand_of_int_group(0, [&] (const MemPointerRawSummand& s) { + if (long_count > 0) { st->print(" + "); } + long_count++; + if (s.is_con()) { + // Long constant. + NoOverflowInt con = s.scaleI() * s.scaleL(); + con.print_on(st); + st->print("L"); + } else { + // Long variable. + assert(s.scaleI().is_one(), "must be long variable"); + s.scaleL().print_on(st); + st->print("L * [%d %s]", s.variable()->_idx, s.variable()->Name()); + } + }); + + // Int groups, i.e. "ConvI2L(...)" + for (int int_group = 1; int_group <= max_int_group(); int_group++) { + if (long_count > 0) { st->print(" + "); } + long_count++; + int int_count = 0; + for_each_raw_summand_of_int_group(int_group, [&] (const MemPointerRawSummand& s) { + if (int_count == 0) { + s.scaleL().print_on(st); + st->print("L * ConvI2L("); + } else { + st->print(" + "); + } + int_count++; + s.scaleI().print_on(st); + if (!s.is_con()) { + st->print(" * [%d %s]", s.variable()->_idx, s.variable()->Name()); + } + }); + st->print(")"); + } + st->cr(); } #endif }; @@ -838,9 +1217,13 @@ class MemPointerParser : public StackObj { private: const MemNode* _mem; - // Internal data-structures for parsing. - NoOverflowInt _con; - GrowableArray _worklist; + // Internal data-structures for parsing raw summands. + int _next_int_group = 1; + GrowableArray _worklist; + GrowableArray _raw_summands; + + // Internal data-structures for parsing "regular" summands. + NoOverflowInt _con = NoOverflowInt(0); GrowableArray _summands; // Resulting decomposed-form. @@ -850,7 +1233,6 @@ private: MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)) : _mem(mem), - _con(NoOverflowInt(0)), _mem_pointer(parse(callback NOT_PRODUCT(COMMA trace))) {} public: @@ -881,10 +1263,14 @@ private: MemPointer parse(MemPointerParserCallback& callback NOT_PRODUCT(COMMA const TraceMemPointer& trace)); - void parse_sub_expression(const MemPointerSummand& summand, MemPointerParserCallback& callback); + void parse_sub_expression(const MemPointerRawSummand& summand, MemPointerParserCallback& callback); static bool sub_expression_has_native_base_candidate(Node* n); bool is_safe_to_decompose_op(const int opc, const NoOverflowInt& scale) const; + + void canonicalize_raw_summands(); + void create_summands(); + void canonicalize_summands(); }; #endif // SHARE_OPTO_MEMPOINTER_HPP diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index ef7c5600853..32b1c1cd3c4 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OPTO_PREDICATES_HPP #define SHARE_OPTO_PREDICATES_HPP +#include "opto/c2_globals.hpp" #include "opto/cfgnode.hpp" #include "opto/opaquenode.hpp" #include "opto/predicates_enums.hpp" @@ -44,12 +45,15 @@ class TemplateAssertionPredicate; * - Parse Predicate: Added during parsing to capture the current JVM state. This predicate represents a "placeholder" * above which Regular Predicates can be created later after parsing. * - * There are initially three Parse Predicates for each loop: - * - Loop Parse Predicate: The Parse Predicate added for Loop Predicates. - * - Profiled Loop Parse Predicate: The Parse Predicate added for Profiled Loop Predicates. - * - Loop Limit Check Parse Predicate: The Parse Predicate added for a Loop Limit Check Predicate. + * There are initially five Parse Predicates for each loop: + * - Loop Parse Predicate: The Parse Predicate added for Loop Predicates. + * - Profiled Loop Parse Predicate: The Parse Predicate added for Profiled Loop Predicates. + * - Loop Limit Check Parse Predicate: The Parse Predicate added for a Loop Limit Check Predicate. + * - Short Running Loop Parse Predicate: The Parse Predicate added for the short running long loop check. + * - AutoVectorization Parse Predicate: The Parse Predicate added for AutoVectorization runtime checks. * - Runtime Predicate: This term is used to refer to a Hoisted Check Predicate (either a Loop Predicate or a Profiled - * Loop Predicate) or a Loop Limit Check Predicate. These predicates will be checked at runtime while + * Loop Predicate), a Loop Limit Check Predicate, a Short Running Long Loop Predicate, or a + * AutoVectorization Runtime Check Predicate. These predicates will be checked at runtime while * the Parse and Assertion Predicates are always removed before code generation (except for * Initialized Assertion Predicates which are kept in debug builds while being removed in product * builds). @@ -81,6 +85,21 @@ class TemplateAssertionPredicate; * int counted loops with long range checks for which a loop nest also needs to be created * in the general case (so the transformation of long range checks to int range checks is * legal). + * - AutoVectorization: This predicate is used for speculative runtime checks required for AutoVectorization. + * Runtime Check There are multiple reasons why we need a runtime check to allow vectorization: + * Predicate - Unknown aliasing: + * An important compoinent of AutoVectorization is proving that memory addresses do not + * alias, and can therefore be reordered. In some cases, this cannot be done statically + * and a runtime check is necessary. + * - Unknown alignment of native memory: + * While heap objects have 8-byte alignment, off-heap (native) memory often has no alignment + * guarantees. On platforms that require vectors to be aligned, we need to prove alignment. + * We cannot do that statically with native memory, hence we need a runtime check. + * The benefit of using a predicate is that we only have to compile the vectorized loop. If + * the runtime check fails, we simply deoptimize. Should we eventually recompile, then the + * predicate is not available any more, and we instead use a multiversioning approach with + * both a vectorized and a scalar loop, where the runtime determines which loop is taken. + * See: PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks * - Assertion Predicate: An always true predicate which will never fail (its range is already covered by an earlier * Hoisted Check Predicate or the main-loop entry guard) but is required in order to fold away a * dead sub loop in which some data could be proven to be dead (by the type system) and replaced @@ -157,19 +176,27 @@ class TemplateAssertionPredicate; * Predicates, and the associated Parse Predicate which all share the same uncommon trap. This block * could be empty if there were no Runtime Predicates created and the Parse Predicate was already * removed. - * There are three different Predicate Blocks: + * There are five different Predicate Blocks: + * - Short Running Long Groups the Short Running Long Loop Predicate (if created), and the + * Loop Predicate Block: Short Running Long Loop Parse Predicate together. * - Loop Predicate Block: Groups the Loop Predicates (if any), including the Assertion Predicates, * and the Loop Parse Predicate (if not removed, yet) together. * - Profiled Loop Groups the Profiled Loop Predicates (if any), including the Assertion * Predicate Block: Predicates, and the Profiled Loop Parse Predicate (if not removed, yet) * together. + * - AutoVectorization Groups the AutoVectorization Runtime Check Predicates (if any), and the + * Runtime Check AutoVectorization Runtime Check Parse Predicate together. + * Predicate Block: * - Loop Limit Check Groups the Loop Limit Check Predicate (if created) and the Loop Limit * Predicate Block: Check Parse Predicate (if not removed, yet) together. * - Regular Predicate Block: A block that only contains the Regular Predicates of a Predicate Block without the * Parse Predicate. * * Initially, before applying any loop-splitting optimizations, we find the following structure after Loop Predication - * (predicates inside square brackets [] do not need to exist if there are no checks to hoist): + * (predicates inside square brackets [] do not need to exist if there are no checks to hoist / insert): + * + * [Short Running Long Loop Predicate] (at most one) \ Short Running Long + * Short Running Long Loop Parse Predicate / Loop Predicate Block * * [Loop Predicate 1 + two Template Assertion Predicates] \ * [Loop Predicate 2 + two Template Assertion Predicates] | @@ -183,6 +210,12 @@ class TemplateAssertionPredicate; * [Profiled Loop Predicate m + two Template Assertion Predicates] | * Profiled Loop Parse Predicate / * + * [AutoVectorization Runtime Check Predicate 1] \ + * [AutoVectorization Runtime Check Predicate 2] | AutoVectorization + * ... | Runtime Check + * [AutoVectorization Runtime Check Predicate l] | Predicate Block + * AutoVectorization Runtime Check Parse Predicate / + * * [Loop Limit Check Predicate] (at most one) \ Loop Limit Check * Loop Limit Check Parse Predicate / Predicate Block * Loop Head @@ -782,8 +815,10 @@ class PredicateIterator : public StackObj { Node* current_node = _start_node; PredicateBlockIterator loop_limit_check_predicate_iterator(current_node, Deoptimization::Reason_loop_limit_check); current_node = loop_limit_check_predicate_iterator.for_each(predicate_visitor); - PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check); - current_node = auto_vectorization_check_iterator.for_each(predicate_visitor); + if (UseAutoVectorizationPredicate) { + PredicateBlockIterator auto_vectorization_check_iterator(current_node, Deoptimization::Reason_auto_vectorization_check); + current_node = auto_vectorization_check_iterator.for_each(predicate_visitor); + } if (UseLoopPredicate) { if (UseProfiledLoopPredicate) { PredicateBlockIterator profiled_loop_predicate_iterator(current_node, Deoptimization::Reason_profile_predicate); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2316b0bb49a..cb92febf803 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -461,6 +461,9 @@ bool SuperWord::transform_loop() { // inserting scalar promotion, vector creation from multiple scalars, and // extraction of scalar values from vectors. // +// Runtime Checks: +// Some required properties cannot be proven statically, and require a +// runtime check. See VTransform::add_speculative_check bool SuperWord::SLP_extract() { assert(cl()->is_main_loop(), "SLP should only work on main loops"); @@ -832,12 +835,18 @@ bool VLoopDependencyGraph::independent(Node* s1, Node* s2) const { Node* shallow = d1 > d2 ? s2 : s1; int min_d = MIN2(d1, d2); // prune traversal at min_d + // If we can speculate (using the aliasing runtime check), we can drop the weak edges, + // and later insert a runtime check. + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool speculate_away_weak_edges = _vloop.use_speculative_aliasing_checks(); + ResourceMark rm; Unique_Node_List worklist; worklist.push(deep); for (uint i = 0; i < worklist.size(); i++) { Node* n = worklist.at(i); for (PredsIterator preds(*this, n); !preds.done(); preds.next()) { + if (speculate_away_weak_edges && preds.is_current_weak_memory_edge()) { continue; } Node* pred = preds.current(); if (_vloop.in_bb(pred) && depth(pred) >= min_d) { if (pred == shallow) { @@ -869,9 +878,16 @@ bool VLoopDependencyGraph::mutually_independent(const Node_List* nodes) const { worklist.push(n); // start traversal at all nodes in nodes list nodes_set.set(_body.bb_idx(n)); } + + // If we can speculate (using the aliasing runtime check), we can drop the weak edges, + // and later insert a runtime check. + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool speculate_away_weak_edges = _vloop.use_speculative_aliasing_checks(); + for (uint i = 0; i < worklist.size(); i++) { Node* n = worklist.at(i); for (PredsIterator preds(*this, n); !preds.done(); preds.next()) { + if (speculate_away_weak_edges && preds.is_current_weak_memory_edge()) { continue; } Node* pred = preds.current(); if (_vloop.in_bb(pred) && depth(pred) >= min_d) { if (nodes_set.test(_body.bb_idx(pred))) { @@ -1936,6 +1952,7 @@ bool SuperWord::schedule_and_apply() const { VTransformTrace trace(_vloop.vtrace(), is_trace_superword_rejections(), is_trace_align_vector(), + _vloop.is_trace_speculative_aliasing_analysis(), _vloop.is_trace_speculative_runtime_checks(), is_trace_superword_info()); #endif @@ -1989,7 +2006,8 @@ void VTransform::apply() { adjust_pre_loop_limit_to_align_main_loop_vectors(); C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); - apply_speculative_runtime_checks(); + apply_speculative_alignment_runtime_checks(); + apply_speculative_aliasing_runtime_checks(); C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, 4, cl()); apply_vectorization(); diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 57a403b4498..0940e752f85 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -55,6 +55,8 @@ // Definition 3.3 A Pair is a Pack of size two, where the // first statement is considered the left element, and the // second statement is considered the right element. +// +// For more documentation, see: SuperWord::SLP_extract // The PairSet is a set of pairs. These are later combined to packs, // and stored in the PackSet. diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index 83496f9d0be..404eb02372e 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -94,7 +94,7 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } else if (p0->is_CMove()) { // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. set_all_req_with_vectors(pack, vtn); - VTransformBoolVectorNode* vtn_mask_cmp = vtn->in(1)->isa_BoolVector(); + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(1)->isa_BoolVector(); if (vtn_mask_cmp->test()._is_negated) { vtn->swap_req(2, 3); // swap if test was negated. } @@ -299,17 +299,24 @@ void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, } } -void SuperWordVTransformBuilder::add_memory_dependencies_of_node_to_vtnode(Node*n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies) { +void SuperWordVTransformBuilder::add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies) { + // If we cannot speculate, then all dependencies must be strong edges, i.e. scheduling must respect them. + bool are_speculative_checks_possible = _vloop.are_speculative_checks_possible(); + for (VLoopDependencyGraph::PredsIterator preds(_vloop_analyzer.dependency_graph(), n); !preds.done(); preds.next()) { Node* pred = preds.current(); if (!_vloop.in_bb(pred)) { continue; } if (!preds.is_current_memory_edge()) { continue; } + assert(n->is_Mem() && pred->is_Mem(), "only memory edges"); // Only track every memory edge once. VTransformNode* dependency = get_vtnode(pred); if (vtn_memory_dependencies.test_set(dependency->_idx)) { continue; } - assert(n->is_Mem() && pred->is_Mem(), "only memory edges"); - vtn->add_memory_dependency(dependency); // Add every dependency only once per vtn. + if (are_speculative_checks_possible && preds.is_current_weak_memory_edge()) { + vtn->add_weak_memory_edge(dependency); + } else { + vtn->add_strong_memory_edge(dependency); + } } } diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 0e14964263d..6713ed6cac6 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -46,6 +46,7 @@ flags(SW_INFO, "Trace SuperWord info (equivalent to TraceSuperWord)") \ flags(SW_VERBOSE, "Trace SuperWord verbose (all SW tags enabled)") \ flags(ALIGN_VECTOR, "Trace AlignVector") \ + flags(SPECULATIVE_ALIASING_ANALYSIS, "Trace Speculative Aliasing Analysis") \ flags(SPECULATIVE_RUNTIME_CHECKS, "Trace VTransform::apply_speculative_runtime_checks") \ flags(VTRANSFORM, "Trace VTransform Graph") \ flags(ALL, "Trace everything (very verbose)") diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index d2cb62c92c9..cd5aba6c31d 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -23,9 +23,14 @@ */ #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" +#include "opto/divnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/noOverflowInt.hpp" +#include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/vectorization.hpp" @@ -257,13 +262,17 @@ void VLoopVPointers::print() const { // - No Load-Load edges. // - Inside a slice, add all Store-Load, Load-Store, Store-Store edges, // except if we can prove that the memory does not overlap. +// - Strong edge: must be respected. +// - Weak edge: if we add a speculative aliasing check, we can violate +// the edge, i.e. spaw the order. void VLoopDependencyGraph::construct() { const GrowableArray& mem_slice_heads = _memory_slices.heads(); const GrowableArray& mem_slice_tails = _memory_slices.tails(); ResourceMark rm; GrowableArray slice_nodes; - GrowableArray memory_pred_edges; + GrowableArray strong_memory_edges; + GrowableArray weak_memory_edges; // For each memory slice, create the memory subgraph for (int i = 0; i < mem_slice_heads.length(); i++) { @@ -275,7 +284,8 @@ void VLoopDependencyGraph::construct() { // In forward order (reverse of reverse), visit all memory nodes in the slice. for (int j = slice_nodes.length() - 1; j >= 0 ; j--) { MemNode* n1 = slice_nodes.at(j); - memory_pred_edges.clear(); + strong_memory_edges.clear(); + weak_memory_edges.clear(); const VPointer& p1 = _vpointers.vpointer(n1); // For all memory nodes before it, check if we need to add a memory edge. @@ -286,15 +296,20 @@ void VLoopDependencyGraph::construct() { if (n1->is_Load() && n2->is_Load()) { continue; } const VPointer& p2 = _vpointers.vpointer(n2); + + // If we can prove that they will never overlap -> drop edge. if (!p1.never_overlaps_with(p2)) { - // Possibly overlapping memory - memory_pred_edges.append(_body.bb_idx(n2)); + if (p1.can_make_speculative_aliasing_check_with(p2)) { + weak_memory_edges.append(_body.bb_idx(n2)); + } else { + strong_memory_edges.append(_body.bb_idx(n2)); + } } } - if (memory_pred_edges.is_nonempty()) { + if (strong_memory_edges.is_nonempty() || weak_memory_edges.is_nonempty()) { // Data edges are taken implicitly from the C2 graph, thus we only add // a dependency node if we have memory edges. - add_node(n1, memory_pred_edges); + add_node(n1, strong_memory_edges, weak_memory_edges); } } slice_nodes.clear(); @@ -305,16 +320,18 @@ void VLoopDependencyGraph::construct() { NOT_PRODUCT( if (_vloop.is_trace_dependency_graph()) { print(); } ) } -void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& memory_pred_edges) { +void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges) { assert(_dependency_nodes.at_grow(_body.bb_idx(n), nullptr) == nullptr, "not yet created"); - assert(!memory_pred_edges.is_empty(), "no need to create a node without edges"); - DependencyNode* dn = new (_arena) DependencyNode(n, memory_pred_edges, _arena); + DependencyNode* dn = new (_arena) DependencyNode(n, strong_memory_edges, weak_memory_edges, _arena); _dependency_nodes.at_put_grow(_body.bb_idx(n), dn, nullptr); } int VLoopDependencyGraph::find_max_pred_depth(const Node* n) const { int max_pred_depth = 0; if (!n->is_Phi()) { // ignore backedge + // We must compute the dependence graph depth with all edges (including the weak edges), so that + // the independence queries work correctly, no matter if we check independence with or without + // weak edges. for (PredsIterator it(*this, n); !it.done(); it.next()) { Node* pred = it.current(); if (_vloop.in_bb(pred)) { @@ -358,8 +375,13 @@ void VLoopDependencyGraph::print() const { const DependencyNode* dn = dependency_node(n); if (dn != nullptr) { tty->print(" DependencyNode[%d %s:", n->_idx, n->Name()); - for (uint j = 0; j < dn->memory_pred_edges_length(); j++) { - Node* pred = _body.body().at(dn->memory_pred_edge(j)); + for (uint j = 0; j < dn->num_strong_memory_edges(); j++) { + Node* pred = _body.body().at(dn->strong_memory_edge(j)); + tty->print(" %d %s", pred->_idx, pred->Name()); + } + tty->print(" | weak:"); + for (uint j = 0; j < dn->num_weak_memory_edges(); j++) { + Node* pred = _body.body().at(dn->weak_memory_edge(j)); tty->print(" %d %s", pred->_idx, pred->Name()); } tty->print_cr("]"); @@ -367,11 +389,18 @@ void VLoopDependencyGraph::print() const { } tty->cr(); - tty->print_cr(" Complete dependency graph:"); + // If we cannot speculate (aliasing analysis runtime checks), we need to respect all edges. + bool with_weak_memory_edges = !_vloop.use_speculative_aliasing_checks(); + if (with_weak_memory_edges) { + tty->print_cr(" Complete dependency graph (with weak edges, because we cannot speculate):"); + } else { + tty->print_cr(" Dependency graph without weak edges (because we can speculate):"); + } for (int i = 0; i < _body.body().length(); i++) { Node* n = _body.body().at(i); tty->print(" d%02d Dependencies[%d %s:", depth(n), n->_idx, n->Name()); for (PredsIterator it(*this, n); !it.done(); it.next()) { + if (!with_weak_memory_edges && it.is_current_weak_memory_edge()) { continue; } Node* pred = it.current(); tty->print(" %d %s", pred->_idx, pred->Name()); } @@ -381,16 +410,25 @@ void VLoopDependencyGraph::print() const { #endif VLoopDependencyGraph::DependencyNode::DependencyNode(MemNode* n, - GrowableArray& memory_pred_edges, + GrowableArray& strong_memory_edges, + GrowableArray& weak_memory_edges, Arena* arena) : _node(n), - _memory_pred_edges_length(memory_pred_edges.length()), - _memory_pred_edges(nullptr) + _num_strong_memory_edges(strong_memory_edges.length()), + _num_weak_memory_edges(weak_memory_edges.length()), + _memory_edges(nullptr) { - assert(memory_pred_edges.is_nonempty(), "not empty"); - uint bytes = memory_pred_edges.length() * sizeof(int); - _memory_pred_edges = (int*)arena->Amalloc(bytes); - memcpy(_memory_pred_edges, memory_pred_edges.adr_at(0), bytes); + assert(strong_memory_edges.is_nonempty() || weak_memory_edges.is_nonempty(), "only generate DependencyNode if there are pred edges"); + uint bytes_strong = strong_memory_edges.length() * sizeof(int); + uint bytes_weak = weak_memory_edges.length() * sizeof(int); + uint bytes_total = bytes_strong + bytes_weak; + _memory_edges = (int*)arena->Amalloc(bytes_total); + if (strong_memory_edges.length() > 0) { + memcpy(_memory_edges, strong_memory_edges.adr_at(0), bytes_strong); + } + if (weak_memory_edges.length() > 0) { + memcpy(_memory_edges + strong_memory_edges.length(), weak_memory_edges.adr_at(0), bytes_weak); + } } VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& dependency_graph, @@ -400,36 +438,726 @@ VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& d _dependency_node(dependency_graph.dependency_node(node)), _current(nullptr), _is_current_memory_edge(false), - _next_pred(0), - _end_pred(node->req()), - _next_memory_pred(0), - _end_memory_pred((_dependency_node != nullptr) ? _dependency_node->memory_pred_edges_length() : 0) + _is_current_weak_memory_edge(false), + _next_data_edge(0), + _end_data_edge(node->req()), + _next_strong_memory_edge(0), + _end_strong_memory_edge((_dependency_node != nullptr) ? _dependency_node->num_strong_memory_edges() : 0), + _next_weak_memory_edge(0), + _end_weak_memory_edge((_dependency_node != nullptr) ? _dependency_node->num_weak_memory_edges() : 0) { if (_node->is_Store() || _node->is_Load()) { - // Load: address - // Store: address, value - _next_pred = MemNode::Address; + // Ignore ctrl and memory, only address and value are data dependencies. + // Memory edges are already covered by the strong and weak memory edges. + // Load: [ctrl, memory] address + // Store: [ctrl, memory] address, value + _next_data_edge = MemNode::Address; } else { assert(!_node->is_Mem(), "only loads and stores are expected mem nodes"); - _next_pred = 1; // skip control + _next_data_edge = 1; // skip control } next(); } void VLoopDependencyGraph::PredsIterator::next() { - if (_next_pred < _end_pred) { - _current = _node->in(_next_pred++); + if (_next_data_edge < _end_data_edge) { + _current = _node->in(_next_data_edge++); _is_current_memory_edge = false; - } else if (_next_memory_pred < _end_memory_pred) { - int pred_bb_idx = _dependency_node->memory_pred_edge(_next_memory_pred++); + _is_current_weak_memory_edge = false; + } else if (_next_strong_memory_edge < _end_strong_memory_edge) { + int pred_bb_idx = _dependency_node->strong_memory_edge(_next_strong_memory_edge++); _current = _dependency_graph._body.body().at(pred_bb_idx); _is_current_memory_edge = true; + _is_current_weak_memory_edge = false; + } else if (_next_weak_memory_edge < _end_weak_memory_edge) { + int pred_bb_idx = _dependency_node->weak_memory_edge(_next_weak_memory_edge++); + _current = _dependency_graph._body.body().at(pred_bb_idx); + _is_current_memory_edge = true; + _is_current_weak_memory_edge = true; } else { _current = nullptr; // done _is_current_memory_edge = false; + _is_current_weak_memory_edge = false; } } +// Computing aliasing runtime check using init and last of main-loop +// ----------------------------------------------------------------- +// +// We have two VPointer vp1 and vp2, and would like to create a runtime check that +// guarantees that the corresponding pointers p1 and p2 do not overlap (alias) for +// any iv value in the strided range r = [init, init + iv_stride, .. limit). +// Remember that vp1 and vp2 both represent a region in memory, starting at a +// "pointer", and extending for "size" bytes: +// +// vp1(iv) = [p1(iv), size1) +// vp2(iv) = [p2(iv), size2) +// +// |---size1---> |-------size2-------> +// | | +// p1(iv) p2(iv) +// +// In each iv value (intuitively: for each iteration), we check that there is no +// overlap: +// +// for all iv in r: p1(iv) + size1 <= p2(iv) OR p2(iv) + size2 <= p1(iv) +// +// This would allow situations where for some iv p1 is lower than p2, and for +// other iv p1 is higher than p2. This is not very useful in practice. We can +// strengthen the condition, which will make the check simpler later: +// +// for all iv in r: p1(iv) + size1 <= p2(iv) (P1-BEFORE-P2) +// OR +// for all iv in r: p2(iv) + size2 <= p1(iv) (P1-AFTER-P2) +// +// Note: apart from this strengthening, the checks we derive below are byte accurate, +// i.e. they are equivalent to the conditions above. This means we have NO case +// where: +// 1) The check passes (predicts no overlap) but the pointers do actually overlap. +// This would be bad because we would wrongly vectorize, possibly leading to +// wrong results. +// 2) The check does not pass (predicts overlap) but the pointers do not overlap. +// This would be suboptimal, as we would not be able to vectorize, and either +// trap (with predicate), or go into the slow-loop (with multiversioning). +// +// +// We apply the "MemPointer Linearity Corrolary" to VPointer vp and the corresponding +// pointer p: +// (C0) is given by the construction of VPointer vp, which simply wraps a MemPointer mp. +// (c1) with v = iv and scale_v = iv_scale +// (C2) with r = [init, init + iv_stride, .. last - stride_v, last], which is the set +// of possible iv values in the loop, with "init" the first iv value, and "last" +// the last iv value which is closest to limit. +// Note: iv_stride > 0 -> limit - iv_stride <= last < limit +// iv_stride < 0 -> limit < last <= limit - iv_stride +// We have to be a little careful, and cannot just use "limit" instead of "last" as +// the last value in r, because the iv never reaches limit in the main-loop, and +// so we are not sure if the memory access at p(limit) is still in bounds. +// For now, we just assume that we can compute init and limit, and we will derive +// the computation of these values later on. +// (C3) the memory accesses for every iv value in the loop must be in bounds, otherwise +// the program has undefined behaviour already. +// (C4) abs(iv_scale * iv_stride) < 2^31 is given by the checks in +// VPointer::init_are_scale_and_stride_not_too_large. +// +// Hence, it follows that we can see p and vp as linear functions of iv in r, i.e. for +// all iv values in the loop: +// p(iv) = p(init) - init * iv_scale + iv * iv_scale +// vp(iv) = vp(init) - init * iv_scale + iv * iv_scale +// +// Hence, p1 and p2 have the linear form: +// p1(iv) = p1(init) - init * iv_scale1 + iv * iv_scale1 (LINEAR-FORM-INIT) +// p2(iv) = p2(init) - init * iv_scale2 + iv * iv_scale2 +// +// With the (Alternative Corrolary P) we get the alternative linar form: +// p1(iv) = p1(last) - last * iv_scale1 + iv * iv_scale1 (LINEAR-FORM-LAST) +// p2(iv) = p2(last) - last * iv_scale2 + iv * iv_scale2 +// +// +// We can now use this linearity to construct aliasing runtime checks, depending on the +// different "geometry" of the two VPointer over their iv, i.e. the "slopes" of the linear +// functions. In the following graphs, the x-axis denotes the values of iv, from init to +// last. And the y-axis denotes the pointer position p(iv). Intuitively, this problem +// can be seen as having two bands that should not overlap. +// +// Case 1 Case 2 Case 3 +// parallel lines same sign slope different sign slope +// but not parallel +// +// +---------+ +---------+ +---------+ +// | | | #| |# | +// | | | # | | # | +// | #| | # | | # | +// | # | | # | | # | +// | # | | # | | #| +// | # ^ | | # | | ^| +// |# | #| | # | | || +// | v # | | # | | v| +// | # | |# #| | #| +// | # | |^ # | | # | +// |# | || # | | # | +// | | |v # | | # | +// | | |# | |# | +// +---------+ +---------+ +---------+ +// +// +// Case 1: parallel lines, i.e. iv_scale = iv_scale1 = iv_scale2 +// +// p1(iv) = p1(init) - init * iv_scale + iv * iv_scale +// p2(iv) = p2(init) - init * iv_scale + iv * iv_scale +// +// Given this, it follows: +// p1(iv) + size1 <= p2(iv) <==> p1(init) + size1 <= p2(init) +// p2(iv) + size2 <= p1(iv) <==> p2(init) + size2 <= p1(init) +// +// Hence, we do not have to check the condition for every iv, but only for init. +// +// p1(init) + size1 <= p2(init) OR p2(init) + size2 <= p1(init) +// ----- is equivalent to ----- ---- is equivalent to ------ +// (P1-BEFORE-P2) OR (P1-AFTER-P2) +// +// +// Case 2 and 3: different slopes, i.e. iv_scale1 != iv_scale2 +// +// Without loss of generality, we assume iv_scale1 < iv_scale2. +// (Otherwise, we just swap p1 and p2). +// +// If iv_stride >= 0, i.e. init <= iv <= last: +// (iv - init) * iv_scale1 <= (iv - init) * iv_scale2 +// (iv - last) * iv_scale1 >= (iv - last) * iv_scale2 (POS-STRIDE) +// If iv_stride <= 0, i.e. last <= iv <= init: +// (iv - init) * iv_scale1 >= (iv - init) * iv_scale2 +// (iv - last) * iv_scale1 <= (iv - last) * iv_scale2 (NEG-STRIDE) +// +// Below, we show that these conditions are equivalent: +// +// p1(init) + size1 <= p2(init) (if iv_stride >= 0) | p2(last) + size2 <= p1(last) (if iv_stride >= 0) | +// p1(last) + size1 <= p2(last) (if iv_stride <= 0) | p2(init) + size2 <= p1(init) (if iv_stride <= 0) | +// ---- are equivalent to ----- | ---- are equivalent to ----- | +// (P1-BEFORE-P2) | (P1-AFTER-P2) | +// | | +// Proof: | | +// | | +// Assume: (P1-BEFORE-P2) | Assume: (P1-AFTER-P2) | +// for all iv in r: p1(iv) + size1 <= p2(iv) | for all iv in r: p2(iv) + size2 <= p1(iv) | +// => And since init and last in r => | => And since init and last in r => | +// p1(init) + size1 <= p2(init) | p2(init) + size2 <= p1(init) | +// p1(last) + size1 <= p2(last) | p2(last) + size2 <= p1(last) | +// | | +// | | +// Assume: p1(init) + size1 <= p2(init) | Assume: p2(last) + size2 <= p1(last) | +// and: iv_stride >= 0 | and: iv_stride >= 0 | +// | | +// size1 + p1(iv) | size2 + p2(iv) | +// --------- apply (LINEAR-FORM-INIT) --------- | --------- apply (LINEAR-FORM-LAST) --------- | +// = size1 + p1(init) - init * iv_scale1 + iv * iv_scale1 | = size2 + p2(last) - last * iv_scale2 + iv * iv_scale2 | +// ------ apply (POS-STRIDE) --------- | ------ apply (POS-STRIDE) --------- | +// <= size1 + p1(init) - init * iv_scale2 + iv * iv_scale2 | <= size2 + p2(last) - last * iv_scale1 + iv * iv_scale1 | +// -- assumption -- | -- assumption -- | +// <= p2(init) - init * iv_scale2 + iv * iv_scale2 | <= p1(last) - last * iv_scale1 + iv * iv_scale1 | +// --------- apply (LINEAR-FORM-INIT) --------- | --------- apply (LINEAR-FORM-LAST) --------- | +// = p2(iv) | = p1(iv) | +// | | +// | | +// Assume: p1(last) + size1 <= p2(last) | Assume: p2(init) + size2 <= p1(init) | +// and: iv_stride <= 0 | and: iv_stride <= 0 | +// | | +// size1 + p1(iv) | size2 + p2(iv) | +// --------- apply (LINEAR-FORM-LAST) --------- | --------- apply (LINEAR-FORM-INIT) --------- | +// = size1 + p1(last) - last * iv_scale1 + iv * iv_scale1 | = size2 + p2(init) - init * iv_scale2 + iv * iv_scale2 | +// ------ apply (NEG-STRIDE) --------- | ------ apply (NEG-STRIDE) --------- | +// <= size1 + p1(last) - last * iv_scale2 + iv * iv_scale2 | <= size2 + p2(init) - init * iv_scale1 + iv * iv_scale1 | +// -- assumption -- | -- assumption -- | +// <= p2(last) - last * iv_scale2 + iv * iv_scale2 | <= p1(init) - init * iv_scale1 + iv * iv_scale1 | +// --------- apply (LINEAR-FORM-LAST) --------- | --------- apply (LINEAR-FORM-INIT) --------- | +// = p2(iv) | = p1(iv) | +// | | +// +// The obtained conditions already look very simple. However, we would like to avoid +// computing 4 addresses (p1(init), p1(last), p2(init), p2(last)), and would instead +// prefer to only compute 2 addresses, and derive the other two from the distance (span) +// between the pointers at init and last. Using (LINEAR-FORM-INIT), we get: +// +// p1(last) = p1(init) - init * iv_scale1 + last * iv_scale1 (SPAN-1) +// --------------- defines ------------- +// p1(init) + span1 +// +// p2(last) = p2(init) - init * iv_scale2 + last * iv_scale2 (SPAN-2) +// --------------- defines ------------- +// p1(init) + span2 +// +// span1 = - init * iv_scale1 + last * iv_scale1 = (last - init) * iv_scale1 +// span2 = - init * iv_scale2 + last * iv_scale2 = (last - init) * iv_scale2 +// +// Thus, we can use the conditions below: +// p1(init) + size1 <= p2(init) OR p2(init) + span2 + size2 <= p1(init) + span1 (if iv_stride >= 0) +// p1(init) + span1 + size1 <= p2(init) + span2 OR p2(init) + size2 <= p1(init) (if iv_stride <= 0) +// +// Below, we visualize the conditions, so that the reader can gain an intuitiion. +// For simplicity, we only show the case with iv_stride > 0. Also, remember that +// iv_scale1 < iv_scale2. +// +// +---------+ +---------+ +// | #| | #| <-- p1(init) + span1 +// | # | ^ span2 span1 ^ | # ^| +// | # | | | | # || +// | # | | | | # v| <-- p2(init) + span2 + size2 +// | # | | v |# #| +// | # | | span2 ^ | # | +// | # | | | | # | +// | # | | | | # | +// p2(init) --> |# #| v | | # | +// |^ # | ^ span1 | | # | +// || # | | | | # | +// p1(init) + size1 --> |v # | | | | # | +// |# | v v |# | +// +---------+ +---------+ +// +// ------------------------------------------------------------------------------------------------------------------------- +// +// Computing the last iv value in a loop +// ------------------------------------- +// +// Let us define a helper function, that computes the last iv value in a loop, +// given variable init and limit values, and a constant stride. If the loop +// is never entered, we just return the init value. +// +// LAST(init, stride, limit), where stride > 0: | LAST(init, stride, limit), where stride < 0: +// last = init | last = init +// for (iv = init; iv < limit; iv += stride) | for (iv = init; iv > limit; iv += stride) +// last = iv | last = iv +// +// It follows that for some k: +// last = init + k * stride +// +// If the loop is not entered, we can set k=0. +// +// If the loop is entered: +// last is very close to limit: +// stride > 0 -> limit - stride <= last < limit +// stride < 0 -> limit < last <= limit - stride +// +// If stride > 0: +// limit - stride <= last < limit +// limit - stride <= init + k * stride < limit +// limit - init - stride <= k * stride < limit - init +// limit - init - stride - 1 < k * stride <= limit - init - 1 +// (limit - init - stride - 1) / stride < k <= (limit - init - 1) / stride +// (limit - init - 1) / stride - 1 < k <= (limit - init - 1) / stride +// -> k = (limit - init - 1) / stride +// -> dividend "limit - init - 1" is >=0. So a regular round to zero division can be used. +// Note: to incorporate the case where the loop is not entered (init >= limit), we see +// that the divident is zero or negative, and so the result will be zero or +// negative. Thus, we can just clamp k to zero, or last to init, so that we get +// a solution that also works when the loop is not entered: +// +// k = (limit - init - 1) / abs(stride) +// last = MAX(init, init + k * stride) +// +// If stride < 0: +// limit < last <= limit - stride +// limit < init + k * stride <= limit - stride +// limit - init < k * stride <= limit - init - stride +// limit - init + 1 <= k * stride < limit - init - stride + 1 +// (limit - init + 1) / stride >= k > (limit - init - stride + 1) / stride +// -(limit - init + 1) / abs(stride) >= k > -(limit - init - stride + 1) / abs(stride) +// -(limit - init + 1) / abs(stride) >= k > -(limit - init + 1) / abs(stride) - 1 +// (init - limit - 1) / abs(stride) >= k > (init - limit - 1) / abs(stride) - 1 +// (init - limit - 1) / abs(stride) >= k > (init - limit - 1) / abs(stride) - 1 +// -> k = (init - limit - 1) / abs(stride) +// -> dividend "init - limit" is >=0. So a regular round to zero division can be used. +// Note: to incorporate the case where the loop is not entered (init <= limit), we see +// that the divident is zero or negative, and so the result will be zero or +// negative. Thus, we can just clamp k to zero, or last to init, so that we get +// a solution that also works when the loop is not entered: +// +// k = (init - limit - 1) / abs(stride) +// last = MIN(init, init + k * stride) +// +// Now we can put it all together: +// LAST(init, stride, limit) +// If stride > 0: +// k = (limit - init - 1) / abs(stride) +// last = MAX(init, init + k * stride) +// If stride < 0: +// k = (init - limit - 1) / abs(stride) +// last = MIN(init, init + k * stride) +// +// We will have to consider the implications of clamping to init when the loop is not entered +// at the use of LAST further down. +// +// ------------------------------------------------------------------------------------------------------------------------- +// +// Computing init and last for the main-loop +// ----------------------------------------- +// +// As we have seen above, we always need the "init" of the main-loop. And if "iv_scale1 != iv_scale2", then we +// also need the "last" of the main-loop. These values need to be pre-loop invariant, because the check is +// to be performed before the pre-loop (at the predicate or multiversioning selector_if). It will be helpful +// to recall the iv structure in the pre and main-loop: +// +// | iv = pre_init +// | +// Pre-Loop | +----------------+ +// phi | +// | | -> pre_last: last iv value in pre-loop +// + pre_iv_stride | +// |-----------------+ +// | exit check: < pre_limit +// | +// | iv = main_init = init +// | +// Main-Loop | +------------------------------+ +// phi | +// | | -> last: last iv value in main-loop +// + main_iv_stride = iv_stride | +// |-------------------------------+ +// | exit check: < main_limit = limit +// +// Unfortunately, the init (aka. main_init) is not pre-loop invariant, rather it is only available +// after the pre-loop. We will have to compute: +// +// pre_last = LAST(pre_init, pre_iv_stride, pre_limit) +// init = pre_last + pre_iv_stride +// +// If we need "last", we unfortunately must compute it as well: +// +// last = LAST(init, iv_stride, limit) +// +// +// These computations assume that we indeed do enter the main-loop - otherwise +// it does not make sense to talk about the "last main iteration". Of course +// entering the main-loop implies that we entered the pre-loop already. But +// what happens if we check the aliasing runtime check, but later would never +// enter the main-loop? +// +// First: no matter if we pass or fail the aliasing runtime check, we will +// not get wrong results. If we fail the check, we end up in the less optimized +// slow-loop. If we pass the check, and we don't enter the main-loop, we +// never rely on the aliasing check, after all only the vectorized main-loop +// (and the vectorized post-loop) rely on the aliasing check. +// +// But: The worry is that we may fail the aliasing runtime check "spuriously", +// i.e. even though we would never enter the main-loop, and that this could have +// unfortunate side-effects (for example deopting unnecessarily). Let's +// look at the two possible cases: +// 1) We would never even enter the pre-loop. +// There are only predicates between the aliasing runtime check and the pre-loop, +// so a predicate would have to fail. These are rather rare cases. If we +// are using multiversioning for the aliasing runtime check, we would +// immediately fail the predicate in either the slow or fast loop, so +// the decision of the aliasing runtime check does not matter. But if +// we are using a predicate for the aliaing runtime check, then we may +// end up deopting twice: once for the aliasing runtime check, and then +// again for the other predicate. This would not be great, but again, +// failing predicates are rare in the first place. +// +// 2) We would enter the pre-loop, but not the main-loop. +// The pre_last must be accurate, because we are entering the pre-loop. +// But then we fail the zero-trip guard of the main-loop. Thus, for the +// main-loop, the init lies "after" the limit. Thus, the computed last +// for the main-loop equals the init. This means that span1 and span2 +// are zero. Hence, p1(init) and p2(init) would have to alias for the +// aliasing runtime check to fail. Hence, it would not be surprising +// at all if we deopted because of the aliasing runtime check. +// +bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) const { + const VPointer& vp1 = *this; + const VPointer& vp2 = other; + + if (!_vloop.use_speculative_aliasing_checks()) { return false; } + + // Both pointers need a nice linear form, otherwise we cannot formulate the check. + if (!vp1.is_valid() || !vp2.is_valid()) { return false; } + + // The pointers always overlap -> a speculative check would always fail. + if (vp1.always_overlaps_with(vp2)) { return false; } + + // The pointers never overlap -> a speculative check would always succeed. + assert(!vp1.never_overlaps_with(vp2), "ensured by caller"); + + // The speculative aliasing check happens either at the AutoVectorization predicate + // or at the multiversion_if. That is before the pre-loop. From the construction of + // VPointer, we already know that all its variables (except iv) are pre-loop invariant. + // + // For the computation of main_init, we also need the pre_limit, and so we need + // to check that this value is pre-loop invariant. In the case of non-equal iv_scales, + // we also need the main_limit in the aliasing check, and so this value must then + // also be pre-loop invariant. + Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); + Node* pre_limit = pre_limit_opaq->in(1); + Node* main_limit = _vloop.cl()->limit(); + + if (!_vloop.is_pre_loop_invariant(pre_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not pre-loop independent!"); + } +#endif + return false; + } + + if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_pre_loop_invariant(main_limit)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not pre-loop independent!"); + } +#endif + return false; + } + + return true; +} + +// For description and derivation see "Computing the last iv value in a loop". +// Note: the iv computations here should not overflow. But out of an abundance +// of caution, we compute everything in long anyway. +Node* make_last(Node* initL, jint stride, Node* limitL, PhaseIdealLoop* phase) { + PhaseIterGVN& igvn = phase->igvn(); + + Node* abs_strideL = igvn.longcon(abs(stride)); + Node* strideL = igvn.longcon(stride); + + // If in some rare case the limit is "before" init, then + // this subtraction could overflow. Doing the calculations + // in long prevents this. Below, we clamp the "last" value + // back to init, which gets us back into the safe int range. + Node* diffL = (stride > 0) ? new SubLNode(limitL, initL) + : new SubLNode(initL, limitL); + Node* diffL_m1 = new AddLNode(diffL, igvn.longcon(-1)); + Node* k = new DivLNode(nullptr, diffL_m1, abs_strideL); + + // Compute last = init + k * iv_stride + Node* k_mul_stride = new MulLNode(k, strideL); + Node* last = new AddLNode(initL, k_mul_stride); + + // Make sure that the last does not lie "before" init. + Node* last_clamped = MaxNode::build_min_max_long(&igvn, initL, last, stride > 0); + + phase->register_new_node_with_ctrl_of(diffL, initL); + phase->register_new_node_with_ctrl_of(diffL_m1, initL); + phase->register_new_node_with_ctrl_of(k, initL); + phase->register_new_node_with_ctrl_of(k_mul_stride, initL); + phase->register_new_node_with_ctrl_of(last, initL); + phase->register_new_node_with_ctrl_of(last_clamped, initL); + + return last_clamped; +} + +BoolNode* make_a_plus_b_leq_c(Node* a, Node* b, Node* c, PhaseIdealLoop* phase) { + Node* a_plus_b = new AddLNode(a, b); + Node* cmp = CmpNode::make(a_plus_b, c, T_LONG, true); + BoolNode* bol = new BoolNode(cmp, BoolTest::le); + phase->register_new_node_with_ctrl_of(a_plus_b, a); + phase->register_new_node_with_ctrl_of(cmp, a); + phase->register_new_node_with_ctrl_of(bol, a); + return bol; +} + +BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) const { + // Ensure iv_scale1 <= iv_scale2. + const VPointer& vp1 = (this->iv_scale() <= other.iv_scale()) ? *this : other; + const VPointer& vp2 = (this->iv_scale() <= other.iv_scale()) ? other :*this ; + assert(vp1.iv_scale() <= vp2.iv_scale(), "ensured by swapping if necessary"); + + assert(vp1.can_make_speculative_aliasing_check_with(vp2), "sanity"); + + PhaseIdealLoop* phase = _vloop.phase(); + PhaseIterGVN& igvn = phase->igvn(); + + // init (aka main_init): compute it from the the pre-loop structure. + // As described above, we cannot just take the _vloop.cl().init_trip(), because that + // value is pre-loop dependent, and we need a pre-loop independent value, so we can + // have it available at the predicate / multiversioning selector_if. + // For this, we need to be sure that the pre_limit is pre-loop independent as well, + // see can_make_speculative_aliasing_check_with. + Node* pre_init = _vloop.pre_loop_end()->init_trip(); + jint pre_iv_stride = _vloop.pre_loop_end()->stride_con(); + Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); + Node* pre_limit = pre_limit_opaq->in(1); + assert(_vloop.is_pre_loop_invariant(pre_init), "needed for aliasing check before pre-loop"); + assert(_vloop.is_pre_loop_invariant(pre_limit), "needed for aliasing check before pre-loop"); + + Node* pre_initL = new ConvI2LNode(pre_init); + Node* pre_limitL = new ConvI2LNode(pre_limit); + phase->register_new_node_with_ctrl_of(pre_initL, pre_init); + phase->register_new_node_with_ctrl_of(pre_limitL, pre_init); + + Node* pre_lastL = make_last(pre_initL, pre_iv_stride, pre_limitL, phase); + + Node* main_initL = new AddLNode(pre_lastL, igvn.longcon(pre_iv_stride)); + phase->register_new_node_with_ctrl_of(main_initL, pre_init); + + Node* main_init = new ConvL2INode(main_initL); + phase->register_new_node_with_ctrl_of(main_init, pre_init); + + Node* p1_init = vp1.make_pointer_expression(main_init); + Node* p2_init = vp2.make_pointer_expression(main_init); + Node* size1 = igvn.longcon(vp1.size()); + Node* size2 = igvn.longcon(vp2.size()); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr("\nVPointer::make_speculative_aliasing_check_with:"); + tty->print("pre_init: "); pre_init->dump(); + tty->print("pre_limit: "); pre_limit->dump(); + tty->print("pre_lastL: "); pre_lastL->dump(); + tty->print("main_init: "); main_init->dump(); + tty->print_cr("p1_init:"); + p1_init->dump_bfs(5, nullptr, ""); + tty->print_cr("p2_init:"); + p2_init->dump_bfs(5, nullptr, ""); + } +#endif + + BoolNode* condition1 = nullptr; + BoolNode* condition2 = nullptr; + if (vp1.iv_scale() == vp2.iv_scale()) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr(" Same iv_scale(%d) -> parallel lines -> simple conditions:", vp1.iv_scale()); + tty->print_cr(" p1(init) + size1 <= p2(init) OR p2(init) + size2 <= p1(init)"); + tty->print_cr(" -------- condition1 -------- ------- condition2 ---------"); + } +#endif + condition1 = make_a_plus_b_leq_c(p1_init, size1, p2_init, phase); + condition2 = make_a_plus_b_leq_c(p2_init, size2, p1_init, phase); + } else { + assert(vp1.iv_scale() < vp2.iv_scale(), "assumed in proof, established above by swapping"); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr(" Different iv_scale -> lines with different slopes -> more complex conditions:"); + tty->print_cr(" p1(init) + size1 <= p2(init) OR p2(init) + span2 + size2 <= p1(init) + span1 (if iv_stride >= 0)"); + tty->print_cr(" p1(init) + span1 + size1 <= p2(init) + span2 OR p2(init) + size2 <= p1(init) (if iv_stride <= 0)"); + tty->print_cr(" ---------------- condition1 ---------------- --------------- condition2 -----------------"); + } +#endif + + // last (aka main_last): compute from main-loop structure. + jint main_iv_stride = _vloop.iv_stride(); + Node* main_limit = _vloop.cl()->limit(); + assert(_vloop.is_pre_loop_invariant(main_limit), "needed for aliasing check before pre-loop"); + + Node* main_limitL = new ConvI2LNode(main_limit); + phase->register_new_node_with_ctrl_of(main_limitL, pre_init); + + Node* main_lastL = make_last(main_initL, main_iv_stride, main_limitL, phase); + + // Compute span1 = (last - init) * iv_scale1 + // span2 = (last - init) * iv_scale2 + Node* last_minus_init = new SubLNode(main_lastL, main_initL); + Node* iv_scale1 = igvn.longcon(vp1.iv_scale()); + Node* iv_scale2 = igvn.longcon(vp2.iv_scale()); + Node* span1 = new MulLNode(last_minus_init, iv_scale1); + Node* span2 = new MulLNode(last_minus_init, iv_scale2); + + phase->register_new_node_with_ctrl_of(last_minus_init, pre_init); + phase->register_new_node_with_ctrl_of(span1, pre_init); + phase->register_new_node_with_ctrl_of(span2, pre_init); + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print("main_limitL: "); main_limitL->dump(); + tty->print("main_lastL: "); main_lastL->dump(); + tty->print("p1_init: "); p1_init->dump(); + tty->print("p2_init: "); p2_init->dump(); + tty->print("size1: "); size1->dump(); + tty->print("size2: "); size2->dump(); + tty->print_cr("span1: "); span1->dump_bfs(5, nullptr, ""); + tty->print_cr("span2: "); span2->dump_bfs(5, nullptr, ""); + } +#endif + + Node* p1_init_plus_span1 = new AddLNode(p1_init, span1); + Node* p2_init_plus_span2 = new AddLNode(p2_init, span2); + phase->register_new_node_with_ctrl_of(p1_init_plus_span1, pre_init); + phase->register_new_node_with_ctrl_of(p2_init_plus_span2, pre_init); + if (_vloop.iv_stride() >= 0) { + condition1 = make_a_plus_b_leq_c(p1_init, size1, p2_init, phase); + condition2 = make_a_plus_b_leq_c(p2_init_plus_span2, size2, p1_init_plus_span1, phase); + } else { + condition1 = make_a_plus_b_leq_c(p1_init_plus_span1, size1, p2_init_plus_span2, phase); + condition2 = make_a_plus_b_leq_c(p2_init, size2, p1_init, phase); + } + } + +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis() || _vloop.is_trace_speculative_runtime_checks()) { + tty->print_cr("condition1:"); + condition1->dump_bfs(5, nullptr, ""); + tty->print_cr("condition2:"); + condition2->dump_bfs(5, nullptr, ""); + } +#endif + + // Construct "condition1 OR condition2". Convert the bol value back to an int value + // that we can "OR" to create a single bol value. On x64, the two CMove are converted + // to two setbe instructions which capture the condition bits to a register, meaning + // we only have a single branch in the end. + Node* zero = igvn.intcon(0); + Node* one = igvn.intcon(1); + Node* cmov1 = new CMoveINode(condition1, zero, one, TypeInt::INT); + Node* cmov2 = new CMoveINode(condition2, zero, one, TypeInt::INT); + phase->register_new_node_with_ctrl_of(cmov1, main_initL); + phase->register_new_node_with_ctrl_of(cmov2, main_initL); + + Node* c1_or_c2 = new OrINode(cmov1, cmov2); + Node* cmp = CmpNode::make(c1_or_c2, zero, T_INT); + BoolNode* bol = new BoolNode(cmp, BoolTest::ne); + phase->register_new_node_with_ctrl_of(c1_or_c2, main_initL); + phase->register_new_node_with_ctrl_of(cmp, main_initL); + phase->register_new_node_with_ctrl_of(bol, main_initL); + + return bol; +} + +Node* VPointer::make_pointer_expression(Node* iv_value) const { + assert(is_valid(), "must be valid"); + + PhaseIdealLoop* phase = _vloop.phase(); + PhaseIterGVN& igvn = phase->igvn(); + Node* iv = _vloop.iv(); + Node* ctrl = phase->get_ctrl(iv_value); + + auto maybe_add = [&] (Node* n1, Node* n2, BasicType bt) { + if (n1 == nullptr) { return n2; } + Node* add = AddNode::make(n1, n2, bt); + phase->register_new_node(add, ctrl); + return add; + }; + + Node* expression = nullptr; + mem_pointer().for_each_raw_summand_of_int_group(0, [&] (const MemPointerRawSummand& s) { + Node* node = nullptr; + if (s.is_con()) { + // Long constant. + NoOverflowInt con = s.scaleI() * s.scaleL(); + node = igvn.longcon(con.value()); + } else { + // Long variable. + assert(s.scaleI().is_one(), "must be long variable"); + Node* scaleL = igvn.longcon(s.scaleL().value()); + Node* variable = (s.variable() == iv) ? iv_value : s.variable(); + if (variable->bottom_type()->isa_ptr() != nullptr) { + variable = new CastP2XNode(nullptr, variable); + phase->register_new_node(variable, ctrl); + } + node = new MulLNode(scaleL, variable); + phase->register_new_node(node, ctrl); + } + expression = maybe_add(expression, node, T_LONG); + }); + + int max_int_group = mem_pointer().max_int_group(); + for (int int_group = 1; int_group <= max_int_group; int_group++) { + Node* int_expression = nullptr; + NoOverflowInt int_group_scaleL; + mem_pointer().for_each_raw_summand_of_int_group(int_group, [&] (const MemPointerRawSummand& s) { + Node* node = nullptr; + if (s.is_con()) { + node = igvn.intcon(s.scaleI().value()); + } else { + Node* scaleI = igvn.intcon(s.scaleI().value()); + Node* variable = (s.variable() == iv) ? iv_value : s.variable(); + node = new MulINode(scaleI, variable); + phase->register_new_node(node, ctrl); + } + int_group_scaleL = s.scaleL(); // remember for multiplication after ConvI2L + int_expression = maybe_add(int_expression, node, T_INT); + }); + assert(int_expression != nullptr, "no empty int group"); + int_expression = new ConvI2LNode(int_expression); + phase->register_new_node(int_expression, ctrl); + Node* scaleL = igvn.longcon(int_group_scaleL.value()); + int_expression = new MulLNode(scaleL, int_expression); + phase->register_new_node(int_expression, ctrl); + expression = maybe_add(expression, int_expression, T_LONG); + } + + return expression; +} + #ifndef PRODUCT void VPointer::print_on(outputStream* st, bool end_with_cr) const { st->print("VPointer["); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 0af97eb78e4..baca0d5b927 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -29,6 +29,7 @@ #include "opto/matcher.hpp" #include "opto/mempointer.hpp" #include "opto/traceAutoVectorizationTag.hpp" +#include "utilities/growableArray.hpp" #include "utilities/pair.hpp" // Code in this file and the vectorization.cpp contains shared logics and @@ -161,6 +162,10 @@ public: _multiversioning_fast_proj != nullptr; } + bool use_speculative_aliasing_checks() const { + return are_speculative_checks_possible() && UseAutoVectorizationSpeculativeAliasingChecks; + } + // Estimate maximum size for data structures, to avoid repeated reallocation int estimated_body_length() const { return lpt()->_body.size(); }; int estimated_node_count() const { return (int)(1.10 * phase()->C->unique()); }; @@ -203,6 +208,10 @@ public: bool is_trace_speculative_runtime_checks() const { return _vtrace.is_trace(TraceAutoVectorizationTag::SPECULATIVE_RUNTIME_CHECKS); } + + bool is_trace_speculative_aliasing_analysis() const { + return _vtrace.is_trace(TraceAutoVectorizationTag::SPECULATIVE_ALIASING_ANALYSIS); + } #endif // Is the node in the basic block of the loop? @@ -222,15 +231,18 @@ public: return false; } + // Usually the ctrl of n is already before the pre-loop. Node* ctrl = phase()->get_ctrl(n); - - // Quick test: is it in the main-loop? - if (lpt()->is_member(phase()->get_loop(ctrl))) { - return false; + if (is_before_pre_loop(ctrl)) { + return true; } - // Is it before the pre-loop? - return phase()->is_dominator(ctrl, pre_loop_head()); + // But in some cases, the ctrl of n is between the pre and + // main loop, but the early ctrl is before the pre-loop. + // As long as the early ctrl is before the pre-loop, we can + // compute n before the pre-loop. + Node* early = phase()->compute_early_ctrl(n, ctrl); + return is_before_pre_loop(early); } // Check if the loop passes some basic preconditions for vectorization. @@ -239,6 +251,16 @@ public: private: VStatus check_preconditions_helper(); + + bool is_before_pre_loop(Node* ctrl) const { + // Quick test: is it in the main-loop? + if (lpt()->is_member(phase()->get_loop(ctrl))) { + return false; + } + + // Is it before the pre-loop? + return phase()->is_dominator(ctrl, pre_loop_head()); + } }; // Optimization to keep allocation of large arrays in AutoVectorization low. @@ -569,6 +591,9 @@ private: // - Memory-dependencies: the edges in the C2 memory-slice are too restrictive: for example all // stores are serialized, even if their memory does not overlap. Thus, // we refine the memory-dependencies (see construct method). +// - Strong edge: must be respected. +// - Weak edge: if we add a speculative aliasing check, we can violate +// the edge, i.e. swap the order. class VLoopDependencyGraph : public StackObj { private: class DependencyNode; @@ -611,7 +636,7 @@ public: bool mutually_independent(const Node_List* nodes) const; private: - void add_node(MemNode* n, GrowableArray& memory_pred_edges); + void add_node(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges); int depth(const Node* n) const { return _depths.at(_body.bb_idx(n)); } void set_depth(const Node* n, int d) { _depths.at_put(_body.bb_idx(n), d); } int find_max_pred_depth(const Node* n) const; @@ -625,16 +650,23 @@ private: class DependencyNode : public ArenaObj { private: MemNode* _node; // Corresponding ideal node - const uint _memory_pred_edges_length; - int* _memory_pred_edges; // memory pred-edges, mapping to bb_idx + const uint _num_strong_memory_edges; + const uint _num_weak_memory_edges; + int* _memory_edges; // memory pred-edges, mapping to bb_idx public: - DependencyNode(MemNode* n, GrowableArray& memory_pred_edges, Arena* arena); + DependencyNode(MemNode* n, GrowableArray& strong_memory_edges, GrowableArray& weak_memory_edges, Arena* arena); NONCOPYABLE(DependencyNode); - uint memory_pred_edges_length() const { return _memory_pred_edges_length; } + uint num_strong_memory_edges() const { return _num_strong_memory_edges; } + uint num_weak_memory_edges() const { return _num_weak_memory_edges; } - int memory_pred_edge(uint i) const { - assert(i < _memory_pred_edges_length, "bounds check"); - return _memory_pred_edges[i]; + int strong_memory_edge(uint i) const { + assert(i < _num_strong_memory_edges, "bounds check"); + return _memory_edges[i]; + } + + int weak_memory_edge(uint i) const { + assert(i < _num_weak_memory_edges, "bounds check"); + return _memory_edges[_num_strong_memory_edges + i]; } }; @@ -649,27 +681,40 @@ public: Node* _current; bool _is_current_memory_edge; + bool _is_current_weak_memory_edge; - // Iterate in node->in(i) - int _next_pred; - int _end_pred; + // Iterate in data edges, i.e. iterate node->in(i), excluding control and memory edges. + int _next_data_edge; + int _end_data_edge; + + // Iterate in dependency_node->strong_memory_edges() + int _next_strong_memory_edge; + int _end_strong_memory_edge; + + // Iterate in dependency_node->weak_memory_edge() + int _next_weak_memory_edge; + int _end_weak_memory_edge; - // Iterate in dependency_node->memory_pred_edge(i) - int _next_memory_pred; - int _end_memory_pred; public: PredsIterator(const VLoopDependencyGraph& dependency_graph, const Node* node); NONCOPYABLE(PredsIterator); void next(); bool done() const { return _current == nullptr; } + Node* current() const { assert(!done(), "not done yet"); return _current; } + bool is_current_memory_edge() const { assert(!done(), "not done yet"); return _is_current_memory_edge; } + + bool is_current_weak_memory_edge() const { + assert(!done(), "not done yet"); + return _is_current_weak_memory_edge; + } }; }; @@ -934,6 +979,43 @@ public: return mem_pointer().never_overlaps_with(other.mem_pointer()); } + // Delegate to MemPointer::always_overlaps_with, but guard for invalid cases + // where we must return a conservative answer: unknown overlap, return false. + bool always_overlaps_with(const VPointer& other) const { + if (!is_valid() || !other.is_valid()) { +#ifndef PRODUCT + if (_vloop.mptrace().is_trace_overlap()) { + tty->print_cr("VPointer::always_overlaps_with: invalid VPointer, overlap unknown."); + } +#endif + return false; + } + return mem_pointer().always_overlaps_with(other.mem_pointer()); + } + + static int cmp_summands(const VPointer& vp1, const VPointer& vp2) { + return MemPointer::cmp_summands(vp1.mem_pointer(), vp2.mem_pointer()); + } + + static int cmp_con(const VPointer& vp1, const VPointer& vp2) { + // We use two comparisons, because a subtraction could underflow. + jint con1 = vp1.con(); + jint con2 = vp2.con(); + if (con1 < con2) { return -1; } + if (con1 > con2) { return 1; } + return 0; + } + + static int cmp_summands_and_con(const VPointer& vp1, const VPointer& vp2) { + int cmp = cmp_summands(vp1, vp2); + if (cmp != 0) { return cmp; } + return cmp_con(vp1, vp2); + } + + bool can_make_speculative_aliasing_check_with(const VPointer& other) const; + Node* make_pointer_expression(Node* iv_value) const; + BoolNode* make_speculative_aliasing_check_with(const VPointer& other) const; + NOT_PRODUCT( void print_on(outputStream* st, bool end_with_cr = true) const; ) private: diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 8a9d4aed13e..1675b8d9fdb 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -23,6 +23,7 @@ #include "opto/castnode.hpp" #include "opto/convertnode.hpp" +#include "opto/vectorization.hpp" #include "opto/vectornode.hpp" #include "opto/vtransform.hpp" @@ -57,7 +58,7 @@ bool VTransformGraph::schedule() { VectorSet pre_visited; VectorSet post_visited; - collect_nodes_without_req_or_dependency(stack); + collect_nodes_without_strong_in_edges(stack); // We create a reverse-post-visit order. This gives us a linearization, if there are // no cycles. Then, we simply reverse the order, and we have a schedule. @@ -72,8 +73,11 @@ bool VTransformGraph::schedule() { // No -> we are mid-visit. bool all_uses_already_visited = true; - for (int i = 0; i < vtn->outs(); i++) { - VTransformNode* use = vtn->out(i); + // We only need to respect the strong edges (data edges and strong memory edges). + // Violated weak memory edges are allowed, but require a speculative aliasing + // runtime check, see VTransform::apply_speculative_aliasing_runtime_checks. + for (uint i = 0; i < vtn->out_strong_edges(); i++) { + VTransformNode* use = vtn->out_strong_edge(i); if (post_visited.test(use->_idx)) { continue; } if (pre_visited.test(use->_idx)) { // Cycle detected! @@ -109,11 +113,11 @@ bool VTransformGraph::schedule() { return true; } -// Push all "root" nodes, i.e. those that have no inputs (req or dependency): -void VTransformGraph::collect_nodes_without_req_or_dependency(GrowableArray& stack) const { +// Push all "root" nodes, i.e. those that have no strong input edges (data edges and strong memory edges): +void VTransformGraph::collect_nodes_without_strong_in_edges(GrowableArray& stack) const { for (int i = 0; i < _vtnodes.length(); i++) { VTransformNode* vtn = _vtnodes.at(i); - if (!vtn->has_req_or_dependency()) { + if (!vtn->has_strong_in_edge()) { stack.push(vtn); } } @@ -144,11 +148,11 @@ void VTransformApplyResult::trace(VTransformNode* vtnode) const { } #endif -void VTransform::apply_speculative_runtime_checks() { +void VTransform::apply_speculative_alignment_runtime_checks() { if (VLoop::vectors_should_be_aligned()) { #ifdef ASSERT if (_trace._align_vector || _trace._speculative_runtime_checks) { - tty->print_cr("\nVTransform::apply_speculative_runtime_checks: native memory alignment"); + tty->print_cr("\nVTransform::apply_speculative_alignment_runtime_checks: native memory alignment"); } #endif @@ -216,6 +220,206 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { add_speculative_check(bol_alignment); } +class VPointerWeakAliasingPair : public StackObj { +private: + // Using references instead of pointers would be preferrable, but GrowableArray + // requires a default constructor, and we do not have a default constructor for + // VPointer. + const VPointer* _vp1 = nullptr; + const VPointer* _vp2 = nullptr; + + VPointerWeakAliasingPair(const VPointer& vp1, const VPointer& vp2) : _vp1(&vp1), _vp2(&vp2) { + assert(vp1.is_valid(), "sanity"); + assert(vp2.is_valid(), "sanity"); + assert(!vp1.never_overlaps_with(vp2), "otherwise no aliasing"); + assert(!vp1.always_overlaps_with(vp2), "otherwise must be strong"); + assert(VPointer::cmp_summands_and_con(vp1, vp2) <= 0, "must be sorted"); + } + +public: + // Default constructor to make GrowableArray happy. + VPointerWeakAliasingPair() : _vp1(nullptr), _vp2(nullptr) {} + + static VPointerWeakAliasingPair make(const VPointer& vp1, const VPointer& vp2) { + if (VPointer::cmp_summands_and_con(vp1, vp2) <= 0) { + return VPointerWeakAliasingPair(vp1, vp2); + } else { + return VPointerWeakAliasingPair(vp2, vp1); + } + } + + const VPointer& vp1() const { return *_vp1; } + const VPointer& vp2() const { return *_vp2; } + + // Sort by summands, so that pairs with same summands (summand1, summands2) are adjacent. + static int cmp_for_sort(VPointerWeakAliasingPair* pair1, VPointerWeakAliasingPair* pair2) { + int cmp_summands1 = VPointer::cmp_summands(pair1->vp1(), pair2->vp1()); + if (cmp_summands1 != 0) { return cmp_summands1; } + return VPointer::cmp_summands(pair1->vp2(), pair2->vp2()); + } +}; + +void VTransform::apply_speculative_aliasing_runtime_checks() { + + if (_vloop.use_speculative_aliasing_checks()) { + +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nVTransform::apply_speculative_aliasing_runtime_checks: speculative aliasing analysis runtime checks"); + } +#endif + + // It would be nice to add a ResourceMark here. But it would collide with resource allocation + // in PhaseIdealLoop::set_idom for _idom and _dom_depth. See also JDK-8337015. + VectorSet visited; + GrowableArray weak_aliasing_pairs; + + const GrowableArray& schedule = _graph.get_schedule(); + for (int i = 0; i < schedule.length(); i++) { + VTransformNode* vtn = schedule.at(i); + for (uint i = 0; i < vtn->out_weak_edges(); i++) { + VTransformNode* use = vtn->out_weak_edge(i); + if (visited.test(use->_idx)) { + // The use node was already visited, i.e. is higher up in the schedule. + // The "out" edge thus points backward, i.e. it is violated. + const VPointer& vp1 = vtn->vpointer(_vloop_analyzer); + const VPointer& vp2 = use->vpointer(_vloop_analyzer); +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nViolated Weak Edge:"); + vtn->print(); + vp1.print_on(tty); + use->print(); + vp2.print_on(tty); + } +#endif + + // We could generate checks for the pair (vp1, vp2) directly. But in + // some graphs, this generates quadratically many checks. Example: + // + // set1: a[i+0] a[i+1] a[i+2] a[i+3] + // set2: b[i+0] b[i+1] b[i+2] b[i+3] + // + // We may have a weak memory edge between every memory access from + // set1 to every memory access from set2. In this example, this would + // be 4 * 4 = 16 checks. But instead, we can create a union VPointer + // for set1 and set2 each, and only create a single check. + // + // set1: a[i+0, size = 4] + // set1: b[i+0, size = 4] + // + // For this, we add all pairs to an array, and process it below. + weak_aliasing_pairs.push(VPointerWeakAliasingPair::make(vp1, vp2)); + } + } + visited.set(vtn->_idx); + } + + // Sort so that all pairs with the same summands (summands1, summands2) + // are consecutive, i.e. in the same group. This allows us to do a linear + // walk over all pairs of a group and create the union VPointers. + weak_aliasing_pairs.sort(VPointerWeakAliasingPair::cmp_for_sort); + + int group_start = 0; + while (group_start < weak_aliasing_pairs.length()) { + // New group: pick the first pair as the reference. + const VPointer* vp1 = &weak_aliasing_pairs.at(group_start).vp1(); + const VPointer* vp2 = &weak_aliasing_pairs.at(group_start).vp2(); + jint size1 = vp1->size(); + jint size2 = vp2->size(); + int group_end = group_start + 1; + while (group_end < weak_aliasing_pairs.length()) { + const VPointer* vp1_next = &weak_aliasing_pairs.at(group_end).vp1(); + const VPointer* vp2_next = &weak_aliasing_pairs.at(group_end).vp2(); + jint size1_next = vp1_next->size(); + jint size2_next = vp2_next->size(); + + // Different summands -> different group. + if (VPointer::cmp_summands(*vp1, *vp1_next) != 0) { break; } + if (VPointer::cmp_summands(*vp2, *vp2_next) != 0) { break; } + + // Pick the one with the lower con as the reference. + if (vp1->con() > vp1_next->con()) { + swap(vp1, vp1_next); + swap(size1, size1_next); + } + if (vp2->con() > vp2_next->con()) { + swap(vp2, vp2_next); + swap(size2, size2_next); + } + + // Compute the distance from vp1 to vp1_next + size, to get a size that would include vp1_next. + NoOverflowInt new_size1 = NoOverflowInt(vp1_next->con()) + NoOverflowInt(size1_next) - NoOverflowInt(vp1->con()); + NoOverflowInt new_size2 = NoOverflowInt(vp2_next->con()) + NoOverflowInt(size2_next) - NoOverflowInt(vp2->con()); + if (new_size1.is_NaN() || new_size2.is_NaN()) { break; /* overflow -> new group */ } + + // The "next" VPointer indeed belong to the group. + // + // vp1: |--------------> + // vp1_next: |----------------> + // result: |--------------------------> + // + // vp1: |--------------------------> + // vp1_next: |-------> + // result: |--------------------------> + // + size1 = MAX2(size1, new_size1.value()); + size2 = MAX2(size2, new_size2.value()); + group_end++; + } + // Create "union" VPointer that cover all VPointer from the group. + const VPointer vp1_union = vp1->make_with_size(size1); + const VPointer vp2_union = vp2->make_with_size(size2); + +#ifdef ASSERT + if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { + tty->print_cr("\nUnion of %d weak aliasing edges:", group_end - group_start); + vp1_union.print_on(tty); + vp2_union.print_on(tty); + } + + // Verification - union must contain all VPointer of the group. + for (int i = group_start; i < group_end; i++) { + const VPointer& vp1_i = weak_aliasing_pairs.at(i).vp1(); + const VPointer& vp2_i = weak_aliasing_pairs.at(i).vp2(); + assert(vp1_union.con() <= vp1_i.con(), "must start before"); + assert(vp2_union.con() <= vp2_i.con(), "must start before"); + assert(vp1_union.size() >= vp1_i.size(), "must end after"); + assert(vp2_union.size() >= vp2_i.size(), "must end after"); + } +#endif + + BoolNode* bol = vp1_union.make_speculative_aliasing_check_with(vp2_union); + add_speculative_check(bol); + + group_start = group_end; + } + } +} + +// Runtime Checks: +// Some required properties cannot be proven statically, and require a +// runtime check: +// - Alignment: +// See VTransform::add_speculative_alignment_check +// - Aliasing: +// See VTransform::apply_speculative_aliasing_runtime_checks +// There is a two staged approach for compilation: +// - AutoVectorization Predicate: +// See VM flag UseAutoVectorizationPredicate and documentation in predicates.hpp +// We speculate that the checks pass, and only compile a vectorized loop. +// We expect the checks to pass in almost all cases, and so we only need +// to compile and cache the vectorized loop. +// If the predicate ever fails, we deoptimize, and eventually compile +// without predicate. This means we will recompile with multiversioning. +// - Multiversioning: +// See VM Flag LoopMultiversioning and documentaiton in loopUnswitch.cpp +// If the predicate is not available or previously failed, then we compile +// a vectorized and a scalar loop. If the runtime check passes we take the +// vectorized loop, else the scalar loop. +// Multiversioning takes more compile time and code cache, but it also +// produces fast code for when the runtime check passes (vectorized) and +// when it fails (scalar performance). void VTransform::add_speculative_check(BoolNode* bol) { assert(_vloop.are_speculative_checks_possible(), "otherwise we cannot make speculative assumptions"); ParsePredicateSuccessProj* parse_predicate_proj = _vloop.auto_vectorization_parse_predicate_proj(); @@ -494,7 +698,7 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& } Node* VTransformNode::find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const { - Node* n = vnode_idx_to_transformed_node.at(in(i)->_idx); + Node* n = vnode_idx_to_transformed_node.at(in_req(i)->_idx); assert(n != nullptr, "must find input IR node"); return n; } @@ -616,7 +820,7 @@ VTransformApplyResult VTransformBoolVectorNode::apply(const VLoopAnalyzer& vloop BasicType bt = vloop_analyzer.types().velt_basic_type(first); // Cmp + Bool -> VectorMaskCmp - VTransformElementWiseVectorNode* vtn_cmp = in(1)->isa_ElementWiseVector(); + VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), "bool vtn expects cmp vtn as input"); @@ -750,15 +954,27 @@ void VTransformNode::print() const { print_node_idx(_in.at(i)); } if ((uint)_in.length() > _req) { - tty->print(" |"); - for (int i = _req; i < _in.length(); i++) { + tty->print(" | strong:"); + for (uint i = _req; i < _in_end_strong_memory_edges; i++) { + print_node_idx(_in.at(i)); + } + } + if ((uint)_in.length() > _in_end_strong_memory_edges) { + tty->print(" | weak:"); + for (uint i = _in_end_strong_memory_edges; i < (uint)_in.length(); i++) { print_node_idx(_in.at(i)); } } tty->print(") ["); - for (int i = 0; i < _out.length(); i++) { + for (uint i = 0; i < _out_end_strong_edges; i++) { print_node_idx(_out.at(i)); } + if ((uint)_out.length() > _out_end_strong_edges) { + tty->print(" | weak:"); + for (uint i = _out_end_strong_edges; i < (uint)_out.length(); i++) { + print_node_idx(_out.at(i)); + } + } tty->print("] "); print_spec(); tty->cr(); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 555f565360d..397d712366b 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -109,19 +109,22 @@ public: const bool _verbose; const bool _rejections; const bool _align_vector; + const bool _speculative_aliasing_analysis; const bool _speculative_runtime_checks; const bool _info; VTransformTrace(const VTrace& vtrace, const bool is_trace_rejections, const bool is_trace_align_vector, + const bool is_trace_speculative_aliasing_analysis, const bool is_trace_speculative_runtime_checks, const bool is_trace_info) : _verbose (vtrace.is_trace(TraceAutoVectorizationTag::ALL)), - _rejections (_verbose | is_trace_vtransform(vtrace) | is_trace_rejections), - _align_vector (_verbose | is_trace_vtransform(vtrace) | is_trace_align_vector), - _speculative_runtime_checks(_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_runtime_checks), - _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} + _rejections (_verbose | is_trace_vtransform(vtrace) | is_trace_rejections), + _align_vector (_verbose | is_trace_vtransform(vtrace) | is_trace_align_vector), + _speculative_aliasing_analysis (_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_aliasing_analysis), + _speculative_runtime_checks (_verbose | is_trace_vtransform(vtrace) | is_trace_speculative_runtime_checks), + _info (_verbose | is_trace_vtransform(vtrace) | is_trace_info) {} static bool is_trace_vtransform(const VTrace& vtrace) { return vtrace.is_trace(TraceAutoVectorizationTag::VTRANSFORM); @@ -161,6 +164,7 @@ public: DEBUG_ONLY( bool is_empty() const { return _vtnodes.is_empty(); } ) DEBUG_ONLY( bool is_scheduled() const { return _schedule.is_nonempty(); } ) const GrowableArray& vtnodes() const { return _vtnodes; } + const GrowableArray& get_schedule() const { return _schedule; } bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; @@ -173,7 +177,7 @@ private: PhaseIterGVN& igvn() const { return _vloop.phase()->igvn(); } bool in_bb(const Node* n) const { return _vloop.in_bb(n); } - void collect_nodes_without_req_or_dependency(GrowableArray& stack) const; + void collect_nodes_without_strong_in_edges(GrowableArray& stack) const; template void for_each_memop_in_schedule(Callback callback) const; @@ -248,7 +252,8 @@ private: void determine_mem_ref_and_aw_for_main_loop_alignment(); void adjust_pre_loop_limit_to_align_main_loop_vectors(); - void apply_speculative_runtime_checks(); + void apply_speculative_alignment_runtime_checks(); + void apply_speculative_aliasing_runtime_checks(); void add_speculative_alignment_check(Node* node, juint alignment); void add_speculative_check(BoolNode* bol); @@ -259,22 +264,52 @@ private: // VTransform. Many such vtnodes make up the VTransformGraph. The vtnodes represent // the resulting scalar and vector nodes as closely as possible. // See description at top of this file. +// +// There are 3 tyes of edges: +// - data edges (req): corresponding to C2 IR Node data edges, except control +// and memory. +// - strong memory edges: memory edges that must be respected when scheduling. +// - weak memory edges: memory edges that can be violated, but if violated then +// corresponding aliasing analysis runtime checks must be +// inserted. +// +// Strong edges: union of data edges and strong memory edges. +// These must be respected by scheduling in all cases. +// +// The C2 IR Node memory edges essentially define a linear order of all memory operations +// (only Loads with the same memory input can be executed in an arbitrary order). This is +// efficient, because it means every Load and Store has exactly one input memory edge, +// which keeps the memory edge count linear. This is approach is too restrictive for +// vectorization, for example, we could never vectorize stores, since they are all in a +// dependency chain. Instead, we model the memory edges between all memory nodes, which +// could be quadratic in the worst case. For vectorization, we must essentially reorder the +// instructions in the graph. For this we must model all memory dependencies. class VTransformNode : public ArenaObj { public: const VTransformNodeIDX _idx; private: - // _in is split into required inputs (_req, i.e. all data dependencies), - // and memory dependencies. + // We split _in into 3 sections: + // - data edges (req): _in[0 .. _req-1] + // - strong memory edges: _in[_req .. _in_end_strong_memory_edges-1] + // - weak memory edges: _in[_in_end_strong_memory_edges .. ] const uint _req; + uint _in_end_strong_memory_edges; GrowableArray _in; + + // We split _out into 2 sections: + // - strong edges: _out[0 .. _out_end_strong_edges-1] + // - weak memory edges: _out[_out_end_strong_edges .. _len-1] + uint _out_end_strong_edges; GrowableArray _out; public: VTransformNode(VTransform& vtransform, const uint req) : _idx(vtransform.graph().new_idx()), _req(req), + _in_end_strong_memory_edges(req), _in(vtransform.arena(), req, req, nullptr), + _out_end_strong_edges(0), _out(vtransform.arena(), 4, 0, nullptr) { vtransform.graph().add_vtnode(this); @@ -284,7 +319,7 @@ public: assert(i < _req, "must be a req"); assert(_in.at(i) == nullptr && n != nullptr, "only set once"); _in.at_put(i, n); - n->add_out(this); + n->add_out_strong_edge(this); } void swap_req(uint i, uint j) { @@ -295,23 +330,67 @@ public: _in.at_put(j, tmp); } - void add_memory_dependency(VTransformNode* n) { + void add_strong_memory_edge(VTransformNode* n) { assert(n != nullptr, "no need to add nullptr"); - _in.push(n); - n->add_out(this); + if (_in_end_strong_memory_edges < (uint)_in.length()) { + // Put n in place of first weak memory edge, and move + // the weak memory edge to the end. + VTransformNode* first_weak = _in.at(_in_end_strong_memory_edges); + _in.at_put(_in_end_strong_memory_edges, n); + _in.push(first_weak); + } else { + _in.push(n); + } + _in_end_strong_memory_edges++; + n->add_out_strong_edge(this); } - void add_out(VTransformNode* n) { + void add_weak_memory_edge(VTransformNode* n) { + assert(n != nullptr, "no need to add nullptr"); + _in.push(n); + n->add_out_weak_memory_edge(this); + } + +private: + void add_out_strong_edge(VTransformNode* n) { + if (_out_end_strong_edges < (uint)_out.length()) { + // Put n in place of first weak memory edge, and move + // the weak memory edge to the end. + VTransformNode* first_weak = _out.at(_out_end_strong_edges); + _out.at_put(_out_end_strong_edges, n); + _out.push(first_weak); + } else { + _out.push(n); + } + _out_end_strong_edges++; + } + + void add_out_weak_memory_edge(VTransformNode* n) { _out.push(n); } +public: uint req() const { return _req; } - VTransformNode* in(int i) const { return _in.at(i); } - int outs() const { return _out.length(); } - VTransformNode* out(int i) const { return _out.at(i); } + uint out_strong_edges() const { return _out_end_strong_edges; } + uint out_weak_edges() const { return _out.length() - _out_end_strong_edges; } - bool has_req_or_dependency() const { - for (int i = 0; i < _in.length(); i++) { + VTransformNode* in_req(uint i) const { + assert(i < _req, "must be a req"); + return _in.at(i); + } + + VTransformNode* out_strong_edge(uint i) const { + assert(i < out_strong_edges(), "must be a strong memory edge or data edge"); + return _out.at(i); + } + + VTransformNode* out_weak_edge(uint i) const { + assert(i < out_weak_edges(), "must be a strong memory edge"); + return _out.at(_out_end_strong_edges + i); + } + + bool has_strong_in_edge() const { + for (uint i = 0; i < _in_end_strong_memory_edges; i++) { if (_in.at(i) != nullptr) { return true; } } return false; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java index 20e6d631ffd..7d474f942a4 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java @@ -31,6 +31,7 @@ import jdk.internal.misc.Unsafe; import java.util.Random; import java.util.Arrays; import java.nio.ByteOrder; +import java.util.List; /* * @test @@ -50,19 +51,24 @@ public class TestVectorizationMismatchedAccess { private final static WhiteBox wb = WhiteBox.getWhiteBox(); public static void main(String[] args) { - // Cross-product: +-AlignVector and +-UseCompactObjectHeaders - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:-UseCompactObjectHeaders", - "-XX:-AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:-UseCompactObjectHeaders", - "-XX:+AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UseCompactObjectHeaders", - "-XX:-AlignVector"); - TestFramework.runWithFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+UseCompactObjectHeaders", - "-XX:+AlignVector"); + TestFramework framework = new TestFramework(); + framework.addFlags("--add-modules", "java.base", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:+UnlockExperimentalVMOptions"); + + // Cross-product: + // +-AlignVector + // +-UseCompactObjectHeaders + // +-UseAutoVectorizationSpeculativeAliasingChecks + int idx = 0; + for (String av : List.of("-XX:-AlignVector", "-XX:+AlignVector")) { + for (String coh : List.of("-XX:-UseCompactObjectHeaders", "-XX:+UseCompactObjectHeaders")) { + for (String sac : List.of("-XX:-UseAutoVectorizationSpeculativeAliasingChecks", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks")) { + framework.addScenarios(new Scenario(idx++, av, coh, sac)); + } + } + } + + framework.start(); } static int size = 1024; @@ -126,7 +132,7 @@ public class TestVectorizationMismatchedAccess { } } for (; i < Math.min(byteArray.length + offset, byteArray.length); i++) { - int val = offset > 0 ? verifyByteArray[(i-offset) % 8] : verifyByteArray[i-offset]; + int val = offset >=1 ? verifyByteArray[(i-offset) % 8] : verifyByteArray[i-offset]; if (byteArray[i] != val) { throw new RuntimeException("Incorrect result at " + i + " " + byteArray[i] + " != " + verifyByteArray[i-offset]); } @@ -479,7 +485,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte3a(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -487,7 +500,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte3b(byte[] dest, byte[] src) { for (int i = 0; i < src.length / 8 - 1; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); @@ -501,7 +521,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte4a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -509,7 +536,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte4b(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); @@ -524,7 +558,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte5a(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i)); @@ -532,7 +573,14 @@ public class TestVectorizationMismatchedAccess { } @Test - @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }) + @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR }, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1", ".*multiversion.*", ">=1"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true", "rvv", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}) + // We have unknown aliasing. At runtime "dest == src", so the AutoVectorization Predicate fails, and recompiles with Multiversioning. public static void testByteByte5b(byte[] dest, byte[] src, int start, int stop) { for (int i = start; i < stop; i++) { UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i)); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java new file mode 100644 index 00000000000..33cef6e5e6b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing nCOH_yAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestAliasing yCOH_yAV_nSAC + */ + +package compiler.loopopts.superword; + +import jdk.test.lib.Utils; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import static compiler.lib.generators.Generators.G; +import compiler.lib.generators.Generator; + +/** + * More complicated test cases can be found in {@link TestAliasingFuzzing}. + */ +public class TestAliasing { + static int SIZE = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + private static final Generator INT_GEN = G.ints(); + + // Invariants used in tests. + public static int INVAR_ZERO = 0; + + // Original data. + public static byte[] ORIG_AB = fillRandom(new byte[SIZE]); + public static byte[] ORIG_BB = fillRandom(new byte[SIZE]); + public static int[] ORIG_AI = fillRandom(new int[SIZE]); + public static int[] ORIG_BI = fillRandom(new int[SIZE]); + + // The data we use in the tests. It is initialized from ORIG_* every time. + public static byte[] AB = new byte[SIZE]; + public static byte[] BB = new byte[SIZE]; + public static int[] AI = new int[SIZE]; + public static int[] BI = new int[SIZE]; + + // Parallel to data above, but for use in reference methods. + public static byte[] AB_REFERENCE = new byte[SIZE]; + public static byte[] BB_REFERENCE = new byte[SIZE]; + public static int[] AI_REFERENCE = new int[SIZE]; + public static int[] BI_REFERENCE = new int[SIZE]; + + interface TestFunction { + void run(); + } + + // Map of goldTests, i.e. tests that work with a golds value generated from the same test method, + // at the beginning when we are still executing in the interpreter. + Map goldTests = new HashMap(); + + // Map of gold, the results from the first run before compilation, one per goldTests entry. + Map golds = new HashMap(); + + // Map of referenceTests, i.e. tests that have a reference implementation that is run with the interpreter. + // The TestFunction must run both the test and reference methods. + Map referenceTests = new HashMap(); + + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestAliasing.class); + switch (args[0]) { + case "nCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + }; + framework.start(); + } + + public TestAliasing() { + // Add all goldTests to list + goldTests.put("copy_B_sameIndex_noalias", () -> { copy_B_sameIndex_noalias(AB, BB); }); + goldTests.put("copy_B_sameIndex_alias", () -> { copy_B_sameIndex_alias(AB, AB); }); + goldTests.put("copy_B_differentIndex_noalias", () -> { copy_B_differentIndex_noalias(AB, BB); }); + goldTests.put("copy_B_differentIndex_noalias_v2", () -> { copy_B_differentIndex_noalias_v2(); }); + goldTests.put("copy_B_differentIndex_alias", () -> { copy_B_differentIndex_alias(AB, AB); }); + + goldTests.put("copy_I_sameIndex_noalias", () -> { copy_I_sameIndex_noalias(AI, BI); }); + goldTests.put("copy_I_sameIndex_alias", () -> { copy_I_sameIndex_alias(AI, AI); }); + goldTests.put("copy_I_differentIndex_noalias", () -> { copy_I_differentIndex_noalias(AI, BI); }); + goldTests.put("copy_I_differentIndex_alias", () -> { copy_I_differentIndex_alias(AI, AI); }); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + init(); + test.run(); + Object gold = snapshotCopy(); + golds.put(name, gold); + } + + referenceTests.put("fill_B_sameArray_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_B_sameArray_alias(AB, AB, invar1, invar2); + reference_fill_B_sameArray_alias(AB_REFERENCE, AB_REFERENCE, invar1, invar2); + }); + referenceTests.put("fill_B_sameArray_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_B_sameArray_noalias(AB, AB, invar1, invar2, limit); + reference_fill_B_sameArray_noalias(AB_REFERENCE, AB_REFERENCE, invar1, invar2, limit); + }); + } + + public static void init() { + System.arraycopy(ORIG_AB, 0, AB, 0, SIZE); + System.arraycopy(ORIG_BB, 0, BB, 0, SIZE); + System.arraycopy(ORIG_AI, 0, AI, 0, SIZE); + System.arraycopy(ORIG_BI, 0, BI, 0, SIZE); + } + + public static void initReference() { + System.arraycopy(ORIG_AB, 0, AB_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_BB, 0, BB_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_AI, 0, AI_REFERENCE, 0, SIZE); + System.arraycopy(ORIG_BI, 0, BI_REFERENCE, 0, SIZE); + } + + public static Object snapshotCopy() { + return new Object[] { + AB.clone(), BB.clone(), + AI.clone(), BI.clone() + }; + } + + public static Object snapshot() { + return new Object[] { + AB, BB, + AI, BI + }; + } + + public static Object snapshotReference() { + return new Object[] { + AB_REFERENCE, BB_REFERENCE, + AI_REFERENCE, BI_REFERENCE + }; + } + + @Warmup(100) + @Run(test = {"copy_B_sameIndex_noalias", + "copy_B_sameIndex_alias", + "copy_B_differentIndex_noalias", + "copy_B_differentIndex_noalias_v2", + "copy_B_differentIndex_alias", + "copy_I_sameIndex_noalias", + "copy_I_sameIndex_alias", + "copy_I_differentIndex_noalias", + "copy_I_differentIndex_alias", + "test_fill_B_sameArray_alias", + "test_fill_B_sameArray_noalias"}) + public void runTests() { + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object gold = golds.get(name); + // Compute new result + init(); + test.run(); + Object result = snapshot(); + // Compare gold and new result + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + + for (Map.Entry entry : referenceTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Init data for test and reference + init(); + initReference(); + // Run test and reference + test.run(); + // Capture results from test and reference + Object result = snapshot(); + Object expected = snapshotReference(); + // Compare expected and new result + try { + Verify.checkEQ(expected, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + } + + static byte[] fillRandom(byte[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = (byte)(int)INT_GEN.next(); + } + return a; + } + + static int[] fillRandom(int[] a) { + G.fill(INT_GEN, a); + return a; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_B_sameIndex_noalias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_B_sameIndex_alias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_B_differentIndex_noalias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + // + // Same as "copy_B_differentIndex_noalias, but somehow loading from fields rather + // than arguments does not lead to vectorization. + static void copy_B_differentIndex_noalias_v2() { + for (int i = 0; i < AB.length; i++) { + BB[i] = AB[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_B_differentIndex_alias(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_I_sameIndex_noalias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Should always vectorize, no speculative runtime check required. + static void copy_I_sameIndex_alias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, they never fail, so no multiversioning required. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_I_differentIndex_noalias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + static void copy_I_differentIndex_alias(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i + INVAR_ZERO]; + } + } + + @Test + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + ".*pre .* multiversion_fast.*", "= 1", + ".*main .* multiversion_fast.*", "= 1", + ".*post .* multiversion_fast.*", "= 2", // vectorized and scalar versions + ".*multiversion_slow.*", "= 2", // main and post (pre-loop only has a single iteration) + ".*multiversion.*", "= 6"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, it fails and so we do need multiversioning. + // With AlignVector we cannot prove that both accesses are alignable. + // + // FYI: invar1 and invar2 are small values, only used to test that everything runs + // correctly with at different offsets / with different alignment. + static void test_fill_B_sameArray_alias(byte[] a, byte[] b, int invar1, int invar2) { + for (int i = 0; i < a.length - 100; i++) { + a[i + invar1] = (byte)0x0a; + b[a.length - i - 1 - invar2] = (byte)0x0b; + } + } + + @DontCompile + static void reference_fill_B_sameArray_alias(byte[] a, byte[] b, int invar1, int invar2) { + for (int i = 0; i < a.length - 100; i++) { + a[i + invar1] = (byte)0x0a; + b[a.length - i - 1 - invar2] = (byte)0x0b; + } + } + + @Test + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Without speculative runtime check we cannot know that there is no aliasing. + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // We use speculative runtime checks, and they should not fail, so no multiversioning. + static void test_fill_B_sameArray_noalias(byte[] a, byte[] b, int invar1, int invar2, int limit) { + for (int i = 0; i < limit; i++) { + a[invar1 + i] = (byte)0x0a; + b[invar2 - i] = (byte)0x0b; + } + } + + @DontCompile + static void reference_fill_B_sameArray_noalias(byte[] a, byte[] b, int invar1, int invar2, int limit) { + for (int i = 0; i < limit; i++) { + a[invar1 + i] = (byte)0x0a; + b[invar2 - i] = (byte)0x0b; + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java new file mode 100644 index 00000000000..e13baf6882b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingFuzzer.java @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=vanilla + * @bug 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @compile ../../../compiler/lib/generators/Generators.java + * @compile ../../../compiler/lib/verify/Verify.java + * @run driver compiler.loopopts.superword.TestAliasingFuzzer vanilla + */ + +/* + * @test id=random-flags + * @bug 8324751 + * @summary Test Speculative Aliasing checks in SuperWord + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../../compiler/lib/ir_framework/TestFramework.java + * @compile ../../../compiler/lib/generators/Generators.java + * @compile ../../../compiler/lib/verify/Verify.java + * @run driver compiler.loopopts.superword.TestAliasingFuzzer random-flags + */ + +package compiler.loopopts.superword; + +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.Random; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import jdk.test.lib.Utils; + +import compiler.lib.compile_framework.*; +import compiler.lib.generators.Generators; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.body; +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.$; + +import compiler.lib.template_framework.library.TestFrameworkClass; + +/** + * Simpler test cases can be found in {@link TestAliasing}. + * + * We randomly generate tests to verify the behavior of the aliasing runtime checks. We feature: + * - Different primitive types: + * - for access type (primitive, we can have multiple types in a single loop) + * - for backing type (primitive and additionally we have native memory) + * - Different AccessScenarios: + * - copy (load and store) + * - fill (using two stores) + * - Different Aliasing: in some cases we never alias at runtime, in other cases we might + * -> Should exercise both the predicate and the multiversioning approach with the + * aliasing runtime checks. + * - Backing memory + * - Arrays: using int-index + * - MemorySegment (backed by primitive array or native memory): + * - Using long-index with MemorySegment::getAtIndex + * - Using byte-offset with MemorySegment::get + * - Loop iv: + * - forward (counting up) and backward (counting down) + * - Different iv stride: + * - inc/dec by one, and then scale with ivScale: for (..; i++) { access(i * 4); } + * - abs(ivScale) == 1, but use iv stride instead: for (..; i+=4) { access(i); } + * - type of index, invars, and bounds (see isLongIvType) + * - int: for array and MemorySegment + * - long: for MemorySegment + * - IR rules: + * - Verify that verification does (not) happen as expected. + * - Verify that we do not use multiversioning when no aliasing is expected at runtime. + * -> verify that the aliasing runtime check is not overly sensitive, so that the + * predicate does not fail unnecessarily and we have to recompile with multiversioning. + * + * Possible extensions (Future Work): + * - Access with Unsafe + * - Backing memory with Buffers + * - AccessScenario: + * - More than two accesses + * - Improve IR rules, once more cases vectorize (see e.g. JDK-8359688) + * - Aliasing: + * - MemorySegment on same backing memory, creating different MemorySegments + * via slicing. Possibly overlapping MemorySegments. + * - CONTAINER_UNKNOWN_ALIASING_NEVER: currently always has different + * memory and split ranges. But we could alternate between same memory + * and split ranges, and then different memory but overlapping ranges. + * This would also be never aliasing. + * + */ +public class TestAliasingFuzzer { + private static final Random RANDOM = Utils.getRandomInstance(); + + public record MyType(String name, int byteSize, String con1, String con2, String layout) { + @Override + public String toString() { return name(); } + + public String letter() { return name().substring(0, 1).toUpperCase(); } + } + public static final String con1 = "0x0102030405060708L"; + public static final String con2 = "0x0910111213141516L"; + public static final String con1F = "Float.intBitsToFloat(0x01020304)"; + public static final String con2F = "Float.intBitsToFloat(0x09101112)"; + public static final String con1D = "Double.longBitsToDouble(" + con1 + ")"; + public static final String con2D = "Double.longBitsToDouble(" + con2 + ")"; + + // List of primitive types for accesses and arrays. + public static final MyType myByte = new MyType("byte", 1, con1, con2, "ValueLayout.JAVA_BYTE"); + public static final MyType myChar = new MyType("char", 2, con1, con2, "ValueLayout.JAVA_CHAR_UNALIGNED"); + public static final MyType myShort = new MyType("short", 2, con1, con2, "ValueLayout.JAVA_SHORT_UNALIGNED"); + public static final MyType myInt = new MyType("int", 4, con1, con2, "ValueLayout.JAVA_INT_UNALIGNED"); + public static final MyType myLong = new MyType("long", 8, con1, con2, "ValueLayout.JAVA_LONG_UNALIGNED"); + public static final MyType myFloat = new MyType("float", 4, con1F, con2F, "ValueLayout.JAVA_FLOAT_UNALIGNED"); + public static final MyType myDouble = new MyType("double", 8, con1D, con2D, "ValueLayout.JAVA_DOUBLE_UNALIGNED"); + public static final List primitiveTypes + = List.of(myByte, myChar, myShort, myInt, myLong, myFloat, myDouble); + + // For native memory, we use this "fake" type. It has a byteSize of 1, since we measure the memory in bytes. + public static final MyType myNative = new MyType("native", 1, null, null, null); + public static final List primitiveTypesAndNative + = List.of(myByte, myChar, myShort, myInt, myLong, myFloat, myDouble, myNative); + + // Do the containers (array, MemorySegment, etc) ever overlap? + enum Aliasing { + CONTAINER_DIFFERENT, + CONTAINER_SAME_ALIASING_NEVER, + CONTAINER_SAME_ALIASING_UNKNOWN, + CONTAINER_UNKNOWN_ALIASING_NEVER, + CONTAINER_UNKNOWN_ALIASING_UNKNOWN, + } + + enum AccessScenario { + COPY_LOAD_STORE, // a[i1] = b[i2]; + FILL_STORE_STORE, // a[i1] = x; b[i2] = y; + } + + enum ContainerKind { + ARRAY, + MEMORY_SEGMENT_LONG_ADR_SCALE, // for (..; i++) { access(i * 4); } + MEMORY_SEGMENT_LONG_ADR_STRIDE, // for (..; i+=4) { access(i); } + MEMORY_SEGMENT_AT_INDEX, + } + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + long t0 = System.nanoTime(); + // Add a java source file. + comp.addJavaSourceCode("compiler.loopopts.superword.templated.AliasingFuzzer", generate(comp)); + + long t1 = System.nanoTime(); + // Compile the source file. + comp.compile(); + + long t2 = System.nanoTime(); + + String[] flags = switch(args[0]) { + case "vanilla" -> new String[] {}; + case "random-flags" -> randomFlags(); + default -> throw new RuntimeException("unknown run id=" + args[0]); + }; + // Run the tests without any additional VM flags. + // compiler.loopopts.superword.templated.AliasingFuzzer.main(new String[] {}); + comp.invoke("compiler.loopopts.superword.templated.AliasingFuzzer", "main", new Object[] {flags}); + long t3 = System.nanoTime(); + + System.out.println("Code Generation: " + (t1-t0) * 1e-9f); + System.out.println("Code Compilation: " + (t2-t1) * 1e-9f); + System.out.println("Running Tests: " + (t3-t2) * 1e-9f); + } + + public static String[] randomFlags() { + // We don't want to always run with all flags, that is too expensive. + // But let's make sure things don't completely, rot by running with some + // random flags that are relevant. + // We set the odds towards the "default" we are targetting. + return new String[] { + // Default disabled. + "-XX:" + randomPlusMinus(1, 5) + "AlignVector", + // Default enabled. + "-XX:" + randomPlusMinus(5, 1) + "UseAutoVectorizationSpeculativeAliasingChecks", + "-XX:" + randomPlusMinus(5, 1) + "UseAutoVectorizationPredicate", + "-XX:" + randomPlusMinus(5, 1) + "ShortRunningLongLoop", + // Either way is ok. + "-XX:" + randomPlusMinus(1, 1) + "UseCompactObjectHeaders", + "-XX:SuperWordAutomaticAlignment=" + RANDOM.nextInt(0,3) + }; + } + + public static String randomPlusMinus(int plus, int minus) { + return (RANDOM.nextInt(plus + minus) < plus) ? "+" : "-"; + } + + public static T sample(List list) { + int r = RANDOM.nextInt(list.size()); + return list.get(r); + } + + public static String generate(CompileFramework comp) { + // Create a list to collect all tests. + List testTemplateTokens = new ArrayList<>(); + + // Add some basic functionalities. + testTemplateTokens.add(generateIndexForm()); + + // Array tests + for (int i = 0; i < 10; i++) { + testTemplateTokens.add(TestGenerator.makeArray().generate()); + } + + // MemorySegment with getAtIndex / setAtIndex + for (int i = 0; i < 20; i++) { + testTemplateTokens.add(TestGenerator.makeMemorySegment().generate()); + } + + // Create the test class, which runs all testTemplateTokens. + return TestFrameworkClass.render( + // package and class name. + "compiler.loopopts.superword.templated", "AliasingFuzzer", + // List of imports. + Set.of("compiler.lib.generators.*", + "compiler.lib.verify.*", + "java.lang.foreign.*", + "java.util.Random", + "jdk.test.lib.Utils"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + testTemplateTokens); + } + + // The IndexForm is used to model the index. We can use it for arrays, but also by + // restricting the MemorySegment index to a simple index. + // + // Form: + // index = con + iv * ivScale + invar0 * invar0Scale + invarRest + // [err] + // + // The index has a size >= 1, so that the index refers to a region: + // [index, index + size] + // + // The idea is that invarRest is always close to zero, with some small range [-err .. err]. + // The invar variables for invarRest must be in the range [-1, 0, 1], so that we can + // estimate the error range from the invarRestScales. + // + // At runtime, we will have to generate inputs for the iv.lo/iv.hi, as well as the invar0, + // so that the index range lays in some predetermined range [range.lo, range.hi] and the + // ivStride: + // + // for (int iv = iv.lo; iv < iv.hi; iv += ivStride) { + // assert: range.lo <= index(iv) + // index(iv) + size <= range.hi + // } + // + // Since there are multiple memory accesses, we may have multiple indices to compute. + // Since they are all in the same loop, the indices share the same iv.lo and iv.hi. Hence, + // we fix either iv.lo or iv.hi, and compute the other via the constraints. + // + // Fix iv.lo, assume ivScale > 0: + // index(iv) is smallest for iv = iv.lo, so we must satisfy + // range.lo <= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.lo * ivScale + invar0 * invar0Scale - err + // It follows: + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // This allows us to pick a invar0. + // Now, we can compute the largest iv.lo possible. + // index(iv) is largest for iv = iv.hi, so we must satisfy: + // range.hi >= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.hi * ivScale + invar0 * invar0Scale + err + size + // It follows: + // iv.hi * ivScale <= range.hi - con - invar0 * invar0Scale - err - size + // This allows us to pick a iv.hi. + // + // More details can be found in the implementation below. + // + public static record IndexForm(int con, int ivScale, int invar0Scale, int[] invarRestScales, int size) { + public static IndexForm random(int numInvarRest, int size, int ivStrideAbs) { + int con = RANDOM.nextInt(-100_000, 100_000); + int ivScale = randomScale(size / ivStrideAbs); + int invar0Scale = randomScale(size); + int[] invarRestScales = new int[numInvarRest]; + // Sample values [-1, 0, 1] + for (int i = 0; i < invarRestScales.length; i++) { + invarRestScales[i] = RANDOM.nextInt(-1, 2); + } + return new IndexForm(con, ivScale, invar0Scale, invarRestScales, size); + } + + public static int randomScale(int size) { + int scale = switch(RANDOM.nextInt(10)) { + case 0 -> RANDOM.nextInt(1, 4 * size + 1); // any strided access + default -> size; // in most cases, we do not want it to be strided + }; + return RANDOM.nextBoolean() ? scale : -scale; + } + + public String generate() { + return "new IndexForm(" + con() + ", " + ivScale() + ", " + invar0Scale() + ", new int[] {" + + Arrays.stream(invarRestScales) + .mapToObj(String::valueOf) + .collect(Collectors.joining(", ")) + + "}, " + size() + ")"; + } + + public TemplateToken index(String invar0, String[] invarRest) { + var template = Template.make(() -> body( + let("con", con), + let("ivScale", ivScale), + let("invar0Scale", invar0Scale), + let("invar0", invar0), + "#con + #ivScale * i + #invar0Scale * #invar0", + IntStream.range(0, invarRestScales.length).mapToObj( + i -> List.of(" + ", invarRestScales[i], " * ", invarRest[i]) + ).toList() + )); + return template.asToken(); + } + + // MemorySegment need to be long-addressed, otherwise there can be int-overflow + // in the index, and that prevents RangeCheck Elimination and Vectorization. + public TemplateToken indexLong(String invar0, String[] invarRest) { + var template = Template.make(() -> body( + let("con", con), + let("ivScale", ivScale), + let("invar0Scale", invar0Scale), + let("invar0", invar0), + "#{con}L + #{ivScale}L * i + #{invar0Scale}L * #invar0", + IntStream.range(0, invarRestScales.length).mapToObj( + i -> List.of(" + ", invarRestScales[i], "L * ", invarRest[i]) + ).toList() + )); + return template.asToken(); + } + } + + // Mirror the IndexForm from the generator to the test. + public static TemplateToken generateIndexForm() { + var template = Template.make(() -> body( + """ + private static final Random RANDOM = Utils.getRandomInstance(); + + public static record IndexForm(int con, int ivScale, int invar0Scale, int[] invarRestScales, int size) { + public IndexForm { + if (ivScale == 0 || invar0Scale == 0) { + throw new RuntimeException("Bad scales: " + ivScale + " " + invar0Scale); + } + } + + public static record Range(int lo, int hi) { + public Range { + if (lo >= hi) { throw new RuntimeException("Bad range: " + lo + " " + hi); } + } + } + + public int err() { + int sum = 0; + for (int scale : invarRestScales) { sum += Math.abs(scale); } + return sum; + } + + public int invar0ForIvLo(Range range, int ivLo) { + if (ivScale > 0) { + // index(iv) is smallest for iv = ivLo, so we must satisfy: + // range.lo <= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.lo * ivScale + invar0 * invar0Scale - err + // It follows: + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + int rhs = range.lo() - con - ivLo * ivScale + err(); + int invar0 = (invar0Scale > 0) + ? + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // invar0 >= (range.lo - con - iv.lo * ivScale + err) / invar0Scale + Math.floorDiv(rhs + invar0Scale - 1, invar0Scale) // round up division + : + // invar0 * invar0Scale >= range.lo - con - iv.lo * ivScale + err + // invar0 <= (range.lo - con - iv.lo * ivScale + err) / invar0Scale + Math.floorDiv(rhs, invar0Scale); // round down division + if (range.lo() > con + ivLo * ivScale + invar0 * invar0Scale - err()) { + throw new RuntimeException("sanity check failed (1)"); + } + return invar0; + } else { + // index(iv) is largest for iv = ivLo, so we must satisfy: + // range.hi >= con + iv.lo * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.lo * ivScale + invar0 * invar0Scale + err + size + // It follows: + // invar0 * invar0Scale <= range.hi - con - iv.lo * ivScale - err - size + int rhs = range.hi() - con - ivLo * ivScale - err() - size(); + int invar0 = (invar0Scale > 0) + ? + // invar0 * invar0Scale <= rhs + // invar0 <= rhs / invar0Scale + Math.floorDiv(rhs, invar0Scale) // round down division + : + // invar0 * invar0Scale <= rhs + // invar0 >= rhs / invar0Scale + Math.floorDiv(rhs + invar0Scale + 1, invar0Scale); // round up division + if (range.hi() < con + ivLo * ivScale + invar0 * invar0Scale + err() + size()) { + throw new RuntimeException("sanity check failed (2)"); + } + return invar0; + + } + } + + public int ivHiForInvar0(Range range, int invar0) { + if (ivScale > 0) { + // index(iv) is largest for iv = ivHi, so we must satisfy: + // range.hi >= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + size + // >= con + iv.hi * ivScale + invar0 * invar0Scale + err + size + // It follows: + // iv.hi * ivScale <= range.hi - con - invar0 * invar0Scale - err - size + // iv.hi <= (range.hi - con - invar0 * invar0Scale - err - size) / ivScale + int rhs = range.hi() - con - invar0 * invar0Scale - err() - size(); + int ivHi = Math.floorDiv(rhs, ivScale); // round down division + if (range.hi() < con + ivHi * ivScale + invar0 * invar0Scale + err() + size()) { + throw new RuntimeException("sanity check failed (3)"); + } + return ivHi; + } else { + // index(iv) is smallest for iv = ivHi, so we must satisfy: + // range.lo <= con + iv.hi * ivScale + invar0 * invar0Scale + invarRest + // <= con + iv.hi * ivScale + invar0 * invar0Scale - err + // It follows: + // iv.hi * ivScale >= range.lo - con - invar0 * invar0Scale + err + // iv.hi <= (range.lo - con - invar0 * invar0Scale + err) / ivScale + int rhs = range.lo() - con - invar0 * invar0Scale + err(); + int ivHi = Math.floorDiv(rhs, ivScale); // round down division + if (range.lo() > con + ivHi * ivScale + invar0 * invar0Scale - err()) { + throw new RuntimeException("sanity check failed (4)"); + } + return ivHi; + + } + } + } + """ + )); + return template.asToken(); + } + + public static record TestGenerator( + // The containers. + int numContainers, + int containerByteSize, + ContainerKind containerKind, + MyType containerElementType, + + // Do we count up or down, iterate over the containers forward or backward? + boolean loopForward, + int ivStrideAbs, + boolean isLongIvType, + + // For all index forms: number of invariants in the rest, i.e. the [err] term. + int numInvarRest, + + // Each access has an index form and a type. + IndexForm[] accessIndexForm, + MyType[] accessType, + + // The scenario. + Aliasing aliasing, + AccessScenario accessScenario) { + + public static TestGenerator makeArray() { + // Sample some random parameters: + Aliasing aliasing = sample(Arrays.asList(Aliasing.values())); + AccessScenario accessScenario = sample(Arrays.asList(AccessScenario.values())); + MyType type = sample(primitiveTypes); + + // size must be large enough for: + // - scale = 4 + // - range with size / 4 + // -> need at least size 16_000 to ensure we have 1000 iterations + // We want there to be a little variation, so alignment is not always the same. + int numElements = Generators.G.safeRestrict(Generators.G.ints(), 18_000, 20_000).next(); + int containerByteSize = numElements * type.byteSize(); + boolean loopForward = RANDOM.nextBoolean(); + + int numInvarRest = RANDOM.nextInt(5); + int ivStrideAbs = 1; + boolean isLongIvType = false; // int index + var form0 = IndexForm.random(numInvarRest, 1, ivStrideAbs); + var form1 = IndexForm.random(numInvarRest, 1, ivStrideAbs); + + return new TestGenerator( + 2, + containerByteSize, + ContainerKind.ARRAY, + type, + loopForward, + ivStrideAbs, + isLongIvType, + numInvarRest, + new IndexForm[] {form0, form1}, + new MyType[] {type, type}, + aliasing, + accessScenario); + } + + public static int alignUp(int value, int align) { + return Math.ceilDiv(value, align) * align; + } + + public static TestGenerator makeMemorySegment() { + // Sample some random parameters: + Aliasing aliasing = sample(Arrays.asList(Aliasing.values())); + AccessScenario accessScenario = sample(Arrays.asList(AccessScenario.values())); + // Backing memory can be native, access must be primitive. + MyType containerElementType = sample(primitiveTypesAndNative); + MyType accessType0 = sample(primitiveTypes); + MyType accessType1 = sample(primitiveTypes); + ContainerKind containerKind = sample(List.of( + ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE + )); + + if (containerKind == ContainerKind.MEMORY_SEGMENT_AT_INDEX) { + // The access types must be the same, it is a limitation of the index computation. + accessType1 = accessType0; + } + + final int minAccessSize = Math.min(accessType0.byteSize(), accessType1.byteSize()); + final int maxAccessSize = Math.max(accessType0.byteSize(), accessType1.byteSize()); + + // size must be large enough for: + // - scale = 4 + // - range with size / 4 + // -> need at least size 16_000 to ensure we have 1000 iterations + // We want there to be a little variation, so alignment is not always the same. + final int numAccessElements = Generators.G.safeRestrict(Generators.G.ints(), 18_000, 20_000).next(); + final int align = Math.max(maxAccessSize, containerElementType.byteSize()); + // We need to align up, so the size is divisible exactly by all involved type sizes. + final int containerByteSize = alignUp(numAccessElements * maxAccessSize, align); + final boolean loopForward = RANDOM.nextBoolean(); + + final int numInvarRest = RANDOM.nextInt(5); + int indexSize0 = accessType0.byteSize(); + int indexSize1 = accessType1.byteSize(); + if (containerKind == ContainerKind.MEMORY_SEGMENT_AT_INDEX) { + // These are int-indeces for getAtIndex, so we index by element and not bytes. + indexSize0 = 1; + indexSize1 = 1; + } + + boolean withAbsOneIvScale = containerKind == ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE; + int ivStrideAbs = containerKind == ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE ? minAccessSize : 1; + boolean isLongIvType = RANDOM.nextBoolean(); + var form0 = IndexForm.random(numInvarRest, indexSize0, ivStrideAbs); + var form1 = IndexForm.random(numInvarRest, indexSize1, ivStrideAbs); + + return new TestGenerator( + 2, + containerByteSize, + containerKind, + containerElementType, + loopForward, + ivStrideAbs, + isLongIvType, + numInvarRest, + new IndexForm[] {form0, form1}, + new MyType[] {accessType0, accessType1}, + aliasing, + accessScenario); + } + + public TemplateToken generate() { + var testTemplate = Template.make(() -> { + // Let's generate the variable names that are to be shared for the nested Templates. + String[] invarRest = new String[numInvarRest]; + for (int i = 0; i < invarRest.length; i++) { + invarRest[i] = $("invar" + i); + } + String[] containerNames = new String[numContainers]; + for (int i = 0; i < numContainers; i++) { + containerNames[i] = $("container" + i); + } + String[] indexFormNames = new String[accessIndexForm.length]; + for (int i = 0; i < indexFormNames.length; i++) { + indexFormNames[i] = $("index" + i); + } + return body( + """ + // --- $test start --- + """, + generateTestFields(invarRest, containerNames, indexFormNames), + """ + // Count the run invocations. + private static int $iterations = 0; + + @Run(test = "$test") + @Warmup(100) + public static void $run(RunInfo info) { + + // Once warmup is over (100x), repeat 10x to get reasonable coverage of the + // randomness in the tests. + int reps = info.isWarmUp() ? 10 : 1; + for (int r = 0; r < reps; r++) { + + $iterations++; + """, + generateContainerInit(containerNames), + generateContainerAliasing(containerNames, $("iterations")), + generateRanges(), + generateBoundsAndInvariants(indexFormNames, invarRest), + """ + // Run test and compare with interpreter results. + """, + generateCallMethod("result", $("test"), "test"), + generateCallMethod("expected", $("reference"), "reference"), + """ + Verify.checkEQ(result, expected); + } // end reps + } // end $run + + @Test + """, + generateIRRules(), + generateTestMethod($("test"), invarRest), + """ + @DontCompile + """, + generateTestMethod($("reference"), invarRest), + """ + + // --- $test end --- + """ + ); + }); + return testTemplate.asToken(); + } + + private TemplateToken generateArrayField(String name, MyType type) { + var template = Template.make(() -> body( + let("size", containerByteSize / type.byteSize()), + let("name", name), + let("type", type), + """ + private static #type[] original_#name = new #type[#size]; + private static #type[] test_#name = new #type[#size]; + private static #type[] reference_#name = new #type[#size]; + """ + )); + return template.asToken(); + } + + private TemplateToken generateMemorySegmentField(String name, MyType type) { + var template = Template.make(() -> body( + let("size", containerByteSize / type.byteSize()), + let("byteSize", containerByteSize), + let("name", name), + let("type", type), + (type == myNative + ? """ + private static MemorySegment original_#name = Arena.ofAuto().allocate(#byteSize); + private static MemorySegment test_#name = Arena.ofAuto().allocate(#byteSize); + private static MemorySegment reference_#name = Arena.ofAuto().allocate(#byteSize); + """ + : """ + private static MemorySegment original_#name = MemorySegment.ofArray(new #type[#size]); + private static MemorySegment test_#name = MemorySegment.ofArray(new #type[#size]); + private static MemorySegment reference_#name = MemorySegment.ofArray(new #type[#size]); + """ + ) + )); + return template.asToken(); + } + + private TemplateToken generateIndexField(String name, IndexForm form) { + var template = Template.make(() -> body( + let("name", name), + let("form", form.generate()), + """ + private static IndexForm #name = #form; + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestFields(String[] invarRest, String[] containerNames, String[] indexFormNames) { + var template = Template.make(() -> body( + let("ivType", isLongIvType ? "long" : "int"), + """ + // invarRest fields: + """, + Arrays.stream(invarRest).map(invar -> + List.of("private static #ivType ", invar, " = 0;\n") + ).toList(), + """ + // Containers fields: + """, + Arrays.stream(containerNames).map(name -> + switch (containerKind) { + case ContainerKind.ARRAY -> + generateArrayField(name, containerElementType); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateMemorySegmentField(name, containerElementType); + } + ).toList(), + """ + // Index forms for the accesses: + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + generateIndexField(indexFormNames[i], accessIndexForm[i]) + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateContainerInitArray(String name) { + var template = Template.make(() -> body( + let("size", containerByteSize / containerElementType.byteSize()), + let("name", name), + """ + System.arraycopy(original_#name, 0, test_#name, 0, #size); + System.arraycopy(original_#name, 0, reference_#name, 0, #size); + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerInitMemorySegment(String name) { + var template = Template.make(() -> body( + let("size", containerByteSize / containerElementType.byteSize()), + let("name", name), + """ + test_#name.copyFrom(original_#name); + reference_#name.copyFrom(original_#name); + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerInit(String[] containerNames) { + var template = Template.make(() -> body( + """ + // Init containers from original data: + """, + Arrays.stream(containerNames).map(name -> + switch (containerKind) { + case ContainerKind.ARRAY -> + generateContainerInitArray(name); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateContainerInitMemorySegment(name); + } + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateContainerAliasingAssignment(int i, String name1, String name2, String iterations) { + var template = Template.make(() -> body( + let("i", i), + let("name1", name1), + let("name2", name2), + let("iterations", iterations), + """ + var test_#i = (#iterations % 2 == 0) ? test_#name1 : test_#name2; + var reference_#i = (#iterations % 2 == 0) ? reference_#name1 : reference_#name2; + """ + )); + return template.asToken(); + } + + private TemplateToken generateContainerAliasing(String[] containerNames, String iterations) { + var template = Template.make(() -> body( + """ + // Container aliasing: + """, + IntStream.range(0, containerNames.length).mapToObj(i -> + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT -> + generateContainerAliasingAssignment(i, containerNames[i], containerNames[i], iterations); + case Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN -> + generateContainerAliasingAssignment(i, containerNames[0], containerNames[0], iterations); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + generateContainerAliasingAssignment(i, containerNames[i], containerNames[0], iterations); + } + ).toList() + )); + return template.asToken(); + } + + private TemplateToken generateRanges() { + int size = switch (containerKind) { + case ContainerKind.ARRAY, + ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + // Access with element index + containerByteSize / accessType[0].byteSize(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + // Access with byte offset + containerByteSize; + }; + + if (accessIndexForm.length != 2) { throw new RuntimeException("not yet implemented"); } + + var templateSplitRanges = Template.make(() -> body( + let("size", size), + """ + int middle = RANDOM.nextInt(#size / 3, #size * 2 / 3); + int rnd = Math.min(256, #size / 10); + int range = #size / 3 - RANDOM.nextInt(rnd); + """, + (RANDOM.nextBoolean() + // Maximal range + ? """ + var r0 = new IndexForm.Range(0, middle); + var r1 = new IndexForm.Range(middle, #size); + """ + // Same size range + // If the accesses run towards each other, and the runtime + // check is too relaxed, we may fail the checks even though + // there is no overlap. Having same size ranges makes this + // more likely, and we could detect it if we get multiversioning + // unexpectedly. + : """ + var r0 = new IndexForm.Range(middle - range, middle); + var r1 = new IndexForm.Range(middle, middle + range); + """ + ), + """ + if (RANDOM.nextBoolean()) { + var tmp = r0; + r0 = r1; + r1 = tmp; + } + """ + )); + + var templateWholeRanges = Template.make(() -> body( + let("size", size), + """ + var r0 = new IndexForm.Range(0, #size); + var r1 = new IndexForm.Range(0, #size); + """ + )); + + var templateRandomRanges = Template.make(() -> body( + let("size", size), + """ + int lo0 = RANDOM.nextInt(0, #size * 3 / 4); + int lo1 = RANDOM.nextInt(0, #size * 3 / 4); + var r0 = new IndexForm.Range(lo0, lo0 + #size / 4); + var r1 = new IndexForm.Range(lo1, lo1 + #size / 4); + """ + )); + + var templateSmallOverlapRanges = Template.make(() -> body( + // Idea: same size ranges, with size "range". A small overlap, + // so that bad runtime checks would create wrong results. + let("size", size), + """ + int rnd = Math.min(256, #size / 10); + int middle = #size / 2 + RANDOM.nextInt(-rnd, rnd); + int range = #size / 3 - RANDOM.nextInt(rnd); + int overlap = RANDOM.nextInt(-rnd, rnd); + var r0 = new IndexForm.Range(middle - range + overlap, middle + overlap); + var r1 = new IndexForm.Range(middle, middle + range); + if (RANDOM.nextBoolean()) { + var tmp = r0; + r0 = r1; + r1 = tmp; + } + """ + // Can this go out of bounds? Assume worst case on lower end: + // middle - range + overlap + // (size/2 - rnd) - (size/3 - rnd) - rnd + // size/6 - rnd + // -> safe with rnd = size/10 + )); + + var templateAnyRanges = Template.make(() -> body( + switch(RANDOM.nextInt(4)) { + case 0 -> templateSplitRanges.asToken(); + case 1 -> templateWholeRanges.asToken(); + case 2 -> templateRandomRanges.asToken(); + case 3 -> templateSmallOverlapRanges.asToken(); + default -> throw new RuntimeException("impossible"); + } + )); + + var template = Template.make(() -> body( + """ + // Generate ranges: + """, + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT -> + templateAnyRanges.asToken(); + case Aliasing.CONTAINER_SAME_ALIASING_NEVER -> + templateSplitRanges.asToken(); + case Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN -> + templateAnyRanges.asToken(); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> + templateSplitRanges.asToken(); + case Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + templateAnyRanges.asToken(); + } + )); + return template.asToken(); + } + + private TemplateToken generateBoundsAndInvariants(String[] indexFormNames, String[] invarRest) { + // We want there to be at least 1000 iterations. + final int minIvRange = ivStrideAbs * 1000; + + var template = Template.make(() -> body( + let("containerByteSize", containerByteSize), + """ + // Compute loop bounds and loop invariants. + int ivLo = RANDOM.nextInt(-1000, 1000); + int ivHi = ivLo + #containerByteSize; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + Template.make(() -> body( + let("i", i), + let("form", indexFormNames[i]), + """ + int invar0_#i = #form.invar0ForIvLo(r#i, ivLo); + ivHi = Math.min(ivHi, #form.ivHiForInvar0(r#i, invar0_#i)); + """ + )).asToken() + ).toList(), + let("minIvRange", minIvRange), + """ + // Let's check that the range is large enough, so that the vectorized + // main loop can even be entered. + if (ivLo + #minIvRange > ivHi) { throw new RuntimeException("iv range too small: " + ivLo + " " + ivHi); } + """, + Arrays.stream(invarRest).map(invar -> + List.of(invar, " = RANDOM.nextInt(-1, 2);\n") + ).toList(), + """ + // Verify the bounds we just created, just to be sure there is no unexpected aliasing! + int i = ivLo; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + List.of("int lo_", i, " = (int)(", accessIndexForm[i].index("invar0_" + i, invarRest), ");\n") + ).toList(), + """ + i = ivHi; + """, + IntStream.range(0, indexFormNames.length).mapToObj(i -> + List.of("int hi_", i, " = (int)(", accessIndexForm[i].index("invar0_" + i, invarRest), ");\n") + ).toList(), + switch(aliasing) { + case Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> // could fail in the future if we make it smarter + List.of( + """ + // Bounds should not overlap. + if (false + """, + IntStream.range(0, indexFormNames.length).mapToObj(i1 -> + IntStream.range(0, i1).mapToObj(i2 -> + Template.make(() -> body( + let("i1", i1), + let("i2", i2), + // i1 < i2 or i1 > i2 + """ + || (lo_#i1 < lo_#i2 && lo_#i1 < hi_#i2 && hi_#i1 < lo_#i2 && hi_#i1 < hi_#i2) + || (lo_#i1 > lo_#i2 && lo_#i1 > hi_#i2 && hi_#i1 > lo_#i2 && hi_#i1 > hi_#i2) + """ + )).asToken() + ).toList() + ).toList(), + """ + ) { + // pass + } else { + throw new RuntimeException("bounds overlap!"); + } + """); + case Aliasing.CONTAINER_DIFFERENT, + Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + """ + // Aliasing unknown, cannot verify bounds. + """; + } + )); + return template.asToken(); + } + + + private TemplateToken generateCallMethod(String output, String methodName, String containerPrefix) { + var template = Template.make(() -> body( + let("output", output), + let("methodName", methodName), + "var #output = #methodName(", + IntStream.range(0, numContainers).mapToObj(i -> + List.of(containerPrefix, "_", i, ", invar0_", i, ", ") + ).toList(), + "ivLo, ivHi);\n" + )); + return template.asToken(); + } + + private TemplateToken generateIRRules() { + var template = Template.make(() -> body( + switch (containerKind) { + case ContainerKind.ARRAY -> + generateIRRulesArray(); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + generateIRRulesMemorySegmentAtIndex(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE -> + generateIRRulesMemorySegmentLongAdrScale(); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateIRRulesMemorySegmentLongAdrStride(); + }, + // In same scnearios, we know that a aliasing runtime check will never fail. + // That means if we have UseAutoVectorizationPredicate enabled, that predicate + // will never fail, and we will not have to do multiversioning. + switch(aliasing) { + case Aliasing.CONTAINER_DIFFERENT, + Aliasing.CONTAINER_SAME_ALIASING_NEVER, + Aliasing.CONTAINER_UNKNOWN_ALIASING_NEVER -> + // We would have liked to check that there is no multiversioning. + // + // But sadly there are some cases that have issues with RCE and/or + // predicates, and so we end up using multiversioning anyway. We + // should fix those cases eventually, to strengthen the checks here. + // + // The array cases are a little more tame, and do not have the same + // issues as the MemorySegment cases. + (containerKind == ContainerKind.ARRAY) + ? """ + // Aliasing check should never fail at runtime, so the predicate + // should never fail, and we do not have to use multiversioning. + // Failure could have a few causes: + // - issues with doing RCE / missing predicates + // -> other loop-opts need to be fixed + // - predicate fails: recompile with multiversioning + // -> logic in runtime check may be wrong + @IR(counts = {".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationPredicate", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Due to cases like JDK-8360204 and JDK-8365982, there can be issues + // with RCE leading cases where we remove predicates and then unroll again + // and then end up multiversioning. These cases seem relatively rare but + // prevent us from asserting that there is never multiversioning in these cases. + """; + case Aliasing.CONTAINER_SAME_ALIASING_UNKNOWN, + Aliasing.CONTAINER_UNKNOWN_ALIASING_UNKNOWN -> + """ + // Aliasing unknown, we may use the predicate or multiversioning. + """; + } + )); + return template.asToken(); + } + + // Regular array-accesses are vectorized quite predictably, and we can create nice + // IR rules - even for cases where we do not expect vectorization. + private TemplateToken generateIRRulesArray() { + var template = Template.make(() -> body( + let("T", containerElementType.letter()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // Currently, we do not allow strided access or shuffle. + // Since the load and store are connected, we either vectorize both or none. + (accessIndexForm[0].ivScale() == accessIndexForm[1].ivScale() && + Math.abs(accessIndexForm[0].ivScale()) == 1) + ? """ + // Good ivScales, vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Bad ivScales, no vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """; + case FILL_STORE_STORE -> + // Currently, we do not allow strided access. + // We vectorize any contiguous pattern. Possibly only one is vectorized. + (Math.abs(accessIndexForm[0].ivScale()) == 1 || + Math.abs(accessIndexForm[1].ivScale()) == 1) + ? """ + // Good ivScales, vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", + "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """ + : """ + // Bad ivScales, no vectorization expected. + @IR(counts = {IRNode.LOAD_VECTOR_#T, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + """; + } + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentAtIndex() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + // JDK-8359688: it seems we only vectorize with ivScale=1, and not ivScale=-1 + // The issue seems to be RangeCheck elimination + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentLongAdrStride() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + )); + return template.asToken(); + } + + private TemplateToken generateIRRulesMemorySegmentLongAdrScale() { + var template = Template.make(() -> body( + """ + // Unfortunately, there are some issues that prevent RangeCheck elimination. + // The cases are currently quite unpredictable, so we cannot create any IR + // rules - sometimes there are vectors sometimes not. + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestMethod(String methodName, String[] invarRest) { + var template = Template.make(() -> body( + let("methodName", methodName), + let("containerElementType", containerElementType), + let("ivStrideAbs", ivStrideAbs), + let("ivType", isLongIvType ? "long" : "int"), + // Method head / signature. + "public static Object #methodName(", + IntStream.range(0, numContainers).mapToObj(i -> + switch (containerKind) { + case ContainerKind.ARRAY -> + List.of("#containerElementType[] container_", i, ", #ivType invar0_", i, ", "); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + List.of("MemorySegment container_", i, ", #ivType invar0_", i, ", "); + } + ).toList(), + "#ivType ivLo, #ivType ivHi) {\n", + // Method loop body. + (loopForward + ? "for (#ivType i = ivLo; i < ivHi; i+=#ivStrideAbs) {\n" + : "for (#ivType i = ivHi-#ivStrideAbs; i >= ivLo; i-=#ivStrideAbs) {\n"), + // Loop iteration. + switch (containerKind) { + case ContainerKind.ARRAY -> + generateTestLoopIterationArray(invarRest); + case ContainerKind.MEMORY_SEGMENT_AT_INDEX -> + generateTestLoopIterationMemorySegmentAtIndex(invarRest); + case ContainerKind.MEMORY_SEGMENT_LONG_ADR_SCALE, + ContainerKind.MEMORY_SEGMENT_LONG_ADR_STRIDE -> + generateTestLoopIterationMemorySegmentLongAdr(invarRest); + }, + """ + } + return new Object[] { + """, + // Return a list of all containers that are involved in the test. + // The caller can then compare the results of the test and reference method. + IntStream.range(0, numContainers).mapToObj(i -> + "container_" + i + ).collect(Collectors.joining(", ")), "\n", + """ + }; + } + """ + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationArray(String[] invarRest) { + var template = Template.make(() -> body( + let("type", containerElementType), + switch (accessScenario) { + case COPY_LOAD_STORE -> + List.of("container_0[", accessIndexForm[0].index("invar0_0", invarRest), "] = ", + "container_1[", accessIndexForm[1].index("invar0_1", invarRest), "];\n"); + case FILL_STORE_STORE -> + List.of("container_0[", accessIndexForm[0].index("invar0_0", invarRest), "] = (#type)0x0102030405060708L;\n", + "container_1[", accessIndexForm[1].index("invar0_1", invarRest), "] = (#type)0x1112131415161718L;\n"); + } + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationMemorySegmentAtIndex(String[] invarRest) { + var template = Template.make(() -> body( + let("type0", accessType[0]), + let("type1", accessType[1]), + let("type0Layout", accessType[0].layout()), + let("type1Layout", accessType[1].layout()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // Conversion not implemented, index bound computation is too limited for this currently. + List.of("var v = ", + "container_0.getAtIndex(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ");\n", + "container_1.setAtIndex(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", v);\n"); + case FILL_STORE_STORE -> + List.of("container_0.setAtIndex(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ", (#type0)0x0102030405060708L);\n", + "container_1.setAtIndex(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", (#type1)0x1112131415161718L);\n"); + } + )); + return template.asToken(); + } + + private TemplateToken generateTestLoopIterationMemorySegmentLongAdr(String[] invarRest) { + var template = Template.make(() -> body( + let("type0", accessType[0]), + let("type1", accessType[1]), + let("type0Layout", accessType[0].layout()), + let("type1Layout", accessType[1].layout()), + switch (accessScenario) { + case COPY_LOAD_STORE -> + // We allow conversions here. + List.of("#type1 v = (#type1)", + "container_0.get(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ");\n", + "container_1.set(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", v);\n"); + case FILL_STORE_STORE -> + List.of("container_0.set(#type0Layout, ", accessIndexForm[0].indexLong("invar0_0", invarRest), ", (#type0)0x0102030405060708L);\n", + "container_1.set(#type1Layout, ", accessIndexForm[1].indexLong("invar0_1", invarRest), ", (#type1)0x1112131415161718L);\n"); + } + )); + return template.asToken(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java index 74152645a48..b7e62c394ec 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCyclicDependency.java @@ -31,12 +31,12 @@ * @run driver TestCyclicDependency */ +import java.util.List; import jdk.test.lib.Asserts; import compiler.lib.ir_framework.*; public class TestCyclicDependency { static final int RANGE = 512; - static final int ITER = 100; int[] goldI0 = new int[RANGE]; float[] goldF0 = new float[RANGE]; int[] goldI1 = new int[RANGE]; @@ -73,12 +73,28 @@ public class TestCyclicDependency { float[] goldF9 = new float[RANGE]; public static void main(String args[]) { - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-AlignVector", "-XX:-VerifyAlignVector"); - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlignVector", "-XX:-VerifyAlignVector"); - TestFramework.runWithFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlignVector", "-XX:+VerifyAlignVector"); + // Cross-product: + // - AlignVector (+VerifyAlignVector) + // - UseAutoVectorizationSpeculativeAliasingChecks + List avList = List.of( + new String[] {"-XX:-AlignVector", "-XX:-VerifyAlignVector"}, + new String[] {"-XX:+AlignVector", "-XX:-VerifyAlignVector"}, + new String[] {"-XX:+AlignVector", "-XX:+VerifyAlignVector"} + ); + List sacList = List.of( + new String[] {"-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}, + new String[] {"-XX:+UseAutoVectorizationSpeculativeAliasingChecks"} + ); + for (String[] av : avList) { + for (String[] sac : sacList) { + TestFramework framework = new TestFramework(); + framework.addFlags("-XX:CompileCommand=compileonly,TestCyclicDependency::test*", + "-XX:+IgnoreUnrecognizedVMOptions"); + framework.addFlags(av); + framework.addFlags(sac); + framework.start(); + } + } } TestCyclicDependency() { @@ -134,7 +150,7 @@ public class TestCyclicDependency { } @Run(test = "test0") - @Warmup(100) + @Warmup(1000) public void runTest0() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -145,7 +161,7 @@ public class TestCyclicDependency { } @Run(test = "test1") - @Warmup(100) + @Warmup(1000) public void runTest1() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -156,7 +172,7 @@ public class TestCyclicDependency { } @Run(test = "test2") - @Warmup(100) + @Warmup(1000) public void runTest2() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -167,7 +183,7 @@ public class TestCyclicDependency { } @Run(test = "test3") - @Warmup(100) + @Warmup(1000) public void runTest3() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -178,7 +194,7 @@ public class TestCyclicDependency { } @Run(test = "test4") - @Warmup(100) + @Warmup(1000) public void runTest4() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -189,7 +205,7 @@ public class TestCyclicDependency { } @Run(test = "test5a") - @Warmup(100) + @Warmup(1000) public void runTest5a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -200,7 +216,7 @@ public class TestCyclicDependency { } @Run(test = "test5b") - @Warmup(100) + @Warmup(1000) public void runTest5b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -211,7 +227,7 @@ public class TestCyclicDependency { } @Run(test = "test6a") - @Warmup(100) + @Warmup(1000) public void runTest6a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -222,7 +238,7 @@ public class TestCyclicDependency { } @Run(test = "test6b") - @Warmup(100) + @Warmup(1000) public void runTest6b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -233,7 +249,7 @@ public class TestCyclicDependency { } @Run(test = "test7a") - @Warmup(100) + @Warmup(1000) public void runTest7a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -244,7 +260,7 @@ public class TestCyclicDependency { } @Run(test = "test7b") - @Warmup(100) + @Warmup(1000) public void runTest7b() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -257,7 +273,7 @@ public class TestCyclicDependency { } @Run(test = "test7c") - @Warmup(100) + @Warmup(1000) public void runTest7c() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -268,7 +284,7 @@ public class TestCyclicDependency { } @Run(test = "test8a") - @Warmup(100) + @Warmup(1000) public void runTest8a() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -279,7 +295,7 @@ public class TestCyclicDependency { } @Run(test = "test8b") - @Warmup(100) + @Warmup(1000) public void runTest8b() { int[] dataI = new int[RANGE]; int[] dataI_2 = new int[RANGE]; @@ -292,7 +308,7 @@ public class TestCyclicDependency { } @Run(test = "test8c") - @Warmup(100) + @Warmup(1000) public void runTest8c() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -303,7 +319,7 @@ public class TestCyclicDependency { } @Run(test = "test9") - @Warmup(100) + @Warmup(1000) public void runTest9() { int[] dataI = new int[RANGE]; float[] dataF = new float[RANGE]; @@ -430,11 +446,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, "= 0"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, "= 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -445,10 +471,14 @@ public class TestCyclicDependency { dataI[i + 32] = v + 5; // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always different. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two float-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // Note: at runtime the float-arrays are always different -> predicate suffices, no multiversioning. float f = dataF[i]; dataF_2[i + 3] = f + 3.5f; } @@ -456,11 +486,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "2", "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.ADD_VF, "= 0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -471,10 +511,15 @@ public class TestCyclicDependency { dataI[i + 32] = v + 5; // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always the same. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two float-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // multiversion_slow loop can still vectorize, but only with 2 elements. + // Note: at runtime the float-arrays are always the same -> predicate fails -> multiversioning. float f = dataF[i]; dataF_2[i + 3] = f + 3.5f; } @@ -508,11 +553,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "= 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -520,10 +575,14 @@ public class TestCyclicDependency { for (int i = 0; i < RANGE - 32; i++) { // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always different. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two int-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataI and dataI_2 do not alias -> full vectorization. + // Note: at runtime the int-arrays are always different -> predicate suffices, no multiversioning. int v = dataI[i]; dataI_2[i + 3] = v + 5; // write forward 32 -> more than vector size -> can vectorize @@ -534,11 +593,21 @@ public class TestCyclicDependency { @Test @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", - IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", "=0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.ADD_VI, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE + "2", "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + ".*multiversion.*", ">0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.ADD_VI, "= 0", IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) // Some aarch64 machines have AlignVector == true, like ThunderX2 @@ -546,10 +615,15 @@ public class TestCyclicDependency { for (int i = 0; i < RANGE - 32; i++) { // write forward 3 to different array reference: // AlignVector=true -> cannot vectorize because load and store cannot be both aligned - // AlignVector=false -> vectorizes because we cannot prove store-to-load forwarding - // failure. But we can only have 2-element vectors in case - // the two float-arrays reference the same array. - // Note: at runtime the float-arrays are always the same. + // AlignVector=false + // UseAutoVectorizationSpeculativeAliasingChecks=false + // vectorizes because we cannot prove store-to-load forwarding + // failure. But we can only have 2-element vectors in case + // the two int-arrays reference the same array. + // UseAutoVectorizationSpeculativeAliasingChecks=true + // Speculate that dataF and dataF_2 do not alias -> full vectorization. + // multiversion_slow loop can still vectorize, but only with 2 elements. + // Note: at runtime the int-arrays are always the same -> predicate fails -> multiversioning. int v = dataI[i]; dataI_2[i + 3] = v + 5; // write forward 32 -> more than vector size -> can vectorize diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 24a8581434f..d760c87ad19 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -751,11 +751,13 @@ public class TestDependencyOffsets { // we use shorter vectors to avoid cycles and still vectorize. Vector lengths have to // be powers-of-2, and smaller or equal to the byteOffset. So we round down to the next // power of two. + // If we have two array references, then we can speculate that they do not alias, and + // still produce full vectorization. int infinity = 256; // No vector size is ever larger than this. int maxVectorWidth = infinity; // no constraint by default int log2 = 31 - Integer.numberOfLeadingZeros(offset); int floorPow2Offset = 1 << log2; - if (0 < byteOffset && byteOffset < maxVectorWidth) { + if (isSingleArray && 0 < byteOffset && byteOffset < maxVectorWidth) { maxVectorWidth = Math.min(maxVectorWidth, floorPow2Offset * type.size); builder.append(" // Vectors must have at most " + floorPow2Offset + " elements: maxVectorWidth = " + maxVectorWidth + diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java index 502fad5be96..a2b5434a5a2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java @@ -47,6 +47,22 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector */ +/* + * @test id=byte-array-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector NoSpeculativeAliasingCheck + */ + /* * @test id=byte-array-NoShortRunningLongLoop * @bug 8329273 8342692 @@ -63,6 +79,13 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray AlignVector NoShortRunningLongLoop */ +/* + * @test id=byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ /* * @test id=char-array @@ -160,6 +183,46 @@ import java.lang.foreign.*; * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector */ +/* + * @test id=native-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-AlignVector-NoSpeculativeAliasingCheck + * @bug 8329273 8348263 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-NoShortRunningLongLoop + * @bug 8329273 8342692 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoShortRunningLongLoop + */ + +/* + * @test id=native-AlignVector-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8329273 8348263 8342692 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment Native NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + // FAILS: mixed providers currently do not vectorize. Maybe there is some inlining issue. // /* // * @test id=mixed-array @@ -193,12 +256,14 @@ public class TestMemorySegment { String tag = args[i]; switch (tag) { case "AlignVector" -> framework.addFlags("-XX:+AlignVector"); + case "NoSpeculativeAliasingCheck" -> framework.addFlags("-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); + // Disabling the ShortRunningLongLoop optimization changes the shape of the loop. + // Testing both with and without it allows us to simulate long running loops with short running loops, + // i.e. we don't need to allocate massive amounts of memory. case "NoShortRunningLongLoop" -> framework.addFlags("-XX:-ShortRunningLongLoop"); + default -> throw new RuntimeException("Bad tag: " + tag); } } - if (args.length > 1 && args[1].equals("AlignVector")) { - framework.addFlags("-XX:+AlignVector"); - } framework.setDefaultWarmup(100); framework.start(); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java new file mode 100644 index 00000000000..c956ac9a0d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentAliasing.java @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import jdk.test.lib.Utils; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.lang.foreign.*; + +/* + * @test id=byte-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray + */ + +/* + * @test id=byte-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector + */ + +/* + * @test id=byte-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=byte-array-NoAutoAlignment + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoAutoAlignment + */ + +/* + * @test id=byte-array-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoShortRunningLongLoop + */ + +/* + * @test id=byte-array-AlignVector-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=byte-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +/* + * @test id=char-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing CharArray + */ + +/* + * @test id=short-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ShortArray + */ + +/* + * @test id=int-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray + */ + +/* + * @test id=int-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector + */ + +/* + * @test id=int-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=int-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=int-array-NoAutoAlignment + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoAutoAlignment + */ + +/* + * @test id=int-array-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoShortRunningLongLoop + */ + +/* + * @test id=int-array-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing IntArray NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +/* + * @test id=long-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray + */ + +/* + * @test id=long-array-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector + */ + +/* + * @test id=long-array-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray NoSpeculativeAliasingCheck + */ + +/* + * @test id=long-array-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing LongArray AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=float-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing FloatArray + */ + +/* + * @test id=double-array + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing DoubleArray + */ + +/* + * @test id=byte-buffer + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBuffer + */ + +/* + * @test id=byte-buffer-direct + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing ByteBufferDirect + */ + +/* + * @test id=native + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native + */ + +/* + * @test id=native-AlignVector + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-AlignVector-NoSpeculativeAliasingCheck + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoSpeculativeAliasingCheck + */ + +/* + * @test id=native-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoShortRunningLongLoop + */ + +/* + * @test id=native-AlignVector-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native AlignVector NoShortRunningLongLoop + */ + +/* + * @test id=native-NoSpeculativeAliasingCheck-NoShortRunningLongLoop + * @bug 8324751 + * @summary Test vectorization of loops over MemorySegment + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentAliasing Native NoSpeculativeAliasingCheck NoShortRunningLongLoop + */ + +public class TestMemorySegmentAliasing { + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestMemorySegmentAliasingImpl.class); + framework.addFlags("-DmemorySegmentProviderNameForTestVM=" + args[0]); + for (int i = 1; i < args.length; i++) { + String tag = args[i]; + switch (tag) { + case "AlignVector" -> framework.addFlags("-XX:+AlignVector"); + case "NoSpeculativeAliasingCheck" -> framework.addFlags("-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); + // automatic alignment has an impact on where the main-loop starts, and that affects init and limit + // of the main loop. + case "NoAutoAlignment" -> framework.addFlags("-XX:SuperWordAutomaticAlignment=0"); + // Disabling the ShortRunningLongLoop optimization changes the shape of the loop. + // Testing both with and without it allows us to simulate long running loops with short running loops, + // i.e. we don't need to allocate massive amounts of memory. + case "NoShortRunningLongLoop" -> framework.addFlags("-XX:-ShortRunningLongLoop"); + default -> throw new RuntimeException("Bad tag: " + tag); + } + } + framework.setDefaultWarmup(100); + framework.start(); + } +} + +class TestMemorySegmentAliasingImpl { + static final int BACKING_SIZE = 1024 * 8; + static final Random RANDOM = Utils.getRandomInstance(); + + + interface TestFunction { + void run(); + } + + interface MemorySegmentProvider { + MemorySegment newMemorySegment(); + } + + public static MemorySegmentProvider provider; + + static { + String providerName = System.getProperty("memorySegmentProviderNameForTestVM"); + provider = switch (providerName) { + case "ByteArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteArray; + case "CharArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfCharArray; + case "ShortArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfShortArray; + case "IntArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfIntArray; + case "LongArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfLongArray; + case "FloatArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfFloatArray; + case "DoubleArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfDoubleArray; + case "ByteBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBuffer; + case "ByteBufferDirect" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfByteBufferDirect; + case "Native" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfNative; + case "MixedArray" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedArray; + case "MixedBuffer" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixedBuffer; + case "Mixed" -> TestMemorySegmentAliasingImpl::newMemorySegmentOfMixed; + default -> throw new RuntimeException("Test argument not recognized: " + providerName); + }; + } + + // Map of goldTests + public static Map goldTests = new HashMap<>(); + + // Map of gold for the goldTests, the results from the first run before compilation + public static Map golds = new HashMap<>(); + + // Map of referenceTests, i.e. tests that have a reference implementation that is run with the interpreter. + // The TestFunction must run both the test and reference methods. + public static Map referenceTests = new HashMap<>(); + + // Original data. + public static MemorySegment ORIG_A = fillRandom(newMemorySegment()); + public static MemorySegment ORIG_B = fillRandom(newMemorySegment()); + public static MemorySegment ORIG_C = fillRandom(newMemorySegment()); + + // The data we use in the tests. It is initialized from ORIG_* every time. + public static MemorySegment A = newMemorySegment(); + public static MemorySegment B = newMemorySegment(); + public static MemorySegment C = newMemorySegment(); + + // Parallel to data above, but for use in reference methods. + public static MemorySegment A_REFERENCE = newMemorySegment(); + public static MemorySegment B_REFERENCE = newMemorySegment(); + public static MemorySegment C_REFERENCE = newMemorySegment(); + + public TestMemorySegmentAliasingImpl () { + // Add all goldTests to list + goldTests.put("test_byte_incr_noaliasing", () -> test_byte_incr_noaliasing(A, B)); + goldTests.put("test_byte_incr_aliasing", () -> test_byte_incr_aliasing(A, A)); + goldTests.put("test_byte_incr_aliasing_fwd3", () -> { + MemorySegment x = A.asSlice(0, BACKING_SIZE - 3); + MemorySegment y = A.asSlice(3, BACKING_SIZE - 3); + test_byte_incr_aliasing_fwd3(x, y); + }); + goldTests.put("test_byte_incr_noaliasing_fwd128", () -> { + MemorySegment x = A.asSlice(0, BACKING_SIZE - 128); + MemorySegment y = A.asSlice(120, BACKING_SIZE - 128); + test_byte_incr_noaliasing_fwd128(x, y); + }); + + goldTests.put("test_int_to_long_noaliasing", () -> test_int_to_long_noaliasing(A, B)); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + init(); + test.run(); + Object gold = snapshotCopy(); + golds.put(name, gold); + } + + referenceTests.put("test_fill_byte_sameMS_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_byte_sameMS_alias(A, A, invar1, invar2); + reference_fill_byte_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2); + }); + referenceTests.put("test_fill_byte_sameMS_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_byte_sameMS_noalias(A, A, invar1, invar2, limit); + reference_fill_byte_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_byte_sameMS_maybeAlias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // In the middle, sometimes we overlap and sometimes not. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle + RANDOM.nextInt(-256, 256); + int invar2 = middle + RANDOM.nextInt(-256, 256); + // Are the bounds safe? Assume extreme values: + // invar1 = 8k/2 + 256 + 256 + // limit = 8k/3 + 256 + // invar1 + limit = 8k * 5/6 + 3 * 256 + // = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_byte_sameMS_maybeAlias(A, A, invar1, invar2, limit); + reference_fill_byte_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_int_sameMS_alias", () -> { + int invar1 = RANDOM.nextInt(64); + int invar2 = RANDOM.nextInt(64); + test_fill_int_sameMS_alias(A, A, invar1, invar2); + reference_fill_int_sameMS_alias(A_REFERENCE, A_REFERENCE, invar1, invar2); + }); + referenceTests.put("test_fill_int_sameMS_noalias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // But they never overlap. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle; + int invar2 = middle; + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_int_sameMS_noalias(A, A, invar1, invar2, limit); + reference_fill_int_sameMS_noalias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + referenceTests.put("test_fill_int_sameMS_maybeAlias", () -> { + // The accesses either start at the middle and go out, + // or start from opposite sides and meet in the middle. + // In the middle, sometimes we overlap and sometimes not. + // <------|------> + // ------>|<------ + // + // This tests that the checks we emit are not too relaxed. + int middle = BACKING_SIZE / 2 + RANDOM.nextInt(-256, 256); + int limit = BACKING_SIZE / 3 + RANDOM.nextInt(256); + int invar1 = middle + RANDOM.nextInt(-256, 256); + int invar2 = middle + RANDOM.nextInt(-256, 256); + // Are the bounds safe? Assume extreme values: + // invar1 = 8k/2 + 256 + 256 + // limit = 8k/3 + 256 + // invar1 + limit = 8k * 5/6 + 3 * 256 + // = 8k * 5/6 + 3/4 * 1k = 7.41k < 8k + if (RANDOM.nextBoolean()) { + invar1 -= limit; + invar2 += limit; + } + test_fill_int_sameMS_maybeAlias(A, A, invar1, invar2, limit); + reference_fill_int_sameMS_maybeAlias(A_REFERENCE, A_REFERENCE, invar1, invar2, limit); + }); + } + + static MemorySegment newMemorySegment() { + return provider.newMemorySegment(); + } + + static MemorySegment copy(MemorySegment src) { + MemorySegment dst = newMemorySegment(); + dst.copyFrom(src); + return dst; + } + + static MemorySegment newMemorySegmentOfByteArray() { + return MemorySegment.ofArray(new byte[BACKING_SIZE]); + } + + static MemorySegment newMemorySegmentOfCharArray() { + return MemorySegment.ofArray(new char[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfShortArray() { + return MemorySegment.ofArray(new short[BACKING_SIZE / 2]); + } + + static MemorySegment newMemorySegmentOfIntArray() { + return MemorySegment.ofArray(new int[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfLongArray() { + return MemorySegment.ofArray(new long[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfFloatArray() { + return MemorySegment.ofArray(new float[BACKING_SIZE / 4]); + } + + static MemorySegment newMemorySegmentOfDoubleArray() { + return MemorySegment.ofArray(new double[BACKING_SIZE / 8]); + } + + static MemorySegment newMemorySegmentOfByteBuffer() { + return MemorySegment.ofBuffer(ByteBuffer.allocate(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfByteBufferDirect() { + return MemorySegment.ofBuffer(ByteBuffer.allocateDirect(BACKING_SIZE)); + } + + static MemorySegment newMemorySegmentOfNative() { + // Auto arena: GC decides when there is no reference to the MemorySegment, + // and then it deallocates the backing memory. + return Arena.ofAuto().allocate(BACKING_SIZE, 1); + } + + static MemorySegment newMemorySegmentOfMixedArray() { + switch(RANDOM.nextInt(7)) { + case 0 -> { return newMemorySegmentOfByteArray(); } + case 1 -> { return newMemorySegmentOfCharArray(); } + case 2 -> { return newMemorySegmentOfShortArray(); } + case 3 -> { return newMemorySegmentOfIntArray(); } + case 4 -> { return newMemorySegmentOfLongArray(); } + case 5 -> { return newMemorySegmentOfFloatArray(); } + default -> { return newMemorySegmentOfDoubleArray(); } + } + } + + static MemorySegment newMemorySegmentOfMixedBuffer() { + switch (RANDOM.nextInt(2)) { + case 0 -> { return newMemorySegmentOfByteBuffer(); } + default -> { return newMemorySegmentOfByteBufferDirect(); } + } + } + + static MemorySegment newMemorySegmentOfMixed() { + switch (RANDOM.nextInt(3)) { + case 0 -> { return newMemorySegmentOfMixedArray(); } + case 1 -> { return newMemorySegmentOfMixedBuffer(); } + default -> { return newMemorySegmentOfNative(); } + } + } + + static MemorySegment fillRandom(MemorySegment data) { + for (int i = 0; i < (int)data.byteSize(); i += 8) { + data.set(ValueLayout.JAVA_LONG_UNALIGNED, i, RANDOM.nextLong()); + } + return data; + } + + public static void init() { + A.copyFrom(ORIG_A); + B.copyFrom(ORIG_B); + C.copyFrom(ORIG_C); + } + + public static void initReference() { + A_REFERENCE.copyFrom(ORIG_A); + B_REFERENCE.copyFrom(ORIG_B); + C_REFERENCE.copyFrom(ORIG_C); + } + + public static Object snapshotCopy() { + return new Object[]{copy(A), copy(B), copy(C)}; + } + + public static Object snapshot() { + return new Object[]{A, B, C}; + } + + public static Object snapshotReference() { + return new Object[]{A_REFERENCE, B_REFERENCE, C_REFERENCE}; + } + + @Run(test = {"test_byte_incr_noaliasing", + "test_byte_incr_aliasing", + "test_byte_incr_aliasing_fwd3", + "test_byte_incr_noaliasing_fwd128", + "test_int_to_long_noaliasing", + "test_fill_byte_sameMS_alias", + "test_fill_byte_sameMS_noalias", + "test_fill_byte_sameMS_maybeAlias", + "test_fill_int_sameMS_alias", + "test_fill_int_sameMS_noalias", + "test_fill_int_sameMS_maybeAlias"}) + void runTests(RunInfo info) { + for (Map.Entry entry : goldTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object gold = golds.get(name); + // Compute new result + init(); + test.run(); + Object result = snapshot(); + // Compare gold and new result + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + + // Once warmup is over (100x), repeat 10x to get reasonable coverage of the + // randomness in the tests. + int reps = info.isWarmUp() ? 10 : 1; + for (int r = 0; r < reps; r++) { + for (Map.Entry entry : referenceTests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Init data for test and reference + init(); + initReference(); + // Run test and reference + test.run(); + // Capture results from test and reference + Object result = snapshot(); + Object expected = snapshotReference(); + // Compare expected and new result + try { + Verify.checkEQ(expected, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify failed for " + name, e); + } + } + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_noaliasing(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_aliasing(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_aliasing_fwd3(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.ADD_VB, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_byte_incr_noaliasing_fwd128(MemorySegment a, MemorySegment b) { + for (long i = 0; i < a.byteSize(); i++) { + byte v = a.get(ValueLayout.JAVA_BYTE, i); + b.set(ValueLayout.JAVA_BYTE, i, (byte)(v + 1)); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // In this case, the limit is pre-loop independent, but its assigned + // ctrl sits between main and pre loop. Only the early ctrl is before + // the pre loop. + static void test_int_to_long_noaliasing(MemorySegment a, MemorySegment b) { + long limit = a.byteSize() / 8L; + for (long i = 0; i < limit; i++) { + int v = a.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i); + b.set(ValueLayout.JAVA_LONG_UNALIGNED, 8L * i, v); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + static void test_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i++) { + a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a); + b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i++) { + a.set(ValueLayout.JAVA_BYTE, i + invar1, (byte)0x0a); + b.set(ValueLayout.JAVA_BYTE, a.byteSize() - i - 1 - invar2, (byte)0x0b); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // For now, we just assert that there is never multiversioning, which holds with or without vectorization: + @IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0"}, + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // Note: we may or may not use multiversioning, depending if we alias or not at runtime. + static void test_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @DontCompile + static void reference_fill_byte_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i < limit; i++) { + a.set(ValueLayout.JAVA_BYTE, invar1 + i, (byte)0xa); + b.set(ValueLayout.JAVA_BYTE, invar2 - i, (byte)0xb); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "> 0"}, // AutoVectorization Predicate FAILS + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + static void test_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_alias(MemorySegment a, MemorySegment b, long invar1, long invar2) { + for (long i = 0; i < a.byteSize() - 100; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, i + invar1, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, a.byteSize() - i - 4 - invar2, 0x11121314); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0", + // ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // For now, we just assert that there is never multiversioning, which holds with or without vectorization: + @IR(counts = {".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + static void test_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_noalias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @Test + // @IR(counts = {IRNode.STORE_VECTOR, "> 0"}, + // phase = CompilePhase.PRINT_IDEAL, + // applyIfPlatform = {"64-bit", "true"}, + // applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + // applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // + // FAILS: but only on "native" and "byte-buffer-direct" + // The issue is that one of the VPointers is invalid. + // + // Note: we may or may not use multiversioning, depending if we alias or not at runtime. + static void test_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } + + @DontCompile + static void reference_fill_int_sameMS_maybeAlias(MemorySegment a, MemorySegment b, long invar1, long invar2, long limit) { + for (long i = 0; i <= limit - 4; i+=4) { + a.set(ValueLayout.JAVA_INT_UNALIGNED, invar1 + i, 0x01020304); + b.set(ValueLayout.JAVA_INT_UNALIGNED, invar2 - i, 0x11121314); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java new file mode 100644 index 00000000000..cac69901a32 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8359688.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8359688: C2 SuperWord: missing RCE with MemorySegment + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8359688 + */ + + +public class TestMemorySegment_8359688 { + + public static MemorySegment b = MemorySegment.ofArray(new long[4 * 30_000]); + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { b, 0, 5_000, 0 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "= 0", + IRNode.REPLICATE_L, "= 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES, there is no aliasing + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Does not manage to remove all RangeChecks -> no vectorization + // If you see this IR rule fail: investigate JDK-8359688, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test1(MemorySegment b, int ivLo, int ivHi, int invar) { + for (int i = ivLo; i < ivHi; i++) { + b.setAtIndex(ValueLayout.JAVA_LONG_UNALIGNED, 30_000L - (long)i + (long)invar, 42); + // ^ subtraction here + } + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_L, "> 0", + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES, there is no aliasing + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Is fully RFE'd and vectorized + public static void test2(MemorySegment b, int ivLo, int ivHi, int invar) { + for (int i = ivLo; i < ivHi; i++) { + b.setAtIndex(ValueLayout.JAVA_LONG_UNALIGNED, 1_000L + 1L * i + (long)invar, 42); + // ^ addition here + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java new file mode 100644 index 00000000000..ecefcec8afa --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8360204.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8360204: C2 SuperWord: missing RCE with MemorySegment.getAtIndex + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8360204 + */ + +public class TestMemorySegment_8360204 { + + public static MemorySegment a = Arena.ofAuto().allocate(10_000); + public static MemorySegment b = Arena.ofAuto().allocate(10_000); + + private static long invar0_1159 = 0; + private static long invar1_1159 = 0; + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { a, -19125L, b, 71734L + 2_000L, 0, 1_000 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + ".*multiversion.*", "> 0"}, // Sadly, we now multiversion + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // There is no aliasing, so we should compile without multiversioning. + // But currently, there seems to be some issue with RCE, we peel and lose the predicate. + // Then we multiversion. + // We could imagine that this would eventually vectorize, but since one counts up, and the other down, + // we would have to implement shuffle first. + // + // If you see this IR rule fail: investigate JDK-8360204, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test(MemorySegment container_0, long invar0_0, MemorySegment container_1, long invar0_1, long ivLo, long ivHi) { + for (long i = ivLo; i < ivHi; i+=1) { + var v = container_0.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED, 19125L + 1L * i + 1L * invar0_0 + 0L * invar0_1159 + 1L * invar1_1159); + container_1.setAtIndex(ValueLayout.JAVA_INT_UNALIGNED, -71734L + -1L * i + 1L * invar0_1 + 1L * invar0_1159 + 0L * invar1_1159, v); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java new file mode 100644 index 00000000000..65fd3861174 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment_8365982.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts.superword; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8324751 + * @summary Reported issue: JDK-8365982: C2 SuperWord: missing RCE / strange Multiversioning with MemorySegment.set + * The examples are generated from TestAliasingFuzzer.java + * So if you see something change here, you may want to investigate if we + * can also tighten up the IR rules there. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegment_8365982 + */ + +public class TestMemorySegment_8365982 { + + public static MemorySegment a = MemorySegment.ofArray(new short[100_000]); + public static MemorySegment b = MemorySegment.ofArray(new short[100_000]); + + private static long invar0_853 = 0; + private static long invar1_853 = 0; + private static long invar2_853 = 0; + + public static void main(String[] args) { + TestFramework f = new TestFramework(); + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); + f.addScenarios(new Scenario(0, "-XX:-AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(1, "-XX:+AlignVector", "-XX:-ShortRunningLongLoop"), + new Scenario(2, "-XX:-AlignVector", "-XX:+ShortRunningLongLoop"), + new Scenario(3, "-XX:+AlignVector", "-XX:+ShortRunningLongLoop")); + f.start(); + } + + @Setup + static Object[] setup() { + return new Object[] { a, -50_000, b, -30_000, 0, 10_000 }; + } + + @Test + @Arguments(setup = "setup") + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_S, "> 0", + ".*multiversion.*", "= 0"}, // Good: The AutoVectorization predicate suffices. + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "ShortRunningLongLoop", "false"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // + @IR(counts = {IRNode.STORE_VECTOR, "> 0", + IRNode.REPLICATE_S, "> 0", + ".*multiversion.*", "> 0"}, // Bad: Sadly, we now multiversion + phase = CompilePhase.PRINT_IDEAL, + applyIfPlatform = {"64-bit", "true"}, + applyIfAnd = {"AlignVector", "false", "ShortRunningLongLoop", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + // Some but not all predicates are RCE'd at the beginning. After unrolling, we multiversion (why?). + // After PreMainPost, we can do more RangeCheck. Now the main-loop of the multiversion_fast loop + // does not have any range checks any more. + // Now it vectorizes. That's good, but we should be able to vectorize without multiversioning. + // + // If you see this IR rule fail: investigate JDK-8365982, possibly close it and fix this IR rule! + // Also: consider renaming the file to something more descriptive: what have you fixed with this? + // And: you may now be able to tighten IR rules in TestAliasingFuzzer.java + public static void test(MemorySegment container_0, long invar0_0, MemorySegment container_1, long invar0_1, long ivLo, long ivHi) { + for (long i = ivHi-1; i >= ivLo; i-=1) { + container_0.set(ValueLayout.JAVA_CHAR_UNALIGNED, -47143L + -2L * i + -2L * invar0_0 + -1L * invar0_853 + -1L * invar1_853 + 0L * invar2_853, (char)0x0102030405060708L); + container_1.set(ValueLayout.JAVA_CHAR_UNALIGNED, 74770L + 2L * i + 2L * invar0_1 + 0L * invar0_853 + 0L * invar1_853 + 0L * invar2_853, (char)0x1112131415161718L); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java index 80a877bfce5..631b55fc65f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java @@ -37,10 +37,14 @@ import java.nio.ByteOrder; * @bug 8326139 8348659 * @summary Test splitting packs in SuperWord * @library /test/lib / - * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV - * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV - * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV - * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV_ySAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_yAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_nAV_nSAC + * @run driver compiler.loopopts.superword.TestSplitPacks yCOH_yAV_nSAC */ public class TestSplitPacks { @@ -76,10 +80,14 @@ public class TestSplitPacks { TestFramework framework = new TestFramework(TestSplitPacks.class); framework.addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:LoopUnrollLimit=1000"); switch (args[0]) { - case "nCOH_nAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "nCOH_yAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"); } - case "yCOH_nAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "yCOH_yAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); } + case "nCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_ySAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "nCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_nAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } + case "yCOH_yAV_nSAC" -> { framework.addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"); } default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } }; framework.start(); @@ -114,6 +122,13 @@ public class TestSplitPacks { tests.put("test4e", () -> { return test4e(aS.clone(), bS.clone()); }); tests.put("test4f", () -> { return test4f(aS.clone(), bS.clone()); }); tests.put("test4g", () -> { return test4g(aS.clone(), bS.clone()); }); + tests.put("test4a_alias",() -> { short[] x = aS.clone(); return test4a_alias(x, x); }); + tests.put("test4b_alias",() -> { short[] x = aS.clone(); return test4b_alias(x, x); }); + tests.put("test4c_alias",() -> { short[] x = aS.clone(); return test4c_alias(x, x); }); + tests.put("test4d_alias",() -> { short[] x = aS.clone(); return test4d_alias(x, x); }); + tests.put("test4e_alias",() -> { short[] x = aS.clone(); return test4e_alias(x, x); }); + tests.put("test4f_alias",() -> { short[] x = aS.clone(); return test4f_alias(x, x); }); + tests.put("test4g_alias",() -> { short[] x = aS.clone(); return test4g_alias(x, x); }); tests.put("test5a", () -> { return test5a(aS.clone(), bS.clone(), mS); }); tests.put("test6a", () -> { return test6a(aI.clone(), bI.clone()); }); tests.put("test7a", () -> { return test7a(aI.clone(), bI.clone()); }); @@ -145,6 +160,13 @@ public class TestSplitPacks { "test4e", "test4f", "test4g", + "test4a_alias", + "test4b_alias", + "test4c_alias", + "test4d_alias", + "test4e_alias", + "test4f_alias", + "test4g_alias", "test5a", "test6a", "test7a"}) @@ -711,10 +733,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", - IRNode.STORE_VECTOR, "> 0"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true"}) // Cyclic dependency with distance 2 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4a(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+2] = a[i+0]; @@ -724,11 +757,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true"}) // Cyclic dependency with distance 3 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4b(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+3] = a[i+0]; @@ -738,11 +781,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"MaxVectorSize", ">=8"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 4 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4c(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+4] = a[i+0]; @@ -752,11 +805,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 5 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4d(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+5] = a[i+0]; @@ -766,11 +829,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 6 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4e(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+6] = a[i+0]; @@ -780,11 +853,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 7 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4f(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+7] = a[i+0]; @@ -794,11 +877,21 @@ public class TestSplitPacks { @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", - IRNode.STORE_VECTOR, "> 0"}, - applyIf = {"MaxVectorSize", ">=32"}, + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) // Cyclic dependency with distance 8 -> split into 8-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check -> full vectorization. static Object[] test4g(short[] a, short[] b) { for (int i = 0; i < RANGE-64; i++) { b[i+8] = a[i+0]; @@ -806,6 +899,181 @@ public class TestSplitPacks { return new Object[]{ a, b }; } + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 2 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4a_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+2] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 3 -> split into 2-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4b_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+3] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 4 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4c_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+4] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 5 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4d_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+5] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 6 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4e_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+6] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 7 -> split into 4-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4f_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+7] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "= 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) + // Cyclic dependency with distance 8 -> split into 8-packs + @IR(counts = {IRNode.LOAD_VECTOR_S, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0", + ".*multiversion.*", "> 0"}, + phase = CompilePhase.PRINT_IDEAL, + applyIfAnd = {"MaxVectorSize", ">=32", "UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + // Speculative aliasing check with multiversioning -> full vectorization & split packs. + static Object[] test4g_alias(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+8] = a[i+0]; + } + return new Object[]{ a, b }; + } + @Test @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java index 8df1e03e3f4..8d4822ade57 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java @@ -31,10 +31,18 @@ * compiler.vectorization.runner.VectorizationTestRunner * * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI - * compiler.vectorization.runner.LoopArrayIndexComputeTest + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest nAV_ySAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest yAV_ySAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest nAV_nSAC + * + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.vectorization.runner.LoopArrayIndexComputeTest yAV_nSAC * * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") * @requires vm.compiler2.enabled @@ -48,6 +56,18 @@ import java.util.Random; public class LoopArrayIndexComputeTest extends VectorizationTestRunner { + // We must pass the flags directly to the test-VM, and not the driver vm in the @run above. + @Override + protected String[] testVMFlags(String[] args) { + return switch (args[0]) { + case "nAV_ySAC" -> new String[]{"-XX:-AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"}; + case "yAV_ySAC" -> new String[]{"-XX:+AlignVector", "-XX:+UseAutoVectorizationSpeculativeAliasingChecks"}; + case "nAV_nSAC" -> new String[]{"-XX:-AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}; + case "yAV_nSAC" -> new String[]{"-XX:+AlignVector", "-XX:-UseAutoVectorizationSpeculativeAliasingChecks"}; + default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } + }; + } + private static final int SIZE = 6543; private int[] ints; @@ -175,7 +195,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] indexWithDifferentConstantsNeg() { int[] res = new int[SIZE]; for (int i = 1; i < SIZE / 4; i++) { @@ -186,7 +215,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] indexWithDifferentInvariants() { int[] res = new int[SIZE]; for (int i = SIZE / 4; i < SIZE / 2; i++) { @@ -276,7 +314,17 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.MUL_VS, ">0", + IRNode.LOAD_VECTOR_S, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public short[] shortArrayWithDependenceNeg() { short[] res = new short[SIZE]; System.arraycopy(shorts, 0, res, 0, SIZE); @@ -304,8 +352,11 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Data dependency at distance 2: restrict vector size to 2 @IR(applyIfCPUFeatureOr = {"sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + phase = CompilePhase.PRINT_IDEAL, counts = {IRNode.STORE_VECTOR, ">0", - IRNode.MUL_VS, IRNode.VECTOR_SIZE_2, ">0"}) // size 2 only + IRNode.MUL_VS, IRNode.VECTOR_SIZE_2, ">0", // size 2 only + ".*multiversion.*", "= 0"}) public char[] charArrayWithDependenceNeg() { char[] res = new char[SIZE]; System.arraycopy(chars, 0, res, 0, SIZE); @@ -332,12 +383,22 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + failOn = {IRNode.STORE_VECTOR}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.ADD_VB, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public byte[] byteArrayWithDependenceNeg() { byte[] res = new byte[SIZE]; System.arraycopy(bytes, 0, res, 0, SIZE); for (int i = 3; i < SIZE / 2; i++) { - res[i] *= bytes[i - 3]; + res[i] += bytes[i - 3]; } return res; } @@ -359,8 +420,19 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Data dependency at distance 4: restrict vector size to 4 @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}, + phase = CompilePhase.PRINT_IDEAL, counts = {IRNode.STORE_VECTOR, ">0", - IRNode.OR_VB, IRNode.VECTOR_SIZE_4, ">0"}) // size 4 only + IRNode.OR_VB, IRNode.VECTOR_SIZE_4, ">0", // size 4 only + ".*multiversion.*", "= 0"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfAnd = {"UseAutoVectorizationSpeculativeAliasingChecks", "true", "AlignVector", "false"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.OR_VB, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public boolean[] booleanArrayWithDependenceNeg() { boolean[] res = new boolean[SIZE]; System.arraycopy(booleans, 0, res, 0, SIZE); @@ -386,7 +458,16 @@ public class LoopArrayIndexComputeTest extends VectorizationTestRunner { @Test // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "false"}) + // Speculative aliasing check -> never fails -> only predicate, no multiversioning. + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIf = {"UseAutoVectorizationSpeculativeAliasingChecks", "true"}, + phase = CompilePhase.PRINT_IDEAL, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.LOAD_VECTOR_I, ">0", // full vectorization + ".*multiversion.*", "= 0"}) + // JDK-8354303: could we prove statically that there is no aliasing? public int[] differentIndexWithSameType() { int[] res1 = new int[SIZE]; int[] res2 = new int[SIZE]; diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java new file mode 100644 index 00000000000..9c8270e4660 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAliasing.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1) +public abstract class VectorAliasing { + @Param({/*"512", "1024", */ "10000"}) + public int SIZE; + + public static int INVAR_ZERO = 0; + + // For all types we have an "a" and "b" series. Each series is an alias to the same array. + private byte[] aB; + private byte[] bB; + + private int[] aI; + private int[] bI; + + private long[] aL; + private long[] bL; + + private int iteration = 0; + + @Param("0") + private int seed; + private Random r = new Random(seed); + + @Setup + public void init() { + aB = new byte[SIZE]; + bB = new byte[SIZE]; + + aI = new int[SIZE]; + bI = new int[SIZE]; + + aL = new long[SIZE]; + bL = new long[SIZE]; + + for (int i = 0; i < SIZE; i++) { + aB[i] = (byte) r.nextInt(); + bB[i] = (byte) r.nextInt(); + + aI[i] = r.nextInt(); + bI[i] = r.nextInt(); + + aL[i] = r.nextLong(); + bL[i] = r.nextLong(); + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_B(byte[] a, byte b[]) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_B(byte[] a, byte b[], int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_I(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_I(int[] a, int[] b, int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_L(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void copy_L(long[] a, long[] b, int aOffset, int bOffset, int size) { + for (int i = 0; i < size; i++) { + b[i + bOffset] = a[i + aOffset]; + } + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_B_sameIndex_noalias() { + copy_B(bB, aB); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_B_sameIndex_alias() { + copy_B(aB, aB); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_B_differentIndex_noalias() { + copy_B(bB, aB, 0, 0, aB.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_B_differentIndex_alias() { + copy_B(aB, aB, 0, 0, aB.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_B_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_B(bB, aB, 0, 0, aB.length); // noalias + } else { + copy_B(aB, aB, 0, 0, aB.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_B_half() { + copy_B(aB, aB, 0, aB.length / 2, aB.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_B_partial_overlap() { + copy_B(aB, aB, 0, aB.length / 4, aB.length / 4 * 3); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_I_sameIndex_noalias() { + copy_I(bI, aI); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_I_sameIndex_alias() { + copy_I(aI, aI); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_I_differentIndex_noalias() { + copy_I(bI, aI, 0, 0, aI.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_I_differentIndex_alias() { + copy_I(aI, aI, 0, 0, aI.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_I_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_I(bI, aI, 0, 0, aI.length); // noalias + } else { + copy_I(aI, aI, 0, 0, aI.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_I_half() { + copy_I(aI, aI, 0, aI.length / 2, aI.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_I_partial_overlap() { + copy_I(aI, aI, 0, aI.length / 4, aI.length / 4 * 3); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_L_sameIndex_noalias() { + copy_L(bL, aL); + } + + @Benchmark + // Vectorizes with static analysis, since using same index -> iterations trivially independent. + public void bench_copy_array_L_sameIndex_alias() { + copy_L(aL, aL); + } + + @Benchmark + // Vectorizes if has at least one of: predicate or multiversioning + public void bench_copy_array_L_differentIndex_noalias() { + copy_L(bL, aL, 0, 0, aL.length); + } + + @Benchmark + // never vectorizes, with our without runtime check + public void bench_copy_array_L_differentIndex_alias() { + copy_L(aL, aL, 0, 0, aL.length); + } + + @Benchmark + // Requires multiversioning for vectorization. + // With only the predicate, we will eventually deopt and compile without vectorization. + public void bench_copy_array_L_differentIndex_mixed() { + if ((iteration++) % 2 == 0) { + copy_L(bL, aL, 0, 0, aL.length); // noalias + } else { + copy_L(aL, aL, 0, 0, aL.length); // alias + } + } + + // No overlap -> expect vectoirzation. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_L_half() { + copy_L(aL, aL, 0, aL.length / 2, aL.length / 2); + } + + // Overlap, but never alias -> expect vectorization. + // Vectorizes if has at least one of: predicate or multiversioning + @Benchmark + public void bench_copy_array_L_partial_overlap() { + copy_L(aL, aL, 0, aL.length / 4, aL.length / 4 * 3); + } + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseAutoVectorizationSpeculativeAliasingChecks" + }) + public static class VectorAliasingSuperWordWithoutSpeculativeAliasingChecks extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseAutoVectorizationPredicate" + }) + public static class VectorAliasingSuperWordWithoutAutoVectorizationPredicate extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-LoopMultiversioning" + }) + public static class VectorAliasingSuperWordWithoutMultiversioning extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:AutoVectorizationOverrideProfitability=0" + }) + public static class VectorAliasingSuperWordPretendNotProfitable extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UseSuperWord" + }) + public static class VectorAliasingSuperWord extends VectorAliasing {} + + @Fork(value = 1, jvmArgs = { + "-XX:-UseSuperWord" + }) + public static class VectorAliasingNoSuperWord extends VectorAliasing {} +} From 57df267e4269b26f7450309b54c55ddee458f75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 28 Aug 2025 06:30:25 +0000 Subject: [PATCH 256/471] 8365262: [IR-Framework] Add simple way to add cross-product of flags Reviewed-by: bmaillard, epeter --- .../jtreg/compiler/lib/ir_framework/README.md | 2 +- .../lib/ir_framework/TestFramework.java | 67 +++++++ .../TestFloatConversionsVector.java | 16 +- .../tests/TestScenariosCrossProduct.java | 164 ++++++++++++++++++ 4 files changed, 237 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index 6bdae262599..2a454f2990d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -146,7 +146,7 @@ More information about IR matching can be found in the Javadocs of [IR](./IR.jav ### 2.3 Test VM Flags and Scenarios The recommended way to use the framework is by defining a single `@run driver` statement in the JTreg header which, however, does not allow the specification of additional test VM flags. Instead, the user has the possibility to provide VM flags by calling `TestFramework.runWithFlags()` or by creating a `TestFramework` builder object on which `addFlags()` can be called. -If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). +If a user wants to provide multiple flag combinations for a single test, he or she has the option to provide different scenarios. A scenario based flag will always have precedence over other user defined flags. More information about scenarios can be found in the Javadocs of [Scenario](./Scenario.java). If a user wants to test all combinations of multiple sets of flags, they can use `TestFramework.addCrossProductScenarios()`. ### 2.4 Compiler Controls The framework allows the use of additional compiler control annotations for helper method and classes in the same fashion as JMH does. The following annotations are supported and described in the referenced Javadocs for the annotation class: diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 8e509c66c9a..85c52ef33da 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -46,7 +46,9 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This class represents the main entry point to the test framework whose main purpose is to perform regex-based checks on @@ -333,6 +335,71 @@ public class TestFramework { return this; } + /** + * Add the cross-product (cartesian product) of sets of flags as Scenarios. Unlike when when constructing + * scenarios directly a string can contain multiple flags separated with a space. This allows grouping + * flags that have to be specified togeher. Further, an empty string in a set stands in for "no flag". + *

        + * Example: + *

        +     *     addCrossProductScenarios(Set.of("", "-Xint", "-Xbatch -XX:-TieredCompilation"),
        +     *                              Set.of("-XX:+UseNewCode", "-XX:UseNewCode2"))
        +     * 
        + * produces the following Scenarios + *
        +     *     Scenario(0, "-XX:+UseNewCode")
        +     *     Scenario(1, "-XX:+UseNewCode2")
        +     *     Scenario(2, "-Xint", "-XX:+UseNewCode")
        +     *     Scenario(3, "-Xint", "-XX:+UseNewCode2")
        +     *     Scenario(4, "-Xbatch -XX:-TieredCompilation", "-XX:+UseNewCode")
        +     *     Scenario(5, "-Xbatch -XX:-TieredCompilation", "-XX:+UseNewCode2")
        +     * 
        + * + * @param sets sets of flags to generate the cross product for. + * @return the same framework instance. + */ + @SafeVarargs + final public TestFramework addCrossProductScenarios(Set... flagSets) { + TestFormat.checkAndReport(flagSets != null && + Arrays.stream(flagSets).noneMatch(Objects::isNull) && + Arrays.stream(flagSets).flatMap(Set::stream).noneMatch(Objects::isNull), + "Flags must not be null"); + if (flagSets.length == 0) { + return this; + } + + int initIdx = 0; + if (this.scenarioIndices != null && !this.scenarioIndices.isEmpty()) { + initIdx = this.scenarioIndices.stream().max(Comparator.comparingInt(Integer::intValue)).get() + 1; + } + AtomicInteger idx = new AtomicInteger(initIdx); + + Stream> crossProduct = Arrays.stream(flagSets) + .reduce( + Stream.of(Collections.emptyList()), // Initialize Stream> acc with a Stream containing an empty list of Strings. + (Stream> acc, Set set) -> + acc.flatMap(lAcc -> // For each List> lAcc in acc... + set.stream().map(flag -> { // ...and each flag in the current set... + List newList = new ArrayList<>(lAcc); // ...create a new list containing lAcc... + newList.add(flag); // ...and append the flag. + return newList; + }) // This results in one List> for each lAcc... + ), // ...that get flattend into one big List>. + (a, b) -> Stream.concat(a, b)); // combiner; if any reduction steps are executed in parallel, just concat two streams. + + Scenario[] newScenarios = crossProduct + .map(flags -> new Scenario( // For each List flags in crossProduct create a new Scenario. + idx.getAndIncrement(), + flags.stream() // Process flags + .map(s -> Set.of(s.split("[ ]"))) // Split muliple flags in the same string into separate strings. + .flatMap(Collection::stream) // Flatten the Stream> into Stream>. + .filter(s -> !s.isEmpty()) // Remove empty string flags. + .collect(Collectors.toList()) + .toArray(new String[0]))) + .collect(Collectors.toList()).toArray(new Scenario[0]); + return addScenarios(newScenarios); + } + /** * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES} * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode. diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java index 482dcf934c5..3ba9fe7472c 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java @@ -27,14 +27,13 @@ * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs * @requires vm.compiler2.enabled * @library /test/lib / - * @run driver compiler.vectorization.TestFloatConversionsVector nCOH_nAV - * @run driver compiler.vectorization.TestFloatConversionsVector nCOH_yAV - * @run driver compiler.vectorization.TestFloatConversionsVector yCOH_nAV - * @run driver compiler.vectorization.TestFloatConversionsVector yCOH_yAV + * @run driver compiler.vectorization.TestFloatConversionsVector */ package compiler.vectorization; +import java.util.Set; + import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -49,13 +48,8 @@ public class TestFloatConversionsVector { public static void main(String args[]) { TestFramework framework = new TestFramework(TestFloatConversionsVector.class); framework.addFlags("-XX:-TieredCompilation", "-XX:CompileThresholdScaling=0.3"); - switch (args[0]) { - case "nCOH_nAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "nCOH_yAV" -> { framework.addFlags("-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"); } - case "yCOH_nAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); } - case "yCOH_yAV" -> { framework.addFlags("-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); } - default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); } - }; + framework.addCrossProductScenarios(Set.of("-XX:-UseCompactObjectHeaders", "-XX:+UseCompactObjectHeaders"), + Set.of("-XX:-AlignVector", "-XX:+AlignVector")); framework.start(); System.out.println("PASSED"); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java new file mode 100644 index 00000000000..496fcbddb0f --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestScenariosCrossProduct.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.tests; + +import java.util.Set; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.shared.TestRunException; +import compiler.lib.ir_framework.shared.TestFormatException; +import jdk.test.lib.Asserts; + +/* + * @test + * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless + * @summary Test cross product scenarios with the framework. + * @library /test/lib /testlibrary_tests / + * @run driver ir_framework.tests.TestScenariosCrossProduct + */ + +public class TestScenariosCrossProduct { + static void hasNFailures(String s, int count) { + if (!s.matches("The following scenarios have failed: (#[0-9](, )?){" + count + "}. Please check stderr for more information.")) { + throw new RuntimeException("Expected " + count + " failures in \"" + s + "\""); + } + } + + public static void main(String[] args) { + // Test argument handling + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios((Set[]) null); + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(Set.of("foo", "bar"), null); + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(Set.of("blub"), Set.of("foo", null)); + Asserts.fail("Should have thrown exception"); + } catch (NullPointerException e) {} // Set.of prevents null elements + try { + TestFramework t = new TestFramework(); + t.addCrossProductScenarios(); + } catch (TestFormatException e) { + Asserts.fail("Should not have thrown exception"); + } + + // Single set should test all flags in the set by themselves. + try { + TestFramework t1 = new TestFramework(); + t1.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=51", + "-XX:TLABRefillWasteFraction=53", + "-XX:TLABRefillWasteFraction=64")); + t1.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 3); + } + + // The cross product of a set with one element and a set with three elements is three sets. + try { + TestFramework t2 = new TestFramework(); + t2.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2", "-XX:+UseNewCode3")); + t2.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 3); + } + + // The cross product of two sets with two elements is four sets. + try { + TestFramework t3 = new TestFramework(); + t3.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=53", "-XX:TLABRefillWasteFraction=64"), + Set.of("-XX:+UseNewCode", "-XX:-UseNewCode")); + t3.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 4); + } + + // Test with a pair of flags. + try { + TestFramework t4 = new TestFramework(); + t4.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=50 -XX:+UseNewCode", "-XX:TLABRefillWasteFraction=40"), + Set.of("-XX:+UseNewCode2")); + t4.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 1); + } + + // Test with an empty string. All 6 scenarios fail because 64 is the default value for TLABRefillWasteFraction. + try { + TestFramework t5 = new TestFramework(); + t5.addCrossProductScenarios(Set.of("", "-XX:TLABRefillWasteFraction=51", "-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2")); + t5.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 6); + } + + try { + TestFramework t6 = new TestFramework(); + t6.addScenarios(new Scenario(0, "-XX:TLABRefillWasteFraction=50", "-XX:+UseNewCode")); // failPair + t6.addCrossProductScenarios(Set.of("-XX:TLABRefillWasteFraction=51", "-XX:TLABRefillWasteFraction=53"), + Set.of("-XX:+UseNewCode", "-XX:+UseNewCode2")); + try { + t6.addScenarios(new Scenario(4, "-XX:+UseNewCode3")); // fails because index 4 is already used + Asserts.fail("Should have thrown exception"); + } catch (TestFormatException e) {} + t6.addScenarios(new Scenario(5, "-XX:+UseNewCode3")); // fail default + t6.start(); + Asserts.fail("Should have thrown exception"); + } catch (TestRunException e) { + hasNFailures(e.getMessage(), 6); + } + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "64"}, counts = {IRNode.CALL, "1"}) + public void failDefault() { + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "51"}, counts = {IRNode.CALL, "1"}) + public void fail1() { + } + + @Test + @IR(applyIf = {"TLABRefillWasteFraction", "53"}, counts = {IRNode.CALL, "1"}) + public void fail2() { + } + + @Test + @IR(applyIfAnd = {"TLABRefillWasteFraction", "50", "UseNewCode", "true"}, counts = {IRNode.CALL, "1"}) + public void failPair() { + } +} From ab1f2af4f0e9d3bea53f394413720c19fc7cae62 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 28 Aug 2025 06:57:57 +0000 Subject: [PATCH 257/471] 8366255: Remove 'package_to_module' function from imageFile.cpp Reviewed-by: rriggs, coleenp --- .../share/native/libjimage/imageFile.cpp | 84 +------------------ .../share/native/libjimage/imageFile.hpp | 21 +---- .../share/native/libjimage/jimage.cpp | 19 +---- .../share/native/libjimage/jimage.hpp | 21 +---- 4 files changed, 6 insertions(+), 139 deletions(-) diff --git a/src/java.base/share/native/libjimage/imageFile.cpp b/src/java.base/share/native/libjimage/imageFile.cpp index 4a8f35cd6fa..d97a8f95a60 100644 --- a/src/java.base/share/native/libjimage/imageFile.cpp +++ b/src/java.base/share/native/libjimage/imageFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -148,65 +148,6 @@ void ImageLocation::clear_data() { memset(_attributes, 0, sizeof(_attributes)); } -// ImageModuleData constructor maps out sub-tables for faster access. -ImageModuleData::ImageModuleData(const ImageFileReader* image_file) : - _image_file(image_file), - _endian(image_file->endian()) { -} - -// Release module data resource. -ImageModuleData::~ImageModuleData() { -} - - -// Return the module in which a package resides. Returns NULL if not found. -const char* ImageModuleData::package_to_module(const char* package_name) { - // replace all '/' by '.' - char* replaced = new char[(int) strlen(package_name) + 1]; - assert(replaced != NULL && "allocation failed"); - int i; - for (i = 0; package_name[i] != '\0'; i++) { - replaced[i] = package_name[i] == '/' ? '.' : package_name[i]; - } - replaced[i] = '\0'; - - // build path /packages/ - const char* radical = "/packages/"; - char* path = new char[(int) strlen(radical) + (int) strlen(package_name) + 1]; - assert(path != NULL && "allocation failed"); - strcpy(path, radical); - strcat(path, replaced); - delete[] replaced; - - // retrieve package location - ImageLocation location; - bool found = _image_file->find_location(path, location); - delete[] path; - if (!found) { - return NULL; - } - - // retrieve offsets to module name - int size = (int)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); - u1* content = new u1[size]; - assert(content != NULL && "allocation failed"); - _image_file->get_resource(location, content); - u1* ptr = content; - // sequence of sizeof(8) isEmpty|offset. Use the first module that is not empty. - u4 offset = 0; - for (i = 0; i < size; i+=8) { - u4 isEmpty = _endian->get(*((u4*)ptr)); - ptr += 4; - if (!isEmpty) { - offset = _endian->get(*((u4*)ptr)); - break; - } - ptr += 4; - } - delete[] content; - return _image_file->get_strings().get(offset); -} - // Manage a table of open image files. This table allows multiple access points // to share an open image. ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) { @@ -340,8 +281,7 @@ ImageFileReader* ImageFileReader::id_to_reader(u8 id) { } // Constructor initializes to a closed state. -ImageFileReader::ImageFileReader(const char* name, bool big_endian) : - _module_data(NULL) { +ImageFileReader::ImageFileReader(const char* name, bool big_endian) { // Copy the image file name. int len = (int) strlen(name) + 1; _name = new char[len]; @@ -362,10 +302,6 @@ ImageFileReader::~ImageFileReader() { delete[] _name; _name = NULL; } - - if (_module_data != NULL) { - delete _module_data; - } } // Open image file for read access. @@ -414,11 +350,7 @@ bool ImageFileReader::open() { _location_bytes = _index_data + location_bytes_offset; // Compute address of index string table. _string_bytes = _index_data + string_bytes_offset; - - // Initialize the module data - _module_data = new ImageModuleData(this); - // Successful open (if memory allocation succeeded). - return _module_data != NULL; + return true; } // Close image file. @@ -433,11 +365,6 @@ void ImageFileReader::close() { osSupport::close(_fd); _fd = -1; } - - if (_module_data != NULL) { - delete _module_data; - _module_data = NULL; - } } // Read directly from the file. @@ -567,8 +494,3 @@ void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_dat assert(is_read && "error reading from image or short read"); } } - -// Return the ImageModuleData for this image -ImageModuleData * ImageFileReader::get_image_module_data() { - return _module_data; -} diff --git a/src/java.base/share/native/libjimage/imageFile.hpp b/src/java.base/share/native/libjimage/imageFile.hpp index 78b37a38b7f..5fb4ea3baaa 100644 --- a/src/java.base/share/native/libjimage/imageFile.hpp +++ b/src/java.base/share/native/libjimage/imageFile.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -302,20 +302,6 @@ public: } }; -// -// Manage the image module meta data. -class ImageModuleData { - const ImageFileReader* _image_file; // Source image file - Endian* _endian; // Endian handler - -public: - ImageModuleData(const ImageFileReader* image_file); - ~ImageModuleData(); - - // Return the module in which a package resides. Returns NULL if not found. - const char* package_to_module(const char* package_name); -}; - // Image file header, starting at offset 0. class ImageHeader { private: @@ -428,7 +414,6 @@ private: u4* _offsets_table; // Location offset table u1* _location_bytes; // Location attributes u1* _string_bytes; // String table - ImageModuleData *_module_data; // The ImageModuleData for this image ImageFileReader(const char* name, bool big_endian); ~ImageFileReader(); @@ -577,9 +562,5 @@ public: // Return the resource for the supplied path. void get_resource(ImageLocation& location, u1* uncompressed_data) const; - - // Return the ImageModuleData for this image - ImageModuleData * get_image_module_data(); - }; #endif // LIBJIMAGE_IMAGEFILE_HPP diff --git a/src/java.base/share/native/libjimage/jimage.cpp b/src/java.base/share/native/libjimage/jimage.cpp index 7b5eacd1fcb..10e85eb2520 100644 --- a/src/java.base/share/native/libjimage/jimage.cpp +++ b/src/java.base/share/native/libjimage/jimage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -86,23 +86,6 @@ JIMAGE_Close(JImageFile* image) { ImageFileReader::close((ImageFileReader*) image); } -/* - * JImagePackageToModule - Given an open image file (see JImageOpen) and the name - * of a package, return the name of module where the package resides. If the - * package does not exist in the image file, the function returns NULL. - * The resulting string does/should not have to be released. All strings are - * utf-8, zero byte terminated. - * - * Ex. - * const char* package = (*JImagePackageToModule)(image, "java/lang"); - * tty->print_cr(package); - * -> java.base - */ -extern "C" JNIEXPORT const char* -JIMAGE_PackageToModule(JImageFile* image, const char* package_name) { - return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name); -} - /* * JImageFindResource - Given an open image file (see JImageOpen), a module * name, a version string and the name of a class/resource, return location diff --git a/src/java.base/share/native/libjimage/jimage.hpp b/src/java.base/share/native/libjimage/jimage.hpp index 31e47bd67fe..a514e737b49 100644 --- a/src/java.base/share/native/libjimage/jimage.hpp +++ b/src/java.base/share/native/libjimage/jimage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -93,25 +93,6 @@ JIMAGE_Close(JImageFile* jimage); typedef void (*JImageClose_t)(JImageFile* jimage); -/* - * JImagePackageToModule - Given an open image file (see JImageOpen) and the name - * of a package, return the name of module where the package resides. If the - * package does not exist in the image file, the function returns NULL. - * The resulting string does/should not have to be released. All strings are - * utf-8, zero byte terminated. - * - * Ex. - * const char* package = (*JImagePackageToModule)(image, "java/lang"); - * tty->print_cr(package); - * -> java.base - */ - -extern "C" JNIEXPORT const char * -JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name); - -typedef const char* (*JImagePackageToModule_t)(JImageFile* jimage, const char* package_name); - - /* * JImageFindResource - Given an open image file (see JImageOpen), a module * name, a version string and the name of a class/resource, return location From d06c66f7f5a6d3c649c0a10ad735f0cc7c673b2a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 28 Aug 2025 09:21:26 +0000 Subject: [PATCH 258/471] 8365055: G1: Merge Heap Roots phase incorrectly clears young gen remembered set every time Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 6 ++++++ src/hotspot/share/gc/g1/g1CollectionSet.cpp | 5 ++++- src/hotspot/share/gc/g1/g1Policy.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSet.cpp | 10 ---------- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 1 - 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 65d863f43ee..e9834736707 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2441,6 +2441,12 @@ void G1CollectedHeap::update_perf_counter_cpu_time() { } void G1CollectedHeap::start_new_collection_set() { + // Clear current young cset group to allow adding. + // It is fine to clear it this late - evacuation does not add any remembered sets + // by itself, but only marks cards. + // The regions had their association to this group already removed earlier. + young_regions_cset_group()->clear(); + collection_set()->start_incremental_building(); clear_region_attr(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 72033a1ce9a..1e836e3efa2 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -323,7 +323,10 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi verify_young_cset_indices(); - double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, _g1h->young_regions_cardset()->occupied()); + size_t num_young_cards = _g1h->young_regions_cardset()->occupied(); + _policy->record_card_rs_length(num_young_cards); + + double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, num_young_cards); // Base time already includes the whole remembered set related time, so do not add that here // again. double predicted_eden_time = _policy->predict_young_region_other_time_ms(eden_region_length) + diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 3571945d587..d449439df8c 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -129,8 +129,8 @@ public: hr->install_surv_rate_group(_survivor_surv_rate_group); } - void record_card_rs_length(size_t card_rs_length) { - _card_rs_length = card_rs_length; + void record_card_rs_length(size_t num_cards) { + _card_rs_length = num_cards; } double cur_pause_start_sec() const { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 6b7532a99aa..25790a00bd9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1440,16 +1440,6 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { workers->run_task(&cl, num_workers); } - { - size_t young_rs_length = g1h->young_regions_cardset()->occupied(); - // We only use young_rs_length statistics to estimate young regions length. - g1h->policy()->record_card_rs_length(young_rs_length); - - // Clear current young only collection set. Survivor regions will be added - // to the set during evacuation. - g1h->young_regions_cset_group()->clear(); - } - print_merge_heap_roots_stats(); if (initial_evacuation) { diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 29eab44d4a8..04197495033 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -519,7 +519,6 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats(); sampled_card_set_stats.add(_g1h->young_regions_card_set_memory_stats()); _g1h->set_young_gen_card_set_stats(sampled_card_set_stats); - _g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates()); phase_times()->record_register_regions(task_time.seconds() * 1000.0); From 7469a274bb70b2cdc8a47e62cc989f86766c605a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 28 Aug 2025 09:21:52 +0000 Subject: [PATCH 259/471] 8365939: [Redo] G1: Move collection set related full gc reset code into abandon_collection_set() method Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 ++ src/hotspot/share/gc/g1/g1FullCollector.cpp | 5 ----- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e9834736707..618e9b055fe 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2803,6 +2803,8 @@ void G1CollectedHeap::abandon_collection_set() { collection_set()->stop_incremental_building(); collection_set()->abandon_all_candidates(); + + young_regions_cset_group()->clear(true /* uninstall_group_cardset */); } bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 70cded3220a..33202658c46 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -244,11 +244,6 @@ void G1FullCollector::complete_collection(size_t allocation_word_size) { _heap->resize_all_tlabs(); - // We clear remembered sets for young regions this late in the full GC because - // G1HeapVerifier expects the remembered sets for all young regions to be complete - // throughout most of the collection process (e.g. G1FullCollector::verify_after_marking). - _heap->young_regions_cset_group()->clear(); - _heap->policy()->record_full_collection_end(); _heap->gc_epilogue(true); diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 4227a90960b..c5af7e34dd9 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -235,6 +235,8 @@ private: VerifyOption _vo; bool _failures; + bool is_in_full_gc() const { return G1CollectedHeap::heap()->collector_state()->in_full_gc(); } + public: VerifyRegionClosure(VerifyOption vo) : _vo(vo), @@ -246,7 +248,7 @@ public: bool do_heap_region(G1HeapRegion* r) { guarantee(!r->has_index_in_opt_cset(), "Region %u still has opt collection set index %u", r->hrm_index(), r->index_in_opt_cset()); - guarantee(!r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete, is %s", r->hrm_index(), r->rem_set()->get_state_str()); + guarantee(is_in_full_gc() || !r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete outside full gc, is %s", r->hrm_index(), r->rem_set()->get_state_str()); // Humongous and old regions regions might be of any state, so can't check here. guarantee(!r->is_free() || !r->rem_set()->is_tracked(), "Remembered set for free region %u must be untracked, is %s", r->hrm_index(), r->rem_set()->get_state_str()); From a5a234005414a58f66c7e646a8f9b0042e9f9eec Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 28 Aug 2025 09:28:58 +0000 Subject: [PATCH 260/471] 8365053: Refresh hotspot precompiled.hpp with headers based on current frequency Reviewed-by: shade, ihse, erikj, qamai --- make/scripts/update_pch.sh | 101 ++++++++++++++++++ src/hotspot/share/precompiled/precompiled.hpp | 66 ++++-------- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 3 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 make/scripts/update_pch.sh diff --git a/make/scripts/update_pch.sh b/make/scripts/update_pch.sh new file mode 100644 index 00000000000..534525353fd --- /dev/null +++ b/make/scripts/update_pch.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# Copyright (c) 2025, Oracle and/or its affiliates. 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. +# +# 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. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# The output of this script may require some degree of human curation: +# - Redundant headers, e.g. both x.hpp, x.inline.hpp are included; +# - Headers relative to a non-default feature should be protected by an +# appropriate 'if' clause to make sure all variants can build without +# errors. + +# Time threshold for header compilation, if the time exceeds the +# threshold the header will be precompiled. +if [ -z "$MIN_MS" ]; then + MIN_MS=100000 +fi + +if [ -z "$CLEAN" ]; then + CLEAN=true +elif [ "$CLEAN" != "true" ] && [ "$CLEAN" != "false" ]; then + echo "Expected either 'true' or 'false' for CLEAN" +fi + +# CBA_PATH should point to a valid ClangBuildAnalyzer executable. +# Build steps: +# git clone --depth 1 git@github.com:aras-p/ClangBuildAnalyzer.git +# cd ClangBuildAnalyzer +# make -f projects/make/Makefile +if [ -z "$CBA_PATH" ]; then + CBA_PATH="./ClangBuildAnalyzer/build/ClangBuildAnalyzer" +fi + +set -eux + +PRECOMPILED_HPP="src/hotspot/share/precompiled/precompiled.hpp" +CBA_CONFIG="ClangBuildAnalyzer.ini" +TIMESTAMP="$(date +%Y%m%d-%H%M)" +RUN_NAME="pch_update_$TIMESTAMP" +CBA_OUTPUT="cba_out_$TIMESTAMP" + +if [ "$CLEAN" = "true" ]; then + trap 'rm -rf "build/'"$RUN_NAME"'" "$CBA_OUTPUT" "$CBA_CONFIG"' EXIT +fi + +sh configure --with-toolchain-type=clang \ + --with-conf-name="$RUN_NAME" \ + --disable-precompiled-headers \ + --with-extra-cxxflags="-ftime-trace" \ + --with-extra-cflags="-ftime-trace" + +make clean CONF_NAME="$RUN_NAME" +make hotspot CONF_NAME="$RUN_NAME" +"$CBA_PATH" --all "./build/$RUN_NAME/hotspot/variant-server/libjvm/objs" \ + "$CBA_OUTPUT" + +# Preserve license and comments on top +cat "$PRECOMPILED_HPP" | awk '/^#include/ {exit} {print}' > "$PRECOMPILED_HPP.tmp" + +if [ ! -f "$CBA_CONFIG" ]; then +cat < "$CBA_CONFIG" +[counts] +header=100 +headerChain=0 +template=0 +function=0 +fileCodegen=0 +fileParse=0 + +[misc] +onlyRootHeaders=true +EOF +fi + +"$CBA_PATH" --analyze "$CBA_OUTPUT" | \ + grep " ms: " | \ + # Keep the headers more expensive than ${1}ms + awk -v x="$MIN_MS" '$1 < x { exit } { print $3 }' | \ + # Filter away non-hotspot headers + grep hotspot/share | \ + awk -F "hotspot/share/" '{ printf "#include \"%s\"\n", $2 }' \ + >> "$PRECOMPILED_HPP.tmp" +mv "$PRECOMPILED_HPP.tmp" "$PRECOMPILED_HPP" + +java test/hotspot/jtreg/sources/SortIncludes.java --update "$PRECOMPILED_HPP" diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index a5f42a0fe86..670bd55e423 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -25,53 +25,27 @@ // Precompiled headers are turned off if the user passes // --disable-precompiled-headers to configure. -// These header files are included in at least 130 C++ files, as of -// measurements made in November 2018. This list excludes files named -// *.inline.hpp, since including them decreased build performance. +// These header files are selected using the output of Clang +// '-ftime-trace' as a measure of how much time we spend +// compiling them. -#include "classfile/classLoaderData.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcCause.hpp" -#include "logging/log.hpp" +#include "classfile/javaClasses.inline.hpp" #include "memory/allocation.hpp" -#include "memory/iterator.hpp" -#include "memory/memRegion.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "nmt/memTracker.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/klass.hpp" -#include "oops/method.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/objArrayOop.hpp" -#include "oops/oop.hpp" -#include "oops/oopsHierarchy.hpp" -#include "runtime/atomic.hpp" -#include "runtime/globals.hpp" -#include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/mutex.hpp" -#include "runtime/orderAccess.hpp" -#include "runtime/os.hpp" -#include "runtime/timer.hpp" -#include "utilities/align.hpp" -#include "utilities/bitMap.hpp" -#include "utilities/copy.hpp" -#include "utilities/debug.hpp" -#include "utilities/exceptions.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/macros.hpp" -#include "utilities/ostream.hpp" -#include "utilities/ticks.hpp" - -#ifdef TARGET_COMPILER_visCPP -// For Visual Studio, including the *.inline.hpp files actually -// increased performance. -#include "memory/allocation.inline.hpp" +#include "memory/iterator.inline.hpp" #include "oops/access.inline.hpp" +#include "oops/instanceStackChunkKlass.inline.hpp" +#include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/handles.inline.hpp" -#endif // TARGET_COMPILER_visCPP +#include "oops/oopHandle.inline.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/javaThread.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#if INCLUDE_SHENANDOAHGC +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#endif +#if INCLUDE_ZGC +#include "gc/z/zBarrier.inline.hpp" +#include "gc/z/zGeneration.inline.hpp" +#include "gc/z/zHeap.inline.hpp" +#endif diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 74da9626bae..f7b70079673 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -59,6 +59,7 @@ public class TestIncludesAreSorted { "share/metaprogramming", "share/oops", "share/opto", + "share/precompiled", "share/services", "share/utilities" }; From b0f5b23ed2a2f3b9d97754ced5382bb3fb3e8f40 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 28 Aug 2025 11:37:48 +0000 Subject: [PATCH 261/471] 8366145: G1: Help diagnose ubsan division by zero in computing pause time ratios (g1Analytics.cpp) Reviewed-by: tschatzl, kbarrett --- src/hotspot/share/gc/g1/g1Analytics.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/g1/g1Analytics.cpp b/src/hotspot/share/gc/g1/g1Analytics.cpp index 686554ffaa4..8fe0b25ceb7 100644 --- a/src/hotspot/share/gc/g1/g1Analytics.cpp +++ b/src/hotspot/share/gc/g1/g1Analytics.cpp @@ -181,6 +181,7 @@ void G1Analytics::update_gc_time_ratios(double end_time_sec, double pause_time_m double short_interval_ms = (end_time_sec - most_recent_gc_end_time_sec()) * 1000.0; + assert(short_interval_ms != 0.0, "short_interval_ms should not be zero, calculated from %f and %f", end_time_sec, most_recent_gc_end_time_sec()); _short_term_gc_time_ratio = gc_time_ms / short_interval_ms; _short_term_gc_time_ratio = clamp(_short_term_gc_time_ratio, 0.0, 1.0); From 5c78c7cd83d2d1ca1ba19151d6be40f5bd6077c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 28 Aug 2025 12:15:03 +0000 Subject: [PATCH 262/471] 8366341: [BACKOUT] JDK-8365256: RelocIterator should use indexes instead of pointers Reviewed-by: ayang --- src/hotspot/share/code/codeBlob.cpp | 30 +++++++++------ src/hotspot/share/code/nmethod.cpp | 20 +++++----- src/hotspot/share/code/relocInfo.cpp | 55 +++++++++++++--------------- src/hotspot/share/code/relocInfo.hpp | 28 +++++++------- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 6d34204d074..9ec5478a071 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -128,7 +128,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size int mutable_data_size) : _oop_maps(nullptr), // will be set by set_oop_maps() call _name(name), - _mutable_data(nullptr), + _mutable_data(header_begin() + size), // default value is blob_end() _size(size), _relocation_size(align_up(cb->total_relocation_size(), oopSize)), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -158,8 +158,10 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size if (_mutable_data == nullptr) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } + } else { + // We need unique and valid not null address + assert(_mutable_data == blob_end(), "sanity"); } - assert(_mutable_data != nullptr || _mutable_data_size == 0, "No mutable data => mutable data size is 0"); set_oop_maps(oop_maps); } @@ -168,7 +170,7 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) : _oop_maps(nullptr), _name(name), - _mutable_data(nullptr), + _mutable_data(header_begin() + size), // default value is blob_end() _size(size), _relocation_size(0), _content_offset(CodeBlob::align_code_offset(header_size)), @@ -182,9 +184,9 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade _kind(kind), _caller_must_gc_arguments(false) { - assert(_mutable_data == nullptr && _mutable_data_size == 0, "invariant"); assert(is_aligned(size, oopSize), "unaligned size"); assert(is_aligned(header_size, oopSize), "unaligned size"); + assert(_mutable_data == blob_end(), "sanity"); } void CodeBlob::restore_mutable_data(address reloc_data) { @@ -195,7 +197,7 @@ void CodeBlob::restore_mutable_data(address reloc_data) { vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); } } else { - _mutable_data = nullptr; + _mutable_data = blob_end(); // default value } if (_relocation_size > 0) { assert(_mutable_data_size > 0, "relocation is part of mutable data section"); @@ -204,13 +206,17 @@ void CodeBlob::restore_mutable_data(address reloc_data) { } void CodeBlob::purge() { - os::free(_mutable_data); - _mutable_data = nullptr; - _mutable_data_size = 0; - delete _oop_maps; - _oop_maps = nullptr; - _relocation_size = 0; - + assert(_mutable_data != nullptr, "should never be null"); + if (_mutable_data != blob_end()) { + os::free(_mutable_data); + _mutable_data = blob_end(); // Valid not null address + _mutable_data_size = 0; + _relocation_size = 0; + } + if (_oop_maps != nullptr) { + delete _oop_maps; + _oop_maps = nullptr; + } NOT_PRODUCT(_asm_remarks.clear()); NOT_PRODUCT(_dbg_strings.clear()); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a45ca141455..b8b3a70bf58 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1327,8 +1327,8 @@ nmethod::nmethod( "wrong mutable data size: %d != %d + %d", _mutable_data_size, _relocation_size, metadata_size); - // native wrapper does not have read-only data - _immutable_data = nullptr; + // native wrapper does not have read-only data but we need unique not null address + _immutable_data = blob_end(); _immutable_data_size = 0; _nul_chk_table_offset = 0; _handler_table_offset = 0; @@ -1510,7 +1510,8 @@ nmethod::nmethod( assert(immutable_data != nullptr, "required"); _immutable_data = immutable_data; } else { - _immutable_data = nullptr; + // We need unique not null address + _immutable_data = blob_end(); } CHECKED_CAST(_nul_chk_table_offset, uint16_t, (align_up((int)dependencies->size_in_bytes(), oopSize))); CHECKED_CAST(_handler_table_offset, uint16_t, (_nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize))); @@ -2146,14 +2147,15 @@ void nmethod::purge(bool unregister_nmethod) { delete ec; ec = next; } - - delete _pc_desc_container; + if (_pc_desc_container != nullptr) { + delete _pc_desc_container; + } delete[] _compiled_ic_data; - os::free(_immutable_data); - _immutable_data = nullptr; - _immutable_data_size = 0; - + if (_immutable_data != blob_end()) { + os::free(_immutable_data); + _immutable_data = blob_end(); // Valid not null address + } if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index fb24844000d..8fc22596d01 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -116,6 +116,9 @@ void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, re // ---------------------------------------------------------------------------------------------------- // Implementation of RelocIterator +// A static dummy to serve as a safe pointer when there is no relocation info. +static relocInfo dummy_relocInfo = relocInfo(relocInfo::none, 0); + void RelocIterator::initialize(nmethod* nm, address begin, address limit) { initialize_misc(); @@ -127,9 +130,14 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { guarantee(nm != nullptr, "must be able to deduce nmethod from other arguments"); _code = nm; - _base = nm->relocation_begin(); - _current = -1; - _len = nm->relocation_end() - _base; + if (nm->relocation_size() == 0) { + _current = &dummy_relocInfo - 1; + _end = &dummy_relocInfo; + } else { + assert(((nm->relocation_begin() != nullptr) && (nm->relocation_end() != nullptr)), "valid start and end pointer"); + _current = nm->relocation_begin() - 1; + _end = nm->relocation_end(); + } _addr = nm->content_begin(); // Initialize code sections. @@ -148,21 +156,11 @@ void RelocIterator::initialize(nmethod* nm, address begin, address limit) { } -RelocIterator::RelocIterator(relocInfo& ri) { - initialize_misc(); - _base = &ri; - _len = 1; - _current = -1; - _limit = nullptr; - _addr = 0; -} - RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { initialize_misc(); assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)), "valid start and end pointer"); - _base = cs->locs_start(); - _len = cs->locs_end() - _base; - _current = -1; + _current = cs->locs_start() - 1; + _end = cs->locs_end(); _addr = cs->start(); _code = nullptr; // Not cb->blob(); @@ -188,9 +186,8 @@ RelocIterator::RelocIterator(CodeBlob* cb) { } else { _code = nullptr; } - _base = cb->relocation_begin(); - _len = cb->relocation_end() - _base; - _current = -1; + _current = cb->relocation_begin() - 1; + _end = cb->relocation_end(); _addr = cb->content_begin(); _section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin(); @@ -219,7 +216,7 @@ void RelocIterator::set_limits(address begin, address limit) { // the limit affects this next stuff: if (begin != nullptr) { - int backup; + relocInfo* backup; address backup_addr; while (true) { backup = _current; @@ -241,12 +238,12 @@ void RelocIterator::set_limits(address begin, address limit) { // very efficiently (a single extra halfword). Larger chunks of // relocation data need a halfword header to hold their size. void RelocIterator::advance_over_prefix() { - if (current()->is_datalen()) { - _data = (short*) current()->data(); - _datalen = current()->datalen(); + if (_current->is_datalen()) { + _data = (short*) _current->data(); + _datalen = _current->datalen(); _current += _datalen + 1; // skip the embedded data & header } else { - _databuf = current()->immediate(); + _databuf = _current->immediate(); _data = &_databuf; _datalen = 1; _current++; // skip the header @@ -353,9 +350,9 @@ void Relocation::const_verify_data_value(address x) { RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; - relocInfo ri(rtype, 0); - RelocIterator itr(ri); - itr.next(); + relocInfo ri = relocInfo(rtype, 0); + RelocIterator itr; + itr.set_current(ri); itr.reloc(); return itr._rh; } @@ -842,7 +839,7 @@ void RelocIterator::print_current_on(outputStream* st) { return; } st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - p2i(current()), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), current()->addr_offset()); + p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); if (current()->format() != 0) st->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -993,7 +990,7 @@ void RelocIterator::print_current_on(outputStream* st) { void RelocIterator::print_on(outputStream* st) { RelocIterator save_this = (*this); - relocInfo* scan = current_no_check(); + relocInfo* scan = _current; if (!has_current()) scan += 1; // nothing to scan here! bool skip_next = has_current(); @@ -1003,7 +1000,7 @@ void RelocIterator::print_on(outputStream* st) { skip_next = false; st->print(" @" INTPTR_FORMAT ": ", p2i(scan)); - relocInfo* newscan = current_no_check()+1; + relocInfo* newscan = _current+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { st->print("%04x", *(short*)scan & 0xFFFF); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 58dbf61abbe..714a964b28d 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -562,13 +562,12 @@ class RelocIterator : public StackObj { private: address _limit; // stop producing relocations after this _addr - relocInfo* _base; // base pointer into relocInfo array - int _current; // current index - int _len; // length + relocInfo* _current; // the current relocation information + relocInfo* _end; // end marker; we're done iterating when _current == _end nmethod* _code; // compiled method containing _addr address _addr; // instruction to which the relocation applies - short* _data; // pointer to the relocation's data short _databuf; // spare buffer for compressed data + short* _data; // pointer to the relocation's data short _datalen; // number of halfwords in _data // Base addresses needed to compute targets of section_word_type relocs. @@ -579,14 +578,15 @@ class RelocIterator : public StackObj { _datalen = !b ? -1 : 0; DEBUG_ONLY(_data = nullptr); } + void set_current(relocInfo& ri) { + _current = &ri; + set_has_current(true); + } RelocationHolder _rh; // where the current relocation is allocated - relocInfo* current_no_check() const { return &_base[_current]; } - relocInfo* current() const { - assert(has_current(), "must have current"); - return current_no_check(); - } + relocInfo* current() const { assert(has_current(), "must have current"); + return _current; } void set_limits(address begin, address limit); @@ -597,7 +597,6 @@ class RelocIterator : public StackObj { void initialize(nmethod* nm, address begin, address limit); RelocIterator() { initialize_misc(); } - RelocIterator(relocInfo& ri); public: // constructor @@ -608,24 +607,25 @@ class RelocIterator : public StackObj { // get next reloc info, return !eos bool next() { _current++; - assert(_current <= _len, "must not overrun relocInfo"); - if (_current == _len) { + assert(_current <= _end, "must not overrun relocInfo"); + if (_current == _end) { set_has_current(false); return false; } set_has_current(true); - if (current()->is_prefix()) { + if (_current->is_prefix()) { advance_over_prefix(); assert(!current()->is_prefix(), "only one prefix at a time"); } - _addr += current()->addr_offset(); + _addr += _current->addr_offset(); if (_limit != nullptr && _addr >= _limit) { set_has_current(false); return false; } + return true; } From 8f864fd5637762153f26af5121cabdf21e1ad798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 28 Aug 2025 12:48:29 +0000 Subject: [PATCH 263/471] 8366222: TestCompileTaskTimeout causes asserts after JDK-8365909 Reviewed-by: chagedorn, thartmann --- .../jtreg/compiler/arguments/TestCompileTaskTimeout.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java index 141522744f4..4204f7be92e 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -49,7 +49,7 @@ public class TestCompileTaskTimeout { .shouldHaveExitValue(134) .shouldContain("timed out after"); - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=2000", "--version") .shouldHaveExitValue(0); } -} \ No newline at end of file +} From 79d8a34a92350680848052717c8a1d2a4c4331aa Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:09:46 +0000 Subject: [PATCH 264/471] 8365708: Add missing @Override annotations to WindowsMenuItemUIAccessor Reviewed-by: serb, kizune --- .../sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java | 1 + .../com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java | 3 ++- .../classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java | 1 + .../java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index 02054575d77..f28ae2a9326 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -52,6 +52,7 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index aa90b2f35b3..a9b09085ad1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -69,13 +69,14 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { private PropertyChangeListener changeListener; final WindowsMenuItemUIAccessor accessor = - new WindowsMenuItemUIAccessor() { + new WindowsMenuItemUIAccessor() { @Override public JMenuItem getMenuItem() { return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 1476c6fc152..a20b8eba98a 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -62,6 +62,7 @@ public final class WindowsMenuUI extends BasicMenuUI { return menuItem; } + @Override public State getState(JMenuItem menu) { State state = menu.isEnabled() ? State.NORMAL : State.DISABLED; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 628a4be1637..06ef5db23a1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -52,6 +52,7 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem return menuItem; } + @Override public State getState(JMenuItem menuItem) { return WindowsMenuItemUI.getState(this, menuItem); } From 22ae137400c711a4a991153b04b360a0df57bf0b Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:11:20 +0000 Subject: [PATCH 265/471] 8365711: Declare menuBarHeight and hotTrackingOn private Reviewed-by: serb, prr, kizune --- .../com/sun/java/swing/plaf/windows/WindowsMenuUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index a20b8eba98a..754b394d4ac 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -51,8 +51,8 @@ import com.sun.java.swing.plaf.windows.TMSchema.State; * Windows rendition of the component. */ public final class WindowsMenuUI extends BasicMenuUI { - protected Integer menuBarHeight; - protected boolean hotTrackingOn; + private Integer menuBarHeight; + private boolean hotTrackingOn; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { From afa8e79ba1a76066cf969cb3b5f76ea804780872 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 28 Aug 2025 13:13:10 +0000 Subject: [PATCH 266/471] 8365615: Improve JMenuBar/RightLeftOrientation.java Reviewed-by: prr, psadhukhan --- .../swing/JMenuBar/RightLeftOrientation.java | 93 ++++++++++--------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java index 80779c9ce1d..8308034d060 100644 --- a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java +++ b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -20,75 +20,76 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 4211731 4214512 * @summary * This test checks if menu bars lay out correctly when their - * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is - * manual. The tester is asked to compare left-to-right and - * right-to-left menu bars and judge whether they are mirror images of each - * other. + * ComponentOrientation property is set to RIGHT_TO_LEFT. + * The tester is asked to compare left-to-right and + * right-to-left menu bars and decide whether they are mirror + * images of each other. * @library /test/jdk/java/awt/regtesthelpers * @build PassFailJFrame * @run main/manual RightLeftOrientation */ import java.awt.ComponentOrientation; -import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.List; + import javax.swing.ButtonGroup; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import javax.swing.UIManager; -public class RightLeftOrientation { +public final class RightLeftOrientation { - static JFrame ltrFrame; - static JFrame rtlFrame; + private static List frames; private static final String INSTRUCTIONS = """ - This test checks menu bars for correct Right-To-Left Component Orientation. + This test checks menu bars for correct Right-To-Left component orientation. - You should see two frames, each containing a menu bar. - - One frame will be labelled "Left To Right" and will contain + You should see two frames, each contains a menu bar. + One frame is labelled "Left To Right" and contains a menu bar with menus starting on its left side. - The other frame will be labelled "Right To Left" and will - contain a menu bar with menus starting on its right side. + The other frame is labelled "Right To Left" and + contains a menu bar with menus starting on its right side. - The test will also contain radio buttons that can be used to set - the look and feel of the menu bars. - For each look and feel, you should compare the two menu - bars and make sure they are mirror images of each other. """; + The test also displays a frame with radio buttons + to change the look and feel of the menu bars. + For each look and feel, compare the two menu bars + in LTR and RTL orientation and make sure they are mirror + images of each other."""; public static void main(String[] args) throws Exception { PassFailJFrame.builder() - .title("RTL test Instructions") + .title("Menu Bar RTL Instructions") .instructions(INSTRUCTIONS) - .rows((int) INSTRUCTIONS.lines().count() + 2) .columns(30) .testUI(RightLeftOrientation::createTestUI) + .positionTestUIRightColumn() .build() .awaitAndCheck(); } - private static JFrame createTestUI() { - JFrame frame = new JFrame("RightLeftOrientation"); + private static JFrame createPlafChangerFrame() { + JFrame frame = new JFrame("Change Look and Feel"); JPanel panel = new JPanel(); ButtonGroup group = new ButtonGroup(); - JRadioButton rb; ActionListener plafChanger = new PlafChanger(); UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lafInfos.length; i++) { - rb = new JRadioButton(lafInfos[i].getName()); + JRadioButton rb = new JRadioButton(lafInfos[i].getName()); rb.setActionCommand(lafInfos[i].getClassName()); rb.addActionListener(plafChanger); group.add(rb); @@ -99,33 +100,39 @@ public class RightLeftOrientation { } frame.add(panel); - - ltrFrame = new JFrame("Left To Right"); - ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); - ltrFrame.setSize(400, 100); - ltrFrame.setLocation(new Point(10, 10)); - ltrFrame.setVisible(true); - - rtlFrame = new JFrame("Right To Left"); - rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); - rtlFrame.setSize(400, 100); - rtlFrame.setLocation(new Point(10, 120)); - rtlFrame.setVisible(true); frame.pack(); return frame; } - static class PlafChanger implements ActionListener { + private static List createTestUI() { + JFrame plafFrame = createPlafChangerFrame(); + + JFrame ltrFrame = new JFrame("Left To Right"); + ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 100); + + JFrame rtlFrame = new JFrame("Right To Left"); + rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 100); + + return (frames = List.of(plafFrame, ltrFrame, rtlFrame)); + } + + private static final class PlafChanger implements ActionListener { + @Override public void actionPerformed(ActionEvent e) { String lnfName = e.getActionCommand(); try { UIManager.setLookAndFeel(lnfName); - SwingUtilities.updateComponentTreeUI(ltrFrame); - SwingUtilities.updateComponentTreeUI(rtlFrame); - } - catch (Exception exc) { - System.err.println("Could not load LookAndFeel: " + lnfName); + frames.forEach(SwingUtilities::updateComponentTreeUI); + } catch (Exception exc) { + String message = "Could not set Look and Feel to " + lnfName; + System.err.println(message); + JOptionPane.showMessageDialog(frames.get(0), + message, + "Look and Feel Error", + JOptionPane.ERROR_MESSAGE); } } From 8051aaf0685f7bb23bf3e23d32ad45b0bffbce7b Mon Sep 17 00:00:00 2001 From: Rui Li Date: Thu, 28 Aug 2025 13:54:03 +0000 Subject: [PATCH 267/471] 8342640: GenShen: Silently ignoring ShenandoahGCHeuristics considered poor user-experience Reviewed-by: ysr, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index df2cd18042f..1ff001c5abd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -194,6 +194,13 @@ void ShenandoahArguments::initialize() { err_msg("GCCardSizeInBytes ( %u ) must be >= %u\n", GCCardSizeInBytes, (unsigned int) ShenandoahMinCardSizeInBytes)); } + // Gen shen does not support any ShenandoahGCHeuristics value except for the default "adaptive" + if ((strcmp(ShenandoahGCMode, "generational") == 0) + && strcmp(ShenandoahGCHeuristics, "adaptive") != 0) { + log_warning(gc)("Ignoring -XX:ShenandoahGCHeuristics input: %s, because generational shenandoah only" + " supports adaptive heuristics", ShenandoahGCHeuristics); + } + FullGCForwarding::initialize_flags(MaxHeapSize); } From 993babb326f937dc1630a5a8fa5e469a64c51206 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 28 Aug 2025 13:54:21 +0000 Subject: [PATCH 268/471] 8365863: /test/jdk/sun/security/pkcs11/Cipher tests skip without SkippedException Reviewed-by: weijun, djelinski --- .../security/pkcs11/Cipher/ReinitCipher.java | 7 +- .../security/pkcs11/Cipher/Test4512704.java | 21 ++--- .../pkcs11/Cipher/TestCICOWithGCM.java | 27 ++++--- .../pkcs11/Cipher/TestCICOWithGCMAndAAD.java | 10 +-- .../pkcs11/Cipher/TestChaChaPoly.java | 7 +- .../pkcs11/Cipher/TestChaChaPolyKAT.java | 16 ++-- .../pkcs11/Cipher/TestChaChaPolyNoReuse.java | 15 ++-- .../Cipher/TestChaChaPolyOutputSize.java | 9 +-- .../pkcs11/Cipher/TestCipherMode.java | 37 ++++++--- .../pkcs11/Cipher/TestGCMKeyAndIvCheck.java | 27 ++++--- .../security/pkcs11/Cipher/TestKATForGCM.java | 9 ++- .../security/pkcs11/Cipher/TestRSACipher.java | 6 +- .../pkcs11/Cipher/TestRSACipherWrap.java | 6 +- .../pkcs11/Cipher/TestRawRSACipher.java | 6 +- .../pkcs11/Cipher/TestSymmCiphers.java | 78 +++++++++---------- .../pkcs11/Cipher/TestSymmCiphersNoPad.java | 62 +++++++-------- 16 files changed, 187 insertions(+), 156 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java b/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java index fe93dff5050..c54889fbdc4 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/ReinitCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -32,6 +32,8 @@ * @run main/othervm ReinitCipher */ +import jtreg.SkippedException; + import java.security.Provider; import java.util.Random; import javax.crypto.Cipher; @@ -46,8 +48,7 @@ public class ReinitCipher extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("Cipher", "ARCFOUR") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm ARCFOUR is not supported by provider, skipping"); } Random random = new Random(); byte[] data1 = new byte[10 * 1024]; diff --git a/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java b/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java index ddca64ecb69..7aafa4fd70f 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java +++ b/test/jdk/sun/security/pkcs11/Cipher/Test4512704.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -29,14 +29,16 @@ * @run main Test4512704 * @summary Verify that AES cipher can generate default IV in encrypt mode */ -import java.io.PrintStream; -import java.security.*; -import java.security.spec.*; -import java.util.Random; +import jtreg.SkippedException; -import javax.crypto.*; -import javax.crypto.spec.*; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import java.security.Provider; +import java.security.spec.AlgorithmParameterSpec; public class Test4512704 extends PKCS11Test { @@ -48,9 +50,8 @@ public class Test4512704 extends PKCS11Test { transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java index 06c1e84392c..f6b6157cefa 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -31,13 +31,21 @@ * @key randomness */ -import java.security.*; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.math.*; -import java.io.*; +import jtreg.SkippedException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.util.Arrays; +import java.util.Random; -import java.util.*; public class TestCICOWithGCM extends PKCS11Test { public static void main(String[] args) throws Exception { @@ -55,9 +63,8 @@ public class TestCICOWithGCM extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java index be2b1d18c8f..13ab8541351 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCICOWithGCMAndAAD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @summary Test CipherInputStream/OutputStream with AES GCM mode with AAD. * @key randomness */ +import jtreg.SkippedException; + import java.io.*; import java.security.*; import java.util.*; @@ -44,7 +46,6 @@ public class TestCICOWithGCMAndAAD extends PKCS11Test { @Override public void main(Provider p) throws Exception { test("GCM", p); -// test("CCM", p); } public void test(String mode, Provider p) throws Exception { @@ -53,9 +54,8 @@ public class TestCICOWithGCMAndAAD extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java index 26853ae3ee6..da351bc7493 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -47,7 +47,7 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.crypto.NoSuchPaddingException; -import jdk.test.lib.Utils; +import jtreg.SkippedException; public class TestChaChaPoly extends PKCS11Test { @@ -70,8 +70,7 @@ public class TestChaChaPoly extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } this.p = p; testTransformations(); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java index 5649ed013ef..d2590b2c3cb 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -26,22 +26,25 @@ * @bug 8255410 * @library /test/lib .. * @modules jdk.crypto.cryptoki - * @build jdk.test.lib.Convert * @run main/othervm TestChaChaPolyKAT * @summary ChaCha20-Poly1305 Cipher Implementation (KAT) */ -import java.util.*; +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.Provider; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.crypto.AEADBadTagException; import java.nio.ByteBuffer; -import jdk.test.lib.Convert; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; public class TestChaChaPolyKAT extends PKCS11Test { public static class TestData { @@ -126,8 +129,7 @@ public class TestChaChaPolyKAT extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } int testsPassed = 0; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java index 94272367caa..60d80b9e365 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -30,18 +30,22 @@ * (key/nonce reuse check) */ -import java.util.*; +import jtreg.SkippedException; + import javax.crypto.Cipher; import java.security.spec.AlgorithmParameterSpec; import java.security.Provider; import java.security.NoSuchAlgorithmException; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.crypto.AEADBadTagException; import javax.crypto.SecretKey; import java.security.InvalidKeyException; import java.security.InvalidAlgorithmParameterException; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; public class TestChaChaPolyNoReuse extends PKCS11Test { @@ -238,8 +242,7 @@ public class TestChaChaPolyNoReuse extends PKCS11Test { try { Cipher.getInstance(CIPHER_ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + CIPHER_ALGO); - return; + throw new SkippedException("Skip; no support for " + CIPHER_ALGO); } int testsPassed = 0; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java index 57a7b9a4606..f68340658fa 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -30,14 +30,14 @@ * @run main TestChaChaPolyOutputSize */ +import jtreg.SkippedException; + import java.nio.ByteBuffer; import java.security.GeneralSecurityException; -import java.security.Key; import java.security.SecureRandom; import java.security.Provider; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; -import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -60,8 +60,7 @@ public class TestChaChaPolyOutputSize extends PKCS11Test { try { Cipher.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO); } testGetOutSize(p); testMultiPartAEADDec(p); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java b/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java index 76f0c9dc412..cf3d948be17 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestCipherMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @run main/othervm TestCipherMode */ +import jtreg.SkippedException; + import java.security.Provider; import java.security.Key; import java.security.KeyPair; @@ -38,20 +40,22 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; public class TestCipherMode extends PKCS11Test { - private static String[] TRANSFORMATIONS = { - "AES/ECB/PKCS5Padding", "AES/GCM/NoPadding", - "RSA/ECB/PKCS1Padding" + private static final String[] TRANSFORMATIONS = { + "AES/ECB/PKCS5Padding", "AES/GCM/NoPadding", + "RSA/ECB/PKCS1Padding" }; - private static byte[] BYTES16 = - Arrays.copyOf(TRANSFORMATIONS[0].getBytes(), 16); + private static final byte[] BYTES16 = + Arrays.copyOf("AES/ECB/PKCS5Padding".getBytes(), 16); private static SecretKey AES_KEY = new SecretKeySpec(BYTES16, "AES"); private static PublicKey RSA_PUBKEY = null; private static PrivateKey RSA_PRIVKEY = null; @@ -97,18 +101,29 @@ public class TestCipherMode extends PKCS11Test { // test all cipher impls, e.g. P11Cipher, P11AEADCipher, and // P11RSACipher - for (String t : TRANSFORMATIONS) { - checkModes(t, p); + List skipped = new ArrayList<>(); + for (final String t : TRANSFORMATIONS) { + try { + checkModes(t, p); + } catch (SkippedException skippedException) { + // printing to System.out, so it's easier to see which test it relates to + skippedException.printStackTrace(System.out); + skipped.add(t); + } + } + + if (!skipped.isEmpty()) { + throw new SkippedException("Some tests skipped: " + skipped); + } else { + System.out.println("All tests passed"); } - System.out.println("All tests passed"); } private static void checkModes(String t, Provider p) throws Exception { try { Cipher.getInstance(t, p); } catch (Exception e) { - System.out.println("Skip " + t + " due to " + e.getMessage()); - return; + throw new SkippedException("Skip " + t + " due to " + e.getMessage()); } for (CipherMode m : CipherMode.values()) { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java b/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java index adabcc571aa..4e78d8d39d7 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestGCMKeyAndIvCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -31,13 +31,21 @@ */ -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.math.*; +import jtreg.SkippedException; -import java.util.*; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Provider; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import java.util.Arrays; public class TestGCMKeyAndIvCheck extends PKCS11Test { @@ -77,9 +85,8 @@ public class TestGCMKeyAndIvCheck extends PKCS11Test { String transformation = "AES/" + mode + "/NoPadding"; c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + mode); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + mode); } System.out.println("Testing against " + p.getName()); SecretKey key = new SecretKeySpec(new byte[16], "AES"); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java index 95e6e5b1a0a..9844e8ecfd2 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -30,6 +30,8 @@ * @summary Known Answer Test for AES cipher with GCM mode support in * PKCS11 provider. */ +import jtreg.SkippedException; + import java.security.GeneralSecurityException; import java.security.Provider; import java.util.Arrays; @@ -311,9 +313,8 @@ public class TestKATForGCM extends PKCS11Test { try { c = Cipher.getInstance(transformation, p); } catch (GeneralSecurityException e) { - System.out.println("Skip testing " + p.getName() + - ", no support for " + transformation); - return; + throw new SkippedException("Skip testing " + p.getName() + + ", no support for " + transformation); } try { if (execute(testValues, c)) { diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java index 73039ba2f65..204b852e4d6 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -44,6 +44,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRSACipher extends PKCS11Test { @@ -55,8 +56,7 @@ public class TestRSACipher extends PKCS11Test { try { Cipher.getInstance(RSA_ALGOS[0], p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm " + RSA_ALGOS[0] + " is not supported by provider, skipping"); } String kpgAlgorithm = "RSA"; int keySize = SecurityUtils.getTestKeySize(kpgAlgorithm); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java index 559c7680c06..01d30934049 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRSACipherWrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -43,6 +43,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRSACipherWrap extends PKCS11Test { @@ -54,8 +55,7 @@ public class TestRSACipherWrap extends PKCS11Test { try { Cipher.getInstance(RSA_ALGOS[0], p); } catch (GeneralSecurityException e) { - System.out.println(RSA_ALGOS[0] + " unsupported, skipping"); - return; + throw new SkippedException(RSA_ALGOS[0] + " unsupported, skipping"); } String kpgAlgorithm = "RSA"; KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgorithm, p); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java index 2c553f7e452..8989e951b09 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestRawRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -41,6 +41,7 @@ import java.util.HexFormat; import java.util.Random; import javax.crypto.Cipher; import jdk.test.lib.security.SecurityUtils; +import jtreg.SkippedException; public class TestRawRSACipher extends PKCS11Test { @@ -49,8 +50,7 @@ public class TestRawRSACipher extends PKCS11Test { try { Cipher.getInstance("RSA/ECB/NoPadding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Algorithm RSA/ECB/NoPadding is not supported by provider, skipping"); } String kpgAlgorithm = "RSA"; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java index b818adfe589..2e66370b807 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -32,11 +32,15 @@ * @run main/othervm TestSymmCiphers */ +import jtreg.SkippedException; + import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; @@ -44,43 +48,33 @@ import javax.crypto.SecretKey; public class TestSymmCiphers extends PKCS11Test { - private static class CI { // class for holding Cipher Information + private record CI (String transformation, String keyAlgo, int dataSize){} // record for holding Cipher Information - String transformation; - String keyAlgo; - int dataSize; - - CI(String transformation, String keyAlgo, int dataSize) { - this.transformation = transformation; - this.keyAlgo = keyAlgo; - this.dataSize = dataSize; - } - } private static final CI[] TEST_LIST = { - new CI("ARCFOUR", "ARCFOUR", 400), - new CI("RC4", "RC4", 401), - new CI("DES/CBC/NoPadding", "DES", 400), - new CI("DESede/CBC/NoPadding", "DESede", 160), - new CI("AES/CBC/NoPadding", "AES", 4800), - new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), - new CI("DES/cbc/PKCS5Padding", "DES", 6401), - new CI("DESede/CBC/PKCS5Padding", "DESede", 402), - new CI("AES/CBC/PKCS5Padding", "AES", 30), - new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19), - new CI("DES/ECB/NoPadding", "DES", 400), - new CI("DESede/ECB/NoPadding", "DESede", 160), - new CI("AES/ECB/NoPadding", "AES", 4800), - new CI("DES/ECB/PKCS5Padding", "DES", 32), - new CI("DES/ECB/PKCS5Padding", "DES", 6400), - new CI("DESede/ECB/PKCS5Padding", "DESede", 400), - new CI("AES/ECB/PKCS5Padding", "AES", 64), + new CI("ARCFOUR", "ARCFOUR", 400), + new CI("RC4", "RC4", 401), + new CI("DES/CBC/NoPadding", "DES", 400), + new CI("DESede/CBC/NoPadding", "DESede", 160), + new CI("AES/CBC/NoPadding", "AES", 4800), + new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), + new CI("DES/cbc/PKCS5Padding", "DES", 6401), + new CI("DESede/CBC/PKCS5Padding", "DESede", 402), + new CI("AES/CBC/PKCS5Padding", "AES", 30), + new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19), + new CI("DES/ECB/NoPadding", "DES", 400), + new CI("DESede/ECB/NoPadding", "DESede", 160), + new CI("AES/ECB/NoPadding", "AES", 4800), + new CI("DES/ECB/PKCS5Padding", "DES", 32), + new CI("DES/ECB/PKCS5Padding", "DES", 6400), + new CI("DESede/ECB/PKCS5Padding", "DESede", 400), + new CI("AES/ECB/PKCS5Padding", "AES", 64), - new CI("DES", "DES", 6400), - new CI("DESede", "DESede", 408), - new CI("AES", "AES", 128), + new CI("DES", "DES", 6400), + new CI("DESede", "DESede", 408), + new CI("AES", "AES", 128), - new CI("AES/CTR/NoPadding", "AES", 3200), - new CI("AES/CTS/NoPadding", "AES", 3200), + new CI("AES/CTR/NoPadding", "AES", 3200), + new CI("AES/CTS/NoPadding", "AES", 3200), }; private static final StringBuffer debugBuf = new StringBuffer(); @@ -90,11 +84,10 @@ public class TestSymmCiphers extends PKCS11Test { // NSS reports CKR_DEVICE_ERROR when the data passed to // its EncryptUpdate/DecryptUpdate is not multiple of blocks int firstBlkSize = 16; - boolean status = true; + List skippedList = new ArrayList<>(); Random random = new Random(); try { - for (int i = 0; i < TEST_LIST.length; i++) { - CI currTest = TEST_LIST[i]; + for (CI currTest : TEST_LIST) { System.out.println("===" + currTest.transformation + "==="); try { KeyGenerator kg = @@ -123,7 +116,8 @@ public class TestSymmCiphers extends PKCS11Test { System.out.println("Decryption tests: DONE"); } catch (NoSuchAlgorithmException nsae) { System.out.println("Skipping unsupported algorithm: " + - nsae); + nsae); + skippedList.add(currTest); } } } catch (Exception ex) { @@ -131,11 +125,15 @@ public class TestSymmCiphers extends PKCS11Test { System.out.println(debugBuf); throw ex; } + + if (!skippedList.isEmpty()){ + throw new SkippedException("Some tests skipped: " + skippedList); + } } private static void test(Cipher cipher, int mode, SecretKey key, - AlgorithmParameters params, int firstBlkSize, - byte[] in, byte[] answer) throws Exception { + AlgorithmParameters params, int firstBlkSize, + byte[] in, byte[] answer) throws Exception { // test setup long startTime, endTime; cipher.init(mode, key, params); diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java index 9290fe8d6eb..973da3b0c55 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -32,6 +32,8 @@ * @run main/othervm TestSymmCiphersNoPad */ +import jtreg.SkippedException; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -39,6 +41,8 @@ import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; @@ -47,48 +51,37 @@ import javax.crypto.SecretKey; public class TestSymmCiphersNoPad extends PKCS11Test { - private static class CI { // class for holding Cipher Information - String transformation; - String keyAlgo; - int dataSize; - - CI(String transformation, String keyAlgo, int dataSize) { - this.transformation = transformation; - this.keyAlgo = keyAlgo; - this.dataSize = dataSize; - } - } - - private static final CI TEST_LIST[] = { - new CI("ARCFOUR", "ARCFOUR", 400), - new CI("RC4", "RC4", 401), - new CI("DES/CBC/NoPadding", "DES", 400), - new CI("DESede/CBC/NoPadding", "DESede", 160), - new CI("AES/CBC/NoPadding", "AES", 4800), - new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), - new CI("AES/CTR/NoPadding", "AES", 1600), - new CI("AES/CTR/NoPadding", "AES", 65), - new CI("AES/CTS/NoPadding", "AES", 1600), - new CI("AES/CTS/NoPadding", "AES", 65), - }; + private record CI (String transformation, String keyAlgo, int dataSize){} // record for holding Cipher Information private static final StringBuffer debugBuf = new StringBuffer(); + private static final CI[] TEST_LIST = { + new CI("ARCFOUR", "ARCFOUR", 400), + new CI("RC4", "RC4", 401), + new CI("DES/CBC/NoPadding", "DES", 400), + new CI("DESede/CBC/NoPadding", "DESede", 160), + new CI("AES/CBC/NoPadding", "AES", 4800), + new CI("Blowfish/CBC/NoPadding", "Blowfish", 24), + new CI("AES/CTR/NoPadding", "AES", 1600), + new CI("AES/CTR/NoPadding", "AES", 65), + new CI("AES/CTS/NoPadding", "AES", 1600), + new CI("AES/CTS/NoPadding", "AES", 65), + }; + @Override public void main(Provider p) throws Exception { - boolean status = true; + List skippedList = new ArrayList<>(); Random random = new Random(); try { - for (int i = 0; i < TEST_LIST.length; i++) { - CI currTest = TEST_LIST[i]; + for (CI currTest : TEST_LIST) { System.out.println("===" + currTest.transformation + "==="); try { KeyGenerator kg = - KeyGenerator.getInstance(currTest.keyAlgo, p); + KeyGenerator.getInstance(currTest.keyAlgo, p); SecretKey key = kg.generateKey(); Cipher c1 = Cipher.getInstance(currTest.transformation, p); Cipher c2 = Cipher.getInstance(currTest.transformation, - System.getProperty("test.provider.name", "SunJCE")); + System.getProperty("test.provider.name", "SunJCE")); byte[] plainTxt = new byte[currTest.dataSize]; random.nextBytes(plainTxt); @@ -98,16 +91,17 @@ public class TestSymmCiphersNoPad extends PKCS11Test { AlgorithmParameters params = c2.getParameters(); byte[] answer = c2.doFinal(plainTxt); test(c1, Cipher.ENCRYPT_MODE, key, params, - plainTxt, answer); + plainTxt, answer); System.out.println("Encryption tests: DONE"); c2.init(Cipher.DECRYPT_MODE, key, params); byte[] answer2 = c2.doFinal(answer); test(c1, Cipher.DECRYPT_MODE, key, params, - answer, answer2); + answer, answer2); System.out.println("Decryption tests: DONE"); } catch (NoSuchAlgorithmException nsae) { System.out.println("Skipping unsupported algorithm: " + nsae); + skippedList.add(currTest); } } } catch (Exception ex) { @@ -115,6 +109,10 @@ public class TestSymmCiphersNoPad extends PKCS11Test { System.out.println(debugBuf); throw ex; } + + if (!skippedList.isEmpty()){ + throw new SkippedException("Some tests skipped: " + skippedList); + } } private static void test(Cipher cipher, int mode, SecretKey key, From 452b052fe343a70bc81bf299d08a9f06a1e30fe9 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 28 Aug 2025 15:45:17 +0000 Subject: [PATCH 269/471] 8365726: Test crashed with assert in C1 thread: Possible safepoint reached by thread that does not allow it Reviewed-by: dlong, shade --- src/hotspot/share/oops/trainingData.hpp | 4 ++-- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index baf19773a7b..c47d0a0f66e 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -96,7 +96,7 @@ public: // TrainingDataLocker is used to guard read/write operations on non-MT-safe data structures. // It supports recursive locking and a read-only mode (in which case no locks are taken). - // It is also a part of the TD collection termination protocol (see the "spanshot" field). + // It is also a part of the TD collection termination protocol (see the "snapshot" field). class TrainingDataLocker { static volatile bool _snapshot; // If true we're not allocating new training data static int _lock_mode; @@ -105,7 +105,7 @@ public: #if INCLUDE_CDS assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()"); if (_lock_mode > 0) { - TrainingData_lock->lock(); + TrainingData_lock->lock_without_safepoint_check(); } #endif } diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 8cfecd098f6..3f8915973e2 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -263,7 +263,7 @@ void mutex_init() { MUTEX_DEFN(CompiledIC_lock , PaddedMutex , nosafepoint); // locks VtableStubs_lock MUTEX_DEFN(MethodCompileQueue_lock , PaddedMonitor, safepoint); - MUTEX_DEFL(TrainingData_lock , PaddedMutex , MethodCompileQueue_lock); + MUTEX_DEFN(TrainingData_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(TrainingReplayQueue_lock , PaddedMonitor, safepoint); MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); From 8c6d12250b524c0f4ee25dbbc6fe959581b7617b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 28 Aug 2025 15:58:50 +0000 Subject: [PATCH 270/471] 8333783: java/nio/channels/FileChannel/directio/DirectIOTest.java is unstable with AV software Reviewed-by: bpb --- .../FileChannel/directio/DirectIOTest.java | 90 +++++++++++++------ .../FileChannel/directio/libDirectIO.c | 34 ++++--- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java index 34f2bacc7dd..b9dd309d0f7 100644 --- a/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java +++ b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java @@ -27,11 +27,13 @@ * @summary Test for ExtendedOpenOption.DIRECT flag * @requires (os.family == "linux" | os.family == "aix") * @library /test/lib + * @modules java.base/sun.nio.ch:+open java.base/java.io:+open * @build jdk.test.lib.Platform * @run main/native DirectIOTest */ import java.io.*; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.*; @@ -47,10 +49,25 @@ import com.sun.nio.file.ExtendedOpenOption; public class DirectIOTest { private static final int BASE_SIZE = 4096; + private static final int TRIES = 3; + + public static int getFD(FileChannel channel) throws Exception { + Field fFdFd = channel.getClass().getDeclaredField("fd"); + fFdFd.setAccessible(true); + FileDescriptor fd = (FileDescriptor) fFdFd.get(channel); + + Field fFd = FileDescriptor.class.getDeclaredField("fd"); + fFd.setAccessible(true); + return fFd.getInt(fd); + } + + private static void testWrite(Path p, long blockSize) throws Exception { + try (FileChannel fc = FileChannel.open(p, + StandardOpenOption.READ, + StandardOpenOption.WRITE, + ExtendedOpenOption.DIRECT)) { + int fd = getFD(fc); - private static int testWrite(Path p, long blockSize) throws Exception { - try (FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE, - ExtendedOpenOption.DIRECT)) { int bs = (int)blockSize; int size = Math.max(BASE_SIZE, bs); int alignment = bs; @@ -60,22 +77,55 @@ public class DirectIOTest { for (int j = 0; j < size; j++) { src.put((byte)0); } - src.flip(); - fc.write(src); - return size; + + // If there is AV or other FS tracing software, it may cache the file + // contents on first access, even though we have asked for DIRECT here. + // Do several attempts to make test more resilient. + + for (int t = 0; t < TRIES; t++) { + flushFileCache(size, fd); + src.flip(); + fc.position(0); + fc.write(src); + if (!isFileInCache(size, fd)) { + return; + } + } + + throw new RuntimeException("DirectIO is not working properly with " + + "write. File still exists in cache!"); } } - private static int testRead(Path p, long blockSize) throws Exception { - try (FileChannel fc = FileChannel.open(p, ExtendedOpenOption.DIRECT)) { + private static void testRead(Path p, long blockSize) throws Exception { + try (FileChannel fc = FileChannel.open(p, + StandardOpenOption.READ, + ExtendedOpenOption.DIRECT)) { + int fd = getFD(fc); + int bs = (int)blockSize; int size = Math.max(BASE_SIZE, bs); int alignment = bs; ByteBuffer dest = ByteBuffer.allocateDirect(size + alignment - 1) .alignedSlice(alignment); assert dest.capacity() != 0; - fc.read(dest); - return size; + + // If there is AV or other FS tracing software, it may cache the file + // contents on first access, even though we have asked for DIRECT here. + // Do several attempts to make test more resilient. + + for (int t = 0; t < TRIES; t++) { + flushFileCache(size, fd); + dest.clear(); + fc.position(0); + fc.read(dest); + if (!isFileInCache(size, fd)) { + return; + } + } + + throw new RuntimeException("DirectIO is not working properly with " + + "read. File still exists in cache!"); } } @@ -84,12 +134,8 @@ public class DirectIOTest { Paths.get(System.getProperty("test.dir", ".")), "test", null); } - private static boolean isFileInCache(int size, Path p) { - String path = p.toString(); - return isFileInCache0(size, path); - } - - private static native boolean isFileInCache0(int size, String path); + private static native boolean flushFileCache(int size, int fd); + private static native boolean isFileInCache(int size, int fd); public static void main(String[] args) throws Exception { Path p = createTempFile(); @@ -98,16 +144,8 @@ public class DirectIOTest { System.loadLibrary("DirectIO"); try { - int size = testWrite(p, blockSize); - if (isFileInCache(size, p)) { - throw new RuntimeException("DirectIO is not working properly with " - + "write. File still exists in cache!"); - } - size = testRead(p, blockSize); - if (isFileInCache(size, p)) { - throw new RuntimeException("DirectIO is not working properly with " - + "read. File still exists in cache!"); - } + testWrite(p, blockSize); + testRead(p, blockSize); } finally { Files.delete(p); } diff --git a/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c index 4897500bf2d..5eea51da4c7 100644 --- a/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c +++ b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c @@ -45,13 +45,27 @@ static void ThrowException(JNIEnv *env, const char *name, const char *msg) { /* * Class: DirectIO - * Method: isFileInCache0 - * Signature: (ILjava/lang/String;)Z + * Method: flushFileCache + * Signature: (II;)V */ -JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, +JNIEXPORT void Java_DirectIOTest_flushFileCache(JNIEnv *env, jclass cls, jint file_size, - jstring file_path) { + jint fd) { +#ifdef __linux__ + posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED); +#endif +} + +/* + * Class: DirectIO + * Method: isFileInCache + * Signature: (II;)Z + */ +JNIEXPORT jboolean Java_DirectIOTest_isFileInCache(JNIEnv *env, + jclass cls, + jint file_size, + jint fd) { void *f_mmap; #ifdef __linux__ unsigned char *f_seg; @@ -69,17 +83,10 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, size_t index = (file_size + page_size - 1) /page_size; jboolean result = JNI_FALSE; - const char* path = (*env)->GetStringUTFChars(env, file_path, JNI_FALSE); - - int fd = open(path, O_RDWR); - - (*env)->ReleaseStringUTFChars(env, file_path, path); - f_mmap = mmap(0, file_size, PROT_NONE, MAP_SHARED, fd, 0); if (f_mmap == MAP_FAILED) { - close(fd); ThrowException(env, "java/io/IOException", - "test of whether file exists in cache failed"); + "test of whether file exists in cache failed: mmap failed"); } f_seg = malloc(index); if (f_seg != NULL) { @@ -95,9 +102,8 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env, free(f_seg); } else { ThrowException(env, "java/io/IOException", - "test of whether file exists in cache failed"); + "test of whether file exists in cache failed: malloc failed"); } - close(fd); munmap(f_mmap, file_size); return result; } From 33d00a77f38ea16e4751b216a3bf98a620eb8055 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 28 Aug 2025 16:36:14 +0000 Subject: [PATCH 271/471] 8294035: Remove null ids checking from keytool -gencrl Reviewed-by: weijun --- .../share/classes/sun/security/tools/keytool/Main.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 8c6cd139a0d..9fb830da338 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1562,9 +1562,6 @@ public final class Main { private void doGenCRL(PrintStream out) throws Exception { - if (ids == null) { - throw new Exception("Must provide -id when -gencrl"); - } Certificate signerCert = keyStore.getCertificate(alias); byte[] encoded = signerCert.getEncoded(); X509CertImpl signerCertImpl = new X509CertImpl(encoded); From aaac8c0636e12c40c46170bf4989bd34bb577430 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 28 Aug 2025 17:38:09 +0000 Subject: [PATCH 272/471] 8366254: (fs) UnixException.translateToIOException should translate ELOOP to FileSystemLoopException Reviewed-by: vyazici, alanb --- .../unix/classes/sun/nio/fs/UnixException.java | 10 ++++++---- test/jdk/java/nio/file/Files/IsSameFile.java | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixException.java b/src/java.base/unix/classes/sun/nio/fs/UnixException.java index 9c90911f9cf..0f0de768109 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixException.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -92,9 +92,11 @@ class UnixException extends Exception { return new NoSuchFileException(file, other, null); if (errno() == UnixConstants.EEXIST) return new FileAlreadyExistsException(file, other, null); - if (errno() == UnixConstants.ELOOP) - return new FileSystemException(file, other, errorString() - + " or unable to access attributes of symbolic link"); + if (errno() == UnixConstants.ELOOP) { + String msg = file + ": " + errorString() + + " or unable to access attributes of symbolic link"; + return new FileSystemLoopException(msg); + } // fallback to the more general exception return new FileSystemException(file, other, errorString()); diff --git a/test/jdk/java/nio/file/Files/IsSameFile.java b/test/jdk/java/nio/file/Files/IsSameFile.java index 00bac0fb5a7..44e03a15a02 100644 --- a/test/jdk/java/nio/file/Files/IsSameFile.java +++ b/test/jdk/java/nio/file/Files/IsSameFile.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8154364 + * @bug 8154364 8366254 * @summary Test of Files.isSameFile * @requires (os.family != "windows") * @library .. /test/lib @@ -33,6 +33,7 @@ import java.io.IOException; import java.io.FileOutputStream; import java.nio.file.Files; import java.nio.file.FileSystem; +import java.nio.file.FileSystemLoopException; import java.nio.file.FileSystemException; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -451,6 +452,6 @@ public class IsSameFile { @ParameterizedTest @MethodSource("linkLoopSource") public void linkLoop(boolean expect, Path x, Path y) throws IOException { - assertThrows(FileSystemException.class, () -> Files.isSameFile(x, y)); + assertThrows(FileSystemLoopException.class, () -> Files.isSameFile(x, y)); } } From 9f70965bb9ead2268c02c688c79ec0d80574c725 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 28 Aug 2025 18:08:55 +0000 Subject: [PATCH 273/471] 8366193: Add comments about ResolvedFieldEntry::copy_from() Reviewed-by: adinn, coleenp --- src/hotspot/share/oops/resolvedFieldEntry.hpp | 30 ++++++++++++++++++- src/hotspot/share/oops/resolvedIndyEntry.hpp | 5 +++- .../share/oops/resolvedMethodEntry.hpp | 4 ++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/oops/resolvedFieldEntry.hpp b/src/hotspot/share/oops/resolvedFieldEntry.hpp index c98d5f54d1e..1e89d10ab0c 100644 --- a/src/hotspot/share/oops/resolvedFieldEntry.hpp +++ b/src/hotspot/share/oops/resolvedFieldEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -80,10 +80,38 @@ public: ResolvedFieldEntry() : ResolvedFieldEntry(0) {} + // Notes on copy constructor, copy assignment operator, and copy_from(). + // These are necessary for generating deterministic CDS archives. + // + // We have some unused padding on 64-bit platforms (4 bytes at the tail end). + // + // When ResolvedFieldEntries in a ConstantPoolCache are allocated from the metaspace, + // their entire content (including the padding) is filled with zeros. They are + // then initialized with initialize_resolved_entries_array() in cpCache.cpp from a + // GrowableArray. + // + // The GrowableArray is initialized in rewriter.cpp, using ResolvedFieldEntries that + // are originally allocated from the C++ stack. Functions like GrowableArray::expand_to() + // will also allocate ResolvedFieldEntries from the stack. These may have random bits + // in the padding as the C++ compiler is allowed to leave the padding in uninitialized + // states. + // + // If we use the default copy constructor and/or default copy assignment operator, + // the random padding will be copied into the GrowableArray, from there + // to the ConstantPoolCache, and eventually to the CDS archive. As a result, the + // CDS archive will contain random bits, causing failures in + // test/hotspot/jtreg/runtime/cds/DeterministicDump.java (usually on Windows). + // + // By using copy_from(), we can prevent the random padding from being copied, + // ensuring that the ResolvedFieldEntries in a ConstantPoolCache (and thus the + // CDS archive) will have all zeros in the padding. + + // Copy constructor ResolvedFieldEntry(const ResolvedFieldEntry& other) { copy_from(other); } + // Copy assignment operator ResolvedFieldEntry& operator=(const ResolvedFieldEntry& other) { copy_from(other); return *this; diff --git a/src/hotspot/share/oops/resolvedIndyEntry.hpp b/src/hotspot/share/oops/resolvedIndyEntry.hpp index a7782c88f1e..af0efbadc9f 100644 --- a/src/hotspot/share/oops/resolvedIndyEntry.hpp +++ b/src/hotspot/share/oops/resolvedIndyEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -52,6 +52,9 @@ class ResolvedIndyEntry { u1 _flags; // Flags: [0000|00|has_appendix|resolution_failed] public: + // The copy_from() pattern in resolvedFieldEntry.hpp is not necessary + // as we have no unused padding (on 32- or 64-bit platforms). + ResolvedIndyEntry() : _method(nullptr), _resolved_references_index(0), diff --git a/src/hotspot/share/oops/resolvedMethodEntry.hpp b/src/hotspot/share/oops/resolvedMethodEntry.hpp index 8f49608127f..097f7de8a56 100644 --- a/src/hotspot/share/oops/resolvedMethodEntry.hpp +++ b/src/hotspot/share/oops/resolvedMethodEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -82,6 +82,8 @@ class ResolvedMethodEntry { bool _has_table_index; #endif + // See comments in resolvedFieldEntry.hpp about copy_from and padding. + // We have unused padding on debug builds. void copy_from(const ResolvedMethodEntry& other) { _method = other._method; _entry_specific = other._entry_specific; From 05da2137f1cb6eef1cfc7693905daf789d315b5c Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Thu, 28 Aug 2025 21:23:15 +0000 Subject: [PATCH 274/471] 8362335: [macos] Change value of CFBundleDevelopmentRegion from "English" to "en-US" Reviewed-by: asemenyuk --- .../internal/resources/ApplicationRuntime-Info.plist.template | 2 +- .../jdk/jpackage/internal/resources/Info-lite.plist.template | 2 +- .../jdk/jpackage/internal/resources/Runtime-Info.plist.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template index e24cc94fa8e..af8e19177c2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/ApplicationRuntime-Info.plist.template @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - English + en-US CFBundleExecutable libjli.dylib CFBundleIdentifier diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template index b981dc41d65..7b69368c8dd 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Info-lite.plist.template @@ -5,7 +5,7 @@ LSMinimumSystemVersion 10.11 CFBundleDevelopmentRegion - English + en-US CFBundleAllowMixedLocalizations CFBundleExecutable diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template index 5a1492e2eab..82fbdbbfbfb 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/Runtime-Info.plist.template @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - English + en-US CFBundleExecutable libjli.dylib CFBundleIdentifier From b8cdf31a2e52df857df2badb4f365454443dd89d Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Fri, 29 Aug 2025 00:46:53 +0000 Subject: [PATCH 275/471] 8365898: Specification of java.lang.module.ModuleDescriptor.packages() method can be improved Reviewed-by: alanb, liach --- .../share/classes/java/lang/module/ModuleDescriptor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index 7aac752cc89..c55ccd735df 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -1516,11 +1516,7 @@ public final class ModuleDescriptor } /** - * Returns the set of packages in the module. - * - *

        The set of packages includes all exported and open packages, as well - * as the packages of any service providers, and the package for the main - * class.

        + * Returns the set of all packages in the module. * * @return A possibly-empty unmodifiable set of the packages in the module */ From a2da75a6b69f56be41741bffba2c6874a93dfa40 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 29 Aug 2025 06:13:34 +0000 Subject: [PATCH 276/471] 8362884: [GCC static analyzer] unix NetworkInterface.c addif leak on early returns Reviewed-by: dfuchs, mbaesken --- .../unix/native/libnet/NetworkInterface.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 61267ec13d5..ceb5dd5f751 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -58,10 +58,14 @@ #endif #define CHECKED_MALLOC3(_pointer, _type, _size) \ + CHECKED_MALLOC4(_pointer, _type, _size, {}) + +#define CHECKED_MALLOC4(_pointer, _type, _size, _onFailure) \ do { \ _pointer = (_type)malloc(_size); \ if (_pointer == NULL) { \ JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \ + do _onFailure while (0); \ return ifs; /* return untouched list */ \ } \ } while(0) @@ -995,7 +999,7 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, // If "new" then create a netif structure and insert it into the list. if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { free(addrP); }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, name, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1027,7 +1031,10 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, } if (currif == NULL) { - CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE); + CHECKED_MALLOC4(currif, netif *, sizeof(netif) + IFNAMESIZE, { + free(addrP); + free(parent); + }); currif->name = (char *)currif + sizeof(netif); strncpy(currif->name, vname, IFNAMESIZE); currif->name[IFNAMESIZE - 1] = '\0'; @@ -1039,7 +1046,11 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, parent->childs = currif; } - CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size); + CHECKED_MALLOC4(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size, { + free(addrP); + free(parent); + free(currif); + }); memcpy(tmpaddr, addrP, sizeof(netaddr)); if (addrP->addr != NULL) { tmpaddr->addr = (struct sockaddr *) From 86d6a2e05eb52ea2c603a06bce838a56d5ae507b Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 29 Aug 2025 07:35:03 +0000 Subject: [PATCH 277/471] 8366147: ZGC: ZPageAllocator::cleanup_failed_commit_single_partition may leak memory Reviewed-by: stefank, sjohanss, jsikstro --- src/hotspot/share/gc/z/zPageAllocator.cpp | 23 +++++++++++-------- .../hotspot/jtreg/gc/z/TestCommitFailure.java | 8 +++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index d8f653cc7d0..9f484394521 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1092,7 +1092,8 @@ void ZPartition::free_memory_alloc_failed(ZMemoryAllocation* allocation) { freed += vmem.size(); _cache.insert(vmem); } - assert(allocation->harvested() + allocation->committed_capacity() == freed, "must have freed all"); + assert(allocation->harvested() + allocation->committed_capacity() == freed, "must have freed all" + " %zu + %zu == %zu", allocation->harvested(), allocation->committed_capacity(), freed); // Adjust capacity to reflect the failed capacity increase const size_t remaining = allocation->size() - freed; @@ -1909,23 +1910,27 @@ void ZPageAllocator::cleanup_failed_commit_single_partition(ZSinglePartitionAllo ZMemoryAllocation* const allocation = single_partition_allocation->allocation(); assert(allocation->commit_failed(), "Must have failed to commit"); + assert(allocation->partial_vmems()->is_empty(), "Invariant for single partition commit failure"); - const size_t committed = allocation->committed_capacity(); - const ZVirtualMemory non_harvested_vmem = vmem.last_part(allocation->harvested()); - const ZVirtualMemory committed_vmem = non_harvested_vmem.first_part(committed); - const ZVirtualMemory non_committed_vmem = non_harvested_vmem.last_part(committed); + // For a single partition we have unmapped the harvested memory before we + // started committing, and moved its physical memory association to the start + // of the vmem. As such, the partial_vmems is empty. All the harvested and + // partially successfully committed memory is mapped in the first part of vmem. + const size_t harvested_and_committed_capacity = allocation->harvested() + allocation->committed_capacity(); + const ZVirtualMemory succeeded_vmem = vmem.first_part(harvested_and_committed_capacity); + const ZVirtualMemory failed_vmem = vmem.last_part(harvested_and_committed_capacity); - if (committed_vmem.size() > 0) { + if (succeeded_vmem.size() > 0) { // Register the committed and mapped memory. We insert the committed // memory into partial_vmems so that it will be inserted into the cache // in a subsequent step. - allocation->partial_vmems()->append(committed_vmem); + allocation->partial_vmems()->append(succeeded_vmem); } // Free the virtual and physical memory we fetched to use but failed to commit ZPartition& partition = allocation->partition(); - partition.free_physical(non_committed_vmem); - partition.free_virtual(non_committed_vmem); + partition.free_physical(failed_vmem); + partition.free_virtual(failed_vmem); } void ZPageAllocator::cleanup_failed_commit_multi_partition(ZMultiPartitionAllocation* multi_partition_allocation, const ZVirtualMemory& vmem) { diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java index c1babe7eb83..3cee84d4f95 100644 --- a/test/hotspot/jtreg/gc/z/TestCommitFailure.java +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -23,6 +23,14 @@ package gc.z; +/* + * @test id=Normal + * @requires vm.gc.Z & vm.debug + * @summary Test ZGC graceful failure when a commit fails + * @library / /test/lib + * @run driver gc.z.TestCommitFailure + */ + /* * @test id=ZFakeNUMA * @requires vm.gc.Z & vm.debug From 937d61bfbaba61117076c78358570ec4c35c8c42 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 14:35:26 +0000 Subject: [PATCH 278/471] 8364751: ConstantBootstraps.explicitCast contradictory specification for null-to-primitive Reviewed-by: jvernee, rriggs --- .../java/lang/invoke/ConstantBootstraps.java | 50 +++++++----- test/jdk/java/lang/constant/ConvertTest.java | 79 ------------------- .../invoke/condy/ConstantBootstrapsTest.java | 46 ++++++++++- 3 files changed, 76 insertions(+), 99 deletions(-) delete mode 100644 test/jdk/java/lang/constant/ConvertTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index b7983d18b2e..89d818721a1 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -369,17 +369,32 @@ public final class ConstantBootstraps { *

        * Otherwise one of the following conversions is applied to {@code value}: *

          - *
        1. If {@code dstType} is a reference type, a reference cast - * is applied to {@code value} as if by calling {@code dstType.cast(value)}. - *
        2. If {@code dstType} is a primitive type, then, if the runtime type - * of {@code value} is a primitive wrapper type (such as {@link Integer}), - * a Java unboxing conversion is applied {@jls 5.1.8} followed by a - * Java casting conversion {@jls 5.5} converting either directly to - * {@code dstType}, or, if {@code dstType} is {@code boolean}, - * to {@code int}, which is then converted to either {@code true} - * or {@code false} depending on whether the least-significant-bit - * is 1 or 0 respectively. If the runtime type of {@code value} is - * not a primitive wrapper type a {@link ClassCastException} is thrown. + *
        3. If {@code dstType} is a reference type, a reference cast is applied + * to {@code value} as if by calling {@link Class#cast(Object) + * dstType.cast(value)}. + *
        4. Otherwise, {@code dstType} is a primitive type: + *
            + *
          1. If {@code value} is null, the default value (JVMS {@jvms 2.3}) + * of {@code dstType} is returned. + *
          2. If the runtime type of {@code value} is a primitive wrapper type + * (such as {@link Integer}), a Java unboxing conversion is applied + * (JLS {@jls 5.1.8}). + *
              + *
            • If the runtime type is {@link Boolean}, the unboxing result + * is then converted to {@code int}, where {@code true} becomes + * {@code 1} and {@code false} becomes {@code 0}. + *
            + * Followed by a Java casting conversion (JLS {@jls 5.5}): + *
              + *
            • If {@code dstType} is not {@code boolean}, the cast converts + * directly to {@code dstType}. + *
            • If {@code dstType} is {@code boolean}, the cast converts to + * {@code int}, and the resulting {@code boolean} is produced + * by testing whether the least significant bit of the cast + * {@code int} is 1. + *
            + *
          3. Otherwise, a {@link ClassCastException} is thrown. + *
          *
        *

        * The result is the same as when using the following code: @@ -393,13 +408,12 @@ public final class ConstantBootstraps { * @param lookup unused * @param name unused * @param dstType the destination type of the conversion - * @param value the value to be converted + * @param value the value to be converted, may be null * @return the converted value - * @throws ClassCastException when {@code dstType} is {@code void}, - * when a cast per (1) fails, or when {@code dstType} is a primitive type - * and the runtime type of {@code value} is not a primitive wrapper type - * (such as {@link Integer}) - * + * @throws ClassCastException when {@code dstType} is {@code void}; when + * {@code dstType} is a reference type, and the reference cast fails; or + * when {@code dstType} is primitive, and {@code value} is an + * instance of a reference type that is not a wrapper class * @since 15 */ public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class dstType, Object value) diff --git a/test/jdk/java/lang/constant/ConvertTest.java b/test/jdk/java/lang/constant/ConvertTest.java deleted file mode 100644 index d7018df6352..00000000000 --- a/test/jdk/java/lang/constant/ConvertTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @run testng ConvertTest - */ - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import java.lang.invoke.ConstantBootstraps; -import java.math.BigInteger; - -import static org.testng.Assert.assertEquals; - -public class ConvertTest { - - @DataProvider - public static Object[][] cceInputs() { - return new Object[][]{ - { void.class, null }, - { Integer.class, "a" }, - { int.class, BigInteger.ZERO }, - }; - } - - @Test(dataProvider = "cceInputs", expectedExceptions = ClassCastException.class) - public void testBadConversion(Class dstType, Object value) { - ConstantBootstraps.explicitCast(null, null, dstType, value); - } - - @DataProvider - public static Object[][] goodInputs() { - Object o = new Object(); - return new Object[][]{ - { Object.class, null, null }, - { Object.class, o, o }, - { String.class, "abc", "abc" }, - { short.class, 10, (short) 10 }, - { int.class, (short) 10, 10 }, - { boolean.class, 1, true }, - { boolean.class, 2, false }, - { int.class, true, 1 }, - { int.class, false, 0 }, - { int.class, 10, 10 }, - { Integer.class, 10, 10 }, - { Object.class, 10, 10 }, - { Number.class, 10, 10 }, - }; - } - - @Test(dataProvider = "goodInputs") - public void testSuccess(Class dstType, Object value, Object expected) { - Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); - assertEquals(actual, expected); - } - -} diff --git a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java index 640affeec5c..829f26704f9 100644 --- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java +++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8186046 8195694 + * @bug 8186046 8195694 8241100 8364751 * @summary Test dynamic constant bootstraps * @library /java/lang/invoke/common * @build test.java.lang.invoke.lib.InstructionHelper @@ -31,6 +31,7 @@ * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest */ +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.java.lang.invoke.lib.InstructionHelper; @@ -241,4 +242,45 @@ public class ConstantBootstrapsTest { assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.coordinateTypes(), List.of(String[].class, int.class)); } + + @DataProvider + public static Object[][] cceCasts() { + return new Object[][]{ + { void.class, null }, + { Integer.class, "a" }, + { int.class, BigInteger.ZERO }, + }; + } + + @Test(dataProvider = "cceCasts", expectedExceptions = ClassCastException.class) + public void testBadCasts(Class dstType, Object value) { + ConstantBootstraps.explicitCast(null, null, dstType, value); + } + + @DataProvider + public static Object[][] validCasts() { + Object o = new Object(); + return new Object[][]{ + { Object.class, null, null }, + { Object.class, o, o }, + { String.class, "abc", "abc" }, + { short.class, 10, (short) 10 }, + { int.class, (short) 10, 10 }, + { boolean.class, 1, true }, + { boolean.class, 2, false }, + { int.class, true, 1 }, + { int.class, false, 0 }, + { int.class, 10, 10 }, + { Integer.class, 10, 10 }, + { Object.class, 10, 10 }, + { Number.class, 10, 10 }, + { char.class, null, (char) 0 } + }; + } + + @Test(dataProvider = "validCasts") + public void testSuccessfulCasts(Class dstType, Object value, Object expected) { + Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value); + assertEquals(actual, expected); + } } From ae9607725c8c6a1b2f2728dbb5f7993722497da7 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 14:35:45 +0000 Subject: [PATCH 279/471] 8361614: Missing sub-int value validation in the Class-File API Reviewed-by: asotona --- .../java/lang/classfile/AccessFlags.java | 4 +- .../java/lang/classfile/ClassBuilder.java | 17 ++ .../java/lang/classfile/ClassFileVersion.java | 15 +- .../java/lang/classfile/ClassModel.java | 8 +- .../java/lang/classfile/ClassReader.java | 5 +- .../java/lang/classfile/CodeBuilder.java | 55 +++-- .../java/lang/classfile/FieldBuilder.java | 4 + .../java/lang/classfile/MethodBuilder.java | 6 +- .../java/lang/classfile/TypeAnnotation.java | 39 +++- .../attribute/CharacterRangeInfo.java | 3 + .../classfile/attribute/InnerClassInfo.java | 9 +- .../classfile/attribute/LineNumberInfo.java | 2 + .../attribute/MethodParameterInfo.java | 8 +- .../classfile/attribute/ModuleAttribute.java | 8 +- .../classfile/attribute/ModuleExportInfo.java | 10 +- .../classfile/attribute/ModuleOpenInfo.java | 10 +- .../attribute/ModuleRequireInfo.java | 6 +- .../attribute/ModuleResolutionAttribute.java | 6 +- .../constantpool/ConstantPoolBuilder.java | 4 +- .../classfile/instruction/CharacterRange.java | 4 +- .../instruction/DiscontinuedInstruction.java | 15 +- .../instruction/IncrementInstruction.java | 6 +- .../classfile/instruction/LineNumber.java | 4 +- .../instruction/LoadInstruction.java | 17 +- .../classfile/instruction/LocalVariable.java | 16 +- .../instruction/LocalVariableType.java | 16 +- .../instruction/StoreInstruction.java | 17 +- .../java/lang/classfile/package-info.java | 46 +++- .../impl/AbstractPseudoInstruction.java | 4 +- .../classfile/impl/AccessFlagsImpl.java | 6 +- .../classfile/impl/ClassFileVersionImpl.java | 9 +- .../classfile/impl/DirectClassBuilder.java | 2 +- .../classfile/impl/DirectFieldBuilder.java | 6 +- .../classfile/impl/DirectMethodBuilder.java | 6 +- .../classfile/impl/LineNumberImpl.java | 4 +- .../impl/ModuleAttributeBuilderImpl.java | 4 +- .../classfile/impl/SplitConstantPool.java | 1 + .../classfile/impl/TargetInfoImpl.java | 45 ++-- .../classfile/impl/UnboundAttribute.java | 27 ++- .../jdk/internal/classfile/impl/Util.java | 29 ++- .../classfile/InstructionValidationTest.java | 66 +++++- .../classfile/PreviewMinorVersionTest.java | 57 ----- .../jdk/classfile/SubIntValidationTest.java | 201 ++++++++++++++++++ 43 files changed, 636 insertions(+), 191 deletions(-) delete mode 100644 test/jdk/jdk/classfile/PreviewMinorVersionTest.java create mode 100644 test/jdk/jdk/classfile/SubIntValidationTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java index 33db731efc8..c53609615b8 100644 --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java @@ -64,8 +64,8 @@ public sealed interface AccessFlags permits AccessFlagsImpl { /** - * {@return the access flags, as a bit mask} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the access flags, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. */ int flagsMask(); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 6efd240d8af..86cdb298d9e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -66,6 +66,9 @@ public sealed interface ClassBuilder * @param major the major version number * @param minor the minor version number * @return this builder + * @throws IllegalArgumentException if {@code major} or {@code minor} is not + * {@link java.lang.classfile##u2 u2}; {@code minor} may be {@code + * -1} to indicate {@value ClassFile#PREVIEW_MINOR_VERSION} * @see ClassFileVersion */ default ClassBuilder withVersion(int major, int minor) { @@ -77,6 +80,8 @@ public sealed interface ClassBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see AccessFlags * @see AccessFlag.Location#CLASS */ @@ -188,6 +193,8 @@ public sealed interface ClassBuilder * @param descriptor the field descriptor string * @param flags the access flags for this field, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see FieldModel * @see FieldBuilder#withFlags(int) */ @@ -221,6 +228,8 @@ public sealed interface ClassBuilder * @param descriptor the symbolic field descriptor * @param flags the access flags for this field, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see FieldModel * @see FieldBuilder#withFlags(int) */ @@ -260,6 +269,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ ClassBuilder withMethod(Utf8Entry name, @@ -284,6 +295,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method body * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethodBody(Utf8Entry name, @@ -304,6 +317,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethod(String name, @@ -333,6 +348,8 @@ public sealed interface ClassBuilder * ACC_STATIC} bit definitely set * @param handler handler to supply the contents of the method body * @return this builder + * @throws IllegalArgumentException if {@code methodFlags} is not {@link + * java.lang.classfile##u2 u2} * @see MethodModel */ default ClassBuilder withMethodBody(String name, diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java b/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java index 5a795b94865..a6dfcae8884 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileVersion.java @@ -60,8 +60,8 @@ public sealed interface ClassFileVersion extends ClassElement permits ClassFileVersionImpl { /** - * {@return the major version} It is in the range of unsigned short, {@code - * [0, 65535]}. + * {@return the major version} It is a {@link java.lang.classfile##u2 u2} + * value. * * @apiNote * Constants in {@link ClassFile} named {@code Java_#_VERSION}, where # is @@ -71,15 +71,20 @@ public sealed interface ClassFileVersion int majorVersion(); /** - * {@return the minor version} It is in the range of unsigned short, {@code - * [0, 65535]}. + * {@return the minor version} It is a {@link java.lang.classfile##u2 u2} + * value. */ int minorVersion(); /** - * {@return a {@link ClassFileVersion} element} + * {@return a {@link ClassFileVersion} element} The minor version number + * may be {@code -1} to represent {@value ClassFile#PREVIEW_MINOR_VERSION}. + * * @param majorVersion the major version * @param minorVersion the minor version + * @throws IllegalArgumentException if the major version or the minor + * version is not {@link java.lang.classfile##u2 u2}; the minor + * version may be {@code -1} */ static ClassFileVersion of(int majorVersion, int minorVersion) { return new ClassFileVersionImpl(majorVersion, minorVersion); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassModel.java b/src/java.base/share/classes/java/lang/classfile/ClassModel.java index 2c547e6336d..735ce34d232 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassModel.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassModel.java @@ -84,16 +84,16 @@ public sealed interface ClassModel ClassEntry thisClass(); /** - * {@return the major version of this class} It is in the range of unsigned - * short, {@code [0, 65535]}. + * {@return the major version of this class} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ClassFileVersion */ int majorVersion(); /** - * {@return the minor version of this class} It is in the range of unsigned - * short, {@code [0, 65535]}. + * {@return the minor version of this class} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ClassFileVersion */ diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java index 3de188af8b3..c3d60d7fc31 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -153,8 +153,9 @@ public sealed interface ClassReader extends ConstantPool int readU1(int offset); /** - * {@return the unsigned short at the specified offset within the {@code - * class} file} Reads a 2-byte value and zero-extends it to an {@code int}. + * {@return the {@link java.lang.classfile##u2 u2} at the specified offset + * within the {@code class} file} Reads a 2-byte value and zero-extends it + * to an {@code int}. * * @param offset the offset within the {@code class} file */ diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index c1070bbcc77..656e84adf58 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -465,7 +465,7 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @return this builder * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID - * void} or {@code slot} is out of range + * void} or {@code slot} is not {@link java.lang.classfile##u2 u2} * @see LoadInstruction */ default CodeBuilder loadLocal(TypeKind tk, int slot) { @@ -479,7 +479,8 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @return this builder * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID - * void} or {@code slot} is out of range + * void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see StoreInstruction */ default CodeBuilder storeLocal(TypeKind tk, int slot) { @@ -811,6 +812,8 @@ public sealed interface CodeBuilder * * @param line the line number * @return this builder + * @throws IllegalArgumentException if {@code line} is not {@link + * java.lang.classfile##u2 u2} * @see LineNumber */ default CodeBuilder lineNumber(int line) { @@ -907,6 +910,8 @@ public sealed interface CodeBuilder * @param characterRangeEnd the encoded end of the character range region (exclusive) * @param flags the flags word, indicating the kind of range * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see CharacterRange */ default CodeBuilder characterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { @@ -926,7 +931,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariable */ default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { @@ -946,7 +952,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariable */ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { @@ -974,7 +981,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariableType */ default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { @@ -999,7 +1007,8 @@ public sealed interface CodeBuilder * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see LocalVariableType */ default CodeBuilder localVariableType(int slot, String name, Signature signature, Label startScope, Label endScope) { @@ -1058,7 +1067,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ALOAD * @see #loadLocal * @see LoadInstruction @@ -1128,7 +1138,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ASTORE * @see #storeLocal * @see StoreInstruction @@ -1384,7 +1395,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#DLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -1449,7 +1461,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#DSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -1696,7 +1709,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#FLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -1761,7 +1775,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#FSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -2393,7 +2408,9 @@ public sealed interface CodeBuilder * @param slot the local variable slot * @param val the increment value * @return this builder - * @throws IllegalArgumentException if {@code slot} or {@code val} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} or {@code val} is out of range of + * {@link TypeKind#SHORT short} * @see Opcode#IINC * @see IncrementInstruction */ @@ -2410,7 +2427,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ILOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -2763,7 +2781,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#ISTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction @@ -3001,7 +3020,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#LLOAD * @see #loadLocal(TypeKind, int) * @see LoadInstruction @@ -3103,7 +3123,8 @@ public sealed interface CodeBuilder * * @param slot the local variable slot * @return this builder - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} * @see Opcode#LSTORE * @see #storeLocal(TypeKind, int) * @see StoreInstruction diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java index 477aa6984a2..a71cdb2611f 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java @@ -56,6 +56,8 @@ public sealed interface FieldBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} * @see AccessFlags * @see AccessFlag.Location#FIELD * @see ClassBuilder#withField(String, ClassDesc, int) @@ -69,6 +71,8 @@ public sealed interface FieldBuilder * * @param flags the access flags, as a bit mask * @return this builder + * @throws IllegalArgumentException if any flag cannot be applied to the + * {@link AccessFlag.Location#FIELD} location * @see AccessFlags * @see AccessFlag.Location#FIELD * @see ClassBuilder#withField(String, ClassDesc, int) diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java index ff777246fde..847f5315c5f 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java @@ -58,7 +58,8 @@ public sealed interface MethodBuilder * * @param flags the access flags, as a bit mask * @return this builder - * @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2}, or the {@link ClassFile#ACC_STATIC * ACC_STATIC} flag is modified * @see AccessFlags * @see AccessFlag.Location#METHOD @@ -74,7 +75,8 @@ public sealed interface MethodBuilder * @param flags the access flags, as a bit mask * @return this builder * @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC - * ACC_STATIC} flag is modified + * ACC_STATIC} flag is modified, or if any flag cannot be applied to + * the {@link AccessFlag.Location#METHOD} location * @see AccessFlags * @see AccessFlag.Location#METHOD */ diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 68514a2436c..09dc3b59098 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -31,6 +31,7 @@ import java.util.List; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; +import jdk.internal.classfile.impl.Util; import static java.lang.classfile.TypeAnnotation.TargetInfo.*; @@ -352,6 +353,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on a class or method type parameter declaration} * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER} or {@link TargetType#METHOD_TYPE_PARAMETER} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofTypeParameter(TargetType targetType, int typeParameterIndex) { return new TargetInfoImpl.TypeParameterTargetImpl(targetType, typeParameterIndex); @@ -360,6 +363,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on a class type parameter declaration} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofClassTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.CLASS_TYPE_PARAMETER, typeParameterIndex); @@ -368,6 +373,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on a method type parameter declaration} * @param typeParameterIndex specifies which type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeParameterTarget ofMethodTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.METHOD_TYPE_PARAMETER, typeParameterIndex); @@ -376,6 +383,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the type of an "extends" or "implements" clause} * @param supertypeIndex the index into the interfaces array or 65535 to indicate it is the superclass + * @throws IllegalArgumentException if {@code supertypeIndex} is not + * {@link java.lang.classfile##u2 u2} */ static SupertypeTarget ofClassExtends(int supertypeIndex) { return new TargetInfoImpl.SupertypeTargetImpl(supertypeIndex); @@ -387,6 +396,8 @@ public sealed interface TypeAnnotation * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER_BOUND} or {@link TargetType#METHOD_TYPE_PARAMETER_BOUND} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofTypeParameterBound(TargetType targetType, int typeParameterIndex, int boundIndex) { return new TargetInfoImpl.TypeParameterBoundTargetImpl(targetType, typeParameterIndex, boundIndex); @@ -397,6 +408,8 @@ public sealed interface TypeAnnotation * a generic class, or interface} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofClassTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.CLASS_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); @@ -407,6 +420,8 @@ public sealed interface TypeAnnotation * a generic method, or constructor} * @param typeParameterIndex specifies which type parameter declaration is annotated * @param boundIndex specifies which bound of the type parameter declaration is annotated + * @throws IllegalArgumentException if {@code typeParameterIndex} or + * {@code boundIndex} is not {@link java.lang.classfile##u1 u1} */ static TypeParameterBoundTarget ofMethodTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.METHOD_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); @@ -448,6 +463,8 @@ public sealed interface TypeAnnotation * synthetic or implicit parameters are omitted. * * @param formalParameterIndex specifies which formal parameter declaration has an annotated type + * @throws IllegalArgumentException if {@code formalParameterIndex} is + * not {@link java.lang.classfile##u1 u1} */ static FormalParameterTarget ofMethodFormalParameter(int formalParameterIndex) { return new TargetInfoImpl.FormalParameterTargetImpl(formalParameterIndex); @@ -457,6 +474,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the i'th type in the throws clause of a method or * constructor declaration} * @param throwsTargetIndex the index into the exception table of the Exceptions attribute of the method + * @throws IllegalArgumentException if {@code throwsTargetIndex} is + * not {@link java.lang.classfile##u2 u2} */ static ThrowsTarget ofThrows(int throwsTargetIndex) { return new TargetInfoImpl.ThrowsTargetImpl(throwsTargetIndex); @@ -492,6 +511,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the i'th type in an exception parameter declaration} * @param exceptionTableIndex the index into the exception table of the Code attribute + * @throws IllegalArgumentException if {@code exceptionTableIndex} is + * not {@link java.lang.classfile##u2 u2} */ static CatchTarget ofExceptionParameter(int exceptionTableIndex) { return new TargetInfoImpl.CatchTargetImpl(exceptionTableIndex); @@ -552,6 +573,8 @@ public sealed interface TypeAnnotation * or {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the cast operator or argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofTypeArgument(TargetType targetType, Label target, int typeArgumentIndex) { return new TargetInfoImpl.TypeArgumentTargetImpl(targetType, target, typeArgumentIndex); @@ -561,6 +584,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the i'th type in a cast expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the cast operator is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofCastExpr(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CAST, target, typeArgumentIndex); @@ -571,6 +596,8 @@ public sealed interface TypeAnnotation * an explicit constructor invocation statement} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofConstructorInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -581,6 +608,8 @@ public sealed interface TypeAnnotation * a method invocation expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofMethodInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -591,6 +620,8 @@ public sealed interface TypeAnnotation * a new expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofConstructorReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -601,6 +632,8 @@ public sealed interface TypeAnnotation * a method reference expression} * @param target the label right before the instruction * @param typeArgumentIndex specifies which type in the argument is annotated + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypeArgumentTarget ofMethodReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); @@ -792,6 +825,8 @@ public sealed interface TypeAnnotation * @param startLabel the code label indicating start of an interval where variable has value * @param endLabel the code label indicating start of an interval where variable has value * @param index index into the local variables + * @throws IllegalArgumentException if {@code index} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVarTargetInfo of(Label startLabel, Label endLabel, int index) { return new TargetInfoImpl.LocalVarTargetInfoImpl(startLabel, endLabel, index); @@ -959,9 +994,11 @@ public sealed interface TypeAnnotation * {@return type path component of an annotation} * @param typePathKind the kind of path element * @param typeArgumentIndex the type argument index + * @throws IllegalArgumentException if {@code typeArgumentIndex} is not + * {@link java.lang.classfile##u1 u1} */ static TypePathComponent of(Kind typePathKind, int typeArgumentIndex) { - + Util.checkU1(typeArgumentIndex, "type argument index"); return switch (typePathKind) { case ARRAY -> ARRAY; case INNER_TYPE -> INNER_TYPE; diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java index 7bb0a0d124d..f6f5f9928bc 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java @@ -28,6 +28,7 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.instruction.CharacterRange; import jdk.internal.classfile.impl.UnboundAttribute; +import jdk.internal.classfile.impl.Util; /** * Models a single character range entry in the {@link @@ -166,6 +167,8 @@ public sealed interface CharacterRangeInfo * @param characterRangeEnd the encoded end of character positions in the * source file, exclusive * @param flags the flags of this entry + * @throws IllegalArgumentException if {@code startPc}, {@code endPc}, or + * {@code flags} is not {@link java.lang.classfile##u2 u2} */ static CharacterRangeInfo of(int startPc, int endPc, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java index 960d3755c4c..df6b63ae692 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java @@ -68,8 +68,7 @@ public sealed interface InnerClassInfo /** * {@return a bit mask of flags denoting access permissions and properties - * of the inner class} It is in the range of unsigned short, {@code [0, - * 0xFFFF]}. + * of the inner class} It is a {@link java.lang.classfile##u2 u2} value. * * @see Class#getModifiers() * @see AccessFlag.Location#INNER_CLASS @@ -104,6 +103,8 @@ public sealed interface InnerClassInfo * @param outerClass the class that has the nested class as a member, if it exists * @param innerName the simple name of the nested class, if it is not anonymous * @param flags the inner class access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static InnerClassInfo of(ClassEntry innerClass, Optional outerClass, Optional innerName, int flags) { @@ -116,7 +117,9 @@ public sealed interface InnerClassInfo * @param outerClass the class that has the nested class as a member, if it exists * @param innerName the simple name of the nested class, if it is not anonymous * @param flags the inner class access flags - * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass} represents a primitive type + * @throws IllegalArgumentException if {@code innerClass} or {@code outerClass} + * represents a primitive type, or if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static InnerClassInfo of(ClassDesc innerClass, Optional outerClass, Optional innerName, int flags) { return new UnboundAttribute.UnboundInnerClassInfo(TemporaryConstantPool.INSTANCE.classEntry(innerClass), diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java index 2f4f6d00deb..3a0b5499657 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberInfo.java @@ -60,6 +60,8 @@ public sealed interface LineNumberInfo * * @param startPc the starting index of the code array for this line * @param lineNumber the line number within the original source file + * @throws IllegalArgumentException if {@code startPc} or {@code lineNumber} + * is not {@link java.lang.classfile##u2 u2} */ public static LineNumberInfo of(int startPc, int lineNumber) { return new UnboundAttribute.UnboundLineNumberInfo(startPc, lineNumber); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java index 636c671f25a..a5bc14601e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java @@ -53,8 +53,8 @@ public sealed interface MethodParameterInfo Optional name(); /** - * {@return the access flags, as a bit mask} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the access flags, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see Parameter#getModifiers() * @see AccessFlag.Location#METHOD_PARAMETER @@ -85,6 +85,8 @@ public sealed interface MethodParameterInfo * {@return a method parameter description} * @param name the method parameter name, may be empty * @param flags the method parameter access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static MethodParameterInfo of(Optional name, int flags) { return new UnboundAttribute.UnboundMethodParameterInfo(name, flags); @@ -105,6 +107,8 @@ public sealed interface MethodParameterInfo * {@return a method parameter description} * @param name the method parameter name, may be empty * @param flags the method parameter access flags + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static MethodParameterInfo ofParameter(Optional name, int flags) { return of(name.map(TemporaryConstantPool.INSTANCE::utf8Entry), flags); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index ad564913d84..678c0f29714 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -81,8 +81,8 @@ public sealed interface ModuleAttribute ModuleEntry moduleName(); /** - * {@return the module flags of the module, as a bit mask} It is in the - * range of unsigned short, {@code [0, 0xFFFF]}. + * {@return the module flags of the module, as a bit mask} It is a {@link + * java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor#modifiers() * @see AccessFlag.Location#MODULE @@ -170,6 +170,8 @@ public sealed interface ModuleAttribute * @param opens the opened packages * @param uses the consumed services * @param provides the provided services + * @throws IllegalArgumentException if {@code moduleFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleEntry moduleName, int moduleFlags, Utf8Entry moduleVersion, @@ -230,6 +232,8 @@ public sealed interface ModuleAttribute * * @param flagsMask the module flags * @return this builder + * @throws IllegalArgumentException if {@code flagsMask} is not {@link + * java.lang.classfile##u2 u2} */ ModuleAttributeBuilder moduleFlags(int flagsMask); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index e498b8bc036..af04c83d260 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -58,7 +58,7 @@ public sealed interface ModuleExportInfo /** * {@return the flags associated with this export declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Exports#modifiers() * @see AccessFlag.Location#MODULE_EXPORTS @@ -103,6 +103,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, List exportsTo) { @@ -131,6 +133,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, @@ -161,6 +165,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, List exportsTo) { @@ -191,6 +197,8 @@ public sealed interface ModuleExportInfo * @param exportFlags the export flags, as a bitmask * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export + * @throws IllegalArgumentException if {@code exportFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index d183a0b4985..40a9b929776 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -64,7 +64,7 @@ public sealed interface ModuleOpenInfo /** * {@return the flags associated with this open declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Opens#modifiers() * @see AccessFlag.Location#MODULE_OPENS @@ -109,6 +109,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, List opensTo) { @@ -137,6 +139,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, @@ -166,6 +170,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, List opensTo) { @@ -194,6 +200,8 @@ public sealed interface ModuleOpenInfo * @param opensFlags the open flags * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open + * @throws IllegalArgumentException if {@code opensFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java index 49544554090..6e3e7df5ed0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java @@ -55,7 +55,7 @@ public sealed interface ModuleRequireInfo /** * {@return the flags associated with this require declaration, as a bit mask} - * It is in the range of unsigned short, {@code [0, 0xFFFF]}. + * It is a {@link java.lang.classfile##u2 u2} value. * * @see ModuleDescriptor.Requires#modifiers() * @see AccessFlag.Location#MODULE_REQUIRES @@ -97,6 +97,8 @@ public sealed interface ModuleRequireInfo * @param requires the required module * @param requiresFlags the require-specific flags * @param requiresVersion the required version, may be {@code null} + * @throws IllegalArgumentException if {@code requiresFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleRequireInfo of(ModuleEntry requires, int requiresFlags, Utf8Entry requiresVersion) { return new UnboundAttribute.UnboundModuleRequiresInfo(requires, requiresFlags, Optional.ofNullable(requiresVersion)); @@ -121,6 +123,8 @@ public sealed interface ModuleRequireInfo * @param requires the required module * @param requiresFlags the require-specific flags * @param requiresVersion the required version, may be {@code null} + * @throws IllegalArgumentException if {@code requiresFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleRequireInfo of(ModuleDesc requires, int requiresFlags, String requiresVersion) { return new UnboundAttribute.UnboundModuleRequiresInfo(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(requires.name())), requiresFlags, Optional.ofNullable(requiresVersion).map(s -> TemporaryConstantPool.INSTANCE.utf8Entry(s))); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java index 039700f024a..1d607da2333 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleResolutionAttribute.java @@ -78,8 +78,8 @@ public sealed interface ModuleResolutionAttribute permits BoundAttribute.BoundModuleResolutionAttribute, UnboundAttribute.UnboundModuleResolutionAttribute { /** - * {@return the module resolution flags} It is in the range of unsigned - * short, {@code [0, 0xFFFF]}. + * {@return the module resolution flags} It is a {@link + * java.lang.classfile##u2 u2} value. *

        * The value of the resolution_flags item is a mask of flags used to denote * properties of module resolution. The flags are as follows: @@ -99,6 +99,8 @@ public sealed interface ModuleResolutionAttribute * {@return a {@code ModuleResolution} attribute} * * @param resolutionFlags the resolution flags + * @throws IllegalArgumentException if {@code resolutionFlags} is not {@link + * java.lang.classfile##u2 u2} */ static ModuleResolutionAttribute of(int resolutionFlags) { return new UnboundAttribute.UnboundModuleResolutionAttribute(resolutionFlags); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index 4b443929158..7d3f3c546a7 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -397,12 +397,14 @@ public sealed interface ConstantPoolBuilder /** * {@return a {@link MethodHandleEntry} encoding a reference kind and - * referring to a {@link MemberRefEntry}} The reference kind must be + * referring to a {@link MemberRefEntry}} The reference kind is * in {@code [1, 9]}, and the {@code MemberRefEntry} is subject to * various restrictions based on the reference kind (JVMS {@jvms 4.4.8}). * * @param refKind the reference kind of the method handle * @param reference the {@code MemberRefEntry} + * @throws IllegalArgumentException if {@code refKind} is not {@link + * java.lang.classfile##u1 u1} * @see MethodHandleInfo##refkinds Reference kinds * @see MethodHandleEntry#kind() MethodHandleEntry::kind * @see MethodHandleEntry#reference() MethodHandleEntry::reference diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java index 07d4c116b3a..ec491880fd9 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -149,6 +149,8 @@ public sealed interface CharacterRange extends PseudoInstruction * @param characterRangeStart the encoded start of the character range region (inclusive) * @param characterRangeEnd the encoded end of the character range region (exclusive) * @param flags a flags word, indicating the kind of range + * @throws IllegalArgumentException if {@code flags} is not {@link + * java.lang.classfile##u2 u2} */ static CharacterRange of(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { return new AbstractPseudoInstruction.UnboundCharacterRange(startScope, endScope, characterRangeStart, characterRangeEnd, flags); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 906aaea421d..40c4f06f98c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java @@ -131,7 +131,7 @@ public sealed interface DiscontinuedInstruction extends Instruction { * // @link substring="RetInstruction" target="#of(int)" : * RetInstruction(int slot) // @link substring="slot" target="#slot()" * } - * where {@code slot} must be within {@code [0, 65535]}. + * where {@code slot} must be {@link java.lang.classfile##u2 u2}. *

        * {@link StoreInstruction astore} series of instructions store a {@link * TypeKind##returnAddress returnAddress} value to a local variable slot, @@ -153,16 +153,16 @@ public sealed interface DiscontinuedInstruction extends Instruction { /** * {@return the local variable slot with return address} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); /** * {@return a return from subroutine instruction} *

        - * {@code slot} must be in the closed range of {@code [0, 255]} for - * {@link Opcode#RET ret}, or within {@code [0, 65535]} for {@link - * Opcode#RET_W wide ret}. + * {@code slot} must be {@link java.lang.classfile##u1 u1} for + * {@link Opcode#RET ret}, or {@link java.lang.classfile##u2 u2} for + * {@link Opcode#RET_W wide ret}. * * @apiNote * The explicit {@code op} argument allows creating {@code wide ret} @@ -183,10 +183,11 @@ public sealed interface DiscontinuedInstruction extends Instruction { /** * {@return a return from subroutine instruction} *

        - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot to load return address from - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static RetInstruction of(int slot) { return of(slot < 256 ? Opcode.RET : Opcode.RET_W, slot); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java index a874ef0a954..352f83f529c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -48,7 +48,7 @@ import jdk.internal.classfile.impl.AbstractInstruction; * } * where *

          - *
        • {@code slot} must be within {@code [0, 65535]}. + *
        • {@code slot} must be {@link java.lang.classfile##u2 u2}. *
        • {@code constant} must be within {@code [-32768, 32767]}. *
        * @@ -73,7 +73,7 @@ public sealed interface IncrementInstruction extends Instruction /** * {@return an increment instruction} *
          - *
        • {@code slot} must be within {@code [0, 65535]}. + *
        • {@code slot} must be {@link java.lang.classfile##u2 u2}. *
        • {@code constant} must be within {@code [-32768, 32767]}. *
        * diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java index 3f10a3ada0d..12760df5fcb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LineNumber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -75,6 +75,8 @@ public sealed interface LineNumber extends PseudoInstruction * {@return a line number pseudo-instruction} * * @param line the line number + * @throws IllegalArgumentException if {@code line} is not {@link + * java.lang.classfile##u2 u2} */ static LineNumber of(int line) { return LineNumberImpl.of(line); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java index 81961320be3..16de554b228 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -50,7 +50,7 @@ import jdk.internal.classfile.impl.Util; * ) * } * where {@code TypeKind} is {@linkplain TypeKind##computational-type - * computational}, and {@code slot} is within {@code [0, 65535]}. + * computational}, and {@code slot} is {@link java.lang.classfile##u2 u2}. * * @see Opcode.Kind#LOAD * @see CodeBuilder#loadLocal CodeBuilder::loadLocal @@ -62,7 +62,7 @@ public sealed interface LoadInstruction extends Instruction /** * {@return the local variable slot to load from} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -76,12 +76,13 @@ public sealed interface LoadInstruction extends Instruction * {@return a local variable load instruction} * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its * computational type. - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be a {@link java.lang.classfile##u2 u2} value. * * @param kind the type of the value to be loaded * @param slot the local variable slot to load from * @throws IllegalArgumentException if {@code kind} is - * {@link TypeKind#VOID void} or {@code slot} is out of range + * {@link TypeKind#VOID void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LoadInstruction of(TypeKind kind, int slot) { var opcode = BytecodeHelpers.loadOpcode(kind, slot); // validates slot, trusted @@ -96,8 +97,10 @@ public sealed interface LoadInstruction extends Instruction *
          *
        • If {@code op} has size 1, {@code slot} must be exactly the slot value * implied by the opcode. - *
        • If {@code op} has size 2, {@code slot} must be within {@code [0, 255]}. - *
        • If {@code op} has size 4, {@code slot} must be within {@code [0, 65535]}. + *
        • If {@code op} has size 2, {@code slot} must be {@link + * java.lang.classfile##u1 u1}. + *
        • If {@code op} has size 4, {@code slot} must be {@link + * java.lang.classfile##u2 u2}. *
        * * @apiNote diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java index f44a4e094f1..3c743aadbeb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -57,7 +57,7 @@ import jdk.internal.classfile.impl.Util; * Label endScope // @link substring="endScope" target="#endScope" * ) * } - * Where {@code slot} is within {@code [0, 65535]}. + * Where {@code slot} is {@link java.lang.classfile##u2 u2}. *

        * Another model, {@link LocalVariableInfo}, also models a local variable * entry; it has no dependency on a {@code CodeModel} and represents of bci @@ -79,7 +79,7 @@ public sealed interface LocalVariable extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariable, BoundLocalVariable { /** * {@return the local variable slot} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -116,14 +116,15 @@ public sealed interface LocalVariable extends PseudoInstruction /** * {@return a local variable pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param nameEntry the local variable name * @param descriptorEntry the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariable of(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariable(slot, nameEntry, descriptorEntry, @@ -132,14 +133,15 @@ public sealed interface LocalVariable extends PseudoInstruction /** * {@return a local variable pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param name the local variable name * @param descriptor the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariable of(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java index 1e28804a837..09d8c11d52f 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -50,7 +50,7 @@ import jdk.internal.classfile.impl.TemporaryConstantPool; * Label endScope // @link substring="endScope" target="#endScope" * ) * } - * Where {@code slot} is within {@code [0, 65535]}. + * Where {@code slot} is {@link java.lang.classfile##u2 u2}. *

        * Another model, {@link LocalVariableTypeInfo}, also models a local variable * type entry; it has no dependency on a {@code CodeModel} and represents of bci @@ -72,7 +72,7 @@ public sealed interface LocalVariableType extends PseudoInstruction permits AbstractPseudoInstruction.UnboundLocalVariableType, BoundLocalVariableType { /** * {@return the local variable slot} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -109,14 +109,15 @@ public sealed interface LocalVariableType extends PseudoInstruction /** * {@return a local variable type pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param nameEntry the local variable name * @param signatureEntry the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariableType of(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariableType(slot, nameEntry, signatureEntry, @@ -125,14 +126,15 @@ public sealed interface LocalVariableType extends PseudoInstruction /** * {@return a local variable type pseudo-instruction} - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param slot the local variable slot * @param name the local variable name * @param signature the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope - * @throws IllegalArgumentException if {@code slot} is out of range + * @throws IllegalArgumentException if {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static LocalVariableType of(int slot, String name, Signature signature, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java index 93d33e0b7c2..35190796c19 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -50,7 +50,7 @@ import jdk.internal.classfile.impl.Util; * ) * } * where {@code TypeKind} is {@linkplain TypeKind##computational-type - * computational}, and {@code slot} is within {@code [0, 65535]}. + * computational}, and {@code slot} is {@link java.lang.classfile##u2 u2}. *

        * {@code astore} series of instructions, or {@code reference} type store * instructions, can also operate on the {@link TypeKind##returnAddress @@ -66,7 +66,7 @@ public sealed interface StoreInstruction extends Instruction /** * {@return the local variable slot to store to} - * The value is within {@code [0, 65535]}. + * It is a {@link java.lang.classfile##u2 u2} value. */ int slot(); @@ -82,12 +82,13 @@ public sealed interface StoreInstruction extends Instruction * {@return a local variable store instruction} * {@code kind} is {@linkplain TypeKind#asLoadable() converted} to its * computational type. - * {@code slot} must be within {@code [0, 65535]}. + * {@code slot} must be {@link java.lang.classfile##u2 u2}. * * @param kind the type of the value to be stored * @param slot the local variable slot to store to * @throws IllegalArgumentException if {@code kind} is {@link - * TypeKind#VOID void} or {@code slot} is out of range + * TypeKind#VOID void} or {@code slot} is not {@link + * java.lang.classfile##u2 u2} */ static StoreInstruction of(TypeKind kind, int slot) { var opcode = BytecodeHelpers.storeOpcode(kind, slot); // validates slot @@ -102,8 +103,10 @@ public sealed interface StoreInstruction extends Instruction *

          *
        • If {@code op} has size 1, {@code slot} must be exactly the slot value * implied by the opcode. - *
        • If {@code op} has size 2, {@code slot} must be within {@code [0, 255]}. - *
        • If {@code op} has size 4, {@code slot} must be within {@code [0, 65535]}. + *
        • If {@code op} has size 2, {@code slot} must be {@link + * java.lang.classfile##u1 u1}. + *
        • If {@code op} has size 4, {@code slot} must be {@link + * java.lang.classfile##u2 u2}. *
        * * @apiNote diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index 832dac2fff1..5d905aace65 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -273,13 +273,22 @@ * accepting constant pool entries. * *

        Consistency checks, syntax checks and verification

        + * The Class-File API performs checks to ensure arguments are representable in + * the {@code class} file format. A value that is lost when it is built to a + * {@code class} file and re-parsed to a model is rejected with an {@link + * IllegalArgumentException}. For example, a negative value or a value over + * {@code 65535} is lost when built to a {@link ##u2 u2} item, with + * the range {@code [0, 65535]}. In particular, any variable-sized table + * exceeding its maximum representable size is rejected. + *

        * No consistency checks are performed while building or transforming classfiles - * (except for null arguments checks). All builders and classfile elements factory - * methods accepts the provided information without implicit validation. - * However, fatal inconsistencies (like for example invalid code sequence or + * (except for null and representable arguments checks). All builders and + * classfile elements factory methods accepts the provided information without + * implicit validation, as long as they are representable in the {@code class} + * file format. However, fatal inconsistencies (like invalid code sequence or * unresolved labels) affects internal tools and may cause exceptions later in * the classfile building process. These fatal exceptions are thrown as - * {@link IllegalArgumentException}. + * {@code IllegalArgumentException}. *

        * Using nominal descriptors assures the right serial form is applied by the * ClassFile API library based on the actual context. Also these nominal @@ -294,9 +303,9 @@ *

        * On the other hand it is possible to use builders methods and factories accepting * constant pool entries directly. Constant pool entries can be constructed also - * directly from raw values, with no additional conversions or validations. - * Following example uses intentionally wrong class name form and it is applied - * without any validation or conversion. + * directly from raw values, with no additional conversions or validations, as + * long as they are representable. Following example uses intentionally wrong + * class name form, which is applied without any validation or conversion. * {@snippet lang=java : * var invalidClassEntry = constantPoolBuilder.classEntry( * constantPoolBuilder.utf8Entry("mypackage.MyClass")); @@ -451,6 +460,29 @@ * accept nominal descriptors from {@link java.lang.constant} (e.g., {@link * ClassDesc}.) * + *

        Conventional data types

        + * Chapter {@jvms 4} of the Java Virtual Machine Specification + * defines a few conventional data types in the {@code class} file format. + * They are consistently represented as {@code int} in the API model. + * Out-of-bound values provided for these data types to the API result in {@link + * IllegalArgumentException}. + *
        + *
        {@code u1}
        + *
        One-byte {@linkplain Byte#toUnsignedInt(byte) unsigned} integer, in the + * range {@code [0, 255]}. + *
        See {@link java.io.DataInput#readUnsignedByte()}.
        + *
        {@code u2}
        + *
        Two-byte {@linkplain Short#toUnsignedInt(short) unsigned} integer, in the + * range {@code [0, 65535]}. + *
        Equivalent to a Java {@link Character char}. Frequently used for flag + * fields and indices and sizes of list structures. + *
        See {@link java.io.DataInput#readUnsignedShort()}.
        + *
        {@code u4}
        + *
        Four-byte {@linkplain Integer#toUnsignedLong(int) unsigned} integer, in + * the range {@code [0, 4294967295]}. + *
        See {@link java.io.DataInput#readInt()}.
        + *
        + * *

        Data model

        * We define each kind of element by its name, an optional arity indicator (zero * or more, zero or one, exactly one), and a list of components. The elements diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index ea3af78a600..43d8b2b1b3f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -116,7 +116,7 @@ public abstract sealed class AbstractPseudoInstruction this.endScope = requireNonNull(endScope); this.characterRangeStart = characterRangeStart; this.characterRangeEnd = characterRangeEnd; - this.flags = flags; + this.flags = Util.checkU2(flags, "character range flags"); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java index 43e15c04b6d..c290dd438c5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ public final class AccessFlagsImpl extends AbstractElement private final int flagsMask; private Set flags; - public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { + public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { this.location = location; this.flagsMask = Util.flagsToBits(location, flags); this.flags = Set.of(flags); @@ -43,7 +43,7 @@ public final class AccessFlagsImpl extends AbstractElement public AccessFlagsImpl(AccessFlag.Location location, int mask) { this.location = location; - this.flagsMask = mask; + this.flagsMask = Util.checkFlags(mask); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java index ba2605296cb..93fc4f47c85 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -26,14 +26,17 @@ package jdk.internal.classfile.impl; import java.lang.classfile.ClassFileVersion; +import static java.lang.classfile.ClassFile.PREVIEW_MINOR_VERSION; + public final class ClassFileVersionImpl extends AbstractElement implements ClassFileVersion { private final int majorVersion, minorVersion; public ClassFileVersionImpl(int majorVersion, int minorVersion) { - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; + this.majorVersion = Util.checkU2(majorVersion, "major version"); + this.minorVersion = minorVersion == -1 ? PREVIEW_MINOR_VERSION + : Util.checkU2(minorVersion, "minor version"); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 1e12969f204..0e82c545359 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -81,7 +81,7 @@ public final class DirectClassBuilder @Override public ClassBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index 1af3724766e..8dae9665f83 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -51,7 +51,7 @@ public final class DirectFieldBuilder setOriginal(original); this.name = requireNonNull(name); this.desc = requireNonNull(type); - this.flags = flags; + this.flags = Util.checkFlags(flags); } @Override @@ -71,7 +71,7 @@ public final class DirectFieldBuilder @Override public FieldBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index 938d6c088b7..db8c185a07d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -51,12 +51,12 @@ public final class DirectMethodBuilder setOriginal(original); this.name = requireNonNull(nameInfo); this.desc = requireNonNull(typeInfo); - this.flags = flags; + this.flags = Util.checkFlags(flags); } @Override public MethodBuilder withFlags(int flags) { - setFlags(flags); + setFlags(Util.checkFlags(flags)); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java index 4fc4a342143..36fd4915f71 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LineNumberImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -43,7 +43,7 @@ public final class LineNumberImpl } public static LineNumber of(int line) { - return (line < INTERN_LIMIT) + return (Util.checkU2(line, "line number") < INTERN_LIMIT) ? internCache[line] : new LineNumberImpl(line); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java index 505bbfd6fea..1b77af3746e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -78,7 +78,7 @@ public final class ModuleAttributeBuilderImpl @Override public ModuleAttributeBuilder moduleFlags(int flags) { - this.moduleFlags = flags; + this.moduleFlags = Util.checkFlags(flags); return this; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 5a5f2908ae6..d9ca3ff61bc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -594,6 +594,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder { @Override public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) { + Util.checkU1(refKind, "reference kind"); reference = AbstractPoolEntry.maybeClone(this, reference); int hash = AbstractPoolEntry.hash2(TAG_METHOD_HANDLE, refKind, reference.index()); EntryMap map1 = map(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index 07aa3c8d8c8..a0afb5efae1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -44,13 +44,18 @@ public final class TargetInfoImpl { public record TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) implements TypeParameterTarget { - public TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) { - this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); - this.typeParameterIndex = typeParameterIndex; + public TypeParameterTargetImpl { + checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); + Util.checkU1(typeParameterIndex, "type parameter index"); } } public record SupertypeTargetImpl(int supertypeIndex) implements SupertypeTarget { + + public SupertypeTargetImpl { + Util.checkU2(supertypeIndex, "supertype index"); + } + @Override public TargetType targetType() { return TargetType.CLASS_EXTENDS; @@ -60,10 +65,10 @@ public final class TargetInfoImpl { public record TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) implements TypeParameterBoundTarget { - public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) { - this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); - this.typeParameterIndex = typeParameterIndex; - this.boundIndex = boundIndex; + public TypeParameterBoundTargetImpl { + checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); + Util.checkU1(typeParameterIndex, "type parameter index"); + Util.checkU1(boundIndex, "bound index"); } } @@ -75,6 +80,11 @@ public final class TargetInfoImpl { } public record FormalParameterTargetImpl(int formalParameterIndex) implements FormalParameterTarget { + + public FormalParameterTargetImpl { + Util.checkU1(formalParameterIndex, "formal parameter index"); + } + @Override public TargetType targetType() { return TargetType.METHOD_FORMAL_PARAMETER; @@ -82,6 +92,11 @@ public final class TargetInfoImpl { } public record ThrowsTargetImpl(int throwsTargetIndex) implements ThrowsTarget { + + public ThrowsTargetImpl { + Util.checkU2(throwsTargetIndex, "throws type index"); + } + @Override public TargetType targetType() { return TargetType.THROWS; @@ -107,10 +122,16 @@ public final class TargetInfoImpl { public LocalVarTargetInfoImpl { requireNonNull(startLabel); requireNonNull(endLabel); + BytecodeHelpers.validateSlot(index); } } public record CatchTargetImpl(int exceptionTableIndex) implements CatchTarget { + + public CatchTargetImpl { + Util.checkU2(exceptionTableIndex, "exception table index"); + } + @Override public TargetType targetType() { return TargetType.EXCEPTION_PARAMETER; @@ -128,10 +149,10 @@ public final class TargetInfoImpl { public record TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) implements TypeArgumentTarget { - public TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) { - this.targetType = checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); - this.target = requireNonNull(target); - this.typeArgumentIndex = typeArgumentIndex; + public TypeArgumentTargetImpl { + checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); + requireNonNull(target); + Util.checkU1(typeArgumentIndex, "type argument index"); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 0b0f1836f66..347b0c12657 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -474,7 +474,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleResolutionAttribute(int flags) { super(Attributes.moduleResolution()); - resolutionFlags = flags; + resolutionFlags = Util.checkU2(flags, "resolution flags"); } @Override @@ -888,7 +888,14 @@ public abstract sealed class UnboundAttribute> int characterRangeStart, int characterRangeEnd, int flags) - implements CharacterRangeInfo { } + implements CharacterRangeInfo { + + public UnboundCharacterRangeInfo { + Util.checkU2(startPc, "start pc"); + Util.checkU2(endPc, "end pc"); + Util.checkU2(flags, "flags"); + } + } public record UnboundInnerClassInfo(ClassEntry innerClass, Optional outerClass, @@ -899,11 +906,17 @@ public abstract sealed class UnboundAttribute> requireNonNull(innerClass); requireNonNull(outerClass); requireNonNull(innerName); + Util.checkFlags(flagsMask); } } public record UnboundLineNumberInfo(int startPc, int lineNumber) - implements LineNumberInfo { } + implements LineNumberInfo { + public UnboundLineNumberInfo { + Util.checkU2(startPc, "start pc"); + Util.checkU2(lineNumber, "line number"); + } + } public record UnboundLocalVariableInfo(int startPc, int length, Utf8Entry name, @@ -931,6 +944,7 @@ public abstract sealed class UnboundAttribute> implements MethodParameterInfo { public UnboundMethodParameterInfo { requireNonNull(name); + Util.checkFlags(flagsMask); } } @@ -940,6 +954,7 @@ public abstract sealed class UnboundAttribute> implements ModuleExportInfo { public UnboundModuleExportInfo { requireNonNull(exportedPackage); + Util.checkFlags(exportsFlagsMask); exportsTo = List.copyOf(exportsTo); } } @@ -957,6 +972,7 @@ public abstract sealed class UnboundAttribute> implements ModuleOpenInfo { public UnboundModuleOpenInfo { requireNonNull(openedPackage); + Util.checkFlags(opensFlagsMask); opensTo = List.copyOf(opensTo); } } @@ -975,6 +991,7 @@ public abstract sealed class UnboundAttribute> implements ModuleRequireInfo { public UnboundModuleRequiresInfo { requireNonNull(requires); + Util.checkFlags(requiresFlagsMask); requireNonNull(requiresVersion); } } @@ -1028,7 +1045,7 @@ public abstract sealed class UnboundAttribute> { super(Attributes.module()); this.moduleName = requireNonNull(moduleName); - this.moduleFlags = moduleFlags; + this.moduleFlags = Util.checkFlags(moduleFlags); this.moduleVersion = moduleVersion; this.requires = List.copyOf(requires); this.exports = List.copyOf(exports); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index b0234fb88cc..0eea2bffd22 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -56,7 +56,7 @@ import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void; * represented as JVM type descriptor strings and symbols are represented as * name strings */ -public class Util { +public final class Util { private Util() { } @@ -186,6 +186,31 @@ public class Util { String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); } + /// Ensures the given value won't be truncated when written as a u1 + public static int checkU1(int incoming, String valueName) { + if ((incoming & ~0xFF) != 0) { + throw outOfRangeException(incoming, valueName, "u1"); + } + return incoming; + } + + /// Ensures the given value won't be truncated when written as a u2 + public static char checkU2(int incoming, String valueName) { + if ((incoming & ~0xFFFF) != 0) + throw outOfRangeException(incoming, valueName, "u2"); + return (char) incoming; + } + + public static IllegalArgumentException outOfRangeException(int value, String fieldName, String typeName) { + return new IllegalArgumentException( + String.format("%s out of range of %d: %d", fieldName, typeName, value)); + } + + /// Ensures the given mask won't be truncated when written as an access flag + public static char checkFlags(int mask) { + return checkU2(mask, "access flags"); + } + public static int flagsToBits(AccessFlag.Location location, Collection flags) { int i = 0; for (AccessFlag f : flags) { diff --git a/test/jdk/jdk/classfile/InstructionValidationTest.java b/test/jdk/jdk/classfile/InstructionValidationTest.java index 9d5b4198adf..f02c7a9c78c 100644 --- a/test/jdk/jdk/classfile/InstructionValidationTest.java +++ b/test/jdk/jdk/classfile/InstructionValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -23,12 +23,14 @@ /* * @test - * @bug 8341277 8361102 - * @summary Testing ClassFile instruction argument validation. + * @bug 8341277 8361102 8361182 8361614 + * @summary Testing ClassFile (pseudo-)instruction argument validation. * @run junit InstructionValidationTest */ import java.lang.classfile.*; +import java.lang.classfile.attribute.CharacterRangeInfo; +import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.instruction.*; @@ -278,4 +280,62 @@ class InstructionValidationTest { cob.return_(); }); } + + @Test + void testCharacterRange() { + assertDoesNotThrow(() -> CharacterRangeInfo.of(0, 0, -234, 59494648, 0)); + assertDoesNotThrow(() -> CharacterRangeInfo.of(0, 0, -234, 59494648, 65535)); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeInfo.of(0, 0, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeInfo.of(0, 0, -234, 59494648, 65536)); + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var dummyLabel = cob.startLabel(); + assertDoesNotThrow(() -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 0)); + assertDoesNotThrow(() -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 65535)); + assertThrows(IllegalArgumentException.class, () -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> CharacterRange.of(dummyLabel, dummyLabel, -234, 59494648, 65536)); + assertThrows(IllegalArgumentException.class, () -> cob.characterRange(dummyLabel, dummyLabel, -234, 59494648, -1)); + assertThrows(IllegalArgumentException.class, () -> cob.characterRange(dummyLabel, dummyLabel, -234, 59494648, 65536)); + cob.return_(); + })); + } + + @Test + void testLineNumber() { + assertDoesNotThrow(() -> LineNumberInfo.of(0, 25)); + assertThrows(IllegalArgumentException.class, () -> LineNumberInfo.of(0, -1)); + assertThrows(IllegalArgumentException.class, () -> LineNumberInfo.of(0, 65536)); + assertDoesNotThrow(() -> LineNumber.of(25)); + assertThrows(IllegalArgumentException.class, () -> LineNumber.of(-1)); + assertThrows(IllegalArgumentException.class, () -> LineNumber.of(65536)); + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + assertThrows(IllegalArgumentException.class, () -> cob.lineNumber(-1)); + assertThrows(IllegalArgumentException.class, () -> cob.lineNumber(65536)); + cob.return_(); + })); + } + + @Test + void testTypeAnnotationLocalVarTargetInfo() { + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var label = cob.startLabel(); + assertDoesNotThrow(() -> TypeAnnotation.LocalVarTargetInfo.of(label, label, 256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.LocalVarTargetInfo.of(label, label, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.LocalVarTargetInfo.of(label, label, 65536)); + cob.return_(); + })); + } + + @Test + void testTypeAnnotationTypeArgumentTarget() { + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + var label = cob.startLabel(); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofTypeArgument(TypeAnnotation.TargetType.CAST, label, 0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofCastExpr(label, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodInvocationTypeArgument(label, Integer.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodReferenceTypeArgument(label, 256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofConstructorInvocationTypeArgument(label, 300)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofConstructorReferenceTypeArgument(label, -2)); + cob.return_(); + })); + } } diff --git a/test/jdk/jdk/classfile/PreviewMinorVersionTest.java b/test/jdk/jdk/classfile/PreviewMinorVersionTest.java deleted file mode 100644 index 6cbff76f6d9..00000000000 --- a/test/jdk/jdk/classfile/PreviewMinorVersionTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.lang.classfile.ClassFile; -import org.junit.jupiter.api.Test; - -import java.lang.constant.ClassDesc; - -import static java.lang.constant.ConstantDescs.*; -import static java.lang.classfile.ClassFile.*; -import static org.junit.jupiter.api.Assertions.*; - -/* - * @test - * @bug 8311172 - * @run junit PreviewMinorVersionTest - * @summary Ensures ClassFile.PREVIEW_MINOR_VERSION equals that of classes with - * preview minor version from ClassModel::minorVersion - */ -public class PreviewMinorVersionTest { - - @Test - public void testMinorVersionMatches() { - // compile a class with --enable-preview - // uses Record feature to trigger forcePreview - var cf = ClassFile.of(); - var cd = ClassDesc.of("Test"); - var bytes = cf.build(cd, cb -> cb - .withSuperclass(CD_Object) - // old preview minor version, - // with all bits set to 1 - .withVersion(JAVA_17_VERSION, -1) - ); - - var cm = ClassFile.of().parse(bytes); - assertEquals(ClassFile.PREVIEW_MINOR_VERSION, cm.minorVersion()); - } -} diff --git a/test/jdk/jdk/classfile/SubIntValidationTest.java b/test/jdk/jdk/classfile/SubIntValidationTest.java new file mode 100644 index 00000000000..b455948c4c8 --- /dev/null +++ b/test/jdk/jdk/classfile/SubIntValidationTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassFileVersion; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.MethodParameterInfo; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleExportInfo; +import java.lang.classfile.attribute.ModuleOpenInfo; +import java.lang.classfile.attribute.ModuleRequireInfo; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.ClassDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.JAVA_17_VERSION; +import static java.lang.constant.ConstantDescs.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* + * @test + * @bug 8311172 8361614 + * @summary Testing ClassFile validation of non-instruction subint (u1, u2) arguments. + * @run junit SubIntValidationTest + */ +class SubIntValidationTest { + + @Test + public void testBuilderFlags() { + ClassFile.of().build(CD_Void, clb -> { + assertThrows(IllegalArgumentException.class, () -> clb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> clb.withFlags(70000)); + assertThrows(IllegalArgumentException.class, () -> clb.withField("test", CD_String, -1)); + assertThrows(IllegalArgumentException.class, () -> clb.withField("test", CD_String, 70000)); + assertThrows(IllegalArgumentException.class, () -> clb.withMethod("test", MTD_void, -1, _ -> {})); + assertThrows(IllegalArgumentException.class, () -> clb.withMethod("test", MTD_void, 70000, _ -> {})); + clb.withField("test", CD_String, fb -> { + assertThrows(IllegalArgumentException.class, () -> fb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> fb.withFlags(70000 | ACC_STATIC)); + }); + clb.withMethod("test", MTD_void, ACC_STATIC, mb -> { + assertThrows(IllegalArgumentException.class, () -> mb.withFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> mb.withFlags(70000 | ACC_STATIC)); + }); + }); + } + + @Test + public void testClassFileVersion() { + // Prohibited but representable major/minor + assertDoesNotThrow(() -> ClassFileVersion.of(0, 0)); + // Non-representable major/minor + assertDoesNotThrow(() -> ClassFileVersion.of(JAVA_17_VERSION, 42)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(-1, 0)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(65536, 0)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(0, -2)); + assertThrows(IllegalArgumentException.class, () -> ClassFileVersion.of(0, 65536)); + ClassFile.of().build(CD_Void, clb -> assertThrows(IllegalArgumentException.class, () -> clb.withVersion(-1, 0))); + // Special rule without serializing to class file format + assertEquals(ClassFile.PREVIEW_MINOR_VERSION, ClassFileVersion.of(0, -1).minorVersion()); + } + + @Test + public void testReadMinorVersion() { + var cf = ClassFile.of(); + var cd = ClassDesc.of("Test"); + var bytes = cf.build(cd, cb -> cb + .withSuperclass(CD_Object) + // old preview minor version, + // with all bits set to 1 + .withVersion(JAVA_17_VERSION, -1) + ); + + var cm = ClassFile.of().parse(bytes); + assertEquals(ClassFile.PREVIEW_MINOR_VERSION, cm.minorVersion()); + } + + // LocalVarTargetInfo/TypeArgumentTarget in InstructionValidationTest for Label + @Test + public void testTypeAnnotations() { + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofTypeParameter(TypeAnnotation.TargetType.CLASS_TYPE_PARAMETER, 0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassTypeParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodTypeParameter(300)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofClassExtends(65535)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassExtends(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassExtends(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofClassTypeParameterBound(255, 255)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofClassTypeParameterBound(-1, 255)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodTypeParameterBound(0, 256)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(0)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofMethodFormalParameter(256)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofThrows(256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofThrows(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofThrows(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofExceptionParameter(256)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofExceptionParameter(-1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofExceptionParameter(65536)); + assertDoesNotThrow(() -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.ARRAY, 2)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.INNER_TYPE, -1)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TypePathComponent.of(TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT, 256)); + } + + @Test + public void testInnerClasses() { + assertDoesNotThrow(() -> InnerClassInfo.of(CD_Object, Optional.empty(), Optional.empty(), 65535)); + assertThrows(IllegalArgumentException.class, () -> InnerClassInfo.of(CD_Object, Optional.empty(), Optional.empty(), -1)); + assertThrows(IllegalArgumentException.class, () -> InnerClassInfo.of(ConstantPoolBuilder.of().classEntry(CD_String), + Optional.empty(), Optional.empty(), 65536)); + } + + @Test + public void testMethodParameter() { + assertDoesNotThrow(() -> MethodParameterInfo.of(Optional.empty(), 65535)); + assertThrows(IllegalArgumentException.class, () -> MethodParameterInfo.of(Optional.empty(), -1)); + assertThrows(IllegalArgumentException.class, () -> MethodParameterInfo.ofParameter(Optional.empty(), 65536)); + } + + @Test + public void testModule() { + assertDoesNotThrow(() -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + 65535, null, List.of(), List.of(), List.of(), List.of(), List.of())); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + -1, null, List.of(), List.of(), List.of(), List.of(), List.of())); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(ConstantPoolBuilder.of().moduleEntry(ModuleDesc.of("java.base")), + 65536, null, List.of(), List.of(), List.of(), List.of(), List.of())); + ModuleAttribute.of(ModuleDesc.of("java.base"), b -> { + assertThrows(IllegalArgumentException.class, () -> b.moduleFlags(-1)); + assertThrows(IllegalArgumentException.class, () -> b.moduleFlags(65536)); + b.moduleFlags(0); + }); + } + + @Test + public void testModuleExport() { + assertDoesNotThrow(() -> ModuleExportInfo.of(PackageDesc.of("java.lang"), 0)); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(PackageDesc.of("java.lang"), -1)); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(PackageDesc.of("java.lang"), 65536)); + } + + @Test + public void testModuleOpen() { + assertDoesNotThrow(() -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), 0)); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), -1)); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(PackageDesc.of("java.lang"), 65536)); + } + + @Test + public void testModuleRequire() { + assertDoesNotThrow(() -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), 0, null)); + assertThrows(IllegalArgumentException.class, () -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), -1, null)); + assertThrows(IllegalArgumentException.class, () -> ModuleRequireInfo.of(ModuleDesc.of("java.base"), 65536, null)); + } + + @Test + public void testModuleResolution() { + assertDoesNotThrow(() -> ModuleResolutionAttribute.of(256)); + assertThrows(IllegalArgumentException.class, () -> ModuleResolutionAttribute.of(-1)); + assertThrows(IllegalArgumentException.class, () -> ModuleResolutionAttribute.of(65536)); + } + + @Test + public void testMethodHandleEntry() { + ConstantPoolBuilder cp = ConstantPoolBuilder.of(); + var ref = cp.fieldRefEntry(CD_String, "a", CD_int); + // Intentionally choose an invalid but representable refKind + assertDoesNotThrow(() -> cp.methodHandleEntry(25, ref)); + assertThrows(IllegalArgumentException.class, () -> cp.methodHandleEntry(256, ref)); + assertThrows(IllegalArgumentException.class, () -> cp.methodHandleEntry(-1, ref)); + } +} From d594ef3a3e013b84a392b6d64a54015adc8173cd Mon Sep 17 00:00:00 2001 From: David Holmes Date: Fri, 29 Aug 2025 16:31:13 +0000 Subject: [PATCH 280/471] 8366121: Hotspot Style Guide should document conventions for lock-free code Reviewed-by: stefank, ayang, jsjolen, jwaters, kvn, kbarrett --- doc/hotspot-style.html | 10 ++++++++++ doc/hotspot-style.md | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index dafd29d6f54..88ec07475fd 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -209,6 +209,16 @@ lines of code. Name what you must repeat.

        attribute, the change should be done with a "setter" accessor matched to the simple "getter".

        +

        Conventions for Lock-free +Code

        +

        Sometimes variables are accessed concurrently without appropriate +synchronization context, such as a held mutex or at a safepoint. In such +cases the variable should be declared volatile and it +should NOT be accessed as a normal C++ lvalue. Rather, access should be +performed via functions from Atomic, such as +Atomic::load, Atomic::store, etc.

        +

        This special formulation makes it more clear to maintainers that the +variable is accessed concurrently in a lock-free manner.

        Source Files

        • All source files must have a globally unique basename. The build diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 0a0089ee454..322bdc8458e 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -135,6 +135,17 @@ lines of code. Name what you must repeat. change should be done with a "setter" accessor matched to the simple "getter". +#### Conventions for Lock-free Code + +Sometimes variables are accessed concurrently without appropriate synchronization +context, such as a held mutex or at a safepoint. In such cases the variable should +be declared `volatile` and it should NOT be accessed as a normal C++ lvalue. Rather, +access should be performed via functions from `Atomic`, such as `Atomic::load`, +`Atomic::store`, etc. + +This special formulation makes it more clear to maintainers that the variable is +accessed concurrently in a lock-free manner. + ### Source Files * All source files must have a globally unique basename. The build From 849570a94a3178da7899e5cd36400ef03ad9ae29 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Fri, 29 Aug 2025 17:04:37 +0000 Subject: [PATCH 281/471] 8365288: PEMDecoder should throw ClassCastException Reviewed-by: weijun --- .../classes/java/security/PEMDecoder.java | 8 ++--- .../jdk/java/security/PEM/PEMDecoderTest.java | 30 +++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/security/PEMDecoder.java b/src/java.base/share/classes/java/security/PEMDecoder.java index 7279e75cc98..0b959bf2440 100644 --- a/src/java.base/share/classes/java/security/PEMDecoder.java +++ b/src/java.base/share/classes/java/security/PEMDecoder.java @@ -437,12 +437,12 @@ public final class PEMDecoder { so = getKeyFactory(key.getAlgorithm()) .getKeySpec(key, X509EncodedKeySpec.class); } else { - throw new IllegalArgumentException("Invalid KeySpec."); + throw new ClassCastException("Invalid KeySpec"); } } catch (InvalidKeySpecException e) { - throw new IllegalArgumentException("Invalid KeySpec " + - "specified (" + tClass.getName() +") for key (" + - key.getClass().getName() +")", e); + throw new ClassCastException("Invalid KeySpec " + + "specified: " + tClass.getName() + " for key " + + key.getClass().getName()); } } diff --git a/test/jdk/java/security/PEM/PEMDecoderTest.java b/test/jdk/java/security/PEM/PEMDecoderTest.java index 90d67af2f8d..8e3ae76994d 100644 --- a/test/jdk/java/security/PEM/PEMDecoderTest.java +++ b/test/jdk/java/security/PEM/PEMDecoderTest.java @@ -25,7 +25,7 @@ /* * @test - * @bug 8298420 + * @bug 8298420 8365288 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -78,7 +78,9 @@ public class PEMDecoderTest { System.out.println("Decoder test rsapub PEM asking X509EKS.class returned:"); testClass(PEMData.rsapub, X509EncodedKeySpec.class, true); System.out.println("Decoder test rsapriv PEM asking X509EKS.class returned:"); - testClass(PEMData.rsapriv, X509EncodedKeySpec.class, false); + testClass(PEMData.rsapriv, X509EncodedKeySpec.class, false, ClassCastException.class); + System.out.println("Decoder test rsapriv PEM asking other EKS returned:"); + testClass(PEMData.rsapriv, XEKS.class, false, ClassCastException.class); System.out.println("Decoder test RSAcert PEM asking X509EKS.class returned:"); testClass(PEMData.rsaCert, X509EncodedKeySpec.class, false); System.out.println("Decoder test OAS RFC PEM asking PrivateKey.class returned:"); @@ -484,6 +486,19 @@ public class PEMDecoderTest { } } + static void testClass(PEMData.Entry entry, Class clazz, boolean pass, + Class ec) throws RuntimeException { + try { + testClass(entry, clazz); + } catch (Exception e) { + if (ec.isInstance(e)) { + System.out.println("PASS"); + return; + } + throw new RuntimeException(e); + } + } + // Run test with a given Entry static void testDERCheck(PEMData.Entry entry) { if (entry.name().equals("rsaOpenSSL") || // PKCS1 data @@ -573,4 +588,15 @@ public class PEMDecoderTest { throw new AssertionError(e); } } + + class XEKS extends EncodedKeySpec { + public XEKS(byte[] encodedKey) { + super(encodedKey); + } + + @Override + public String getFormat() { + return ""; + } + } } \ No newline at end of file From d4ce630cea267e746f7feb5124fe2ecd39d7e13a Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 29 Aug 2025 20:44:09 +0000 Subject: [PATCH 282/471] 8366399: Allow custom base reference for update_copyright_year.sh Reviewed-by: erikj --- make/scripts/update_copyright_year.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh index 578ab4cbc99..fa7989d234b 100644 --- a/make/scripts/update_copyright_year.sh +++ b/make/scripts/update_copyright_year.sh @@ -62,17 +62,22 @@ Help() echo "options:" echo "-c Specifies the company. Set to Oracle by default." echo "-y Specifies the copyright year. Set to current year by default." + echo "-b Specifies the base reference for change set lookup." echo "-f Updates the copyright for all change sets in a given year," - echo " as specified by -y." + echo " as specified by -y. Overrides -b flag." echo "-h Print this help." echo } full_year=false +base_reference=master # Process options -while getopts "c:fhy:" option; do +while getopts "b:c:fhy:" option; do case $option in + b) # supplied base reference + base_reference=${OPTARG} + ;; c) # supplied company year company=${OPTARG} ;; @@ -111,7 +116,7 @@ else if [ "$full_year" = "true" ]; then vcs_list_changesets=(git log --no-merges --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") else - vcs_list_changesets=(git log --no-merges 'master..HEAD' --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") + vcs_list_changesets=(git log --no-merges "${base_reference}..HEAD" --since="${year}-01-01T00:00:00Z" --until="${year}-12-31T23:59:59Z" --pretty=tformat:"%H") fi vcs_changeset_message=(git log -1 --pretty=tformat:"%B") # followed by ${changeset} vcs_changeset_files=(git diff-tree --no-commit-id --name-only -r) # followed by ${changeset} From f23c150709fbd6d9b84261a7c99b67d7d08334b9 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 30 Aug 2025 02:20:44 +0000 Subject: [PATCH 283/471] 8366359: Test should throw SkippedException when there is no lpstat Reviewed-by: aivanov, prr --- .../CountPrintServices.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java b/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java index 5be9f0297d2..4da1ed59a27 100644 --- a/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java +++ b/test/jdk/javax/print/PrintServiceLookup/CountPrintServices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -25,25 +25,21 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import javax.print.PrintService; import javax.print.PrintServiceLookup; -import javax.print.attribute.AttributeSet; -import javax.print.attribute.HashAttributeSet; -import javax.print.attribute.standard.PrinterName; +import java.io.IOException; + +import jtreg.SkippedException; /* * @test * @bug 8032693 * @key printer + * @library /test/lib/ + * @requires (os.family == "linux") * @summary Test that lpstat and JDK agree whether there are printers. */ public class CountPrintServices { public static void main(String[] args) throws Exception { - String os = System.getProperty("os.name").toLowerCase(); - System.out.println("OS is " + os); - if (!os.equals("linux")) { - System.out.println("Linux specific test. No need to continue"); - return; - } PrintService services[] = PrintServiceLookup.lookupPrintServices(null, null); if (services.length > 0) { @@ -51,7 +47,16 @@ public class CountPrintServices { return; } String[] lpcmd = { "lpstat", "-a" }; - Process proc = Runtime.getRuntime().exec(lpcmd); + Process proc; + try { + proc = Runtime.getRuntime().exec(lpcmd); + } catch (IOException e) { + if (e.getMessage().contains("No such file or directory")) { + throw new SkippedException("Cannot find lpstat"); + } else { + throw e; + } + } proc.waitFor(); InputStreamReader ir = new InputStreamReader(proc.getInputStream()); BufferedReader br = new BufferedReader(ir); @@ -66,4 +71,3 @@ public class CountPrintServices { } } } - From 0e7399318b6c33c03a72ed1fdfb671f8cd9342a3 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Sat, 30 Aug 2025 14:03:56 +0000 Subject: [PATCH 284/471] 8366264: tools/javac/launcher/SourceLauncherStackTraceTest.java does not cover the scenario for 8362237 Reviewed-by: cstein, jlahoda --- .../SourceLauncherStackTraceTest.java | 84 ------------------- .../javac/launcher/SourceLauncherTest.java | 24 ++++++ 2 files changed, 24 insertions(+), 84 deletions(-) delete mode 100644 test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java diff --git a/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java b/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java deleted file mode 100644 index 7bcb86bde46..00000000000 --- a/test/langtools/tools/javac/launcher/SourceLauncherStackTraceTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8362237 - * @summary Test source launcher with specific VM behaviors - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.launcher - * jdk.compiler/com.sun.tools.javac.main - * java.base/jdk.internal.module - * @build toolbox.JavaTask toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox - * @run main/othervm -XX:-StackTraceInThrowable SourceLauncherStackTraceTest - */ - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -import toolbox.TestRunner; - -/// SourceLauncherTest runs the source launcher in the same VM, so we must -/// use another test to run specific tests with specific VM flags -public class SourceLauncherStackTraceTest extends TestRunner { - - // Inheritance will shadow all parent tests - SourceLauncherTest parent = new SourceLauncherTest(); - - SourceLauncherStackTraceTest() { - super(System.err); - } - - public static void main(String... args) throws Exception { - SourceLauncherStackTraceTest t = new SourceLauncherStackTraceTest(); - t.runTests(m -> new Object[] { Paths.get(m.getName()) }); - } - - /* - * Tests in which main throws an exception without a stacktrace. - */ - @Test - public void testTargetException2(Path base) throws IOException { - parent.tb.writeJavaFiles(base, """ - public class TestLauncher { - public static TestLauncher test() { - throw new RuntimeException("No trace"); - } - - public static void main(String[] args) { - // This will throw a RuntimeException without - // a stack trace due to VM options - test(); - } - } - """); - Path file = base.resolve("TestLauncher.java"); - SourceLauncherTest.Result r = parent.run(file, List.of(), List.of("3")); - parent.checkEmpty("stdout", r.stdOut()); - parent.checkEmpty("stderr", r.stdErr()); - parent.checkTrace("exception", r.exception(), "java.lang.RuntimeException: No trace"); - } -} diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index bb5ba7e133f..6b147d32d00 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8192920 8204588 8246774 8248843 8268869 8235876 8328339 8335896 8344706 + * 8362237 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -714,6 +715,29 @@ public class SourceLauncherTest extends TestRunner { "at Thrower.main(Thrower.java:4)"); } + /* + * Tests in which main throws a traceless exception. + */ + @Test + public void testTracelessTargetException(Path base) throws IOException { + tb.writeJavaFiles(base, """ + class TestLauncherException extends RuntimeException { + TestLauncherException() { + super("No trace", null, true, false); // No writable trace + } + + public static void main(String... args) { + throw new TestLauncherException(); + } + } + """); + Path file = base.resolve("TestLauncherException.java"); + SourceLauncherTest.Result r = run(file, List.of(), List.of("3")); + checkEmpty("stdout", r.stdOut()); + checkEmpty("stderr", r.stdErr()); + checkTrace("exception", r.exception(), "TestLauncherException: No trace"); + } + @Test public void testNoDuplicateIncubatorWarning(Path base) throws Exception { Path module = base.resolve("lib"); From 12e6a0b6d0086caf156cf5513a604320c619b856 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 30 Aug 2025 19:26:45 +0000 Subject: [PATCH 285/471] 8366208: Unexpected exception in sun.java2d.cmm.lcms.LCMSImageLayout Reviewed-by: aivanov, prr --- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 22 ++- .../FilterSemiCustomImages.java | 162 ++++++++++++++++++ 2 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index cfe488fee72..663e11ff172 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -125,7 +125,9 @@ final class LCMSImageLayout { static LCMSImageLayout createImageLayout(BufferedImage image) { LCMSImageLayout l = new LCMSImageLayout(); - switch (image.getType()) { + Raster raster = image.getRaster(); + int type = image.getType(); + switch (type) { case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB: l.pixelType = PT_ARGB_8 ^ SWAP_ENDIAN; break; @@ -164,7 +166,7 @@ final class LCMSImageLayout { return null; } } - return createImageLayout(image.getRaster(), cm); + return createImageLayout(raster, cm); } return null; } @@ -172,11 +174,13 @@ final class LCMSImageLayout { l.width = image.getWidth(); l.height = image.getHeight(); - switch (image.getType()) { + switch (type) { case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR -> { - var intRaster = (IntegerComponentRaster) image.getRaster(); + if (!(raster instanceof IntegerComponentRaster intRaster)) { + return null; + } l.nextRowOffset = safeMult(4, intRaster.getScanlineStride()); l.nextPixelOffset = safeMult(4, intRaster.getPixelStride()); l.offset = safeMult(4, intRaster.getDataOffset(0)); @@ -188,7 +192,9 @@ final class LCMSImageLayout { BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE -> { - var byteRaster = (ByteComponentRaster) image.getRaster(); + if (!(raster instanceof ByteComponentRaster byteRaster)) { + return null; + } l.nextRowOffset = byteRaster.getScanlineStride(); l.nextPixelOffset = byteRaster.getPixelStride(); int firstBand = byteRaster.getSampleModel().getNumBands() - 1; @@ -198,7 +204,9 @@ final class LCMSImageLayout { l.dataType = DT_BYTE; } case BufferedImage.TYPE_USHORT_GRAY -> { - var shortRaster = (ShortComponentRaster) image.getRaster(); + if (!(raster instanceof ShortComponentRaster shortRaster)) { + return null; + } l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride()); l.nextPixelOffset = safeMult(2, shortRaster.getPixelStride()); l.offset = safeMult(2, shortRaster.getDataOffset(0)); diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java new file mode 100644 index 00000000000..ff3fcde7482 --- /dev/null +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/FilterSemiCustomImages.java @@ -0,0 +1,162 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Point; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.io.File; + +import javax.imageio.ImageIO; + +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR; +import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static java.awt.image.BufferedImage.TYPE_INT_BGR; +import static java.awt.image.BufferedImage.TYPE_INT_RGB; +import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY; + +/** + * @test + * @bug 8366208 + * @summary Verifies ColorConvertOp works correctly with BufferedImage and + * semi-custom raster + */ +public final class FilterSemiCustomImages { + + private static final int W = 144; + private static final int H = 123; + + private static final int[] TYPES = { + TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR, + TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE, + TYPE_USHORT_GRAY + }; + + private static final int[] CSS = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + private static final class CustomRaster extends WritableRaster { + CustomRaster(SampleModel sampleModel, Point origin) { + super(sampleModel, origin); + } + } + + public static void main(String[] args) throws Exception { + for (int fromIndex : CSS) { + for (int toIndex : CSS) { + if (fromIndex != toIndex) { + for (int type : TYPES) { + test(fromIndex, toIndex, type); + } + } + } + } + } + + private static void test(int fromIndex, int toIndex, int type) + throws Exception + { + ColorSpace fromCS = ColorSpace.getInstance(fromIndex); + ColorSpace toCS = ColorSpace.getInstance(toIndex); + ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null); + + // standard source -> standard dst + BufferedImage srcGold = new BufferedImage(W, H, type); + fill(srcGold); + BufferedImage dstGold = new BufferedImage(W, H, type); + op.filter(srcGold, dstGold); + + // custom source -> standard dst + BufferedImage srcCustom = makeCustomBI(srcGold); + fill(srcCustom); + BufferedImage dst = new BufferedImage(W, H, type); + op.filter(srcCustom, dst); + verify(dstGold, dst); + + // standard source -> custom dst + BufferedImage src = new BufferedImage(W, H, type); + fill(src); + BufferedImage dstCustom = makeCustomBI(dstGold); + op.filter(src, dstCustom); + verify(dstGold, dstCustom); + + // custom source -> custom dst + srcCustom = makeCustomBI(srcGold); + fill(srcCustom); + dstCustom = makeCustomBI(dstGold); + op.filter(srcCustom, dstCustom); + verify(dstGold, dstCustom); + } + + private static BufferedImage makeCustomBI(BufferedImage bi) { + ColorModel cm = bi.getColorModel(); + SampleModel sm = bi.getSampleModel(); + CustomRaster cr = new CustomRaster(sm, new Point()); + return new BufferedImage(cm, cr, bi.isAlphaPremultiplied(), null) { + @Override + public int getType() { + return bi.getType(); + } + }; + } + + private static void fill(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + // alpha channel may be calculated slightly differently on + // different code paths, so only check fully transparent and + // fully opaque pixels + Color c = new Color(y * 255 / (height - 1), + x * 255 / (width - 1), + x % 255, + (x % 2 == 0) ? 0 : 255); + image.setRGB(x, y, c.getRGB()); + } + } + } + + private static void verify(BufferedImage dstGold, BufferedImage dst) + throws Exception + { + for (int x = 0; x < W; ++x) { + for (int y = 0; y < H; ++y) { + if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) { + ImageIO.write(dst, "png", new File("custom.png")); + ImageIO.write(dstGold, "png", new File("gold.png")); + throw new RuntimeException("Test failed."); + } + } + } + } +} From 9339a6a23236e783e93f967cf6aba16c2f749fdd Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 31 Aug 2025 00:35:09 +0000 Subject: [PATCH 286/471] 8361593: Commented dead code in JDK-8342868 can be removed Reviewed-by: jlu, naoto, jwaters, jpai --- .../libjava/HostLocaleProviderAdapter_md.c | 16 +++++----------- .../windows/native/libjava/TimeZone_md.c | 3 --- .../windows/native/libnet/NTLMAuthSequence.c | 2 -- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c index 10513b28cb6..bf399a68894 100644 --- a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c @@ -965,34 +965,28 @@ void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) { DWORD pattern = 0; int style = numberStyle; - // int got = 0; if (positive) { if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } } else { if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGCURR | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } else { - // got = - getLocaleInfoWrapper(langtag, + getLocaleInfoWrapper(langtag, LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER, (LPWSTR)&pattern, sizeof(pattern)); } diff --git a/src/java.base/windows/native/libjava/TimeZone_md.c b/src/java.base/windows/native/libjava/TimeZone_md.c index 0a73bc26028..5adecff50e7 100644 --- a/src/java.base/windows/native/libjava/TimeZone_md.c +++ b/src/java.base/windows/native/libjava/TimeZone_md.c @@ -232,7 +232,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) WCHAR stdNameInReg[MAX_ZONE_CHAR]; TziValue tempTzi; WCHAR *stdNamePtr = tzi.StandardName; - // int onlyMapID; timeType = GetTimeZoneInformation(&tzi); if (timeType == TIME_ZONE_ID_INVALID) { @@ -304,7 +303,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) * Compare to the "Std" value of each subkey and find the entry that * matches the current control panel setting. */ - // onlyMapID = 0; for (i = 0; i < nSubKeys; ++i) { DWORD size = sizeof(subKeyName); ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL); @@ -325,7 +323,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) * entry in the Time Zones registry. */ RegCloseKey(hSubKey); - // onlyMapID = 1; ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey); if (ret != ERROR_SUCCESS) { goto err; diff --git a/src/java.base/windows/native/libnet/NTLMAuthSequence.c b/src/java.base/windows/native/libnet/NTLMAuthSequence.c index 62627504ecd..507409e0ae6 100644 --- a/src/java.base/windows/native/libnet/NTLMAuthSequence.c +++ b/src/java.base/windows/native/libnet/NTLMAuthSequence.c @@ -47,8 +47,6 @@ static jfieldID ntlm_ctxHandleID; static jfieldID ntlm_crdHandleID; static jfieldID status_seqCompleteID; -// static HINSTANCE lib = NULL; - JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_initFirst (JNIEnv *env, jclass authseq_clazz, jclass status_clazz) { From bdc39818ce7b3c3bad10f4682a2a52fbb696f247 Mon Sep 17 00:00:00 2001 From: Anass Baya Date: Sun, 31 Aug 2025 04:34:04 +0000 Subject: [PATCH 287/471] 8361521: BogusFocusableWindowState.java fails with StackOverflowError on Linux Reviewed-by: aivanov, serb --- src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java | 6 ++++-- test/jdk/ProblemList.txt | 1 - .../BogusFocusableWindowState.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index f2b7efc978f..4911dea5d97 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -1098,9 +1098,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, suppressWmTakeFocus(true); } } - updateFocusability(); - promoteDefaultPosition(); boolean refreshChildsTransientFor = isVisible() != vis; + if (refreshChildsTransientFor) { + updateFocusability(); + } + promoteDefaultPosition(); super.setVisible(vis); if (refreshChildsTransientFor) { for (Window child : ((Window) target).getOwnedWindows()) { diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1193ea45ba7..58fb2c51397 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -119,7 +119,6 @@ java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java 8081489 generi java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java 6849364 generic-all java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 generic-all java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all -java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java 8361521 linux-all java/awt/Frame/MaximizedToMaximized/MaximizedToMaximized.java 8340374 macosx-all java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all diff --git a/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java b/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java index 64621796b4f..efcb9c098f0 100644 --- a/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java +++ b/test/jdk/java/awt/Frame/BogusFocusableWindowState/BogusFocusableWindowState.java @@ -25,7 +25,7 @@ import java.awt.Window; /** * @test - * @bug 8346952 + * @bug 8346952 8361521 * @summary Verifies no exception occurs when triggering updateCG() * for an ownerless window. * @key headful From 80ab094a75a6474c33214e3347e08ea7b9177ec8 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 31 Aug 2025 21:34:16 +0000 Subject: [PATCH 288/471] 8347707: Standardise the use of os::snprintf and os::snprintf_checked Reviewed-by: kbarrett, fbredberg --- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 4 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 24 ++++++------ .../cpu/aarch64/vm_version_aarch64.cpp | 6 +-- src/hotspot/cpu/arm/macroAssembler_arm.cpp | 2 +- src/hotspot/cpu/arm/vm_version_arm_32.cpp | 4 +- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 4 +- src/hotspot/cpu/s390/vm_version_s390.cpp | 4 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 4 +- src/hotspot/cpu/zero/frame_zero.cpp | 30 +++++++-------- src/hotspot/cpu/zero/vm_version_zero.cpp | 4 +- src/hotspot/os/aix/attachListener_aix.cpp | 15 ++++---- src/hotspot/os/aix/os_aix.cpp | 8 ++-- src/hotspot/os/aix/porting_aix.cpp | 5 +-- src/hotspot/os/bsd/memMapPrinter_macosx.cpp | 2 +- src/hotspot/os/bsd/os_bsd.cpp | 38 +++++++++---------- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 4 +- src/hotspot/os/linux/os_linux.cpp | 38 +++++++++---------- src/hotspot/os/linux/os_perf_linux.cpp | 2 +- src/hotspot/os/posix/attachListener_posix.cpp | 15 ++++---- src/hotspot/os/posix/os_posix.cpp | 2 +- src/hotspot/os/posix/perfMemory_posix.cpp | 4 +- src/hotspot/os/windows/os_windows.cpp | 18 ++++----- src/hotspot/os/windows/perfMemory_windows.cpp | 6 +-- .../linux_riscv/vm_version_linux_riscv.cpp | 2 +- src/hotspot/share/ci/ciEnv.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 19 ++++++---- src/hotspot/share/code/codeHeapState.cpp | 2 +- .../compiler/compilationMemoryStatistic.cpp | 4 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 24 ++++++------ src/hotspot/share/gc/shared/oopStorage.cpp | 2 +- src/hotspot/share/gc/shared/satbMarkQueue.cpp | 4 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 2 +- src/hotspot/share/oops/compressedKlass.cpp | 8 ++-- src/hotspot/share/oops/generateOopMap.cpp | 4 +- src/hotspot/share/opto/idealGraphPrinter.cpp | 8 ++-- src/hotspot/share/runtime/os.cpp | 11 +++--- src/hotspot/share/runtime/os.hpp | 18 ++++++--- src/hotspot/share/services/heapDumper.cpp | 2 +- .../share/utilities/forbiddenFunctions.hpp | 1 + .../share/utilities/virtualizationSupport.cpp | 4 +- .../gtest/classfile/test_symbolTable.cpp | 6 +-- test/hotspot/gtest/gtestMain.cpp | 2 +- test/hotspot/gtest/logging/test_asynclog.cpp | 2 +- .../hotspot/gtest/runtime/test_os_windows.cpp | 2 +- 46 files changed, 195 insertions(+), 183 deletions(-) diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index db72218d6d7..aff50b9cf2f 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -702,10 +702,10 @@ static void printbc(Method *m, intptr_t bcx) { if (m->validate_bci_from_bcp((address)bcx) < 0 || !m->contains((address)bcx)) { name = "???"; - snprintf(buf, sizeof buf, "(bad)"); + os::snprintf_checked(buf, sizeof buf, "(bad)"); } else { int bci = m->bci_from((address)bcx); - snprintf(buf, sizeof buf, "%d", bci); + os::snprintf_checked(buf, sizeof buf, "%d", bci); name = Bytecodes::name(m->code_at(bci)); } ResourceMark rm; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index fb307c8831a..3999beeec2b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2259,7 +2259,7 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) { #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64); block_comment(buffer); } #endif @@ -2317,7 +2317,7 @@ void MacroAssembler::mov_immediate64(Register dst, uint64_t imm64) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX64, imm64); block_comment(buffer); } #endif @@ -2430,7 +2430,7 @@ void MacroAssembler::mov_immediate32(Register dst, uint32_t imm32) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIX32, imm32); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIX32, imm32); block_comment(buffer); } #endif @@ -2902,11 +2902,11 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack, FpPushPopMode m { char buffer[48]; if (mode == PushPopSVE) { - snprintf(buffer, sizeof(buffer), "push_fp: %d SVE registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d SVE registers", count); } else if (mode == PushPopNeon) { - snprintf(buffer, sizeof(buffer), "push_fp: %d Neon registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d Neon registers", count); } else { - snprintf(buffer, sizeof(buffer), "push_fp: %d fp registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "push_fp: %d fp registers", count); } block_comment(buffer); } @@ -3014,11 +3014,11 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack, FpPushPopMode mo { char buffer[48]; if (mode == PushPopSVE) { - snprintf(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d SVE registers", count); } else if (mode == PushPopNeon) { - snprintf(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d Neon registers", count); } else { - snprintf(buffer, sizeof(buffer), "pop_fp: %d fp registers", count); + os::snprintf_checked(buffer, sizeof(buffer), "pop_fp: %d fp registers", count); } block_comment(buffer); } @@ -5920,7 +5920,7 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, { const char kind = (elem_size == 2) ? 'U' : 'L'; char comment[64]; - snprintf(comment, sizeof comment, "array_equals%c{", kind); + os::snprintf_checked(comment, sizeof comment, "array_equals%c{", kind); BLOCK_COMMENT(comment); } #endif @@ -6118,7 +6118,7 @@ void MacroAssembler::string_equals(Register a1, Register a2, #ifndef PRODUCT { char comment[64]; - snprintf(comment, sizeof comment, "{string_equalsL"); + os::snprintf_checked(comment, sizeof comment, "{string_equalsL"); BLOCK_COMMENT(comment); } #endif @@ -6266,7 +6266,7 @@ address MacroAssembler::zero_words(Register base, uint64_t cnt) #ifndef PRODUCT { char buf[64]; - snprintf(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt); + os::snprintf_checked(buf, sizeof buf, "zero_words (count = %" PRIu64 ") {", cnt); BLOCK_COMMENT(buf); } #endif diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 24c77174711..308deeaf5e2 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -721,12 +721,12 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64"); - int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); + int desc_len = os::snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); desc_len = (int)strlen(_cpu_desc); - snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); + os::snprintf_checked(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index e101e5631d9..12462e1843c 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -839,7 +839,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, char buffer[64]; #ifdef COMPILER1 if (CommentedAssembly) { - snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset()); + os::snprintf_checked(buffer, sizeof(buffer), "verify_oop at %d", offset()); block_comment(buffer); } #endif diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index d0941936035..209dc41035c 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -362,7 +362,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index ec2766ac75b..1d2b8d3ca04 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -625,7 +625,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b4d286cabbf..1436bc02113 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2679,7 +2679,7 @@ void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset, Register #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIx64, uimm64); + os::snprintf_checked(buffer, sizeof(buffer), "0x%" PRIx64, uimm64); block_comment(buffer); } #endif diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 46324815001..4b437896dcd 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -493,8 +493,8 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index ed925aa23b4..7f5b4870aab 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -1549,7 +1549,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 058ea06ab4e..6eb641daaf9 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4331,10 +4331,10 @@ void StubGenerator::generate_compiler_stubs() { if (libsimdsort != nullptr) { log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "simdsort" JNI_LIB_SUFFIX, p2i(libsimdsort)); - snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_sort" : "avx2_sort"); + os::snprintf_checked(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_sort" : "avx2_sort"); StubRoutines::_array_sort = (address)os::dll_lookup(libsimdsort, ebuf_); - snprintf(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_partition" : "avx2_partition"); + os::snprintf_checked(ebuf_, sizeof(ebuf_), VM_Version::supports_avx512_simd_sort() ? "avx512_partition" : "avx2_partition"); StubRoutines::_array_partition = (address)os::dll_lookup(libsimdsort, ebuf_); } } diff --git a/src/hotspot/cpu/zero/frame_zero.cpp b/src/hotspot/cpu/zero/frame_zero.cpp index 4b4bd1e2b87..52ccad2fa68 100644 --- a/src/hotspot/cpu/zero/frame_zero.cpp +++ b/src/hotspot/cpu/zero/frame_zero.cpp @@ -242,8 +242,8 @@ void frame::zero_print_on_error(int frame_index, int offset = fp() - addr; // Fill in default values, then try and improve them - snprintf(fieldbuf, buflen, "word[%d]", offset); - snprintf(valuebuf, buflen, PTR_FORMAT, *addr); + os::snprintf_checked(fieldbuf, buflen, "word[%d]", offset); + os::snprintf_checked(valuebuf, buflen, PTR_FORMAT, *addr); zeroframe()->identify_word(frame_index, offset, fieldbuf, valuebuf, buflen); fieldbuf[buflen - 1] = '\0'; valuebuf[buflen - 1] = '\0'; @@ -300,7 +300,7 @@ void EntryFrame::identify_word(int frame_index, break; default: - snprintf(fieldbuf, buflen, "local[%d]", offset - 3); + os::snprintf_checked(fieldbuf, buflen, "local[%d]", offset - 3); } } @@ -321,12 +321,12 @@ void InterpreterFrame::identify_word(int frame_index, istate->method()->name_and_sig_as_C_string(valuebuf, buflen); } else if (is_valid && !strcmp(field, "_bcp") && istate->bcp()) { - snprintf(valuebuf, buflen, PTR_FORMAT " (bci %d)", - (intptr_t) istate->bcp(), - istate->method()->bci_from(istate->bcp())); + os::snprintf_checked(valuebuf, buflen, PTR_FORMAT " (bci %d)", + (intptr_t) istate->bcp(), + istate->method()->bci_from(istate->bcp())); } - snprintf(fieldbuf, buflen, "%sistate->%s", - field[strlen(field) - 1] == ')' ? "(": "", field); + os::snprintf_checked(fieldbuf, buflen, "%sistate->%s", + field[strlen(field) - 1] == ')' ? "(": "", field); } else if (addr == (intptr_t *) istate) { strncpy(fieldbuf, "(vtable for istate)", buflen); @@ -358,13 +358,13 @@ void InterpreterFrame::identify_word(int frame_index, else desc = " (this)"; } - snprintf(fieldbuf, buflen, "parameter[%d]%s", param, desc); + os::snprintf_checked(fieldbuf, buflen, "parameter[%d]%s", param, desc); return; } for (int i = 0; i < handler->argument_count(); i++) { if (params[i] == (intptr_t) addr) { - snprintf(fieldbuf, buflen, "unboxed parameter[%d]", i); + os::snprintf_checked(fieldbuf, buflen, "unboxed parameter[%d]", i); return; } } @@ -396,18 +396,18 @@ void ZeroFrame::identify_vp_word(int frame_index, intptr_t offset = (intptr_t) addr - monitor; if (offset == in_bytes(BasicObjectLock::obj_offset())) - snprintf(fieldbuf, buflen, "monitor[%d]->_obj", index); + os::snprintf_checked(fieldbuf, buflen, "monitor[%d]->_obj", index); else if (offset == in_bytes(BasicObjectLock::lock_offset())) - snprintf(fieldbuf, buflen, "monitor[%d]->_lock", index); + os::snprintf_checked(fieldbuf, buflen, "monitor[%d]->_lock", index); return; } // Expression stack if (addr < stack_base) { - snprintf(fieldbuf, buflen, "%s[%d]", - frame_index == 0 ? "stack_word" : "local", - (int) (stack_base - addr - 1)); + os::snprintf_checked(fieldbuf, buflen, "%s[%d]", + frame_index == 0 ? "stack_word" : "local", + (int) (stack_base - addr - 1)); return; } } diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 3ce9227c193..35cbd296a26 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -150,7 +150,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_cores = os::processor_count(); _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; - snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); + os::snprintf_checked(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); + os::snprintf_checked(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/os/aix/attachListener_aix.cpp b/src/hotspot/os/aix/attachListener_aix.cpp index e5101814f97..58de062a2fd 100644 --- a/src/hotspot/os/aix/attachListener_aix.cpp +++ b/src/hotspot/os/aix/attachListener_aix.cpp @@ -209,10 +209,10 @@ int AixAttachListener::init() { ::atexit(listener_cleanup); } - int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); + int n = os::snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); if (n < (int)UNIX_PATH_MAX) { - n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); + n = os::snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); } if (n >= (int)UNIX_PATH_MAX) { return -1; @@ -349,9 +349,8 @@ void AttachListener::vm_start() { struct stat st; int ret; - int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); + os::snprintf_checked(fn, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { @@ -419,8 +418,8 @@ bool AttachListener::is_init_trigger() { RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); - snprintf(fn, sizeof(fn), "%s/.attach_pid%d", - os::get_temp_directory(), os::current_process_id()); + os::snprintf_checked(fn, sizeof(fn), "%s/.attach_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 25a930dc1d9..c58e240719b 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1051,8 +1051,8 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s", - filename, ::getenv("LIBPATH"), ::getenv("LD_LIBRARY_PATH"), error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s, LIBPATH=%s, LD_LIBRARY_PATH=%s : %s", + filename, ::getenv("LIBPATH"), ::getenv("LD_LIBRARY_PATH"), error_report); } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); @@ -1077,7 +1077,7 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { STATIC_ASSERT(sizeof(old_extension) >= sizeof(new_extension)); char* tmp_path = os::strdup(filename); size_t prefix_size = pointer_delta(pointer_to_dot, filename, 1); - os::snprintf(tmp_path + prefix_size, sizeof(old_extension), "%s", new_extension); + os::snprintf_checked(tmp_path + prefix_size, sizeof(old_extension), "%s", new_extension); result = dll_load_library(tmp_path, &eno, ebuf, ebuflen); os::free(tmp_path); } @@ -1094,7 +1094,7 @@ void os::get_summary_os_info(char* buf, size_t buflen) { // There might be something more readable than uname results for AIX. struct utsname name; uname(&name); - snprintf(buf, buflen, "%s %s", name.release, name.version); + os::snprintf_checked(buf, buflen, "%s %s", name.release, name.version); } int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index 2235d3da686..402abd7d579 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -936,7 +936,7 @@ static const char* rtv_linkedin_libpath() { // retrieve the path to the currently running executable binary // to open it - snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); + os::snprintf_checked(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); FILE* f = nullptr; struct xcoffhdr the_xcoff; struct scnhdr the_scn; @@ -1154,7 +1154,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } assert(false, "os::pd_dll_unload() ::dlclose() failed"); } @@ -1189,4 +1189,3 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { return res; } // end: os::pd_dll_unload() - diff --git a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp index ee76214ddfa..a7ddab04d85 100644 --- a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp +++ b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp @@ -177,7 +177,7 @@ public: X1(GENEALOGY, genealogy); default: static char buffer[30]; - snprintf(buffer, sizeof(buffer), "user_tag=0x%x(%d)", user_tag, user_tag); + os::snprintf_checked(buffer, sizeof(buffer), "user_tag=0x%x(%d)", user_tag, user_tag); return buffer; } } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b7b88e8e606..6ef43ba991e 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -522,7 +522,7 @@ void os::init_system_properties_values() { // by the nulls included by the sizeof operator (so actually one byte more // than necessary is allocated). os::snprintf_checked(buf, bufsize, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, - user_home_dir, Arguments::get_java_home()); + user_home_dir, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); FREE_C_HEAP_ARRAY(char, buf); @@ -1242,27 +1242,27 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } if (lib_arch.endianess != arch_array[running_arch_index].endianess) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); return nullptr; } #ifndef S390 if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)"); return nullptr; } #endif // !S390 if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { if (lib_arch.name!=nullptr) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load %s-bit .so on a %s-bit platform)", - lib_arch.name, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load %s-bit .so on a %s-bit platform)", + lib_arch.name, arch_array[running_arch_index].name); } else { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)", - lib_arch.code, - arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)", + lib_arch.code, + arch_array[running_arch_index].name); } } @@ -1364,13 +1364,13 @@ void os::get_summary_os_info(char* buf, size_t buflen) { size = sizeof(build); int mib_build[] = { CTL_KERN, KERN_OSVERSION }; if (sysctl(mib_build, 2, build, &size, nullptr, 0) < 0) { - snprintf(buf, buflen, "%s %s, macOS %s", os, release, osproductversion); + os::snprintf_checked(buf, buflen, "%s %s, macOS %s", os, release, osproductversion); } else { - snprintf(buf, buflen, "%s %s, macOS %s (%s)", os, release, osproductversion, build); + os::snprintf_checked(buf, buflen, "%s %s, macOS %s (%s)", os, release, osproductversion, build); } } else #endif - snprintf(buf, buflen, "%s %s", os, release); + os::snprintf_checked(buf, buflen, "%s %s", os, release); } void os::print_os_info_brief(outputStream* st) { @@ -1447,14 +1447,14 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { #if defined(__APPLE__) && !defined(ZERO) if (VM_Version::is_cpu_emulated()) { - snprintf(buf, buflen, "\"%s\" %s (EMULATED) %d MHz", model, machine, mhz); + os::snprintf_checked(buf, buflen, "\"%s\" %s (EMULATED) %d MHz", model, machine, mhz); } else { - NOT_AARCH64(snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz)); + NOT_AARCH64(os::snprintf_checked(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz)); // aarch64 CPU doesn't report its speed - AARCH64_ONLY(snprintf(buf, buflen, "\"%s\" %s", model, machine)); + AARCH64_ONLY(os::snprintf_checked(buf, buflen, "\"%s\" %s", model, machine)); } #else - snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz); + os::snprintf_checked(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz); #endif } @@ -2156,7 +2156,7 @@ void os::set_native_thread_name(const char *name) { if (name != nullptr) { // Add a "Java: " prefix to the name char buf[MAXTHREADNAMESIZE]; - snprintf(buf, sizeof(buf), "Java: %s", name); + (void) os::snprintf(buf, sizeof(buf), "Java: %s", name); pthread_setname_np(buf); } #endif @@ -2490,7 +2490,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } } diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index c33e49b57f9..84dfcbd6614 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -204,7 +204,7 @@ int ZPhysicalMemoryBacking::create_mem_fd(const char* name) const { // Create file name char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s%s", name, ZLargePages::is_explicit() ? ".hugetlb" : ""); + os::snprintf_checked(filename, sizeof(filename), "%s%s", name, ZLargePages::is_explicit() ? ".hugetlb" : ""); // Create file const int extra_flags = ZLargePages::is_explicit() ? (MFD_HUGETLB | MFD_HUGE_2MB) : 0; @@ -262,7 +262,7 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const { // Create file name char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id()); + os::snprintf_checked(filename, sizeof(filename), "%s/%s.%d", mountpoint.get(), name, os::current_process_id()); // Create file const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 4d6225cf21e..cee8a11b1d2 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1848,32 +1848,32 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { if (lib_arch.name != nullptr) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load %s .so on a %s platform)", - lib_arch.name, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load %s .so on a %s platform)", + lib_arch.name, arch_array[running_arch_index].name); } else { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", - lib_arch.code, arch_array[running_arch_index].name); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", + lib_arch.code, arch_array[running_arch_index].name); } return nullptr; } if (lib_arch.endianness != arch_array[running_arch_index].endianness) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: endianness mismatch)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: endianness mismatch)"); return nullptr; } // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); return nullptr; } if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", - (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); + os::snprintf_checked(diag_msg_buf, diag_msg_max_length-1, + " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", + (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); return nullptr; } @@ -2613,10 +2613,10 @@ static void print_sys_devices_cpu_info(outputStream* st) { char hbuf_type[60]; char hbuf_size[60]; char hbuf_coherency_line_size[80]; - snprintf(hbuf_level, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/level", i); - snprintf(hbuf_type, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/type", i); - snprintf(hbuf_size, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/size", i); - snprintf(hbuf_coherency_line_size, 80, "/sys/devices/system/cpu/cpu0/cache/index%u/coherency_line_size", i); + os::snprintf_checked(hbuf_level, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/level", i); + os::snprintf_checked(hbuf_type, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/type", i); + os::snprintf_checked(hbuf_size, 60, "/sys/devices/system/cpu/cpu0/cache/index%u/size", i); + os::snprintf_checked(hbuf_coherency_line_size, 80, "/sys/devices/system/cpu/cpu0/cache/index%u/coherency_line_size", i); if (os::file_exists(hbuf_level)) { _print_ascii_file_h("cache level", hbuf_level, st); _print_ascii_file_h("cache type", hbuf_type, st); @@ -4217,7 +4217,7 @@ int os::Linux::get_namespace_pid(int vmid) { char fname[24]; int retpid = -1; - snprintf(fname, sizeof(fname), "/proc/%d/status", vmid); + os::snprintf_checked(fname, sizeof(fname), "/proc/%d/status", vmid); FILE *fp = os::fopen(fname, "r"); if (fp) { @@ -4797,7 +4797,7 @@ uint os::processor_id() { void os::set_native_thread_name(const char *name) { if (Linux::_pthread_setname_np) { char buf [16]; // according to glibc manpage, 16 chars incl. '/0' - snprintf(buf, sizeof(buf), "%s", name); + (void) os::snprintf(buf, sizeof(buf), "%s", name); buf[sizeof(buf) - 1] = '\0'; const int rc = Linux::_pthread_setname_np(pthread_self(), buf); // ERANGE should not happen; all other errors should just be ignored. @@ -5008,7 +5008,7 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { long ldummy; FILE *fp; - snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid); + os::snprintf_checked(proc_name, 64, "/proc/self/task/%d/stat", tid); fp = os::fopen(proc_name, "r"); if (fp == nullptr) return -1; statlen = fread(stat, 1, 2047, fp); @@ -5394,7 +5394,7 @@ bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { error_report = "dlerror returned no error description"; } if (ebuf != nullptr && ebuflen > 0) { - snprintf(ebuf, ebuflen - 1, "%s", error_report); + os::snprintf_checked(ebuf, ebuflen - 1, "%s", error_report); } } diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index ea7535edb87..9151049dd1c 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -988,7 +988,7 @@ NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const { char buf[128]; - snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter); + os::snprintf_checked(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter); int fd = os::open(buf, O_RDONLY, 0); if (fd == -1) { diff --git a/src/hotspot/os/posix/attachListener_posix.cpp b/src/hotspot/os/posix/attachListener_posix.cpp index a4bc49c6bf3..d3e24807124 100644 --- a/src/hotspot/os/posix/attachListener_posix.cpp +++ b/src/hotspot/os/posix/attachListener_posix.cpp @@ -195,10 +195,10 @@ int PosixAttachListener::init() { ::atexit(listener_cleanup); } - int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); + int n = os::snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); if (n < (int)UNIX_PATH_MAX) { - n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); + n = os::snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); } if (n >= (int)UNIX_PATH_MAX) { return -1; @@ -346,9 +346,8 @@ void AttachListener::vm_start() { struct stat st; int ret; - int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); + os::snprintf_checked(fn, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { @@ -418,8 +417,8 @@ bool AttachListener::is_init_trigger() { RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); - snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), - os::current_process_id()); + os::snprintf_checked(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), + os::current_process_id()); RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1ece8260948..6a39c95db52 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -323,7 +323,7 @@ int os::create_file_for_heap(const char* dir) { vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno))); return -1; } - int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); + int n = os::snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); assert((size_t)n == fullname_len, "Unexpected number of characters in string"); os::native_path(fullname); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index cbbecea3a6a..c58f216b2c3 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -150,7 +150,7 @@ static char* get_user_tmp_dir(const char* user, int vmid, int nspid) { char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); // construct the path name to user specific tmp directory - snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); + os::snprintf_checked(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); return dirname; } @@ -661,7 +661,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid, int nspid) { size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - snprintf(name, nbytes, "%s/%d", dirname, pid); + os::snprintf_checked(name, nbytes, "%s/%d", dirname, pid); return name; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index ffa22bd0365..27bf196075a 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1411,7 +1411,7 @@ void os::die() { void os::dll_unload(void *lib) { char name[MAX_PATH]; if (::GetModuleFileName((HMODULE)lib, name, sizeof(name)) == 0) { - snprintf(name, MAX_PATH, ""); + os::snprintf_checked(name, MAX_PATH, ""); } JFR_ONLY(NativeLibraryUnloadEvent unload_event(name);) @@ -1427,7 +1427,7 @@ void os::dll_unload(void *lib) { Events::log_dll_message(nullptr, "Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); log_info(os)("Attempt to unload dll \"%s\" [" INTPTR_FORMAT "] failed (error code %d)", name, p2i(lib), errcode); if (tl == 0) { - os::snprintf(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode); + os::snprintf_checked(buf, sizeof(buf), "Attempt to unload dll failed (error code %d)", (int) errcode); } JFR_ONLY(unload_event.set_error_msg(buf);) } @@ -1824,14 +1824,14 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { } if (lib_arch_str != nullptr) { - os::snprintf(ebuf, ebuflen - 1, - "Can't load %s-bit .dll on a %s-bit platform", - lib_arch_str, running_arch_str); + os::snprintf_checked(ebuf, ebuflen - 1, + "Can't load %s-bit .dll on a %s-bit platform", + lib_arch_str, running_arch_str); } else { // don't know what architecture this dll was build for - os::snprintf(ebuf, ebuflen - 1, - "Can't load this .dll (machine code=0x%x) on a %s-bit platform", - lib_arch, running_arch_str); + os::snprintf_checked(ebuf, ebuflen - 1, + "Can't load this .dll (machine code=0x%x) on a %s-bit platform", + lib_arch, running_arch_str); } JFR_ONLY(load_event.set_error_msg(ebuf);) return nullptr; @@ -3198,7 +3198,7 @@ int os::create_file_for_heap(const char* dir) { vm_exit_during_initialization(err_msg("Malloc failed during creation of backing file for heap (%s)", os::strerror(errno))); return -1; } - int n = snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); + int n = os::snprintf(fullname, fullname_len + 1, "%s%s", dir, name_template); assert((size_t)n == fullname_len, "Unexpected number of characters in string"); os::native_path(fullname); diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index 273814f6572..a9b2eebb7be 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -164,7 +164,7 @@ static char* get_user_tmp_dir(const char* user) { char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); // construct the path name to user specific tmp directory - os::snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); + os::snprintf_checked(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); return dirname; } @@ -454,7 +454,7 @@ static char *get_sharedmem_objectname(const char* user, int vmid) { // nbytes += UINT_CHARS; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - os::snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); + os::snprintf_checked(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); return name; } @@ -470,7 +470,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid) { size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - os::snprintf(name, nbytes, "%s\\%d", dirname, vmid); + os::snprintf_checked(name, nbytes, "%s\\%d", dirname, vmid); return name; } diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 506c78cacca..cf9429b6bea 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -126,7 +126,7 @@ void VM_Version::setup_cpu_available_features() { char buf[1024] = {}; if (uarch != nullptr && strcmp(uarch, "") != 0) { // Use at max half the buffer. - snprintf(buf, sizeof(buf)/2, "%s ", uarch); + os::snprintf_checked(buf, sizeof(buf)/2, "%s ", uarch); } os::free((void*) uarch); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 2de77f2828d..79ab881e7f6 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -217,7 +217,7 @@ public: void push_va(ciEnv* ci, const char* fmt, va_list args) { char *e = ci->_dyno_name + strlen(ci->_dyno_name); char *m = ci->_dyno_name + ARRAY_SIZE(ci->_dyno_name) - 1; - os::vsnprintf(e, m - e, fmt, args); + (void) os::vsnprintf(e, m - e, fmt, args); assert(strlen(ci->_dyno_name) < (ARRAY_SIZE(ci->_dyno_name) - 1), "overflow"); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 20534b93290..bf678f94e0e 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2619,14 +2619,16 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m char* buf = NEW_RESOURCE_ARRAY(char, buf_size); // Print stack trace line in buffer - size_t buf_off = os::snprintf_checked(buf, buf_size, "\tat %s.%s(", klass_name, method_name); - + int buf_off = os::snprintf(buf, buf_size, "\tat %s.%s(", klass_name, method_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); // Print module information if (module_name != nullptr) { if (module_version != nullptr) { - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else { - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s/", module_name); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s/", module_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } } @@ -2641,13 +2643,16 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m } else { if (source_file_name != nullptr && (line_number != -1)) { // Sourcename and linenumber - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else if (source_file_name != nullptr) { // Just sourcename - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } else { // Neither sourcename nor linenumber - buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "Unknown Source)"); + buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "Unknown Source)"); + assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); } nmethod* nm = method->code(); if (WizardMode && nm != nullptr) { diff --git a/src/hotspot/share/code/codeHeapState.cpp b/src/hotspot/share/code/codeHeapState.cpp index 065aab5c250..ea4a1519f79 100644 --- a/src/hotspot/share/code/codeHeapState.cpp +++ b/src/hotspot/share/code/codeHeapState.cpp @@ -739,7 +739,7 @@ void CodeHeapState::aggregate(outputStream* out, CodeHeap* heap, size_t granular if (jvmci_name != nullptr) { size_t size = ::strlen(blob_name) + ::strlen(" jvmci_name=") + ::strlen(jvmci_name) + 1; char* new_blob_name = (char*)os::malloc(size, mtInternal); - os::snprintf(new_blob_name, size, "%s jvmci_name=%s", blob_name, jvmci_name); + os::snprintf_checked(new_blob_name, size, "%s jvmci_name=%s", blob_name, jvmci_name); os::free((void*)blob_name); blob_name = new_blob_name; } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index d842bcb2b6f..d22eab8ac55 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -158,10 +158,10 @@ void FootprintTimeline::print_on(outputStream* st) const { st->print("%24s", e.info.text); col += 25; st->fill_to(col); char tmp[64]; - os::snprintf(tmp, sizeof(tmp), "%9zu (%+zd)", e._bytes.cur, e._bytes.end_delta()); + os::snprintf_checked(tmp, sizeof(tmp), "%9zu (%+zd)", e._bytes.cur, e._bytes.end_delta()); st->print("%s ", tmp); // end col += 21; st->fill_to(col); - os::snprintf(tmp, sizeof(tmp), "%6u (%+d)", e._live_nodes.cur, e._live_nodes.end_delta()); + os::snprintf_checked(tmp, sizeof(tmp), "%6u (%+d)", e._live_nodes.cur, e._live_nodes.end_delta()); st->print("%s ", tmp); // end if (e._bytes.temporary_peak_size() > significant_peak_threshold) { col += 20; st->fill_to(col); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 04197495033..f73c4099ce6 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -81,19 +81,19 @@ class G1YoungGCTraceTime { evacuation_failed_string[0] = '\0'; if (_collector->evacuation_failed()) { - snprintf(evacuation_failed_string, - ARRAY_SIZE(evacuation_failed_string), - " (Evacuation Failure: %s%s%s)", - _collector->evacuation_alloc_failed() ? "Allocation" : "", - _collector->evacuation_alloc_failed() && _collector->evacuation_pinned() ? " / " : "", - _collector->evacuation_pinned() ? "Pinned" : ""); + os::snprintf_checked(evacuation_failed_string, + ARRAY_SIZE(evacuation_failed_string), + " (Evacuation Failure: %s%s%s)", + _collector->evacuation_alloc_failed() ? "Allocation" : "", + _collector->evacuation_alloc_failed() && _collector->evacuation_pinned() ? " / " : "", + _collector->evacuation_pinned() ? "Pinned" : ""); } - snprintf(_young_gc_name_data, - MaxYoungGCNameLength, - "Pause Young (%s) (%s)%s", - G1GCPauseTypeHelper::to_string(_pause_type), - GCCause::to_string(_pause_cause), - evacuation_failed_string); + os::snprintf_checked(_young_gc_name_data, + MaxYoungGCNameLength, + "Pause Young (%s) (%s)%s", + G1GCPauseTypeHelper::to_string(_pause_type), + GCCause::to_string(_pause_cause), + evacuation_failed_string); return _young_gc_name_data; } diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index ae3e9c46197..d36e9850bda 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -820,7 +820,7 @@ static Mutex* make_oopstorage_mutex(const char* storage_name, const char* kind, Mutex::Rank rank) { char name[256]; - os::snprintf(name, sizeof(name), "%s %s lock", storage_name, kind); + os::snprintf_checked(name, sizeof(name), "%s %s lock", storage_name, kind); return new PaddedMutex(rank, name); } diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp index 915eaa116fb..3cba3baf5f1 100644 --- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp +++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp @@ -306,7 +306,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { int i = 0; while (nd != nullptr) { void** buf = BufferNode::make_buffer_from_node(nd); - os::snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); + os::snprintf_checked(buffer, SATB_PRINTER_BUFFER_SIZE, "Enqueued: %d", i); print_satb_buffer(buffer, buf, nd->index(), nd->capacity()); nd = nd->next(); i += 1; @@ -321,7 +321,7 @@ void SATBMarkQueueSet::print_all(const char* msg) { _qset(qset), _buffer(buffer) {} virtual void do_thread(Thread* t) { - os::snprintf(_buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name()); + (void) os::snprintf(_buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name()); _qset->satb_queue_for_thread(t).print(_buffer); } } closure(this, buffer); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 23473940178..d8287dad198 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -934,7 +934,7 @@ void JVMCIEnv::fthrow_error(const char* file, int line, const char* format, ...) va_list ap; va_start(ap, format); char msg[max_msg_size]; - os::vsnprintf(msg, max_msg_size, format, ap); + (void) os::vsnprintf(msg, max_msg_size, format, ap); va_end(ap); JavaThread* THREAD = JavaThread::current(); if (is_hotspot()) { diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index 25e80b0a975..d7c97d3c8d5 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -78,10 +78,10 @@ void CompressedKlassPointers::pre_initialize() { void CompressedKlassPointers::sanity_check_after_initialization() { // In expectation of an assert, prepare condensed info to be printed with the assert. char tmp[256]; - os::snprintf(tmp, sizeof(tmp), "klass range: " RANGE2FMT "," - " base " PTR_FORMAT ", shift %d, lowest/highest valid narrowKlass %u/%u", - RANGE2FMTARGS(_klass_range_start, _klass_range_end), - p2i(_base), _shift, _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id); + os::snprintf_checked(tmp, sizeof(tmp), "klass range: " RANGE2FMT "," + " base " PTR_FORMAT ", shift %d, lowest/highest valid narrowKlass %u/%u", + RANGE2FMTARGS(_klass_range_start, _klass_range_end), + p2i(_base), _shift, _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id); #define ASSERT_HERE(cond) assert(cond, " (%s)", tmp); #define ASSERT_HERE_2(cond, msg) assert(cond, msg " (%s)", tmp); diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index a17d1ca4e37..97d8bf3d526 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -2150,10 +2150,10 @@ bool GenerateOopMap::compute_map(Thread* current) { void GenerateOopMap::error_work(const char *format, va_list ap) { _got_error = true; char msg_buffer[512]; - os::vsnprintf(msg_buffer, sizeof(msg_buffer), format, ap); + (void) os::vsnprintf(msg_buffer, sizeof(msg_buffer), format, ap); // Append method name char msg_buffer2[512]; - os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg_buffer, method()->name()->as_C_string()); + (void) os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg_buffer, method()->name()->as_C_string()); Thread* current = Thread::current(); if (current->can_call_java()) { _exception = Exceptions::new_exception(JavaThread::cast(current), diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 1ecb46eaf5a..cbf972166c2 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -640,8 +640,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { jint value = typeInt->get_con(); // Only use up to 4 chars and fall back to a generic "I" to keep it short. - int written_chars = os::snprintf_checked(buffer, sizeof(buffer), "%d", value); - if (written_chars <= 4) { + int written_chars = os::snprintf(buffer, sizeof(buffer), "%d", value); + if (written_chars > 0 && written_chars <= 4) { print_prop(short_name, buffer); } else { print_prop(short_name, "I"); @@ -654,8 +654,8 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { jlong value = typeLong->get_con(); // Only use up to 4 chars and fall back to a generic "L" to keep it short. - int written_chars = os::snprintf_checked(buffer, sizeof(buffer), JLONG_FORMAT, value); - if (written_chars <= 4) { + int written_chars = os::snprintf(buffer, sizeof(buffer), JLONG_FORMAT, value); + if (written_chars > 0 && written_chars <= 4) { print_prop(short_name, buffer); } else { print_prop(short_name, "L"); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 04a363a7aab..e02d13edb8e 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -108,23 +108,24 @@ int os::snprintf(char* buf, size_t len, const char* fmt, ...) { return result; } -int os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { +void os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { va_list args; va_start(args, fmt); int result = os::vsnprintf(buf, len, fmt, args); va_end(args); - assert(result >= 0, "os::snprintf error"); assert(static_cast(result) < len, "os::snprintf truncated"); - return result; } int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { + assert(buf != nullptr || len == 0, "Valid buffer and length must be given"); + assert(fmt != nullptr, "Missing format string"); int result = permit_forbidden_function::vsnprintf(buf, len, fmt, args); - // If an encoding error occurred (result < 0) then it's not clear + // If an error occurred (result < 0) then it's not clear // whether the buffer is NUL terminated, so ensure it is. - if ((result < 0) && (len > 0)) { + if ((result < 0) && (len > 0) && (buf != nullptr)) { buf[len - 1] = '\0'; } + assert(result >= 0, "os::vsnprintf error: %s", strerror(errno)); return result; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index c34bf77e3d6..6d40a646358 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -804,12 +804,20 @@ class os: AllStatic { // Provide wrapper versions of these functions to guarantee NUL-termination // in all cases. - static int vsnprintf(char* buf, size_t len, const char* fmt, va_list args) ATTRIBUTE_PRINTF(3, 0); - static int snprintf(char* buf, size_t len, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4); - // Performs snprintf and asserts the result is non-negative (so there was not - // an encoding error) and that the output was not truncated. - static int snprintf_checked(char* buf, size_t len, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4); + // Performs vsnprintf and asserts the result is non-negative (so there was not + // an encoding error or any other kind of usage error). + [[nodiscard]] + ATTRIBUTE_PRINTF(3, 0) + static int vsnprintf(char* buf, size_t len, const char* fmt, va_list args); + // Delegates to vsnprintf. + [[nodiscard]] + ATTRIBUTE_PRINTF(3, 4) + static int snprintf(char* buf, size_t len, const char* fmt, ...); + + // Delegates to snprintf and asserts that the output was not truncated. + ATTRIBUTE_PRINTF(3, 4) + static void snprintf_checked(char* buf, size_t len, const char* fmt, ...); // Get host name in buffer provided static bool get_host_name(char* buf, size_t buflen); diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 051096ae24a..cd679986a6c 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2113,7 +2113,7 @@ char* DumpMerger::get_writer_path(const char* base_path, int seq) { char* path = NEW_RESOURCE_ARRAY(char, buf_size); memset(path, 0, buf_size); - os::snprintf(path, buf_size, "%s.p%d", base_path, seq); + os::snprintf_checked(path, buf_size, "%s.p%d", base_path, seq); return path; } diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp index 0bc34adf213..a8dcba95a6d 100644 --- a/src/hotspot/share/utilities/forbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -59,6 +59,7 @@ FORBID_IMPORTED_C_FUNCTION(char* strerror(int), "use os::strerror"); FORBID_IMPORTED_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); +FORBID_C_FUNCTION(int snprintf(char*, size_t, const char*, ...), "use os::snprintf"); PRAGMA_DIAG_PUSH FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING diff --git a/src/hotspot/share/utilities/virtualizationSupport.cpp b/src/hotspot/share/utilities/virtualizationSupport.cpp index 5feff1039ef..c2e8a61012e 100644 --- a/src/hotspot/share/utilities/virtualizationSupport.cpp +++ b/src/hotspot/share/utilities/virtualizationSupport.cpp @@ -67,13 +67,13 @@ void VirtualizationSupport::initialize() { VMGuestLibError sg_error = GuestLib_StatGet("text", "resources", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_resource_information = true; - os::snprintf(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); + os::snprintf_checked(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); GuestLib_StatFree(result_info, result_size); } sg_error = GuestLib_StatGet("text", "host", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_host_information = true; - os::snprintf(host_information, sizeof(host_information), "%s", result_info); + os::snprintf_checked(host_information, sizeof(host_information), "%s", result_info); GuestLib_StatFree(result_info, result_size); } } diff --git a/test/hotspot/gtest/classfile/test_symbolTable.cpp b/test/hotspot/gtest/classfile/test_symbolTable.cpp index 57c6b85c949..02d97ca2155 100644 --- a/test/hotspot/gtest/classfile/test_symbolTable.cpp +++ b/test/hotspot/gtest/classfile/test_symbolTable.cpp @@ -105,7 +105,7 @@ TEST_VM(SymbolTable, test_symbol_refcount_parallel) { char symbol_name[symbol_name_length]; // Find a symbol where there will probably be only one instance. for (int i = 0; i < 100; i++) { - os::snprintf(symbol_name, symbol_name_length, "some_symbol%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "some_symbol%d", i); TempNewSymbol ts = SymbolTable::new_symbol(symbol_name); if (ts->refcount() == 1) { EXPECT_TRUE(ts->refcount() == 1) << "Symbol is just created"; @@ -158,7 +158,7 @@ TEST_VM(SymbolTable, test_cleanup_delay) { constexpr int symbol_name_length = 30; char symbol_name[symbol_name_length]; for (uint i = 1; i < TempSymbolCleanupDelayer::QueueSize; i++) { - os::snprintf(symbol_name, symbol_name_length, "temp-filler-%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "temp-filler-%d", i); TempNewSymbol s = SymbolTable::new_symbol(symbol_name); ASSERT_EQ(s->refcount(), 2) << "TempNewSymbol refcount just created is 2"; } @@ -177,7 +177,7 @@ TEST_VM(SymbolTable, test_cleanup_delay_drain) { char symbol_name[symbol_name_length]; TempNewSymbol symbols[TempSymbolCleanupDelayer::QueueSize] = {}; for (uint i = 0; i < TempSymbolCleanupDelayer::QueueSize; i++) { - os::snprintf(symbol_name, symbol_name_length, "temp-%d", i); + os::snprintf_checked(symbol_name, symbol_name_length, "temp-%d", i); TempNewSymbol s = SymbolTable::new_symbol(symbol_name); symbols[i] = s; } diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index c593f8dbb19..842b6547b48 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -256,7 +256,7 @@ static void runUnitTestsInner(int argc, char** argv) { #ifdef __APPLE__ size_t len = strlen(java_home) + strlen("/lib/jli/libjli.dylib") + 1; char* path = new char[len]; - snprintf(path, len, "%s/lib/jli/libjli.dylib", java_home); + os::snprintf_checked(path, len, "%s/lib/jli/libjli.dylib", java_home); dlopen(path, RTLD_NOW | RTLD_GLOBAL); #endif // __APPLE__ diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index efd4027fa3f..fdc3795e9db 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -163,7 +163,7 @@ TEST_VM_F(AsyncLogTest, logBuffer) { LogDecorators()); size_t len = strlen(TestLogFileName) + strlen(LogFileOutput::Prefix) + 1; char* name = NEW_C_HEAP_ARRAY(char, len, mtLogging); - snprintf(name, len, "%s%s", LogFileOutput::Prefix, TestLogFileName); + os::snprintf_checked(name, len, "%s%s", LogFileOutput::Prefix, TestLogFileName); LogFileStreamOutput* output = new LogFileOutput(name); output->initialize(nullptr, nullptr); diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index 83771368b57..9fe0de55515 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -376,7 +376,7 @@ static void record_path(char const* name, char const* len_name, wchar_t* path) { if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { ::testing::Test::RecordProperty(name, buf); - os::snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); + os::snprintf_checked(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); ::testing::Test::RecordProperty(len_name, buf); } } From 2427c901b31dbdccc6f8f39404875a0140460479 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 1 Sep 2025 04:03:08 +0000 Subject: [PATCH 289/471] 8366024: Remove unnecessary InstanceKlass::cast() Reviewed-by: coleenp, dholmes --- .../share/classfile/classFileParser.cpp | 16 ++--- .../share/classfile/fieldLayoutBuilder.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 2 +- src/hotspot/share/classfile/vmClasses.cpp | 4 +- .../jfrEventClassTransformer.cpp | 2 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 70 +++++++++---------- src/hotspot/share/oops/instanceKlass.hpp | 10 +-- src/hotspot/share/oops/klass.cpp | 14 ++-- src/hotspot/share/oops/klass.hpp | 1 - src/hotspot/share/oops/klassVtable.cpp | 39 +++++------ src/hotspot/share/oops/klassVtable.hpp | 12 ++-- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 2 +- 16 files changed, 83 insertions(+), 99 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index c678fa5e058..01e35161efd 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -4092,31 +4092,29 @@ static Array* compute_transitive_interfaces(const InstanceKlass* void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, TRAPS) { assert(this_klass != nullptr, "invariant"); - const Klass* const super = this_klass->super(); + const InstanceKlass* const super = this_klass->java_super(); if (super != nullptr) { - const InstanceKlass* super_ik = InstanceKlass::cast(super); - if (super->is_final()) { - classfile_icce_error("class %s cannot inherit from final class %s", super_ik, THREAD); + classfile_icce_error("class %s cannot inherit from final class %s", super, THREAD); return; } - if (super_ik->is_sealed()) { + if (super->is_sealed()) { stringStream ss; ResourceMark rm(THREAD); - if (!super_ik->has_as_permitted_subclass(this_klass, ss)) { + if (!super->has_as_permitted_subclass(this_klass, ss)) { classfile_icce_error(ss.as_string(), THREAD); return; } } Reflection::VerifyClassAccessResults vca_result = - Reflection::verify_class_access(this_klass, InstanceKlass::cast(super), false); + Reflection::verify_class_access(this_klass, super, false); if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); char* msg = Reflection::verify_class_access_msg(this_klass, - InstanceKlass::cast(super), + super, vca_result); // Names are all known to be < 64k so we know this formatted message is not excessively large. @@ -4218,7 +4216,7 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) // skip supers that don't have final methods. if (k->has_final_method()) { // lookup a matching method in the super class hierarchy - super_m = InstanceKlass::cast(k)->lookup_method(name, signature); + super_m = k->lookup_method(name, signature); if (super_m == nullptr) { break; // didn't find any match; get out } diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 21f47e3de10..d06f5dd96d1 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -316,7 +316,7 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance block->set_offset(fs.offset()); all_fields->append(block); } - ik = ik->super() == nullptr ? nullptr : InstanceKlass::cast(ik->super()); + ik = ik->java_super() == nullptr ? nullptr : ik->java_super(); } assert(last_offset == -1 || last_offset > 0, "Sanity"); if (last_offset > 0 && diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 783ae9d35ba..ae7432c9fce 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1049,7 +1049,7 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle // load from the shared archive. if (ik->super() != nullptr) { - bool check_super = check_shared_class_super_type(ik, InstanceKlass::cast(ik->super()), + bool check_super = check_shared_class_super_type(ik, ik->java_super(), class_loader, true, CHECK_false); if (!check_super) { diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 813926e51a2..9b9222268a6 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -225,10 +225,10 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load } // add super and interfaces first - Klass* super = klass->super(); + InstanceKlass* super = klass->java_super(); if (super != nullptr && super->class_loader_data() == nullptr) { assert(super->is_instance_klass(), "Super should be instance klass"); - resolve_shared_class(InstanceKlass::cast(super), loader_data, domain, CHECK); + resolve_shared_class(super, loader_data, domain, CHECK); } Array* ifs = klass->local_interfaces(); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index 5e7f65aeec1..81e8a82c78d 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -214,7 +214,7 @@ static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_t if (has_annotation(ik, annotation_type, default_value, value)) { return true; } - InstanceKlass* const super = InstanceKlass::cast(ik->super()); + InstanceKlass* const super = ik->java_super(); return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, default_value, value) : false; } diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index 6a38553403d..c9d79a23c2f 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -76,7 +76,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { } jfs.next(); } - ik = (const InstanceKlass*)ik->super(); + ik = ik->java_super(); } *modifiers = 0; return nullptr; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index e4900249dbd..dbc3ebd9c6e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2012,7 +2012,7 @@ C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, ARGUMENT_PAIR(kl JVMCIObjectArray interfaces = JVMCIENV->new_HotSpotResolvedObjectTypeImpl_array(size, JVMCI_CHECK_NULL); for (int index = 0; index < size; index++) { JVMCIKlassHandle klass(THREAD); - Klass* k = iklass->local_interfaces()->at(index); + InstanceKlass* k = iklass->local_interfaces()->at(index); klass = k; JVMCIObject type = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); JVMCIENV->put_object_at(interfaces, index, type); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index dcec45ff4e2..a7641b9a546 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -575,7 +575,7 @@ void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, } void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, - const Klass* super_klass, + const InstanceKlass* super_klass, Array* local_interfaces, Array* transitive_interfaces) { // Only deallocate transitive interfaces if not empty, same as super class @@ -584,7 +584,7 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) { // check that the interfaces don't come from super class Array* sti = (super_klass == nullptr) ? nullptr : - InstanceKlass::cast(super_klass)->transitive_interfaces(); + super_klass->transitive_interfaces(); if (ti != sti && ti != nullptr && !ti->is_shared()) { MetadataFactory::free_array(loader_data, ti); } @@ -677,7 +677,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); - deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); + deallocate_interfaces(loader_data, java_super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); @@ -942,7 +942,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { JavaThread* jt = THREAD; // link super class before linking this class - Klass* super_klass = super(); + InstanceKlass* super_klass = java_super(); if (super_klass != nullptr) { if (super_klass->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -957,8 +957,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { return false; } - InstanceKlass* ik_super = InstanceKlass::cast(super_klass); - ik_super->link_class_impl(CHECK_false); + super_klass->link_class_impl(CHECK_false); } // link all interfaces implemented by this class before linking this class @@ -1805,15 +1804,15 @@ bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* Klass* InstanceKlass::find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const { const int n = local_interfaces()->length(); for (int i = 0; i < n; i++) { - Klass* intf1 = local_interfaces()->at(i); + InstanceKlass* intf1 = local_interfaces()->at(i); assert(intf1->is_interface(), "just checking type"); // search for field in current interface - if (InstanceKlass::cast(intf1)->find_local_field(name, sig, fd)) { + if (intf1->find_local_field(name, sig, fd)) { assert(fd->is_static(), "interface field must be static"); return intf1; } // search for field in direct superinterfaces - Klass* intf2 = InstanceKlass::cast(intf1)->find_interface_field(name, sig, fd); + Klass* intf2 = intf1->find_interface_field(name, sig, fd); if (intf2 != nullptr) return intf2; } // otherwise field lookup fails @@ -1832,8 +1831,8 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { Klass* supr = super(); - if (supr != nullptr) return InstanceKlass::cast(supr)->find_field(name, sig, fd); + { InstanceKlass* supr = java_super(); + if (supr != nullptr) return supr->find_field(name, sig, fd); } // 4) otherwise field lookup fails return nullptr; @@ -1852,8 +1851,8 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { Klass* supr = super(); - if (supr != nullptr) return InstanceKlass::cast(supr)->find_field(name, sig, is_static, fd); + { InstanceKlass* supr = java_super(); + if (supr != nullptr) return supr->find_field(name, sig, is_static, fd); } // 4) otherwise field lookup fails return nullptr; @@ -1872,12 +1871,12 @@ bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fie bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const { - Klass* klass = const_cast(this); + const InstanceKlass* klass = this; while (klass != nullptr) { - if (InstanceKlass::cast(klass)->find_local_field_from_offset(offset, is_static, fd)) { + if (klass->find_local_field_from_offset(offset, is_static, fd)) { return true; } - klass = klass->super(); + klass = klass->java_super(); } return false; } @@ -1920,7 +1919,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAP } void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = superklass(); + InstanceKlass* super = java_super(); if (super != nullptr) { super->do_nonstatic_fields(cl); } @@ -1937,7 +1936,7 @@ static int compare_fields_by_offset(FieldInfo* a, FieldInfo* b) { } void InstanceKlass::print_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = superklass(); + InstanceKlass* super = java_super(); if (super != nullptr) { super->print_nonstatic_fields(cl); } @@ -2232,17 +2231,17 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, OverpassLookupMode overpass_mode, PrivateLookupMode private_mode) const { OverpassLookupMode overpass_local_mode = overpass_mode; - const Klass* klass = this; + const InstanceKlass* klass = this; while (klass != nullptr) { - Method* const method = InstanceKlass::cast(klass)->find_method_impl(name, - signature, - overpass_local_mode, - StaticLookupMode::find, - private_mode); + Method* const method = klass->find_method_impl(name, + signature, + overpass_local_mode, + StaticLookupMode::find, + private_mode); if (method != nullptr) { return method; } - klass = klass->super(); + klass = klass->java_super(); overpass_local_mode = OverpassLookupMode::skip; // Always ignore overpass methods in superclasses } return nullptr; @@ -2252,12 +2251,12 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, // search through class hierarchy and return true if this class or // one of the superclasses was redefined bool InstanceKlass::has_redefined_this_or_super() const { - const Klass* klass = this; + const InstanceKlass* klass = this; while (klass != nullptr) { - if (InstanceKlass::cast(klass)->has_been_redefined()) { + if (klass->has_been_redefined()) { return true; } - klass = klass->super(); + klass = klass->java_super(); } return false; } @@ -3986,7 +3985,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, // Class hierarchy info debug_stream.print(" klass: " PTR_FORMAT " super: " PTR_FORMAT, - p2i(this), p2i(superklass())); + p2i(this), p2i(java_super())); // Interfaces if (local_interfaces() != nullptr && local_interfaces()->length() > 0) { @@ -3994,7 +3993,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, int length = local_interfaces()->length(); for (int i = 0; i < length; i++) { debug_stream.print(" " PTR_FORMAT, - p2i(InstanceKlass::cast(local_interfaces()->at(i)))); + p2i(local_interfaces()->at(i))); } } @@ -4207,19 +4206,17 @@ void InstanceKlass::oop_verify_on(oop obj, outputStream* st) { obj->oop_iterate(&blk); } - // JNIid class for jfieldIDs only // Note to reviewers: // These JNI functions are just moved over to column 1 and not changed // in the compressed oops workspace. -JNIid::JNIid(Klass* holder, int offset, JNIid* next) { +JNIid::JNIid(InstanceKlass* holder, int offset, JNIid* next) { _holder = holder; _offset = offset; _next = next; DEBUG_ONLY(_is_static_field_id = false;) } - JNIid* JNIid::find(int offset) { JNIid* current = this; while (current != nullptr) { @@ -4237,11 +4234,10 @@ void JNIid::deallocate(JNIid* current) { } } - -void JNIid::verify(Klass* holder) { +void JNIid::verify(InstanceKlass* holder) { int first_field_offset = InstanceMirrorKlass::offset_of_static_fields(); int end_field_offset; - end_field_offset = first_field_offset + (InstanceKlass::cast(holder)->static_field_size() * wordSize); + end_field_offset = first_field_offset + (holder->static_field_size() * wordSize); JNIid* current = this; while (current != nullptr) { @@ -4554,7 +4550,7 @@ void ClassHierarchyIterator::next() { } _visit_subclasses = true; // reset while (_current->next_sibling() == nullptr && _current != _root) { - _current = _current->superklass(); // backtrack; no more sibling subclasses left + _current = _current->java_super(); // backtrack; no more sibling subclasses left } if (_current == _root) { // Iteration is over (back at root after backtracking). Invalidate the iterator. diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 3c0dd84b2d2..a158494736b 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -988,7 +988,7 @@ public: static void deallocate_methods(ClassLoaderData* loader_data, Array* methods); void static deallocate_interfaces(ClassLoaderData* loader_data, - const Klass* super_klass, + const InstanceKlass* super_klass, Array* local_interfaces, Array* transitive_interfaces); void static deallocate_record_components(ClassLoaderData* loader_data, @@ -1205,7 +1205,7 @@ public: class JNIid: public CHeapObj { friend class VMStructs; private: - Klass* _holder; + InstanceKlass* _holder; JNIid* _next; int _offset; #ifdef ASSERT @@ -1214,11 +1214,11 @@ class JNIid: public CHeapObj { public: // Accessors - Klass* holder() const { return _holder; } + InstanceKlass* holder() const { return _holder; } int offset() const { return _offset; } JNIid* next() { return _next; } // Constructor - JNIid(Klass* holder, int offset, JNIid* next); + JNIid(InstanceKlass* holder, int offset, JNIid* next); // Identifier lookup JNIid* find(int offset); @@ -1232,7 +1232,7 @@ class JNIid: public CHeapObj { bool is_static_field_id() const { return _is_static_field_id; } void set_is_static_field_id() { _is_static_field_id = true; } #endif - void verify(Klass* holder); + void verify(InstanceKlass* holder); }; // An iterator that's used to access the inner classes indices in the diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 41ab8e325ab..17e2ccbc911 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -611,12 +611,6 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots, } -// superklass links -InstanceKlass* Klass::superklass() const { - assert(super() == nullptr || super()->is_instance_klass(), "must be instance klass"); - return _super == nullptr ? nullptr : InstanceKlass::cast(_super); -} - // subklass links. Used by the compiler (and vtable initialization) // May be cleaned concurrently, so must use the Compile_lock. // The log parameter is for clean_weak_klass_links to report unlinked classes. @@ -679,11 +673,11 @@ void Klass::append_to_sibling_list() { assert_locked_or_safepoint(Compile_lock); } DEBUG_ONLY(verify();) - // add ourselves to superklass' subklass list - InstanceKlass* super = superklass(); + // add ourselves to super' subklass list + InstanceKlass* super = java_super(); if (super == nullptr) return; // special case: class Object assert((!super->is_interface() // interfaces cannot be supers - && (super->superklass() == nullptr || !is_interface())), + && (super->java_super() == nullptr || !is_interface())), "an interface can only be a subklass of Object"); // Make sure there is no stale subklass head @@ -692,7 +686,7 @@ void Klass::append_to_sibling_list() { for (;;) { Klass* prev_first_subklass = Atomic::load_acquire(&_super->_subklass); if (prev_first_subklass != nullptr) { - // set our sibling to be the superklass' previous first subklass + // set our sibling to be the super' previous first subklass assert(prev_first_subklass->is_loader_alive(), "May not attach not alive klasses"); set_next_sibling(prev_first_subklass); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index ac382fdba98..1257f4cbcf8 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -297,7 +297,6 @@ protected: Klass* subklass(bool log = false) const; Klass* next_sibling(bool log = false) const; - InstanceKlass* superklass() const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list void set_next_link(Klass* k) { _next_link = k; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index e9da33b280e..bb47496b406 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -65,7 +65,7 @@ bool klassVtable::is_preinitialized_vtable() { // treated as any other public method in C for method over-ride purposes. void klassVtable::compute_vtable_size_and_num_mirandas( int* vtable_length_ret, int* num_new_mirandas, - GrowableArray* all_mirandas, const Klass* super, + GrowableArray* all_mirandas, const InstanceKlass* super, Array* methods, AccessFlags class_flags, u2 major_version, Handle classloader, Symbol* classname, Array* local_interfaces) { NoSafepointVerifier nsv; @@ -346,7 +346,7 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper break; } // if no override found yet, continue to search up - superk = superk->super() == nullptr ? nullptr : InstanceKlass::cast(superk->super()); + superk = superk->java_super(); } return superk; @@ -631,7 +631,7 @@ void klassVtable::initialize_vtable_and_check_constraints(TRAPS) { // However, the vtable entries are filled in at link time, and therefore // the superclass' vtable may not yet have been filled in. bool klassVtable::needs_new_vtable_entry(Method* target_method, - const Klass* super, + const InstanceKlass* super, Handle classloader, Symbol* classname, AccessFlags class_flags, @@ -683,7 +683,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // a new entry Symbol* name = target_method->name(); Symbol* signature = target_method->signature(); - const Klass* k = super; + const InstanceKlass* k = super; Method* super_method = nullptr; InstanceKlass *holder = nullptr; Method* recheck_method = nullptr; @@ -722,7 +722,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // Start with lookup result and continue to search up, for versions supporting transitive override if (major_version >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) { - k = superk->super(); // haven't found an override match yet; continue to look + k = superk->java_super(); // haven't found an override match yet; continue to look } else { break; } @@ -741,9 +741,8 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // miranda method in the super, whose entry it should re-use. // Actually, to handle cases that javac would not generate, we need // this check for all access permissions. - const InstanceKlass *sk = InstanceKlass::cast(super); - if (sk->has_miranda_methods()) { - if (sk->lookup_method_in_all_interfaces(name, signature, Klass::DefaultsLookupMode::find) != nullptr) { + if (super->has_miranda_methods()) { + if (super->lookup_method_in_all_interfaces(name, signature, Klass::DefaultsLookupMode::find) != nullptr) { return false; // found a matching miranda; we do not need a new entry } } @@ -775,7 +774,7 @@ bool klassVtable::is_miranda_entry_at(int i) { if (holder->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(holder) , "this class should implement the interface"); - if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super(), klass()->is_interface())) { + if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->java_super(), klass()->is_interface())) { return true; } } @@ -837,7 +836,7 @@ bool klassVtable::is_miranda_entry_at(int i) { // Part of the Miranda Rights in the US mean that if you do not have // an attorney one will be appointed for you. bool klassVtable::is_miranda(Method* m, Array* class_methods, - Array* default_methods, const Klass* super, + Array* default_methods, const InstanceKlass* super, bool is_interface) { if (m->is_static() || m->is_private() || m->is_overpass()) { return false; @@ -866,12 +865,11 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, // Overpasses may or may not exist for supers for pass 1, // they should have been created for pass 2 and later. - for (const Klass* cursuper = super; cursuper != nullptr; cursuper = cursuper->super()) - { - Method* found_mth = InstanceKlass::cast(cursuper)->find_local_method(name, signature, - Klass::OverpassLookupMode::find, - Klass::StaticLookupMode::skip, - Klass::PrivateLookupMode::skip); + for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->java_super()) { + Method* found_mth = cursuper->find_local_method(name, signature, + Klass::OverpassLookupMode::find, + Klass::StaticLookupMode::skip, + Klass::PrivateLookupMode::skip); // Ignore non-public methods in java.lang.Object if klass is an interface. if (found_mth != nullptr && (!is_interface || !SystemDictionary::is_nonpublic_Object_method(found_mth))) { @@ -893,7 +891,7 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, void klassVtable::add_new_mirandas_to_lists( GrowableArray* new_mirandas, GrowableArray* all_mirandas, Array* current_interface_methods, Array* class_methods, - Array* default_methods, const Klass* super, bool is_interface) { + Array* default_methods, const InstanceKlass* super, bool is_interface) { // iterate thru the current interface's method to see if it a miranda int num_methods = current_interface_methods->length(); @@ -913,9 +911,8 @@ void klassVtable::add_new_mirandas_to_lists( if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable if (is_miranda(im, class_methods, default_methods, super, is_interface)) { // is it a miranda at all? - const InstanceKlass *sk = InstanceKlass::cast(super); // check if it is a duplicate of a super's miranda - if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::DefaultsLookupMode::find) == nullptr) { + if (super->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::DefaultsLookupMode::find) == nullptr) { new_mirandas->append(im); } if (all_mirandas != nullptr) { @@ -928,7 +925,7 @@ void klassVtable::add_new_mirandas_to_lists( void klassVtable::get_mirandas(GrowableArray* new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* class_methods, Array* default_methods, Array* local_interfaces, @@ -962,7 +959,7 @@ void klassVtable::get_mirandas(GrowableArray* new_mirandas, int klassVtable::fill_in_mirandas(Thread* current, int initialized) { ResourceMark rm(current); GrowableArray mirandas(20); - get_mirandas(&mirandas, nullptr, ik()->super(), ik()->methods(), + get_mirandas(&mirandas, nullptr, ik()->java_super(), ik()->methods(), ik()->default_methods(), ik()->local_interfaces(), klass()->is_interface()); for (int i = 0; i < mirandas.length(); i++) { diff --git a/src/hotspot/share/oops/klassVtable.hpp b/src/hotspot/share/oops/klassVtable.hpp index 3bd07a9143e..b8635e7f14b 100644 --- a/src/hotspot/share/oops/klassVtable.hpp +++ b/src/hotspot/share/oops/klassVtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -77,7 +77,7 @@ class klassVtable { static void compute_vtable_size_and_num_mirandas(int* vtable_length, int* num_new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* methods, AccessFlags class_flags, u2 major_version, @@ -116,7 +116,7 @@ class klassVtable { int initialize_from_super(Klass* super); void put_method_at(Method* m, int index); static bool needs_new_vtable_entry(Method* m, - const Klass* super, + const InstanceKlass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, @@ -135,7 +135,7 @@ class klassVtable { bool is_miranda_entry_at(int i); int fill_in_mirandas(Thread* current, int initialized); static bool is_miranda(Method* m, Array* class_methods, - Array* default_methods, const Klass* super, + Array* default_methods, const InstanceKlass* super, bool is_interface); static void add_new_mirandas_to_lists( GrowableArray* new_mirandas, @@ -143,12 +143,12 @@ class klassVtable { Array* current_interface_methods, Array* class_methods, Array* default_methods, - const Klass* super, + const InstanceKlass* super, bool is_interface); static void get_mirandas( GrowableArray* new_mirandas, GrowableArray* all_mirandas, - const Klass* super, + const InstanceKlass* super, Array* class_methods, Array* default_methods, Array* local_interfaces, diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index abec3bc59b6..f4ec7f8ccbf 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1177,7 +1177,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) if (klass->is_instance_klass()) { // Regular instance klass, fill in all local interfaces for (int index = 0; index < size; index++) { - Klass* k = InstanceKlass::cast(klass)->local_interfaces()->at(index); + InstanceKlass* k = InstanceKlass::cast(klass)->local_interfaces()->at(index); result->obj_at_put(index, k->java_mirror()); } } else { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index dd8ee7c93fa..efc7bfde3dd 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1476,7 +1476,7 @@ public: // Gets the fields of `klass` that are eliminated by escape analysis and need to be reassigned static GrowableArray* get_reassigned_fields(InstanceKlass* klass, GrowableArray* fields, bool is_jvmci) { - InstanceKlass* super = klass->superklass(); + InstanceKlass* super = klass->java_super(); if (super != nullptr) { get_reassigned_fields(super, fields, is_jvmci); } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 6fc16f9b045..b95c1aaf60c 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -321,7 +321,7 @@ /* JNI IDs */ \ /***********/ \ \ - nonstatic_field(JNIid, _holder, Klass*) \ + nonstatic_field(JNIid, _holder, InstanceKlass*) \ nonstatic_field(JNIid, _next, JNIid*) \ nonstatic_field(JNIid, _offset, int) \ \ From a668f437e481d02cbb82d4f40dd14ec3a6036399 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 1 Sep 2025 05:54:54 +0000 Subject: [PATCH 290/471] 8365620: Using enhanced switch in MethodHandleDesc Reviewed-by: liach --- .../java/lang/constant/MethodHandleDesc.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java index 18786481fa6..0ac45657d5f 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java @@ -82,15 +82,11 @@ public sealed interface MethodHandleDesc ClassDesc owner, String name, String lookupDescriptor) { - switch (kind) { - case GETTER: - case SETTER: - case STATIC_GETTER: - case STATIC_SETTER: - return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor)); - default: - return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor)); - } + return switch (kind) { + case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER + -> ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor)); + default -> new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor)); + }; } /** @@ -122,23 +118,13 @@ public sealed interface MethodHandleDesc ClassDesc owner, String name, MethodTypeDesc lookupMethodType) { - switch (kind) { - case GETTER: - case SETTER: - case STATIC_GETTER: - case STATIC_SETTER: - throw new IllegalArgumentException(kind.toString()); - case VIRTUAL: - case SPECIAL: - case INTERFACE_VIRTUAL: - case INTERFACE_SPECIAL: - case INTERFACE_STATIC: - case STATIC: - case CONSTRUCTOR: - return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType); - default: - throw new IllegalArgumentException(kind.toString()); - } + return switch (kind) { + case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER + -> throw new IllegalArgumentException(kind.toString()); + case VIRTUAL, SPECIAL, INTERFACE_VIRTUAL, INTERFACE_SPECIAL, INTERFACE_STATIC, STATIC, CONSTRUCTOR + -> new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType); + default -> throw new IllegalArgumentException(kind.toString()); + }; } /** From 28942406020881be79b7543105b9eb2a0dda429e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 1 Sep 2025 05:55:08 +0000 Subject: [PATCH 291/471] 8177650: JShell tool: packages in classpath don't appear in completions Reviewed-by: asotona --- .../jdk/jshell/SourceCodeAnalysisImpl.java | 69 ++--- test/langtools/jdk/jshell/Compiler.java | 8 +- .../jdk/jshell/CompletionSuggestionTest.java | 16 ++ .../langtools/jdk/jshell/ReplToolTesting.java | 33 ++- .../jdk/jshell/ToolCompletionTest.java | 257 ++++++++++++++++++ 5 files changed, 350 insertions(+), 33 deletions(-) create mode 100644 test/langtools/jdk/jshell/ToolCompletionTest.java diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index cb4861651e3..fffdfd5b33c 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -92,7 +92,6 @@ import javax.lang.model.type.TypeMirror; import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA; import java.io.IOException; -import java.net.URI; import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -101,6 +100,7 @@ import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.Collection; @@ -2002,12 +2002,22 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { //update indexes, either initially or after a classpath change: private void refreshIndexes(int version) { try { - Collection paths = new ArrayList<>(); - MemoryFileManager fm = proc.taskFactory.fileManager(); - - appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, paths); - appendPaths(fm, StandardLocation.CLASS_PATH, paths); - appendPaths(fm, StandardLocation.SOURCE_PATH, paths); + Collection paths = proc.taskFactory.parse("", task -> { + MemoryFileManager fm = proc.taskFactory.fileManager(); + Collection _paths = new ArrayList<>(); + try { + appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, _paths); + appendPaths(fm, StandardLocation.CLASS_PATH, _paths); + appendPaths(fm, StandardLocation.SOURCE_PATH, _paths); + appendModulePaths(fm, StandardLocation.SYSTEM_MODULES, _paths); + appendModulePaths(fm, StandardLocation.UPGRADE_MODULE_PATH, _paths); + appendModulePaths(fm, StandardLocation.MODULE_PATH, _paths); + return _paths; + } catch (Exception ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.refreshIndexes(" + version + ")"); + return List.of(); + } + }); Map newIndexes = new HashMap<>(); @@ -2060,27 +2070,24 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } + private void appendModulePaths(MemoryFileManager fm, Location loc, Collection paths) throws IOException { + for (Set moduleLocations : fm.listLocationsForModules(loc)) { + for (Location moduleLocation : moduleLocations) { + Iterable modulePaths = fm.getLocationAsPaths(moduleLocation); + + if (modulePaths == null) { + continue; + } + + modulePaths.forEach(paths::add); + } + } + } + //create/update index a given JavaFileManager entry (which may be a JDK installation, a jar/zip file or a directory): //if an index exists for the given entry, the existing index is kept unless the timestamp is modified private ClassIndex indexForPath(Path path) { - if (isJRTMarkerFile(path)) { - FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/")); - Path modules = jrtfs.getPath("modules"); - return PATH_TO_INDEX.compute(path, (p, index) -> { - try { - long lastModified = Files.getLastModifiedTime(modules).toMillis(); - if (index == null || index.timestamp != lastModified) { - try (DirectoryStream stream = Files.newDirectoryStream(modules)) { - index = doIndex(lastModified, path, stream); - } - } - return index; - } catch (IOException ex) { - proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")"); - return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap()); - } - }); - } else if (!Files.isDirectory(path)) { + if (!Files.isDirectory(path)) { if (Files.exists(path)) { return PATH_TO_INDEX.compute(path, (p, index) -> { try { @@ -2093,7 +2100,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } return index; - } catch (IOException ex) { + } catch (IOException | ProviderNotFoundException ex) { proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")"); return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap()); } @@ -2112,10 +2119,6 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } } - static boolean isJRTMarkerFile(Path path) { - return path.equals(Paths.get(System.getProperty("java.home"), "lib", "modules")); - } - //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath. private ClassIndex doIndex(long timestamp, Path originalPath, Iterable dirs) { Set packages = new HashSet<>(); @@ -2200,13 +2203,17 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { upToDate = classpathVersion == indexVersion; } while (!upToDate) { - INDEXER.submit(() -> {}).get(); + waitCurrentBackgroundTasksFinished(); synchronized (currentIndexes) { upToDate = classpathVersion == indexVersion; } } } + public static void waitCurrentBackgroundTasksFinished() throws Exception { + INDEXER.submit(() -> {}).get(); + } + /** * A candidate for continuation of the given user's input. */ diff --git a/test/langtools/jdk/jshell/Compiler.java b/test/langtools/jdk/jshell/Compiler.java index 6f6f49da501..a255008b15d 100644 --- a/test/langtools/jdk/jshell/Compiler.java +++ b/test/langtools/jdk/jshell/Compiler.java @@ -72,11 +72,17 @@ public class Compiler { } public void jar(Path directory, String jarName, String...files) { + Path classDirPath = getClassDir(); + Path baseDir = classDirPath.resolve(directory); + Path jarPath = baseDir.resolve(jarName); + jar(directory, jarPath, files); + } + + public void jar(Path directory, Path jarPath, String...files) { Manifest manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); Path classDirPath = getClassDir(); Path baseDir = classDirPath.resolve(directory); - Path jarPath = baseDir.resolve(jarName); new JarTask(tb, jarPath.toString()) .manifest(manifest) .baseDir(baseDir.toString()) diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 6bc7c41e62c..fb9e8eacc4a 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -834,4 +834,20 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletionIncludesExcludes("import module ja|", Set.of("java.base"), Set.of("jdk.compiler")); assertCompletion("import module java/*c*/./*c*/ba|", "java.base"); } + + public void testCustomClassPathIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + "package p1.p2;\n" + + "public class Test {\n" + + "}", + "package p1.p3;\n" + + "public class Test {\n" + + "}"); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + addToClasspath(compiler.getPath(p1.resolve(jarName))); + + assertCompletion("p1.|", "p2.", "p3."); + } } diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index 8bfae2fc390..5ca010af3c2 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -566,6 +567,36 @@ public class ReplToolTesting { } } + public void assertCompletions(boolean after, String input, String expectedCompletionsPattern) { + if (!after) { + try { + Class sourceCodeAnalysisImpl = Class.forName("jdk.jshell.SourceCodeAnalysisImpl"); + Method waitBackgroundTaskFinished = sourceCodeAnalysisImpl.getDeclaredMethod("waitCurrentBackgroundTasksFinished"); + + waitBackgroundTaskFinished.setAccessible(true); + waitBackgroundTaskFinished.invoke(null); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex.getMessage(), ex); + } + + setCommandInput(input + "\t"); + } else { + assertOutput(getCommandOutput().trim(), "", "command output: " + input); + assertOutput(getCommandErrorOutput(), "", "command error: " + input); + assertOutput(getUserOutput(), "", "user output: " + input); + assertOutput(getUserErrorOutput(), "", "user error: " + input); + String actualOutput = getTerminalOutput(); + Pattern compiledPattern = + Pattern.compile(expectedCompletionsPattern, Pattern.DOTALL); + if (!compiledPattern.asMatchPredicate().test(actualOutput)) { + throw new AssertionError("Actual output:\n" + + actualOutput + "\n" + + "does not match expected pattern: " + + expectedCompletionsPattern); + } + } + } + private String normalizeLineEndings(String text) { return normalizeLineEndings(System.getProperty("line.separator"), text); } diff --git a/test/langtools/jdk/jshell/ToolCompletionTest.java b/test/langtools/jdk/jshell/ToolCompletionTest.java new file mode 100644 index 00000000000..9997db45c4d --- /dev/null +++ b/test/langtools/jdk/jshell/ToolCompletionTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8177650 + * @summary Verify JShell tool code completion + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * jdk.jshell/jdk.jshell:+open + * jdk.jshell/jdk.internal.jshell.tool + * java.desktop + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @build ReplToolTesting TestingInputStream Compiler + * @run testng ToolCompletionTest + */ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.testng.annotations.Test; + +public class ToolCompletionTest extends ReplToolTesting { + + private final Compiler compiler = new Compiler(); + private final Path outDir = Paths.get("tool_completion_test"); + + @Test + public void testClassPathOnCmdLineIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--class-path", compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testClassPathViaEnvIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup"}, + (a) -> assertCommand(a, "/env --class-path " + compiler.getPath(p1.resolve(jarName)).toString(), null), + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testClassPathChangeIndexing() { + //verify that changing the classpath has effect: + Path dir1 = outDir.resolve("dir1"); + compiler.compile(dir1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName1 = "test1.jar"; + compiler.jar(dir1, jarName1, "p1/p2/Test.class", "p1/p3/Test.class"); + + Path dir2 = outDir.resolve("dir2"); + compiler.compile(dir2, + """ + package p1.p5; + public class Test { + } + """, + """ + package p1.p6; + public class Test { + } + """); + String jarName2 = "test2.jar"; + compiler.jar(dir2, jarName2, "p1/p5/Test.class", "p1/p6/Test.class"); + + test(false, new String[]{"--no-startup", "--class-path", compiler.getPath(dir1.resolve(jarName1)).toString()}, + (a) -> assertCommand(a, "1", null), + (a) -> assertCommand(a, "/env --class-path " + compiler.getPath(dir2.resolve(jarName2)).toString(), null), + (a) -> assertCompletions(a, "p1.", ".*p5\\..*p6\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testModulePathOnCmdLineIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--module-path", compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testModulePathOnCmdLineIndexing2() throws IOException { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + Path lib = outDir.resolve("lib"); + Files.createDirectories(lib); + compiler.jar(p1, lib.resolve(jarName), "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "--module-path", lib.toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testUpgradeModulePathIndexing() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + module m { + exports p1.p2; + exports p1.p3; + } + """, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "-C--upgrade-module-path", "-C" + compiler.getPath(p1.resolve(jarName)).toString()}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } + + @Test + public void testBootClassPathPrepend() { + Path p1 = outDir.resolve("dir1"); + compiler.compile(p1, + """ + package p1.p2; + public class Test { + } + """, + """ + package p1.p3; + public class Test { + } + """); + String jarName = "test.jar"; + compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class"); + + test(false, new String[]{"--no-startup", "-C-Xbootclasspath/p:" + compiler.getPath(p1.resolve(jarName)).toString(), "-C--source=8"}, + (a) -> assertCompletions(a, "p1.", ".*p2\\..*p3\\..*"), + //cancel the input, so that JShell can be finished: + (a) -> assertCommand(a, "\003", null) + ); + } +} From 685da0323b27abda5ab0484f4c8abaaeeff882ea Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 1 Sep 2025 06:25:45 +0000 Subject: [PATCH 292/471] 8345810: Custom launchers must be linked with pthread to avoid dynamic linker issues Reviewed-by: asemenyuk, erikj, dholmes --- make/modules/jdk.jpackage/Lib.gmk | 4 ++-- make/test/JtregNativeJdk.gmk | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk index d2dd9d92a03..51d70c6d835 100644 --- a/make/modules/jdk.jpackage/Lib.gmk +++ b/make/modules/jdk.jpackage/Lib.gmk @@ -68,7 +68,7 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGEAPPLAUNCHER, \ -rpath @executable_path/../PlugIns/, \ LIBS_macosx := -framework Cocoa, \ LIBS_windows := msi.lib ole32.lib shell32.lib shlwapi.lib user32.lib, \ - LIBS_linux := $(LIBDL), \ + LIBS_linux := $(LIBDL) $(LIBPTHREAD), \ MANIFEST := $(JAVA_MANIFEST), \ MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS) \ )) @@ -97,7 +97,7 @@ ifeq ($(call isTargetOs, linux), true) DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \ LD_SET_ORIGIN := false, \ - LIBS_linux := $(LIBDL), \ + LIBS_linux := $(LIBDL) $(LIBPTHREAD), \ )) TARGETS += $(BUILD_LIBJPACKAGEAPPLAUNCHERAUX) diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index 7578d4a50d0..a204467a77b 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -138,6 +138,7 @@ ifneq ($(filter build-test-jdk-jtreg-native, $(MAKECMDGOALS)), ) OUTPUT_DIR := $(BUILD_JDK_JTREG_OUTPUT_DIR), \ EXCLUDE := $(BUILD_JDK_JTREG_EXCLUDE), \ EXTRA_FILES := $(BUILD_JDK_JTREG_EXTRA_FILES), \ + LIBS := $(LIBPTHREAD), \ )) endif From 12dc568b3d270e4ab6dcd07e1bcddbb024ad724a Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 1 Sep 2025 06:28:10 +0000 Subject: [PATCH 293/471] 8366331: Sort share/prims includes Reviewed-by: shade, lmesnik --- src/hotspot/share/prims/foreignGlobals.cpp | 1 - src/hotspot/share/prims/foreignGlobals.inline.hpp | 2 +- src/hotspot/share/prims/jni.cpp | 2 -- src/hotspot/share/prims/jvm.cpp | 9 ++++----- src/hotspot/share/prims/jvmtiAgent.cpp | 2 +- src/hotspot/share/prims/jvmtiAgentList.cpp | 2 +- src/hotspot/share/prims/jvmtiEnv.cpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 2 +- src/hotspot/share/prims/jvmtiEnvBase.hpp | 2 +- src/hotspot/share/prims/jvmtiEventController.cpp | 3 +-- src/hotspot/share/prims/jvmtiExport.cpp | 2 -- src/hotspot/share/prims/jvmtiManageCapabilities.cpp | 2 +- src/hotspot/share/prims/jvmtiRedefineClasses.cpp | 4 ++-- src/hotspot/share/prims/jvmtiTagMap.cpp | 7 +++---- src/hotspot/share/prims/jvmtiTrace.cpp | 1 - src/hotspot/share/prims/jvmtiUtil.cpp | 1 - src/hotspot/share/prims/methodHandles.cpp | 4 ++-- src/hotspot/share/prims/methodHandles.hpp | 2 +- src/hotspot/share/prims/nativeEntryPoint.cpp | 6 +++--- src/hotspot/share/prims/nativeLookup.cpp | 4 ++-- src/hotspot/share/prims/stackwalk.cpp | 2 +- src/hotspot/share/prims/unsafe.cpp | 2 +- src/hotspot/share/prims/vmstorage.hpp | 4 ++-- src/hotspot/share/prims/wbtestmethods/parserTests.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 26 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp index f8aa73bed05..3d69a91347b 100644 --- a/src/hotspot/share/prims/foreignGlobals.cpp +++ b/src/hotspot/share/prims/foreignGlobals.cpp @@ -21,7 +21,6 @@ * questions. */ -#include "foreignGlobals.hpp" #include "classfile/javaClasses.hpp" #include "memory/resourceArea.hpp" #include "prims/foreignGlobals.inline.hpp" diff --git a/src/hotspot/share/prims/foreignGlobals.inline.hpp b/src/hotspot/share/prims/foreignGlobals.inline.hpp index bc5c47bcbf5..f5c79997764 100644 --- a/src/hotspot/share/prims/foreignGlobals.inline.hpp +++ b/src/hotspot/share/prims/foreignGlobals.inline.hpp @@ -27,9 +27,9 @@ #include "prims/foreignGlobals.hpp" #include "classfile/javaClasses.hpp" -#include "oops/oopsHierarchy.hpp" #include "oops/objArrayOop.hpp" #include "oops/oopCast.inline.hpp" +#include "oops/oopsHierarchy.hpp" template void ForeignGlobals::parse_register_array(objArrayOop jarray, StorageType type_index, GrowableArray& array, T (*converter)(int)) { diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 5a43baeb8d8..cd356863a8e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -29,7 +29,6 @@ #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoadInfo.hpp" -#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/javaThreadStatus.hpp" #include "classfile/moduleEntry.hpp" @@ -45,7 +44,6 @@ #include "jni.h" #include "jvm.h" #include "logging/log.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index f4ec7f8ccbf..0d705c84f82 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -32,7 +32,6 @@ #include "cds/lambdaProxyClassDictionary.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.inline.hpp" -#include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoadInfo.hpp" #include "classfile/javaAssertions.hpp" @@ -61,10 +60,10 @@ #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.hpp" -#include "oops/recordComponent.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/recordComponent.hpp" #include "prims/foreignGlobals.hpp" #include "prims/jvm_misc.hpp" #include "prims/jvmtiExport.hpp" @@ -73,12 +72,12 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/continuation.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/handshake.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/handshake.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/javaThread.hpp" @@ -92,8 +91,8 @@ #include "runtime/threadIdentifier.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadService.hpp" diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 4bf7a447398..192bba72fbc 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -32,11 +32,11 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" -#include "runtime/globals_extension.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.inline.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp index ec64ccaf70c..3c01bee2cd2 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.cpp +++ b/src/hotspot/share/prims/jvmtiAgentList.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "cds/cdsConfig.hpp" #include "cds/cds_globals.hpp" +#include "cds/cdsConfig.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "prims/jvmtiAgentList.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 473db4f2fbc..bc4013a7cab 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -23,8 +23,8 @@ */ #include "classfile/javaClasses.inline.hpp" -#include "classfile/stringTable.hpp" #include "classfile/modules.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index bbd4f7e1154..7450b079d18 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -60,8 +60,8 @@ #include "runtime/threadSMR.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/threadService.hpp" diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index 66f10c85bc9..809385a0604 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_PRIMS_JVMTIENVBASE_HPP #define SHARE_PRIMS_JVMTIENVBASE_HPP +#include "oops/oopHandle.hpp" #include "prims/jvmtiEnvThreadState.hpp" #include "prims/jvmtiEventController.hpp" #include "prims/jvmtiThreadState.hpp" -#include "oops/oopHandle.hpp" #include "runtime/atomic.hpp" #include "runtime/fieldDescriptor.hpp" #include "runtime/frame.hpp" diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index facbaaf9ad0..873470db17d 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -27,7 +27,6 @@ #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -41,8 +40,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/vframe.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #ifdef JVMTI_TRACE #define EC_TRACE(out) do { \ diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index a82ad2db6b6..26284b41ef0 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -44,7 +44,6 @@ #include "oops/oopHandle.inline.hpp" #include "prims/jvmtiAgentList.hpp" #include "prims/jvmtiCodeBlobEvents.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -61,7 +60,6 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp index b9de8d0b8f7..29502bb8cd5 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp @@ -24,9 +24,9 @@ #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" -#include "runtime/mutexLocker.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiManageCapabilities.hpp" +#include "runtime/mutexLocker.hpp" static const jint CAPA_SIZE = (JVMTI_INTERNAL_CAPABILITY_COUNT + 7) / 8; diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index d5509896064..e52fdd164f0 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -28,10 +28,10 @@ #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoadInfo.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/klassFactory.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/stackMapTable.hpp" #include "classfile/symbolTable.hpp" -#include "classfile/klassFactory.hpp" #include "classfile/verifier.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" @@ -55,8 +55,8 @@ #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.inline.hpp" -#include "prims/resolvedMethodTable.hpp" #include "prims/methodComparator.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 8c6376ac901..0375756e219 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -42,7 +42,6 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "prims/jvmtiEventController.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiImpl.hpp" @@ -61,13 +60,13 @@ #include "runtime/mutexLocker.hpp" #include "runtime/reflectionUtils.hpp" #include "runtime/safepoint.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/threadSMR.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" -#include "utilities/objectBitSet.inline.hpp" +#include "runtime/vmThread.hpp" #include "utilities/macros.hpp" +#include "utilities/objectBitSet.inline.hpp" typedef ObjectBitSet JVMTIBitSet; diff --git a/src/hotspot/share/prims/jvmtiTrace.cpp b/src/hotspot/share/prims/jvmtiTrace.cpp index 8dad64cb993..d74f977e7f7 100644 --- a/src/hotspot/share/prims/jvmtiTrace.cpp +++ b/src/hotspot/share/prims/jvmtiTrace.cpp @@ -28,7 +28,6 @@ #include "logging/logConfiguration.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiTrace.hpp" -#include "runtime/javaThread.hpp" #include "runtime/javaThread.inline.hpp" // diff --git a/src/hotspot/share/prims/jvmtiUtil.cpp b/src/hotspot/share/prims/jvmtiUtil.cpp index c6c431d7464..2d31f7187f6 100644 --- a/src/hotspot/share/prims/jvmtiUtil.cpp +++ b/src/hotspot/share/prims/jvmtiUtil.cpp @@ -23,7 +23,6 @@ */ #include "prims/jvmtiUtil.hpp" -#include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/vmOperations.hpp" diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 16617250198..c46b46b1af1 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -31,8 +31,8 @@ #include "code/dependencyContext.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" -#include "interpreter/oopMapCache.hpp" #include "interpreter/linkResolver.hpp" +#include "interpreter/oopMapCache.hpp" #include "jvm_io.h" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -52,11 +52,11 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/reflection.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "sanitizers/leak.hpp" #include "utilities/exceptions.hpp" diff --git a/src/hotspot/share/prims/methodHandles.hpp b/src/hotspot/share/prims/methodHandles.hpp index a44f5a66449..1a419cbb53d 100644 --- a/src/hotspot/share/prims/methodHandles.hpp +++ b/src/hotspot/share/prims/methodHandles.hpp @@ -28,8 +28,8 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "oops/method.hpp" -#include "runtime/frame.hpp" #include "runtime/fieldDescriptor.hpp" +#include "runtime/frame.hpp" #include "runtime/globals.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/prims/nativeEntryPoint.cpp b/src/hotspot/share/prims/nativeEntryPoint.cpp index 172538052f6..6a3d3ebbc3d 100644 --- a/src/hotspot/share/prims/nativeEntryPoint.cpp +++ b/src/hotspot/share/prims/nativeEntryPoint.cpp @@ -22,16 +22,16 @@ * */ -#include "runtime/interfaceSupport.inline.hpp" #include "classfile/javaClasses.inline.hpp" #include "code/codeCache.hpp" #include "code/vmreg.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" -#include "oops/typeArrayOop.inline.hpp" #include "oops/oopCast.inline.hpp" -#include "prims/foreignGlobals.inline.hpp" +#include "oops/typeArrayOop.inline.hpp" #include "prims/downcallLinker.hpp" +#include "prims/foreignGlobals.inline.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" JNI_ENTRY(jlong, NEP_makeDowncallStub(JNIEnv* env, jclass _unused, jobject method_type, jobject jabi, diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 8c8d8510dfc..1d2c78ab3cc 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -36,12 +36,12 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -#include "prims/jvmtiAgentList.hpp" #include "prims/jvm_misc.hpp" +#include "prims/jvmtiAgentList.hpp" #include "prims/jvmtiExport.hpp" #include "prims/nativeLookup.hpp" -#include "prims/unsafe.hpp" #include "prims/scopedMemoryAccess.hpp" +#include "prims/unsafe.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/prims/stackwalk.cpp b/src/hotspot/share/prims/stackwalk.cpp index 3141700b277..304648a8eb2 100644 --- a/src/hotspot/share/prims/stackwalk.cpp +++ b/src/hotspot/share/prims/stackwalk.cpp @@ -31,8 +31,8 @@ #include "memory/universe.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" -#include "oops/oop.inline.hpp" #include "oops/objArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" #include "prims/stackwalk.hpp" #include "runtime/continuationJavaClasses.inline.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 80dfaf90a28..b4718a9a18a 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -52,8 +52,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/threadSMR.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "sanitizers/ub.hpp" #include "services/threadService.hpp" #include "utilities/align.hpp" diff --git a/src/hotspot/share/prims/vmstorage.hpp b/src/hotspot/share/prims/vmstorage.hpp index a50f95ffc56..f605dc28a9f 100644 --- a/src/hotspot/share/prims/vmstorage.hpp +++ b/src/hotspot/share/prims/vmstorage.hpp @@ -24,13 +24,13 @@ #ifndef SHARE_PRIMS_VMSTORAGE_HPP #define SHARE_PRIMS_VMSTORAGE_HPP -#include - #include "code/vmreg.hpp" #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include + enum class StorageType : int8_t; // defined in arch specific headers class VMStorage { diff --git a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp index c06cd6cbd81..dc0604aa31d 100644 --- a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp +++ b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp @@ -29,8 +29,8 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" -#include "prims/whitebox.inline.hpp" #include "prims/wbtestmethods/parserTests.hpp" +#include "prims/whitebox.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "services/diagnosticArgument.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 68fab39b23a..1db9c1c00dd 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -126,8 +126,8 @@ #endif #ifdef LINUX #include "cgroupSubsystem_linux.hpp" -#include "osContainer_linux.hpp" #include "os_linux.hpp" +#include "osContainer_linux.hpp" #endif #define CHECK_JNI_EXCEPTION_(env, value) \ diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index f7b70079673..e2724a93890 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -60,6 +60,7 @@ public class TestIncludesAreSorted { "share/oops", "share/opto", "share/precompiled", + "share/prims", "share/services", "share/utilities" }; From 86f48ab559bb1749109217aaecd1203209a5be19 Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Mon, 1 Sep 2025 06:35:10 +0000 Subject: [PATCH 294/471] 8366157: Clarify in man pages that only G1 and Parallel supports MaxGCPauseMillis Reviewed-by: tschatzl, sjohanss --- src/java.base/share/man/java.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index f7a31fff836..9a750f8cf1f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2501,10 +2501,9 @@ Java HotSpot VM. `-XX:MaxGCPauseMillis=`*time* : Sets a target for the maximum GC pause time (in milliseconds). This is a - soft goal, and the JVM will make its best effort to achieve it. The - specified value doesn't adapt to your heap size. By default, for G1 the - maximum pause time target is 200 milliseconds. The other generational - collectors do not use a pause time goal by default. + soft goal, and the JVM will make its best effort to achieve it. Only G1 + and Parallel support a maximum GC pause time target. For G1, the default + maximum pause time target is 200 milliseconds. The following example shows how to set the maximum target pause time to 500 ms: From ba90ccc6a8ca7b0b728568ea614470c85a5f7f8a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 06:46:23 +0000 Subject: [PATCH 295/471] 8362516: Support of GCC static analyzer (-fanalyzer) Reviewed-by: erikj --- make/autoconf/configure.ac | 3 +++ make/autoconf/jdk-options.m4 | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index e05b5ae3b90..2e608f893d6 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -221,6 +221,9 @@ JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER # LeakSanitizer JDKOPT_SETUP_LEAK_SANITIZER +# Setup static analyzer +JDKOPT_SETUP_STATIC_ANALYZER + # Fallback linker # This needs to go before 'LIB_DETERMINE_DEPENDENCIES' JDKOPT_SETUP_FALLBACK_LINKER diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 289ed935fdf..d4299078abf 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -479,6 +479,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_ADDRESS_SANITIZER], AC_SUBST(ASAN_ENABLED) ]) +################################################################################ +# +# Static analyzer +# +AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_ANALYZER], +[ + UTIL_ARG_ENABLE(NAME: static-analyzer, DEFAULT: false, RESULT: STATIC_ANALYZER_ENABLED, + DESC: [enable the GCC static analyzer], + CHECK_AVAILABLE: [ + AC_MSG_CHECKING([if static analyzer is available]) + if test "x$TOOLCHAIN_TYPE" = "xgcc"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AVAILABLE=false + fi + ], + IF_ENABLED: [ + STATIC_ANALYZER_CFLAGS="-fanalyzer -Wno-analyzer-fd-leak" + CFLAGS_JDKLIB="$CFLAGS_JDKLIB $STATIC_ANALYZER_CFLAGS" + CFLAGS_JDKEXE="$CFLAGS_JDKEXE $STATIC_ANALYZER_CFLAGS" + ]) + AC_SUBST(STATIC_ANALYZER_ENABLED) +]) + ################################################################################ # # LeakSanitizer From a6e2a329a07c71582ac696809fb5349c6a0b681c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 06:48:48 +0000 Subject: [PATCH 296/471] 8366092: [GCC static analyzer] UnixOperatingSystem.c warning: use of uninitialized value 'systemTicks' Reviewed-by: kevinw, asteiner --- .../linux/native/libmanagement_ext/UnixOperatingSystem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c b/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c index af7d52424b7..326dd916f7e 100644 --- a/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c +++ b/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -195,7 +195,7 @@ static int get_jvmticks(ticks *pticks) { uint64_t userTicks; uint64_t systemTicks; - if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) { + if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) { return -1; } From dbac620b996713087f0d1b1189e543e51a0bb09f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 06:56:48 +0000 Subject: [PATCH 297/471] 8366357: C2 SuperWord: refactor VTransformNode::apply with VTransformApplyState Reviewed-by: chagedorn, kvn, mhaessig --- src/hotspot/share/opto/superword.cpp | 19 ++-- src/hotspot/share/opto/vtransform.cpp | 123 ++++++++++++-------------- src/hotspot/share/opto/vtransform.hpp | 63 ++++++++----- 3 files changed, 105 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index cb92febf803..7b47992e77e 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2108,19 +2108,14 @@ void VTransformGraph::apply_memops_reordering_with_schedule() const { void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const { ResourceMark rm; - // We keep track of the resulting Nodes from every "VTransformNode::apply" call. - // Since "apply" is called on defs before uses, this allows us to find the - // generated def (input) nodes when we are generating the use nodes in "apply". - int length = _vtnodes.length(); - GrowableArray vtnode_idx_to_transformed_node(length, length, nullptr); + VTransformApplyState apply_state(_vloop_analyzer, _vtnodes.length()); for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); - VTransformApplyResult result = vtn->apply(_vloop_analyzer, - vtnode_idx_to_transformed_node); + VTransformApplyResult result = vtn->apply(apply_state); NOT_PRODUCT( if (_trace._verbose) { result.trace(vtn); } ) - vtnode_idx_to_transformed_node.at_put(vtn->_idx, result.node()); + apply_state.set_transformed_node(vtn, result.node()); max_vector_length = MAX2(max_vector_length, result.vector_length()); max_vector_width = MAX2(max_vector_width, result.vector_width()); } @@ -3074,7 +3069,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { const bool is_sub = iv_scale * iv_stride > 0; // 1.1: con - Node* xbic = igvn().intcon(is_sub ? -con : con); + Node* xbic = phase()->intcon(is_sub ? -con : con); TRACE_ALIGN_VECTOR_NODE(xbic); // 1.2: invar = SUM(invar_summands) @@ -3091,7 +3086,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { phase()->register_new_node(invar_variable, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(invar_variable); } - Node* invar_scale_con = igvn().intcon(invar_scale); + Node* invar_scale_con = phase()->intcon(invar_scale); TRACE_ALIGN_VECTOR_NODE(invar_scale_con); Node* invar_summand = new MulINode(invar_variable, invar_scale_con); phase()->register_new_node(invar_summand, pre_ctrl); @@ -3143,7 +3138,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { // 2: Compute (14): // XBIC = xbic / abs(iv_scale) // The division is executed as shift - Node* log2_abs_iv_scale = igvn().intcon(exact_log2(abs(iv_scale))); + Node* log2_abs_iv_scale = phase()->intcon(exact_log2(abs(iv_scale))); Node* XBIC = new URShiftINode(xbic, log2_abs_iv_scale); phase()->register_new_node(XBIC, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(log2_abs_iv_scale); @@ -3168,7 +3163,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { // = XBIC_OP_old_limit AND (AW - 1) // Since AW is a power of 2, the modulo operation can be replaced with // a bitmask operation. - Node* mask_AW = igvn().intcon(AW-1); + Node* mask_AW = phase()->intcon(AW-1); Node* adjust_pre_iter = new AndINode(XBIC_OP_old_limit, mask_AW); phase()->register_new_node(adjust_pre_iter, pre_ctrl); TRACE_ALIGN_VECTOR_NODE(mask_AW); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 1675b8d9fdb..f8efe333941 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -203,13 +203,13 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { TRACE_SPECULATIVE_ALIGNMENT_CHECK(node); } - Node* mask_alignment = igvn().intcon(alignment-1); + Node* mask_alignment = phase()->intcon(alignment-1); Node* base_alignment = new AndINode(node, mask_alignment); phase()->register_new_node(base_alignment, ctrl); TRACE_SPECULATIVE_ALIGNMENT_CHECK(mask_alignment); TRACE_SPECULATIVE_ALIGNMENT_CHECK(base_alignment); - Node* zero = igvn().intcon(0); + Node* zero = phase()->intcon(0); Node* cmp_alignment = CmpNode::make(base_alignment, zero, T_INT, false); BoolNode* bol_alignment = new BoolNode(cmp_alignment, BoolTest::eq); phase()->register_new_node(cmp_alignment, ctrl); @@ -697,69 +697,68 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& return false; } -Node* VTransformNode::find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const { - Node* n = vnode_idx_to_transformed_node.at(in_req(i)->_idx); - assert(n != nullptr, "must find input IR node"); +void VTransformApplyState::set_transformed_node(VTransformNode* vtn, Node* n) { + assert(_vtnode_idx_to_transformed_node.at(vtn->_idx) == nullptr, "only set once"); + _vtnode_idx_to_transformed_node.at_put(vtn->_idx, n); +} + +Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { + Node* n = _vtnode_idx_to_transformed_node.at(vtn->_idx); + assert(n != nullptr, "must find IR node for vtnode"); return n; } -VTransformApplyResult VTransformScalarNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformScalarNode::apply(VTransformApplyState& apply_state) const { // This was just wrapped. Now we simply unwap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } -VTransformApplyResult VTransformReplicateNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { - Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); +VTransformApplyResult VTransformReplicateNode::apply(VTransformApplyState& apply_state) const { + Node* val = apply_state.transformed_node(in_req(1)); VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); - register_new_node_from_vectorization(vloop_analyzer, vn, val); + register_new_node_from_vectorization(apply_state, vn, val); return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); } -VTransformApplyResult VTransformConvI2LNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { - Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); +VTransformApplyResult VTransformConvI2LNode::apply(VTransformApplyState& apply_state) const { + Node* val = apply_state.transformed_node(in_req(1)); Node* n = new ConvI2LNode(val); - register_new_node_from_vectorization(vloop_analyzer, n, val); + register_new_node_from_vectorization(apply_state, n, val); return VTransformApplyResult::make_scalar(n); } -VTransformApplyResult VTransformShiftCountNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); - Node* shift_count_in = find_transformed_input(1, vnode_idx_to_transformed_node); +VTransformApplyResult VTransformShiftCountNode::apply(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + Node* shift_count_in = apply_state.transformed_node(in_req(1)); assert(shift_count_in->bottom_type()->isa_int(), "int type only for shift count"); // The shift_count_in would be automatically truncated to the lowest _mask // bits in a scalar shift operation. But vector shift does not truncate, so // we must apply the mask now. - Node* shift_count_masked = new AndINode(shift_count_in, phase->igvn().intcon(_mask)); - register_new_node_from_vectorization(vloop_analyzer, shift_count_masked, shift_count_in); + Node* shift_count_masked = new AndINode(shift_count_in, phase->intcon(_mask)); + register_new_node_from_vectorization(apply_state, shift_count_masked, shift_count_in); // Now that masked value is "boadcast" (some platforms only set the lowest element). VectorNode* vn = VectorNode::shift_count(_shift_opcode, shift_count_masked, _vlen, _element_bt); - register_new_node_from_vectorization(vloop_analyzer, vn, shift_count_in); + register_new_node_from_vectorization(apply_state, vn, shift_count_in); return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); } -VTransformApplyResult VTransformPopulateIndexNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); - Node* val = find_transformed_input(1, vnode_idx_to_transformed_node); +VTransformApplyResult VTransformPopulateIndexNode::apply(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + Node* val = apply_state.transformed_node(in_req(1)); assert(val->is_Phi(), "expected to be iv"); assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); const TypeVect* vt = TypeVect::make(_element_bt, _vlen); - VectorNode* vn = new PopulateIndexNode(val, phase->igvn().intcon(1), vt); - register_new_node_from_vectorization(vloop_analyzer, vn, val); + VectorNode* vn = new PopulateIndexNode(val, phase->intcon(1), vt); + register_new_node_from_vectorization(apply_state, vn, val); return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); } -VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyState& apply_state) const { Node* first = nodes().at(0); uint vlen = nodes().length(); int opc = first->Opcode(); - BasicType bt = vloop_analyzer.types().velt_basic_type(first); + BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); if (first->is_Cmp()) { // Cmp + Bool -> VectorMaskCmp @@ -769,9 +768,9 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer assert(2 <= req() && req() <= 4, "Must have 1-3 inputs"); VectorNode* vn = nullptr; - Node* in1 = find_transformed_input(1, vnode_idx_to_transformed_node); - Node* in2 = (req() >= 3) ? find_transformed_input(2, vnode_idx_to_transformed_node) : nullptr; - Node* in3 = (req() >= 4) ? find_transformed_input(3, vnode_idx_to_transformed_node) : nullptr; + Node* in1 = apply_state.transformed_node(in_req(1)); + Node* in2 = (req() >= 3) ? apply_state.transformed_node(in_req(2)) : nullptr; + Node* in3 = (req() >= 4) ? apply_state.transformed_node(in_req(3)) : nullptr; if (first->is_CMove()) { assert(req() == 4, "three inputs expected: mask, blend1, blend2"); @@ -791,7 +790,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer // The scalar operation was a long -> int operation. // However, the vector operation is long -> long. VectorNode* long_vn = VectorNode::make(opc, in1, nullptr, vlen, T_LONG); - register_new_node_from_vectorization(vloop_analyzer, long_vn, first); + register_new_node_from_vectorization(apply_state, long_vn, first); // Cast long -> int, to mimic the scalar long -> int operation. vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); } else if (req() == 3 || @@ -809,50 +808,47 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(const VLoopAnalyzer vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary } - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); } -VTransformApplyResult VTransformBoolVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& apply_state) const { BoolNode* first = nodes().at(0)->as_Bool(); uint vlen = nodes().length(); - BasicType bt = vloop_analyzer.types().velt_basic_type(first); + BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); // Cmp + Bool -> VectorMaskCmp VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), "bool vtn expects cmp vtn as input"); - Node* cmp_in1 = vtn_cmp->find_transformed_input(1, vnode_idx_to_transformed_node); - Node* cmp_in2 = vtn_cmp->find_transformed_input(2, vnode_idx_to_transformed_node); + Node* cmp_in1 = apply_state.transformed_node(vtn_cmp->in_req(1)); + Node* cmp_in2 = apply_state.transformed_node(vtn_cmp->in_req(2)); BoolTest::mask mask = test()._mask; - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); - ConINode* mask_node = phase->igvn().intcon((int)mask); + PhaseIdealLoop* phase = apply_state.phase(); + ConINode* mask_node = phase->intcon((int)mask); const TypeVect* vt = TypeVect::make(bt, vlen); VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); } -VTransformApplyResult VTransformReductionVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& apply_state) const { Node* first = nodes().at(0); uint vlen = nodes().length(); int opc = first->Opcode(); BasicType bt = first->bottom_type()->basic_type(); - Node* init = find_transformed_input(1, vnode_idx_to_transformed_node); - Node* vec = find_transformed_input(2, vnode_idx_to_transformed_node); + Node* init = apply_state.transformed_node(in_req(1)); + Node* vec = apply_state.transformed_node(in_req(2)); ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); } -VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& apply_state) const { LoadNode* first = nodes().at(0)->as_Load(); uint vlen = nodes().length(); Node* ctrl = first->in(MemNode::Control); @@ -860,14 +856,14 @@ VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop Node* adr = first->in(MemNode::Address); int opc = first->Opcode(); const TypePtr* adr_type = first->adr_type(); - BasicType bt = vloop_analyzer.types().velt_basic_type(first); + BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); // Set the memory dependency of the LoadVector as early as possible. // Walk up the memory chain, and ignore any StoreVector that provably // does not have any memory dependency. - const VPointer& load_p = vpointer(vloop_analyzer); + const VPointer& load_p = vpointer(apply_state.vloop_analyzer()); while (mem->is_StoreVector()) { - VPointer store_p(mem->as_Mem(), vloop_analyzer.vloop()); + VPointer store_p(mem->as_Mem(), apply_state.vloop()); if (store_p.never_overlaps_with(load_p)) { mem = mem->in(MemNode::Memory); } else { @@ -878,12 +874,11 @@ VTransformApplyResult VTransformLoadVectorNode::apply(const VLoopAnalyzer& vloop LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, control_dependency()); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); } -VTransformApplyResult VTransformStoreVectorNode::apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const { +VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& apply_state) const { StoreNode* first = nodes().at(0)->as_Store(); uint vlen = nodes().length(); Node* ctrl = first->in(MemNode::Control); @@ -892,18 +887,18 @@ VTransformApplyResult VTransformStoreVectorNode::apply(const VLoopAnalyzer& vloo int opc = first->Opcode(); const TypePtr* adr_type = first->adr_type(); - Node* value = find_transformed_input(MemNode::ValueIn, vnode_idx_to_transformed_node); + Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(vloop_analyzer, vn); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); } -void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const { - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); +void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { + PhaseIdealLoop* phase = apply_state.phase(); Node* first = nodes().at(0); - register_new_node_from_vectorization(vloop_analyzer, vn, first); + register_new_node_from_vectorization(apply_state, vn, first); for (int i = 0; i < _nodes.length(); i++) { Node* n = _nodes.at(i); @@ -911,8 +906,8 @@ void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scal } } -void VTransformNode::register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const { - PhaseIdealLoop* phase = vloop_analyzer.vloop().phase(); +void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const { + PhaseIdealLoop* phase = apply_state.phase(); phase->register_new_node_with_ctrl_of(vn, old_node); phase->igvn()._worklist.push(vn); VectorNode::trace_new_vector(vn, "AutoVectorization"); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 397d712366b..fb76a3b89d6 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -260,6 +260,32 @@ private: void apply_vectorization() const; }; +// Keeps track of the state during "VTransform::apply" +// -> keep track of the already transformed nodes +class VTransformApplyState : public StackObj { +private: + const VLoopAnalyzer& _vloop_analyzer; + + // We keep track of the resulting Nodes from every "VTransformNode::apply" call. + // Since "apply" is called on defs before uses, this allows us to find the + // generated def (input) nodes when we are generating the use nodes in "apply". + GrowableArray _vtnode_idx_to_transformed_node; + +public: + VTransformApplyState(const VLoopAnalyzer& vloop_analyzer, int num_vtnodes) : + _vloop_analyzer(vloop_analyzer), + _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr) + { + } + + const VLoop& vloop() const { return _vloop_analyzer.vloop(); } + PhaseIdealLoop* phase() const { return vloop().phase(); } + const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } + + void set_transformed_node(VTransformNode* vtn, Node* n); + Node* transformed_node(const VTransformNode* vtn) const; +}; + // The vtnodes (VTransformNode) resemble the C2 IR Nodes, and model a part of the // VTransform. Many such vtnodes make up the VTransformGraph. The vtnodes represent // the resulting scalar and vector nodes as closely as possible. @@ -410,12 +436,11 @@ public: virtual bool is_load_or_store_in_loop() const { return false; } virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const { ShouldNotReachHere(); } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const = 0; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const = 0; Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - void register_new_node_from_vectorization(const VLoopAnalyzer& vloop_analyzer, Node* vn, Node* old_node) const; + void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const; NOT_PRODUCT(virtual const char* name() const = 0;) NOT_PRODUCT(void print() const;) @@ -435,8 +460,7 @@ public: virtual bool is_load_in_loop() const override { return _node->is_Load(); } virtual bool is_load_or_store_in_loop() const override { return _node->is_Load() || _node->is_Store(); } virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return vloop_analyzer.vpointers().vpointer(node()->as_Mem()); } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -462,8 +486,7 @@ private: public: VTransformReplicateNode(VTransform& vtransform, int vlen, BasicType element_type) : VTransformNode(vtransform, 2), _vlen(vlen), _element_type(element_type) {} - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "Replicate"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -472,8 +495,7 @@ public: class VTransformConvI2LNode : public VTransformNode { public: VTransformConvI2LNode(VTransform& vtransform) : VTransformNode(vtransform, 2) {} - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ConvI2L"; };) }; @@ -487,8 +509,7 @@ private: public: VTransformShiftCountNode(VTransform& vtransform, int vlen, BasicType element_bt, juint mask, int shift_opcode) : VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt), _mask(mask), _shift_opcode(shift_opcode) {} - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ShiftCount"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -501,8 +522,7 @@ private: public: VTransformPopulateIndexNode(VTransform& vtransform, int vlen, const BasicType element_bt) : VTransformNode(vtransform, 2), _vlen(vlen), _element_bt(element_bt) {} - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "PopulateIndex"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -523,7 +543,7 @@ public: const GrowableArray& nodes() const { return _nodes; } virtual VTransformVectorNode* isa_Vector() override { return this; } - void register_new_node_from_vectorization_and_replace_scalar_nodes(const VLoopAnalyzer& vloop_analyzer, Node* vn) const; + void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -533,8 +553,7 @@ public: VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : VTransformVectorNode(vtransform, req, number_of_nodes) {} virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) }; @@ -554,8 +573,7 @@ public: VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} VTransformBoolTest test() const { return _test; } virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) }; @@ -565,8 +583,7 @@ public: VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : VTransformVectorNode(vtransform, 3, number_of_nodes) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) }; @@ -592,8 +609,7 @@ public: LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "LoadVector"; };) }; @@ -604,8 +620,7 @@ public: VTransformMemVectorNode(vtransform, 4, number_of_nodes, vpointer) {} virtual VTransformStoreVectorNode* isa_StoreVector() override { return this; } virtual bool is_load_in_loop() const override { return false; } - virtual VTransformApplyResult apply(const VLoopAnalyzer& vloop_analyzer, - const GrowableArray& vnode_idx_to_transformed_node) const override; + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) }; From d5d94db12a6d82a6fe9da18b5f8ce3733a6ee7e7 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 1 Sep 2025 07:43:25 +0000 Subject: [PATCH 298/471] 8357086: os::xxx functions returning memory size should return size_t Reviewed-by: stefank, dholmes --- src/hotspot/os/aix/os_aix.cpp | 37 +++--- src/hotspot/os/aix/os_aix.hpp | 8 +- src/hotspot/os/bsd/os_bsd.cpp | 55 +++++---- src/hotspot/os/bsd/os_bsd.hpp | 8 +- .../os/linux/cgroupSubsystem_linux.cpp | 12 +- src/hotspot/os/linux/cgroupUtil_linux.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 106 +++++++++++------- src/hotspot/os/linux/os_linux.hpp | 8 +- src/hotspot/os/windows/os_windows.cpp | 56 ++++++--- src/hotspot/os/windows/os_windows.hpp | 8 +- src/hotspot/share/compiler/compileBroker.cpp | 4 +- src/hotspot/share/gc/shared/gcInitLogger.cpp | 5 +- src/hotspot/share/gc/z/zLargePages.cpp | 3 +- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 9 +- .../share/jfr/periodic/jfrPeriodic.cpp | 17 ++- .../share/prims/jvmtiRedefineClasses.cpp | 20 ++-- src/hotspot/share/prims/whitebox.cpp | 9 +- src/hotspot/share/runtime/arguments.cpp | 7 +- src/hotspot/share/runtime/os.cpp | 23 ++-- src/hotspot/share/runtime/os.hpp | 12 +- src/hotspot/share/services/heapDumper.cpp | 5 +- src/hotspot/share/services/management.cpp | 2 +- 22 files changed, 254 insertions(+), 162 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index c58e240719b..aa119210f47 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -169,7 +169,7 @@ static void vmembk_print_on(outputStream* os); //////////////////////////////////////////////////////////////////////////////// // global variables (for a description see os_aix.hpp) -julong os::Aix::_physical_memory = 0; +size_t os::Aix::_physical_memory = 0; pthread_t os::Aix::_main_thread = ((pthread_t)0); @@ -254,40 +254,43 @@ static bool is_close_to_brk(address a) { return false; } -julong os::free_memory() { - return Aix::available_memory(); +bool os::free_memory(size_t& value) { + return Aix::available_memory(value); } -julong os::available_memory() { - return Aix::available_memory(); +bool os::available_memory(size_t& value) { + return Aix::available_memory(value); } -julong os::Aix::available_memory() { +bool os::Aix::available_memory(size_t& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { - return mi.real_free; + value = static_cast(mi.real_free); + return true; } else { - return ULONG_MAX; + return false; } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { - return -1; + return false; } - return (jlong)(memory_info.pgsp_total * 4 * K); + value = static_cast(memory_info.pgsp_total * 4 * K); + return true; } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { - return -1; + return false; } - return (jlong)(memory_info.pgsp_free * 4 * K); + value = static_cast(memory_info.pgsp_free * 4 * K); + return true; } -julong os::physical_memory() { +size_t os::physical_memory() { return Aix::physical_memory(); } @@ -326,7 +329,7 @@ void os::Aix::initialize_system_info() { if (!os::Aix::get_meminfo(&mi)) { assert(false, "os::Aix::get_meminfo failed."); } - _physical_memory = (julong) mi.real_total; + _physical_memory = static_cast(mi.real_total); } // Helper function for tracing page sizes. @@ -2193,7 +2196,7 @@ jint os::init_2(void) { os::Posix::init_2(); trcVerbose("processor count: %d", os::_processor_count); - trcVerbose("physical memory: %lu", Aix::_physical_memory); + trcVerbose("physical memory: %zu", Aix::_physical_memory); // Initially build up the loaded dll map. LoadedLibraries::reload(); diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index d17c022e411..1530f2adb76 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -35,7 +35,7 @@ class os::Aix { private: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; // 0 = uninitialized, otherwise 16 bit number: @@ -54,9 +54,9 @@ class os::Aix { // 1 - EXTSHM=ON static int _extshm; - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } static void initialize_system_info(); // OS recognitions (AIX OS level) call this before calling Aix::os_version(). diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 6ef43ba991e..4f5fed2c8c0 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -114,7 +114,7 @@ //////////////////////////////////////////////////////////////////////////////// // global variables -julong os::Bsd::_physical_memory = 0; +size_t os::Bsd::_physical_memory = 0; #ifdef __APPLE__ mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0}; @@ -133,19 +133,19 @@ static volatile int processor_id_next = 0; //////////////////////////////////////////////////////////////////////////////// // utility functions -julong os::available_memory() { - return Bsd::available_memory(); +bool os::available_memory(size_t& value) { + return Bsd::available_memory(value); } -julong os::free_memory() { - return Bsd::available_memory(); +bool os::free_memory(size_t& value) { + return Bsd::available_memory(value); } // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. -julong os::Bsd::available_memory() { - uint64_t available = physical_memory() >> 2; +bool os::Bsd::available_memory(size_t& value) { + uint64_t available = static_cast(physical_memory() >> 2); #ifdef __APPLE__ mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; vm_statistics64_data_t vmstat; @@ -156,9 +156,12 @@ julong os::Bsd::available_memory() { if (kerr == KERN_SUCCESS) { // free_count is just a lowerbound, other page categories can be freed too and make memory available available = (vmstat.free_count + vmstat.inactive_count + vmstat.purgeable_count) * os::vm_page_size(); + } else { + return false; } #endif - return available; + value = static_cast(available); + return true; } // for more info see : @@ -177,33 +180,35 @@ void os::Bsd::print_uptime_info(outputStream* st) { } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { - return -1; + return false; } - return (jlong)vmusage.xsu_total; + value = static_cast(vmusage.xsu_total); + return true; #else - return -1; + return false; #endif } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { - return -1; + return false; } - return (jlong)vmusage.xsu_avail; + value = static_cast(vmusage.xsu_avail); + return true; #else - return -1; + return false; #endif } -julong os::physical_memory() { +size_t os::physical_memory() { return Bsd::physical_memory(); } @@ -281,7 +286,7 @@ void os::Bsd::initialize_system_info() { len = sizeof(mem_val); if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) { assert(len == sizeof(mem_val), "unexpected data size"); - _physical_memory = mem_val; + _physical_memory = static_cast(mem_val); } else { _physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?) } @@ -292,7 +297,7 @@ void os::Bsd::initialize_system_info() { // datasize rlimit restricts us anyway. struct rlimit limits; getrlimit(RLIMIT_DATA, &limits); - _physical_memory = MIN2(_physical_memory, (julong)limits.rlim_cur); + _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); } #endif } @@ -1464,11 +1469,13 @@ void os::print_memory_info(outputStream* st) { st->print("Memory:"); st->print(" %zuk page", os::vm_page_size()>>10); - - st->print(", physical " UINT64_FORMAT "k", - os::physical_memory() >> 10); - st->print("(" UINT64_FORMAT "k free)", - os::available_memory() >> 10); + size_t phys_mem = os::physical_memory(); + st->print(", physical %zuk", + phys_mem >> 10); + size_t avail_mem = 0; + (void)os::available_memory(avail_mem); + st->print("(%zuk free)", + avail_mem >> 10); if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) { if (size >= offset_of(xsw_usage, xsu_used)) { diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 72de9ca5971..173cc5a40ad 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -42,12 +42,12 @@ class os::Bsd { protected: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } static void initialize_system_info(); static void rebuild_cpu_to_node_map(); diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index a9cabc87335..3186d97ec61 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -670,8 +670,8 @@ jlong CgroupSubsystem::memory_limit_in_bytes() { if (!memory_limit->should_check_metric()) { return memory_limit->value(); } - jlong phys_mem = os::Linux::physical_memory(); - log_trace(os, container)("total physical memory: " JLONG_FORMAT, phys_mem); + julong phys_mem = static_cast(os::Linux::physical_memory()); + log_trace(os, container)("total physical memory: " JULONG_FORMAT, phys_mem); jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem); // Update cached metric to avoid re-reading container settings too often memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); @@ -841,19 +841,19 @@ jlong CgroupController::limit_from_str(char* limit_str) { // CgroupSubsystem implementations jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); julong host_swap = os::Linux::host_swap(); return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap); } jlong CgroupSubsystem::memory_and_swap_usage_in_bytes() { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); julong host_swap = os::Linux::host_swap(); return memory_controller()->controller()->memory_and_swap_usage_in_bytes(phys_mem, host_swap); } jlong CgroupSubsystem::memory_soft_limit_in_bytes() { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); } @@ -894,6 +894,6 @@ jlong CgroupSubsystem::cpu_usage_in_micros() { } void CgroupSubsystem::print_version_specific_info(outputStream* st) { - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); memory_controller()->controller()->print_version_specific_info(st, phys_mem); } diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index b52ef87dcae..72dda36504d 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -65,7 +65,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); - julong phys_mem = os::Linux::physical_memory(); + julong phys_mem = static_cast(os::Linux::physical_memory()); char* limit_cg_path = nullptr; jlong limit = mem->read_memory_limit_in_bytes(phys_mem); jlong lowest_limit = limit < 0 ? phys_mem : limit; diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index cee8a11b1d2..ba026442f7f 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -157,7 +157,7 @@ enum CoredumpFilterBit { //////////////////////////////////////////////////////////////////////////////// // global variables -julong os::Linux::_physical_memory = 0; +size_t os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; @@ -232,15 +232,16 @@ julong os::Linux::available_memory_in_container() { return avail_mem; } -julong os::available_memory() { - return Linux::available_memory(); +bool os::available_memory(size_t& value) { + return Linux::available_memory(value); } -julong os::Linux::available_memory() { +bool os::Linux::available_memory(size_t& value) { julong avail_mem = available_memory_in_container(); if (avail_mem != static_cast(-1L)) { log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); - return avail_mem; + value = static_cast(avail_mem); + return true; } FILE *fp = os::fopen("/proc/meminfo", "r"); @@ -255,66 +256,88 @@ julong os::Linux::available_memory() { fclose(fp); } if (avail_mem == static_cast(-1L)) { - avail_mem = free_memory(); + size_t free_mem = 0; + if (!free_memory(free_mem)) { + return false; + } + avail_mem = static_cast(free_mem); } log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); - return avail_mem; + value = static_cast(avail_mem); + return true; } -julong os::free_memory() { - return Linux::free_memory(); +bool os::free_memory(size_t& value) { + return Linux::free_memory(value); } -julong os::Linux::free_memory() { +bool os::Linux::free_memory(size_t& value) { // values in struct sysinfo are "unsigned long" struct sysinfo si; julong free_mem = available_memory_in_container(); if (free_mem != static_cast(-1L)) { log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); - return free_mem; + value = static_cast(free_mem); + return true; } - sysinfo(&si); + int ret = sysinfo(&si); + if (ret != 0) { + return false; + } free_mem = (julong)si.freeram * si.mem_unit; log_trace(os)("free memory: " JULONG_FORMAT, free_mem); - return free_mem; + value = static_cast(free_mem); + return true; } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { if (OSContainer::is_containerized()) { - if (OSContainer::memory_limit_in_bytes() > 0) { - return (jlong)(OSContainer::memory_and_swap_limit_in_bytes() - OSContainer::memory_limit_in_bytes()); + jlong memory_and_swap_limit_in_bytes = OSContainer::memory_and_swap_limit_in_bytes(); + jlong memory_limit_in_bytes = OSContainer::memory_limit_in_bytes(); + if (memory_limit_in_bytes > 0 && memory_and_swap_limit_in_bytes > 0) { + value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); + return true; } - } + } // fallback to the host swap space if the container did return the unbound value of -1 struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { - return -1; + assert(false, "sysinfo failed in total_swap_space(): %s", os::strerror(errno)); + return false; } - return (jlong)(si.totalswap * si.mem_unit); + value = static_cast(si.totalswap * si.mem_unit); + return true; } -static jlong host_free_swap() { +static bool host_free_swap_f(size_t& value) { struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { - return -1; + assert(false, "sysinfo failed in host_free_swap_f(): %s", os::strerror(errno)); + return false; } - return (jlong)(si.freeswap * si.mem_unit); + value = static_cast(si.freeswap * si.mem_unit); + return true; } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { // os::total_swap_space() might return the containerized limit which might be // less than host_free_swap(). The upper bound of free swap needs to be the lower of the two. - jlong host_free_swap_val = MIN2(os::total_swap_space(), host_free_swap()); - assert(host_free_swap_val >= 0, "sysinfo failed?"); + size_t total_swap_space = 0; + size_t host_free_swap = 0; + if (!os::total_swap_space(total_swap_space) || !host_free_swap_f(host_free_swap)) { + return false; + } + size_t host_free_swap_val = MIN2(total_swap_space, host_free_swap); if (OSContainer::is_containerized()) { jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes(); jlong mem_limit = OSContainer::memory_limit_in_bytes(); if (mem_swap_limit >= 0 && mem_limit >= 0) { jlong delta_limit = mem_swap_limit - mem_limit; if (delta_limit <= 0) { - return 0; + value = 0; + return true; } jlong mem_swap_usage = OSContainer::memory_and_swap_usage_in_bytes(); jlong mem_usage = OSContainer::memory_usage_in_bytes(); @@ -322,30 +345,31 @@ jlong os::free_swap_space() { jlong delta_usage = mem_swap_usage - mem_usage; if (delta_usage >= 0) { jlong free_swap = delta_limit - delta_usage; - return free_swap >= 0 ? free_swap : 0; + value = free_swap >= 0 ? static_cast(free_swap) : 0; + return true; } } } // unlimited or not supported. Fall through to return host value log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT - " container_mem_limit=" JLONG_FORMAT " returning host value: " JLONG_FORMAT, + " container_mem_limit=" JLONG_FORMAT " returning host value: %zu", mem_swap_limit, mem_limit, host_free_swap_val); } - return host_free_swap_val; + value = host_free_swap_val; + return true; } -julong os::physical_memory() { - jlong phys_mem = 0; +size_t os::physical_memory() { if (OSContainer::is_containerized()) { jlong mem_limit; if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) { log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit); - return mem_limit; + return static_cast(mem_limit); } } - phys_mem = Linux::physical_memory(); - log_trace(os)("total system memory: " JLONG_FORMAT, phys_mem); + size_t phys_mem = Linux::physical_memory(); + log_trace(os)("total system memory: %zu", phys_mem); return phys_mem; } @@ -520,7 +544,7 @@ void os::Linux::initialize_system_info() { fclose(fp); } } - _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE); + _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); assert(processor_count() > 0, "linux error"); } @@ -2548,11 +2572,13 @@ void os::print_memory_info(outputStream* st) { // values in struct sysinfo are "unsigned long" struct sysinfo si; sysinfo(&si); - - st->print(", physical " UINT64_FORMAT "k", - os::physical_memory() >> 10); - st->print("(" UINT64_FORMAT "k free)", - os::available_memory() >> 10); + size_t phys_mem = physical_memory(); + st->print(", physical %zuk", + phys_mem >> 10); + size_t avail_mem = 0; + (void)os::available_memory(avail_mem); + st->print("(%zuk free)", + avail_mem >> 10); st->print(", swap " UINT64_FORMAT "k", ((jlong)si.totalswap * si.mem_unit) >> 10); st->print("(" UINT64_FORMAT "k free)", diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index bd2e1ea3230..d3e0d6c5668 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -50,11 +50,11 @@ class os::Linux { protected: - static julong _physical_memory; + static size_t _physical_memory; static pthread_t _main_thread; - static julong available_memory(); - static julong free_memory(); + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); static void initialize_system_info(); @@ -117,7 +117,7 @@ class os::Linux { static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; } static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; } - static julong physical_memory() { return _physical_memory; } + static size_t physical_memory() { return _physical_memory; } static julong host_swap(); static intptr_t* ucontext_get_sp(const ucontext_t* uc); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 27bf196075a..3f3d9f6ac63 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -848,39 +848,56 @@ jlong os::elapsed_frequency() { } -julong os::available_memory() { - return win32::available_memory(); +bool os::available_memory(size_t& value) { + return win32::available_memory(value); } -julong os::free_memory() { - return win32::available_memory(); +bool os::free_memory(size_t& value) { + return win32::available_memory(value); } -julong os::win32::available_memory() { +bool os::win32::available_memory(size_t& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - - return (julong)ms.ullAvailPhys; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullAvailPhys); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError()); + return false; + } } -jlong os::total_swap_space() { +bool os::total_swap_space(size_t& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullTotalPageFile; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullTotalPageFile); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::total_swap_space(): %lu", ::GetLastError()); + return false; + } } -jlong os::free_swap_space() { +bool os::free_swap_space(size_t& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); - GlobalMemoryStatusEx(&ms); - return (jlong) ms.ullAvailPageFile; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res == TRUE) { + value = static_cast(ms.ullAvailPageFile); + return true; + } else { + assert(false, "GlobalMemoryStatusEx failed in os::free_swap_space(): %lu", ::GetLastError()); + return false; + } } -julong os::physical_memory() { +size_t os::physical_memory() { return win32::physical_memory(); } @@ -3948,7 +3965,7 @@ int os::current_process_id() { int os::win32::_processor_type = 0; // Processor level is not available on non-NT systems, use vm_version instead int os::win32::_processor_level = 0; -julong os::win32::_physical_memory = 0; +size_t os::win32::_physical_memory = 0; bool os::win32::_is_windows_server = false; @@ -4178,8 +4195,11 @@ void os::win32::initialize_system_info() { // also returns dwAvailPhys (free physical memory bytes), dwTotalVirtual, dwAvailVirtual, // dwMemoryLoad (% of memory in use) - GlobalMemoryStatusEx(&ms); - _physical_memory = ms.ullTotalPhys; + BOOL res = GlobalMemoryStatusEx(&ms); + if (res != TRUE) { + assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError()); + } + _physical_memory = static_cast(ms.ullTotalPhys); if (FLAG_IS_DEFAULT(MaxRAM)) { // Adjust MaxRAM according to the maximum virtual address space available. diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 1aba43fb3d2..1426dc8be93 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -40,7 +40,7 @@ class os::win32 { protected: static int _processor_type; static int _processor_level; - static julong _physical_memory; + static size_t _physical_memory; static bool _is_windows_server; static bool _has_exit_bug; static bool _processor_group_warning_displayed; @@ -102,9 +102,9 @@ class os::win32 { static int processor_level() { return _processor_level; } - static julong available_memory(); - static julong free_memory(); - static julong physical_memory() { return _physical_memory; } + static bool available_memory(size_t& value); + static bool free_memory(size_t& value); + static size_t physical_memory() { return _physical_memory; } // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 177b8b1c161..5f3bdc5ee3c 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1061,7 +1061,9 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { if (new_c2_count <= old_c2_count && new_c1_count <= old_c1_count) return; // Now, we do the more expensive operations. - julong free_memory = os::free_memory(); + size_t free_memory = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_memory(free_memory); // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All). size_t available_cc_np = CodeCache::unallocated_capacity(CodeBlobType::MethodNonProfiled), available_cc_p = CodeCache::unallocated_capacity(CodeBlobType::MethodProfiled); diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp index 91bebf726c1..763c265b65e 100644 --- a/src/hotspot/share/gc/shared/gcInitLogger.cpp +++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp @@ -62,9 +62,8 @@ void GCInitLogger::print_cpu() { } void GCInitLogger::print_memory() { - julong memory = os::physical_memory(); - log_info_p(gc, init)("Memory: " JULONG_FORMAT "%s", - byte_size_in_proper_unit(memory), proper_unit_for_byte_size(memory)); + size_t memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); } void GCInitLogger::print_large_pages() { diff --git a/src/hotspot/share/gc/z/zLargePages.cpp b/src/hotspot/share/gc/z/zLargePages.cpp index 56c94a75713..639c9b0a04f 100644 --- a/src/hotspot/share/gc/z/zLargePages.cpp +++ b/src/hotspot/share/gc/z/zLargePages.cpp @@ -31,7 +31,8 @@ bool ZLargePages::_os_enforced_transparent_mode; void ZLargePages::initialize() { pd_initialize(); - log_info_p(gc, init)("Memory: " JULONG_FORMAT "M", os::physical_memory() / M); + const size_t memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); log_info_p(gc, init)("Large Page Support: %s", to_string()); } diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 1d1f3a62866..57bea5c268b 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -412,9 +412,9 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jclass jvm)) #ifdef LINUX // We want the host memory, not the container limit. // os::physical_memory() would return the container limit. - return os::Linux::physical_memory(); + return static_cast(os::Linux::physical_memory()); #else - return os::physical_memory(); + return static_cast(os::physical_memory()); #endif JVM_END @@ -423,7 +423,10 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) // We want the host swap memory, not the container value. return os::Linux::host_swap(); #else - return os::total_swap_space(); + size_t total_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::total_swap_space(total_swap_space); + return static_cast(total_swap_space); #endif JVM_END diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 49669d1675d..a8a9e191ed8 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -528,17 +528,26 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { * the total memory reported is the amount of memory configured for the guest OS by the hypervisor. */ TRACE_REQUEST_FUNC(PhysicalMemory) { - u8 totalPhysicalMemory = os::physical_memory(); + u8 totalPhysicalMemory = static_cast(os::physical_memory()); EventPhysicalMemory event; event.set_totalSize(totalPhysicalMemory); - event.set_usedSize(totalPhysicalMemory - os::available_memory()); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + event.set_usedSize(totalPhysicalMemory - static_cast(avail_mem)); event.commit(); } TRACE_REQUEST_FUNC(SwapSpace) { EventSwapSpace event; - event.set_totalSize(os::total_swap_space()); - event.set_freeSize(os::free_swap_space()); + size_t total_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::total_swap_space(total_swap_space); + event.set_totalSize(static_cast(total_swap_space)); + size_t free_swap_space = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_swap_space(free_swap_space); + event.set_freeSize(static_cast(free_swap_space)); event.commit(); } diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index e52fdd164f0..dc2d621f694 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1358,10 +1358,12 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // constant pools HandleMark hm(current); InstanceKlass* the_class = get_ik(_class_defs[i].klass); - + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), _class_load_kind, os::available_memory() >> 10); + ("loading name=%s kind=%d (avail_mem=%zuK)", + the_class->external_name(), _class_load_kind, avail_mem >> 10); ClassFileStream st((u1*)_class_defs[i].class_bytes, _class_defs[i].class_byte_count, @@ -1525,9 +1527,10 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { return JVMTI_ERROR_INTERNAL; } } - + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", the_class->external_name(), os::available_memory() >> 10); + ("loaded name=%s (avail_mem=%zuK)", the_class->external_name(), avail_mem >> 10); } return JVMTI_ERROR_NONE; @@ -4435,9 +4438,12 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas ResourceMark rm(current); // increment the classRedefinedCount field in the_class and in any // direct and indirect subclasses of the_class + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); log_info(redefine, class, load) - ("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), os::available_memory() >> 10); + ("redefined name=%s, count=%d (avail_mem=%zuK)", + the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), avail_mem >> 10); Events::log_redefinition(current, "redefined class name=%s, count=%d", the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror())); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 1db9c1c00dd..a22cb9d51ce 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2505,13 +2505,16 @@ WB_END // Physical memory of the host machine (including containers) WB_ENTRY(jlong, WB_HostPhysicalMemory(JNIEnv* env, jobject o)) - LINUX_ONLY(return os::Linux::physical_memory();) - return os::physical_memory(); + LINUX_ONLY(return static_cast(os::Linux::physical_memory());) + return static_cast(os::physical_memory()); WB_END // Available memory of the host machine (container-aware) WB_ENTRY(jlong, WB_HostAvailableMemory(JNIEnv* env, jobject o)) - return os::available_memory(); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + return static_cast(avail_mem); WB_END // Physical swap of the host machine (including containers), Linux only. diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index cc14e5da2c3..063090b93c9 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1517,13 +1517,13 @@ void Arguments::set_heap_size() { !FLAG_IS_DEFAULT(MaxRAM)); if (override_coop_limit) { if (FLAG_IS_DEFAULT(MaxRAM)) { - phys_mem = os::physical_memory(); + phys_mem = static_cast(os::physical_memory()); FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem); } else { phys_mem = (julong)MaxRAM; } } else { - phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) + phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(static_cast(os::physical_memory()), (julong)MaxRAM) : (julong)MaxRAM; } @@ -1645,7 +1645,8 @@ jint Arguments::set_aggressive_heap_flags() { // Thus, we need to make sure we're using a julong for intermediate // calculations. julong initHeapSize; - julong total_memory = os::physical_memory(); + size_t phys_mem = os::physical_memory(); + julong total_memory = static_cast(phys_mem); if (total_memory < (julong) 256 * M) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index e02d13edb8e..3152f734dfa 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1184,9 +1184,10 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { #endif // PRODUCT get_summary_cpu_info(buf, buflen); st->print("%s, ", buf); - size_t mem = physical_memory()/G; + size_t phys_mem = physical_memory(); + size_t mem = phys_mem/G; if (mem == 0) { // for low memory systems - mem = physical_memory()/M; + mem = phys_mem/M; st->print("%d cores, %zuM, ", processor_count(), mem); } else { st->print("%d cores, %zuG, ", processor_count(), mem); @@ -1941,10 +1942,10 @@ bool os::is_server_class_machine() { // We allow some part (1/8?) of the memory to be "missing", // based on the sizes of DIMMs, and maybe graphics cards. const julong missing_memory = 256UL * M; - + size_t phys_mem = os::physical_memory(); /* Is this a server class machine? */ if ((os::active_processor_count() >= (int)server_processors) && - (os::physical_memory() >= (server_memory - missing_memory))) { + (phys_mem >= (server_memory - missing_memory))) { const unsigned int logical_processors = VM_Version::logical_processors_per_package(); if (logical_processors > 1) { @@ -2203,16 +2204,24 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { p2i(addr), p2i(addr) + bytes); } -julong os::used_memory() { +bool os::used_memory(size_t& value) { #ifdef LINUX if (OSContainer::is_containerized()) { jlong mem_usage = OSContainer::memory_usage_in_bytes(); if (mem_usage > 0) { - return mem_usage; + value = static_cast(mem_usage); + return true; + } else { + return false; } } #endif - return os::physical_memory() - os::available_memory(); + size_t avail_mem = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::available_memory(avail_mem); + size_t phys_mem = os::physical_memory(); + value = phys_mem - avail_mem; + return true; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 6d40a646358..9db4380fc07 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -332,14 +332,14 @@ class os: AllStatic { // For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater // than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory // aggressively (e.g. clear caches) so that it becomes available. - static julong available_memory(); - static julong used_memory(); - static julong free_memory(); + [[nodiscard]] static bool available_memory(size_t& value); + [[nodiscard]] static bool used_memory(size_t& value); + [[nodiscard]] static bool free_memory(size_t& value); - static jlong total_swap_space(); - static jlong free_swap_space(); + [[nodiscard]] static bool total_swap_space(size_t& value); + [[nodiscard]] static bool free_swap_space(size_t& value); - static julong physical_memory(); + static size_t physical_memory(); static bool is_server_class_machine(); static size_t rss(); diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index cd679986a6c..59460dbf89b 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2612,7 +2612,10 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool // (DumpWriter buffer, DumperClassCacheTable, GZipCompressor buffers). // For the OOM handling we may already be limited in memory. // Lets ensure we have at least 20MB per thread. - julong max_threads = os::free_memory() / (20 * M); + size_t free_memory = 0; + // Return value ignored - defaulting to 0 on failure. + (void)os::free_memory(free_memory); + julong max_threads = free_memory / (20 * M); if (num_dump_threads > max_threads) { num_dump_threads = MAX2(1, (uint)max_threads); } diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 5b0fc96771a..cfe13d0c8f1 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -975,7 +975,7 @@ static jlong get_long_attribute(jmmLongAttribute att) { return ClassLoadingService::class_method_data_size(); case JMM_OS_MEM_TOTAL_PHYSICAL_BYTES: - return os::physical_memory(); + return static_cast(os::physical_memory()); default: return -1; From a9f3cb23d1802ef3d3042a7f521a0747f70bc732 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 1 Sep 2025 07:47:44 +0000 Subject: [PATCH 299/471] 8366462: Test gc/z/TestCommitFailure.java#Normal failed: expected output missing Reviewed-by: dholmes, eosterlund --- test/hotspot/jtreg/gc/z/TestCommitFailure.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/z/TestCommitFailure.java b/test/hotspot/jtreg/gc/z/TestCommitFailure.java index 3cee84d4f95..c7c8dc12add 100644 --- a/test/hotspot/jtreg/gc/z/TestCommitFailure.java +++ b/test/hotspot/jtreg/gc/z/TestCommitFailure.java @@ -106,7 +106,6 @@ public class TestCommitFailure { ProcessTools.executeTestJava(arguments) .outputTo(System.out) .errorTo(System.out) - .shouldContain("Forced to lower max Java heap size") .shouldHaveExitValue(0); } } From 48f70d7ad85dde49cc8134d4ac0312978a5cc9f7 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 1 Sep 2025 07:50:35 +0000 Subject: [PATCH 300/471] 8361370: runtime/Thread/TestThreadDumpMonitorContention.java fails due to time out on Windows Reviewed-by: dholmes, amenkov --- .../runtime/Thread/TestThreadDumpMonitorContention.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java index c232f257142..a8f8660272d 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java @@ -50,6 +50,11 @@ public class TestThreadDumpMonitorContention { // getJDKTool() which can fall back to "compile.jdk". final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack"); final static String PID = Long.toString(ProcessHandle.current().pid()); + // jstack streaming output should be disabled because if the attach operation is executed at a safepoint, + // the attach streaming output is enabled, and the tool output is lengthy, then we can get both buffers (the attach + // channel and the tool redirection buffer) full and the test hangs. + // Instead the attach operation output is buffered and is sent after the operation is completed. + final static String DISABLE_STREAMING_OUTPUT = "-J-Djdk.attach.allowStreamingOutput=false"; // looking for header lines with these patterns: // "ContendingThread-1" #19 prio=5 os_prio=64 tid=0x000000000079c000 nid=0x23 runnable [0xffff80ffb8b87000] @@ -379,7 +384,7 @@ public class TestThreadDumpMonitorContention { // we don't mix data between the two stack traces that do // match HEADER_PREFIX_PATTERN. // - Process process = new ProcessBuilder(JSTACK, PID) + Process process = new ProcessBuilder(JSTACK, DISABLE_STREAMING_OUTPUT, PID) .redirectErrorStream(true).start(); BufferedReader reader = new BufferedReader(new InputStreamReader( From 3ca44c8dea035588070644e5c1f8f25559f66e53 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 1 Sep 2025 08:03:34 +0000 Subject: [PATCH 301/471] 8364352: Some tests fail when using a limited number of pregenerated .jsa CDS archives Reviewed-by: dholmes, stuefe --- test/hotspot/jtreg/TEST.ROOT | 1 + ...mpressedCPUSpecificClassSpaceReservation.java | 1 + .../runtime/cds/TestDefaultArchiveLoading.java | 16 ++++++++++++---- .../DynamicLoaderConstraintsTest.java | 3 ++- test/jtreg-ext/requires/VMProps.java | 11 +++++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 1857978ebc0..2d0d972744c 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -80,6 +80,7 @@ requires.properties= \ vm.rtm.compiler \ vm.cds \ vm.cds.default.archive.available \ + vm.cds.nocoops.archive.available \ vm.cds.custom.loaders \ vm.cds.supports.aot.class.linking \ vm.cds.supports.aot.code.caching \ diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java index 622573fa709..35e4b9ef233 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java @@ -28,6 +28,7 @@ * @requires vm.bits == 64 & !vm.graal.enabled & vm.debug == true * @requires vm.flagless * @requires vm.cds + * @requires vm.cds.default.archive.available * @requires (os.family != "windows") & (os.family != "aix") * @library /test/lib * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java index 4dd3b63c84a..4bca1ed4581 100644 --- a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java +++ b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java @@ -94,8 +94,8 @@ public class TestDefaultArchiveLoading { "server", archiveName(archiveSuffix)); } - private static boolean isCOHArchiveAvailable(char coops, char coh, - String archiveSuffix) throws Exception { + private static boolean isArchiveAvailable(char coops, char coh, + String archiveSuffix) throws Exception { Path archive= archivePath(archiveSuffix); return Files.exists(archive); } @@ -113,12 +113,16 @@ public class TestDefaultArchiveLoading { case "nocoops_nocoh": coh = coops = '-'; archiveSuffix = "_nocoops"; + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { + throw new SkippedException("Skipping test due to " + + archivePath(archiveSuffix).toString() + " not available"); + } break; case "nocoops_coh": coops = '-'; coh = '+'; archiveSuffix = "_nocoops_coh"; - if (!isCOHArchiveAvailable(coops, coh, archiveSuffix)) { + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { throw new SkippedException("Skipping test due to " + archivePath(archiveSuffix).toString() + " not available"); } @@ -127,11 +131,15 @@ public class TestDefaultArchiveLoading { coops = '+'; coh = '-'; archiveSuffix = ""; + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { + throw new SkippedException("Skipping test due to " + + archivePath(archiveSuffix).toString() + " not available"); + } break; case "coops_coh": coh = coops = '+'; archiveSuffix = "_coh"; - if (!isCOHArchiveAvailable(coops, coh, archiveSuffix)) { + if (!isArchiveAvailable(coops, coh, archiveSuffix)) { throw new SkippedException("Skipping test due to " + archivePath(archiveSuffix).toString() + " not available"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index 91293531611..1d83fb9efa6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -55,6 +55,7 @@ /** * @test id=custom-cl-zgc * @requires vm.cds.custom.loaders + * @requires vm.cds.nocoops.archive.available * @requires vm.gc.Z * @summary Test dumptime_table entries are removed with zgc eager class unloading * @bug 8274935 diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 74ea525b415..96c84115fe3 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -121,6 +121,7 @@ public class VMProps implements Callable> { // vm.cds is true if the VM is compiled with cds support. map.put("vm.cds", this::vmCDS); map.put("vm.cds.default.archive.available", this::vmCDSDefaultArchiveAvailable); + map.put("vm.cds.nocoops.archive.available", this::vmCDSNocoopsArchiveAvailable); map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders); map.put("vm.cds.supports.aot.class.linking", this::vmCDSSupportsAOTClassLinking); map.put("vm.cds.supports.aot.code.caching", this::vmCDSSupportsAOTCodeCaching); @@ -440,6 +441,16 @@ public class VMProps implements Callable> { return "" + ("true".equals(vmCDS()) && Files.exists(archive)); } + /** + * Check for CDS no compressed oops archive existence. + * + * @return true if CDS archive classes_nocoops.jsa exists in the JDK to be tested. + */ + protected String vmCDSNocoopsArchiveAvailable() { + Path archive = Paths.get(System.getProperty("java.home"), "lib", "server", "classes_nocoops.jsa"); + return "" + ("true".equals(vmCDS()) && Files.exists(archive)); + } + /** * Check for CDS support for custom loaders. * From fe4c7a0429a2cf9ef47701d68d0852ce44e1a9ab Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Mon, 1 Sep 2025 08:07:08 +0000 Subject: [PATCH 302/471] 8364135: JPEGImageReader.getImageTypes() should throw exception for negative image index Reviewed-by: aivanov, prr, psadhukhan --- .../imageio/plugins/jpeg/JPEGImageReader.java | 14 ++- .../jpeg/JpegNegativeImageIndexTest.java | 85 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 77c15c7c7fc..1d6bf2dbf8a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -391,6 +391,12 @@ public class JPEGImageReader extends ImageReader { tablesOnlyChecked = true; } + private void verifyImageIndex(int imageIndex) { + if (imageIndex < minIndex) { + throw new IndexOutOfBoundsException("imageIndex < " + minIndex); + } + } + @Override public int getNumImages(boolean allowSearch) throws IOException { setThreadLock(); @@ -497,9 +503,7 @@ public class JPEGImageReader extends ImageReader { if (iis == null) { throw new IllegalStateException("Input not set"); } - if (imageIndex < minIndex) { - throw new IndexOutOfBoundsException(); - } + verifyImageIndex(imageIndex); if (!tablesOnlyChecked) { checkTablesOnly(); } @@ -842,6 +846,7 @@ public class JPEGImageReader extends ImageReader { public int getWidth(int imageIndex) throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); readHeader(imageIndex, true); @@ -856,6 +861,7 @@ public class JPEGImageReader extends ImageReader { public int getHeight(int imageIndex) throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); readHeader(imageIndex, true); @@ -886,6 +892,7 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); if (currentImage != imageIndex) { cbLock.check(); @@ -904,6 +911,7 @@ public class JPEGImageReader extends ImageReader { throws IOException { setThreadLock(); try { + verifyImageIndex(imageIndex); return getImageTypesOnThread(imageIndex); } finally { clearThreadLock(); diff --git a/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java b/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java new file mode 100644 index 00000000000..87843f16853 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/jpeg/JpegNegativeImageIndexTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8364135 + * @summary Test verifies that jpeg image reader throws + * IndexOutOfBoundsException when "-1" image index is used. + * @run main JpegNegativeImageIndexTest + */ + +import java.io.IOException; +import java.util.Iterator; +import java.util.concurrent.Callable; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; + +public class JpegNegativeImageIndexTest { + + private static boolean failed; + + private static void checkException(boolean exceptionReceived, + String testName) { + if (!exceptionReceived) { + System.out.println("Didn't receive IndexOutOfBoundsException for " + + testName); + failed = true; + } + } + + private static void testMethod(String methodName, + Callable method) { + boolean exceptionReceived = false; + System.out.println("Testing " + methodName); + try { + method.call(); + } catch (Exception e) { + if (e instanceof IndexOutOfBoundsException) { + exceptionReceived = true; + } + } + checkException(exceptionReceived, methodName); + } + + public static void main(String[] args) throws IOException { + Iterator readers = + ImageIO.getImageReadersByFormatName("jpeg"); + if (!readers.hasNext()) { + throw new RuntimeException("No jpeg image readers found"); + } + + ImageReader ir = readers.next(); + + testMethod("getImageTypes()", () -> ir.getImageTypes(-1)); + testMethod("getWidth()", () -> ir.getWidth(-1)); + testMethod("getHeight()", () -> ir.getHeight(-1)); + testMethod("getRawImageType()", () -> ir.getRawImageType(-1)); + + if (failed) { + throw new RuntimeException("JpegImageReader didn't throw required" + + " IndexOutOfBoundsException for -1 image index"); + } + } +} From 56713817c0fd060f7106a538b0e795081f4f9d4b Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 08:47:19 +0000 Subject: [PATCH 303/471] 8366361: C2 SuperWord: rename VTransformNode::set_req -> init_req, analogue to Node::init_req Reviewed-by: kvn, chagedorn --- .../share/opto/superwordVTransformBuilder.cpp | 46 +++++++++---------- .../share/opto/superwordVTransformBuilder.hpp | 4 +- src/hotspot/share/opto/vtransform.hpp | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index 404eb02372e..d178fd4394c 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -68,29 +68,29 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { - set_req_with_scalar(p0, vtn, MemNode::Address); + init_req_with_scalar(p0, vtn, MemNode::Address); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (p0->is_Store()) { - set_req_with_scalar(p0, vtn, MemNode::Address); - set_req_with_vector(pack, vtn, MemNode::ValueIn); + init_req_with_scalar(p0, vtn, MemNode::Address); + init_req_with_vector(pack, vtn, MemNode::ValueIn); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (vtn->isa_ReductionVector() != nullptr) { - set_req_with_scalar(p0, vtn, 1); // scalar init - set_req_with_vector(pack, vtn, 2); // vector + init_req_with_scalar(p0, vtn, 1); // scalar init + init_req_with_vector(pack, vtn, 2); // vector } else { assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); if (VectorNode::is_scalar_rotate(p0) && p0->in(2)->is_Con() && Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { - set_req_with_vector(pack, vtn, 1); - set_req_with_scalar(p0, vtn, 2); // constant rotation + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rotation } else if (VectorNode::is_roundopD(p0)) { - set_req_with_vector(pack, vtn, 1); - set_req_with_scalar(p0, vtn, 2); // constant rounding mode + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rounding mode } else if (p0->is_CMove()) { // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. set_all_req_with_vectors(pack, vtn); @@ -113,18 +113,18 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. if (n->is_Load()) { - set_req_with_scalar(n, vtn, MemNode::Address); + init_req_with_scalar(n, vtn, MemNode::Address); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_Store()) { - set_req_with_scalar(n, vtn, MemNode::Address); - set_req_with_scalar(n, vtn, MemNode::ValueIn); + init_req_with_scalar(n, vtn, MemNode::Address); + init_req_with_scalar(n, vtn, MemNode::ValueIn); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_CountedLoop()) { continue; // Is "root", has no dependency. } else if (n->is_Phi()) { // CountedLoop Phi's: ignore backedge (and entry value). assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); - set_req_with_scalar(n, vtn, 0); + init_req_with_scalar(n, vtn, 0); continue; } else { set_all_req_with_scalars(n, vtn); @@ -177,9 +177,9 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co return vtn; } -void SuperWordVTransformBuilder::set_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { +void SuperWordVTransformBuilder::init_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); - vtn->set_req(index, req); + vtn->init_req(index, req); } // Either get the existing vtnode vector input (when input is a pack), or else make a @@ -217,7 +217,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // the ConvI2L/F/D. BasicType element_bt = is_subword_type(p0_bt) ? p0_bt : T_INT; VTransformNode* populate_index = new (_vtransform.arena()) VTransformPopulateIndexNode(_vtransform, pack->size(), element_bt); - populate_index->set_req(1, iv_vtn); + populate_index->init_req(1, iv_vtn); return populate_index; } @@ -230,7 +230,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i BasicType element_bt = _vloop_analyzer.types().velt_basic_type(p0); juint mask = (p0->bottom_type() == TypeInt::INT) ? (BitsPerInt - 1) : (BitsPerLong - 1); VTransformNode* shift_count = new (_vtransform.arena()) VTransformShiftCountNode(_vtransform, pack->size(), element_bt, mask, p0->Opcode()); - shift_count->set_req(1, same_input_vtn); + shift_count->init_req(1, same_input_vtn); return shift_count; } else { // Replicate the scalar same_input to every vector element. @@ -245,11 +245,11 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // Scalar rotate has int rotation value, but the scalar rotate expects longs. assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); - conv->set_req(1, same_input_vtn); + conv->init_req(1, same_input_vtn); same_input_vtn = conv; } VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_type); - replicate->set_req(1, same_input_vtn); + replicate->init_req(1, same_input_vtn); return replicate; } } @@ -274,9 +274,9 @@ VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(N return vtn; } -void SuperWordVTransformBuilder::set_req_with_vector(const Node_List* pack, VTransformNode* vtn, int j) { +void SuperWordVTransformBuilder::init_req_with_vector(const Node_List* pack, VTransformNode* vtn, int j) { VTransformNode* req = get_or_make_vtnode_vector_input_at_index(pack, j); - vtn->set_req(j, req); + vtn->init_req(j, req); } void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { @@ -284,7 +284,7 @@ void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNod for (uint j = 0; j < n->req(); j++) { Node* def = n->in(j); if (def == nullptr) { continue; } - set_req_with_scalar(n, vtn, j); + init_req_with_scalar(n, vtn, j); } } @@ -295,7 +295,7 @@ void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, for (uint j = 1; j < vtn->req(); j++) { Node* def = p0->in(j); if (def == nullptr) { continue; } - set_req_with_vector(pack, vtn, j); + init_req_with_vector(pack, vtn, j); } } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index f2198113d31..fd85b87f825 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -77,8 +77,8 @@ private: VTransformVectorNode* make_vector_vtnode_for_pack(const Node_List* pack) const; VTransformNode* get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index); VTransformNode* get_vtnode_or_wrap_as_input_scalar(Node* n); - void set_req_with_scalar(Node* n, VTransformNode* vtn, const int index); - void set_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); + void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); + void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); void set_all_req_with_scalars(Node* n, VTransformNode* vtn); void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index fb76a3b89d6..74905bc6915 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -341,7 +341,7 @@ public: vtransform.graph().add_vtnode(this); } - void set_req(uint i, VTransformNode* n) { + void init_req(uint i, VTransformNode* n) { assert(i < _req, "must be a req"); assert(_in.at(i) == nullptr && n != nullptr, "only set once"); _in.at_put(i, n); From dacd9af9a02464d2d6144e29d851216641e836c9 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Mon, 1 Sep 2025 08:50:08 +0000 Subject: [PATCH 304/471] 8329829: HttpClient: Add a BodyPublishers.ofFileChannel method Reviewed-by: dfuchs, jpai, michaelm --- .../classes/java/net/http/HttpRequest.java | 44 +- .../internal/net/http/RequestPublishers.java | 80 +- .../jdk/internal/net/http/common/Utils.java | 22 + .../httpclient/FileChannelPublisherTest.java | 708 ++++++++++++++++++ 4 files changed, 849 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/net/httpclient/FileChannelPublisherTest.java diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index 7ba6ed25b41..84a521336b6 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,13 +26,13 @@ package java.net.http; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.OpenOption; import java.nio.file.Path; import java.time.Duration; import java.util.Iterator; @@ -720,6 +720,44 @@ public abstract class HttpRequest { return RequestPublishers.FilePublisher.create(path); } + /** + * {@return a request body publisher whose body is the {@code length} + * content bytes read from the provided file {@code channel} starting + * from the specified {@code offset}} + *

          + * This method and the returned {@code BodyPublisher} do not modify the + * {@code channel}'s position, and do not close the {@code channel}. The + * caller is expected to close the {@code channel} when no longer needed. + * + * @apiNote + * This method can be used to either publish just a region of a file as + * the request body or to publish different regions of a file + * concurrently. A typical usage would be to publish different regions + * of a file by creating a single instance of {@link FileChannel} and + * then send multiple concurrent {@code HttpRequest}s, each of which + * uses a new {@code ofFileChannel BodyPublisher} created from the same + * channel with a different, typically non-overlapping, range of bytes + * specified by offset and length. + * + * @param channel a file channel + * @param offset the offset of the first byte + * @param length the number of bytes to read from the file channel + * + * @throws IndexOutOfBoundsException if the specified byte range is + * found to be {@linkplain Objects#checkFromIndexSize(long, long, long) + * out of bounds} compared with the size of the file referred by the + * channel + * + * @throws IOException if the {@linkplain FileChannel#size() channel's + * size} cannot be determined or the {@code channel} is closed + * + * @since 26 + */ + public static BodyPublisher ofFileChannel(FileChannel channel, long offset, long length) throws IOException { + Objects.requireNonNull(channel, "channel"); + return new RequestPublishers.FileChannelPublisher(channel, offset, length); + } + /** * A request body publisher that takes data from an {@code Iterable} * of byte arrays. An {@link Iterable} is provided which supplies diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java index dd5443c5035..88cabe15419 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java @@ -32,6 +32,7 @@ import java.io.UncheckedIOException; import java.lang.reflect.UndeclaredThrowableException; import java.net.http.HttpRequest.BodyPublisher; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -418,6 +419,81 @@ public final class RequestPublishers { } } + public static final class FileChannelPublisher implements BodyPublisher { + + private final FileChannel channel; + + private final long position; + + private final long limit; + + public FileChannelPublisher(FileChannel channel, long offset, long length) throws IOException { + this.channel = Objects.requireNonNull(channel, "channel"); + long fileSize = channel.size(); + Objects.checkFromIndexSize(offset, length, fileSize); + this.position = offset; + this.limit = offset + length; + } + + @Override + public long contentLength() { + return limit - position; + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + Iterable iterable = () -> new FileChannelIterator(channel, position, limit); + new PullPublisher<>(iterable).subscribe(subscriber); + } + + } + + private static final class FileChannelIterator implements Iterator { + + private final FileChannel channel; + + private final long limit; + + private long position; + + private boolean terminated; + + private FileChannelIterator(FileChannel channel, long position, long limit) { + this.channel = channel; + this.position = position; + this.limit = limit; + } + + @Override + public boolean hasNext() { + return position < limit && !terminated; + } + + @Override + public ByteBuffer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + long remaining = limit - position; + ByteBuffer buffer = Utils.getBufferWithAtMost(remaining); + try { + int readLength = channel.read(buffer, position); + // Short-circuit if `read()` has failed, e.g., due to file content being changed in the meantime + if (readLength < 0) { + // Throw to signal that the request needs to be cancelled + throw new IOException("Unexpected EOF (position=%s)".formatted(position)); + } else { + position += readLength; + } + } catch (IOException ioe) { + terminated = true; + throw new UncheckedIOException(ioe); + } + return buffer.flip(); + } + + } + public static final class PublisherAdapter implements BodyPublisher { private final Publisher publisher; @@ -430,12 +506,12 @@ public final class RequestPublishers { } @Override - public final long contentLength() { + public long contentLength() { return contentLength; } @Override - public final void subscribe(Flow.Subscriber subscriber) { + public void subscribe(Flow.Subscriber subscriber) { publisher.subscribe(subscriber); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index b10c7cd5957..bcedff8844e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -392,10 +392,32 @@ public final class Utils { public static IllegalArgumentException newIAE(String message, Object... args) { return new IllegalArgumentException(format(message, args)); } + + /** + * {@return a new {@link ByteBuffer} instance of {@link #BUFSIZE} capacity} + */ public static ByteBuffer getBuffer() { return ByteBuffer.allocate(BUFSIZE); } + /** + * {@return a new {@link ByteBuffer} instance whose capacity is set to the + * smaller of the specified {@code maxCapacity} and the default + * ({@value BUFSIZE})} + * + * @param maxCapacity a buffer capacity, in bytes + * @throws IllegalArgumentException if {@code maxCapacity < 0} + */ + public static ByteBuffer getBufferWithAtMost(long maxCapacity) { + if (maxCapacity < 0) { + throw new IllegalArgumentException( + // Match the message produced by `ByteBuffer::createCapacityException` + "capacity < 0: (%s < 0)".formatted(maxCapacity)); + } + int effectiveCapacity = (int) Math.min(maxCapacity, BUFSIZE); + return ByteBuffer.allocate(effectiveCapacity); + } + public static Throwable getCompletionCause(Throwable x) { Throwable cause = x; while ((cause instanceof CompletionException) diff --git a/test/jdk/java/net/httpclient/FileChannelPublisherTest.java b/test/jdk/java/net/httpclient/FileChannelPublisherTest.java new file mode 100644 index 00000000000..5b064efa078 --- /dev/null +++ b/test/jdk/java/net/httpclient/FileChannelPublisherTest.java @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verifies `HttpRequest.BodyPublishers::ofFileChannel` + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit FileChannelPublisherTest + */ + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpResponse.BodyHandlers.discarding; +import static java.net.http.HttpResponse.BodyHandlers.ofInputStream; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FileChannelPublisherTest { + + private static final String CLASS_NAME = FileChannelPublisherTest.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final int DEFAULT_BUFFER_SIZE = Utils.getBuffer().capacity(); + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + private static final HttpClient CLIENT = HttpClient.newBuilder().sslContext(SSL_CONTEXT).proxy(NO_PROXY).build(); + + private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); + + private static final ServerRequestPair + HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false), + HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true), + HTTP2 = ServerRequestPair.of(Version.HTTP_2, false), + HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private record ServerRequestPair( + String serverName, + HttpTestServer server, + BlockingQueue serverReadRequestBodyBytes, + HttpRequest.Builder requestBuilder, + boolean secure) { + + private static CountDownLatch SERVER_REQUEST_RECEIVED_SIGNAL = null; + + private static CountDownLatch SERVER_READ_PERMISSION = null; + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server + SSLContext sslContext = secure ? SSL_CONTEXT : null; + HttpTestServer server = createServer(version, sslContext); + String serverName = secure ? version.toString().replaceFirst("_", "S_") : version.toString(); + + // Add the handler + String handlerPath = "/%s/".formatted(CLASS_NAME); + BlockingQueue serverReadRequestBodyBytes = + addRequestBodyConsumingServerHandler(serverName, server, handlerPath); + + // Create the request builder + String requestUriScheme = secure ? "https" : "http"; + // `x` suffix in the URI is not a typo, but ensures that *only* the parent handler path is matched + URI requestUri = URI.create("%s://%s%sx".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(requestUri).version(version); + + // Create the pair + ServerRequestPair pair = new ServerRequestPair(serverName, server, serverReadRequestBodyBytes, requestBuilder, secure); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", pair, server.serverAuthority()); + + return pair; + + } + + private static HttpTestServer createServer(Version version, SSLContext sslContext) { + try { + // The default HTTP/1.1 test server processes requests sequentially. + // This causes a deadlock for concurrent tests such as `testSlicedUpload()`. + // Hence, explicitly providing a multithreaded executor for HTTP/1.1. + ExecutorService executor = Version.HTTP_1_1.equals(version) ? EXECUTOR : null; + return HttpTestServer.create(version, sslContext, executor); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + private static BlockingQueue addRequestBodyConsumingServerHandler( + String serverName, HttpTestServer server, String handlerPath) { + BlockingQueue readRequestBodyBytes = new LinkedBlockingQueue<>(); + HttpTestHandler handler = exchange -> { + // `HttpTestExchange::toString` changes on failure, pin it + String exchangeName = exchange.toString(); + try (exchange) { + + // Discard `HEAD` requests used for initial connection admission + if ("HEAD".equals(exchange.getRequestMethod())) { + exchange.sendResponseHeaders(200, -1L); + return; + } + + signalServerRequestReceived(serverName, exchangeName); + awaitServerReadPermission(serverName, exchangeName); + + LOGGER.log("Server[%s] is reading the request body (exchange=%s)", serverName, exchangeName); + byte[] requestBodyBytes = exchange.getRequestBody().readAllBytes(); + LOGGER.log("Server[%s] has read %s bytes (exchange=%s)", serverName, requestBodyBytes.length, exchangeName); + readRequestBodyBytes.add(requestBodyBytes); + + LOGGER.log("Server[%s] is writing the response (exchange=%s)", serverName, exchangeName); + exchange.sendResponseHeaders(200, requestBodyBytes.length); + exchange.getResponseBody().write(requestBodyBytes); + + } catch (Throwable exception) { + LOGGER.log( + "Server[%s] failed to process the request (exchange=%s)".formatted(serverName, exception), + exception); + readRequestBodyBytes.add(new byte[0]); + } finally { + LOGGER.log("Server[%s] completed processing the request (exchange=%s)", serverName, exchangeName); + } + }; + server.addHandler(handler, handlerPath); + return readRequestBodyBytes; + } + + private static void signalServerRequestReceived(String serverName, String exchangeName) { + if (SERVER_REQUEST_RECEIVED_SIGNAL != null) { + LOGGER.log("Server[%s] is signaling that the request is received (exchange=%s)", serverName, exchangeName); + SERVER_REQUEST_RECEIVED_SIGNAL.countDown(); + } + } + + private static void awaitServerReadPermission(String serverName, String exchangeName) { + if (SERVER_READ_PERMISSION != null) { + LOGGER.log("Server[%s] is waiting for the read permission (exchange=%s)", serverName, exchangeName); + try { + SERVER_READ_PERMISSION.await(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); // Restore the `interrupted` flag + throw new RuntimeException(ie); + } + } + } + + @Override + public String toString() { + return serverName; + } + + } + + @AfterAll + static void shutDown() { + LOGGER.log("Closing the client"); + CLIENT.close(); + LOGGER.log("Closing servers"); + closeServers(); + LOGGER.log("Closing the executor"); + EXECUTOR.shutdownNow(); + } + + private static void closeServers() { + Exception[] exceptionRef = {null}; + Stream + .of(HTTP1, HTTPS1, HTTP2, HTTPS2) + .map(pair -> (Runnable) pair.server::stop) + .forEach(terminator -> { + try { + terminator.run(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + } + + /** + * Resets {@link ServerRequestPair#serverReadRequestBodyBytes()} to avoid leftover state from a test leaking to the next. + */ + @BeforeEach + void resetServerHandlerResults() { + Stream + .of(HTTP1, HTTPS1, HTTP2, HTTPS2) + .forEach(pair -> pair.serverReadRequestBodyBytes.clear()); + } + + static ServerRequestPair[] serverRequestPairs() { + return new ServerRequestPair[]{ + HTTP1, + HTTPS1, + HTTP2, + HTTPS2 + }; + } + + @Test + void testNullFileChannel() { + assertThrows(NullPointerException.class, () -> BodyPublishers.ofFileChannel(null, 0, 1)); + } + + @ParameterizedTest + @CsvSource({ + "6,-1,1", // offset < 0 + "6,7,1", // offset > fileSize + "6,0,-1", // length < 0 + "6,0,7", // length > fileSize + "6,2,5" // (offset + length) > fileSize + }) + void testIllegalOffsetOrLength( + int fileLength, + int fileChannelOffset, + int fileChannelLength, + @TempDir Path tempDir) throws Exception { + withFileChannel(tempDir.resolve("data.txt"), fileLength, (_, fileChannel) -> + assertThrows( + IndexOutOfBoundsException.class, + () -> BodyPublishers.ofFileChannel(fileChannel, fileChannelOffset, fileChannelLength))); + } + + /** + * Stresses corner cases in {@linkplain + * BodyPublishers#ofFileChannel(FileChannel, long, long) the file channel + * publisher}, which uses a {@linkplain #DEFAULT_BUFFER_SIZE fixed size} + * buffer to read files, by providing sub-ranges and files that are + * smaller than the buffer size. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testContentLessThanBufferSize(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Use a file of length smaller than the default buffer size + int fileLength = 6; + assertTrue(fileLength < DEFAULT_BUFFER_SIZE); + + // Publish the `[0, fileLength)` sub-range + testSuccessfulContentDelivery( + "Complete content", + pair, tempDir, fileLength, 0, fileLength); + + // Publish the `[1, fileLength)` sub-range to stress the inclusion of EOF + { + int fileChannelOffset = 1; + int fileChannelLength = fileLength - 1; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength - 1)` sub-range to stress the exclusion of EOF + { + int fileChannelOffset = 1; + int fileChannelLength = fileLength - 2; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + } + + /** + * Stresses corner cases in {@linkplain + * BodyPublishers#ofFileChannel(FileChannel, long, long) the file channel + * publisher}, which uses a {@linkplain #DEFAULT_BUFFER_SIZE fixed size} + * buffer to read files, by providing sub-ranges and files that are + * bigger than the buffer size. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testContentMoreThanBufferSize(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Use a file of length that is + // 1. greater than the default buffer size + // 2. *not* a multitude of the buffer size + int fileLength = 1 + 3 * DEFAULT_BUFFER_SIZE; + + // Publish the `[0, fileLength)` sub-range + testSuccessfulContentDelivery( + "Complete content", + pair, tempDir, fileLength, 0, fileLength); + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is included + // - the total length is a multitude of the buffer size + { + int fileChannelOffset = 1; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF. Occupies exactly 3 buffers. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is included + // - the total length is *not* a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE - 1; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertEquals( + fileLength - fileChannelOffset, fileChannelLength, + "must be until EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content until the EOF. Occupies 3 buffers, the last is custom sized. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is *not* included + // - the total length is a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 2 * DEFAULT_BUFFER_SIZE; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF. Occupies exactly 2 buffers. " + debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + // Publish the `[1, fileLength)` sub-range such that + // - EOF is *not* included + // - the total length is *not* a multitude of the buffer size + { + int fileChannelOffset = 2; + int fileChannelLength = 3 * DEFAULT_BUFFER_SIZE - 2; + String debuggingContext = debuggingContext(fileLength, fileChannelOffset, fileChannelLength); + assertTrue( + fileLength - fileChannelOffset > fileChannelLength, + "must end before EOF " + debuggingContext); + testSuccessfulContentDelivery( + "Partial content *before* the EOF. Occupies 3 buffers, the last is custom sized. "+ debuggingContext, + pair, tempDir, fileLength, fileChannelOffset, fileChannelLength); + } + + } + + private static String debuggingContext(int fileLength, int fileChannelOffset, int fileChannelLength) { + Map context = new LinkedHashMap<>(); // Using `LHM` to preserve the insertion order + context.put("DEFAULT_BUFFER_SIZE", DEFAULT_BUFFER_SIZE); + context.put("fileLength", fileLength); + context.put("fileChannelOffset", fileChannelOffset); + context.put("fileChannelLength", fileChannelLength); + boolean customSizedBuffer = fileChannelLength % DEFAULT_BUFFER_SIZE == 0; + context.put("customSizedBuffer", customSizedBuffer); + return context.toString(); + } + + private void testSuccessfulContentDelivery( + String caseDescription, + ServerRequestPair pair, + Path tempDir, + int fileLength, + int fileChannelOffset, + int fileChannelLength) throws Exception { + + // Case names come handy even when no debug logging is enabled. + // Hence, intentionally avoiding `Logger`. + System.err.printf("Case: %s%n", caseDescription); + + // Create the file to upload + String fileName = "data-%d-%d-%d.txt".formatted(fileLength, fileChannelOffset, fileChannelLength); + Path filePath = tempDir.resolve(fileName); + withFileChannel(filePath, fileLength, (fileBytes, fileChannel) -> { + + // Upload the file + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, fileChannelOffset, fileChannelLength)) + .build(); + CLIENT.send(request, discarding()); + + // Verify the received request body + byte[] expectedRequestBodyBytes = new byte[fileChannelLength]; + System.arraycopy(fileBytes, fileChannelOffset, expectedRequestBodyBytes, 0, fileChannelLength); + byte[] actualRequestBodyBytes = pair.serverReadRequestBodyBytes.take(); + assertArrayEquals(expectedRequestBodyBytes, actualRequestBodyBytes); + + }); + + } + + /** + * Big enough file length to observe the effects of publisher state corruption while uploading. + *

          + * Certain tests follow below steps: + *

          + *
            + *
          1. Issue the request
          2. + *
          3. Wait for the server's signal that the request (not the body!) is received
          4. + *
          5. Corrupt the publisher's state; modify the file, close the file channel, etc.
          6. + *
          7. Signal the server to proceed with reading
          8. + *
          + *

          + * With small files, even before we permit the server to read (step 4), file gets already uploaded. + * This voids the effect of state corruption (step 3). + * To circumvent this, use this big enough file size. + *

          + * + * @see #testChannelCloseDuringPublisherRead(ServerRequestPair, Path) + * @see #testFileModificationDuringPublisherRead(ServerRequestPair, Path) + */ + private static final int BIG_FILE_LENGTH = 8 * 1024 * 1024; // 8 MiB + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testChannelCloseDuringPublisherRead(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + establishInitialConnection(pair); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = new CountDownLatch(1); + ServerRequestPair.SERVER_READ_PERMISSION = new CountDownLatch(1); + try { + + int fileLength = BIG_FILE_LENGTH; + AtomicReference>> responseFutureRef = new AtomicReference<>(); + withFileChannel(tempDir.resolve("data.txt"), fileLength, ((_, fileChannel) -> { + + // Issue the request + LOGGER.log("Issuing the request"); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, 0, fileLength)) + .build(); + responseFutureRef.set(CLIENT.sendAsync(request, discarding())); + + // Wait for server to receive the request + LOGGER.log("Waiting for the request to be received"); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL.await(); + + })); + + LOGGER.log("File channel is closed"); + + // Let the server proceed + LOGGER.log("Permitting the server to proceed"); + ServerRequestPair.SERVER_READ_PERMISSION.countDown(); + + // Verifying the client failure + LOGGER.log("Verifying the client failure"); + Exception requestFailure0 = assertThrows(ExecutionException.class, () -> responseFutureRef.get().get()); + Exception requestFailure1 = assertInstanceOf(UncheckedIOException.class, requestFailure0.getCause()); + assertInstanceOf(ClosedChannelException.class, requestFailure1.getCause()); + + verifyServerIncompleteRead(pair, fileLength); + + } finally { + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = null; + ServerRequestPair.SERVER_READ_PERMISSION = null; + } + } + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testFileModificationDuringPublisherRead(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + establishInitialConnection(pair); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = new CountDownLatch(1); + ServerRequestPair.SERVER_READ_PERMISSION = new CountDownLatch(1); + try { + + int fileLength = BIG_FILE_LENGTH; + Path filePath = tempDir.resolve("data.txt"); + withFileChannel(filePath, fileLength, ((_, fileChannel) -> { + + // Issue the request + LOGGER.log("Issuing the request"); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, 0, fileLength)) + .build(); + Future> responseFuture = CLIENT.sendAsync(request, discarding()); + + // Wait for server to receive the request + LOGGER.log("Waiting for the request to be received"); + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL.await(); + + // Modify the file + LOGGER.log("Modifying the file"); + Files.write(filePath, generateFileBytes(1)); + + // Let the server proceed + LOGGER.log("Permitting the server to proceed"); + ServerRequestPair.SERVER_READ_PERMISSION.countDown(); + + // Verifying the client failure + LOGGER.log("Verifying the client failure"); + Exception requestFailure0 = assertThrows(ExecutionException.class, responseFuture::get); + Exception requestFailure1 = assertInstanceOf(UncheckedIOException.class, requestFailure0.getCause()); + Exception requestFailure2 = assertInstanceOf(IOException.class, requestFailure1.getCause()); + String requestFailure2Message = requestFailure2.getMessage(); + assertTrue( + requestFailure2Message.contains("Unexpected EOF"), + "unexpected message: " + requestFailure2Message); + + verifyServerIncompleteRead(pair, fileLength); + + })); + + } finally { + ServerRequestPair.SERVER_REQUEST_RECEIVED_SIGNAL = null; + ServerRequestPair.SERVER_READ_PERMISSION = null; + } + } + + private static void verifyServerIncompleteRead(ServerRequestPair pair, int fileLength) throws InterruptedException { + LOGGER.log("Verifying the server's incomplete read"); + byte[] readRequestBodyBytes = pair.serverReadRequestBodyBytes.take(); + assertTrue( + readRequestBodyBytes.length < fileLength, + "was expecting `readRequestBodyBytes < fileLength` (%s < %s)".formatted( + readRequestBodyBytes.length, fileLength)); + } + + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSlicedUpload(ServerRequestPair pair, @TempDir Path tempDir) throws Exception { + + // Populate the file + int sliceCount = 4; + int sliceLength = 14_281; // Intentionally using a prime number to increase the chances of hitting corner cases + int fileLength = sliceCount * sliceLength; + byte[] fileBytes = generateFileBytes(fileLength); + Path filePath = tempDir.resolve("data.txt"); + Files.write(filePath, fileBytes, StandardOpenOption.CREATE); + + List responseBodyStreams = new ArrayList<>(sliceCount); + try (FileChannel fileChannel = FileChannel.open(filePath)) { + + // Upload the complete file in mutually exclusive slices + List>> responseFutures = new ArrayList<>(sliceCount); + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Issuing request %d/%d", (sliceIndex + 1), sliceCount); + HttpRequest request = pair + .requestBuilder + .POST(BodyPublishers.ofFileChannel(fileChannel, sliceIndex * sliceLength, sliceLength)) + .build(); + responseFutures.add(CLIENT.sendAsync( + request, + // Intentionally using an `InputStream` response + // handler to defer consuming the response body + // until after the file channel is closed: + ofInputStream())); + } + + // Collect response body `InputStream`s from all requests + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Collecting response body `InputStream` for request %d/%d", (sliceIndex + 1), sliceCount); + HttpResponse response = responseFutures.get(sliceIndex).get(); + assertEquals(200, response.statusCode()); + responseBodyStreams.add(response.body()); + } + + } + + LOGGER.log("File channel is closed"); + + // Verify response bodies + for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { + LOGGER.log("Consuming response body %d/%d", (sliceIndex + 1), sliceCount); + byte[] expectedResponseBodyBytes = new byte[sliceLength]; + System.arraycopy(fileBytes, sliceIndex * sliceLength, expectedResponseBodyBytes, 0, sliceLength); + try (InputStream responseBodyStream = responseBodyStreams.get(sliceIndex)) { + byte[] responseBodyBytes = responseBodyStream.readAllBytes(); + assertArrayEquals(expectedResponseBodyBytes, responseBodyBytes); + } + } + + } + + /** + * Performs the initial {@code HEAD} request to the specified server. This + * effectively admits a connection to the client's pool, where all protocol + * upgrades, handshakes, etc. are already performed. + *

          + * HTTP/2 test server consumes the complete request payload in the very + * first upgrade frame. That is, if a client sends 100 MiB of data, all + * of it will be consumed first before the configured handler is + * invoked. Though certain tests expect the data to be consumed + * piecemeal. To accommodate this, we ensure client has an upgraded + * connection in the pool. + *

          + */ + private static void establishInitialConnection(ServerRequestPair pair) { + LOGGER.log("Server[%s] is getting queried for the initial connection pool admission", pair); + try { + CLIENT.send(pair.requestBuilder.HEAD().build(), discarding()); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + } + + private static void withFileChannel(Path filePath, int fileLength, FileChannelConsumer fileChannelConsumer) throws Exception { + byte[] fileBytes = generateFileBytes(fileLength); + Files.write(filePath, fileBytes, StandardOpenOption.CREATE); + try (FileChannel fileChannel = FileChannel.open(filePath)) { + fileChannelConsumer.consume(fileBytes, fileChannel); + } + } + + @FunctionalInterface + private interface FileChannelConsumer { + + void consume(byte[] fileBytes, FileChannel fileChannel) throws Exception; + + } + + private static byte[] generateFileBytes(int length) { + byte[] bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = (byte) i; + } + return bytes; + } + +} From fc77e7600f217cc91c24d4e512c685e176a66e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 1 Sep 2025 08:55:23 +0000 Subject: [PATCH 305/471] 8365791: IGV: Update build dependencies Reviewed-by: chagedorn, ayang --- src/utils/IdealGraphVisualizer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/IdealGraphVisualizer/pom.xml b/src/utils/IdealGraphVisualizer/pom.xml index 7f9bd67af42..8fdb182ed90 100644 --- a/src/utils/IdealGraphVisualizer/pom.xml +++ b/src/utils/IdealGraphVisualizer/pom.xml @@ -116,7 +116,7 @@ 3.3.0 3.4.1 4.13.2 - 1.17 + 1.19 1.3.34 1.6.2 idealgraphvisualizer From 7f0cd6488ba969d5cffe8ebe9b95e4ad70982188 Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Mon, 1 Sep 2025 09:18:29 +0000 Subject: [PATCH 306/471] 8361582: AArch64: Some ConH values cannot be replicated with SVE Reviewed-by: shade, epeter, aph --- src/hotspot/cpu/aarch64/aarch64.ad | 35 +++-- src/hotspot/cpu/aarch64/aarch64_vector.ad | 32 +++-- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 32 +++-- src/hotspot/cpu/aarch64/assembler_aarch64.cpp | 5 + src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 1 + .../c2/aarch64/TestFloat16Replicate.java | 136 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 10 ++ 7 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 9697ac31350..33466453b76 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -4412,10 +4412,9 @@ operand immI8() %} // 8 bit signed value (simm8), or #simm8 LSL 8. -operand immI8_shift8() +operand immIDupV() %{ - predicate((n->get_int() <= 127 && n->get_int() >= -128) || - (n->get_int() <= 32512 && n->get_int() >= -32768 && (n->get_int() & 0xff) == 0)); + predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->get_int())); match(ConI); op_cost(0); @@ -4424,10 +4423,9 @@ operand immI8_shift8() %} // 8 bit signed value (simm8), or #simm8 LSL 8. -operand immL8_shift8() +operand immLDupV() %{ - predicate((n->get_long() <= 127 && n->get_long() >= -128) || - (n->get_long() <= 32512 && n->get_long() >= -32768 && (n->get_long() & 0xff) == 0)); + predicate(Assembler::operand_valid_for_sve_dup_immediate(n->get_long())); match(ConL); op_cost(0); @@ -4435,6 +4433,17 @@ operand immL8_shift8() interface(CONST_INTER); %} +// 8 bit signed value (simm8), or #simm8 LSL 8. +operand immHDupV() +%{ + predicate(Assembler::operand_valid_for_sve_dup_immediate((int64_t)n->geth())); + match(ConH); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 8 bit integer valid for vector add sub immediate operand immBAddSubV() %{ @@ -7077,18 +7086,16 @@ instruct loadConD(vRegD dst, immD con) %{ %} // Load Half Float Constant -// The "ldr" instruction loads a 32-bit word from the constant pool into a -// 32-bit register but only the bottom half will be populated and the top -// 16 bits are zero. instruct loadConH(vRegF dst, immH con) %{ match(Set dst con); - format %{ - "ldrs $dst, [$constantaddress]\t# load from constant table: half float=$con\n\t" - %} + format %{ "mov rscratch1, $con\n\t" + "fmov $dst, rscratch1" + %} ins_encode %{ - __ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con)); + __ movw(rscratch1, (uint32_t)$con$$constant); + __ fmovs($dst$$FloatRegister, rscratch1); %} - ins_pipe(fp_load_constant_s); + ins_pipe(pipe_class_default); %} // Store Instructions diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 58300992c2a..67c4dad27a7 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -4875,7 +4875,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{ ins_pipe(pipe_slow); %} -instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{ +instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16 && (Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); @@ -4898,7 +4898,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{ ins_pipe(pipe_slow); %} -instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ +instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16); match(Set dst (Replicate con)); format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %} @@ -4909,19 +4909,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} -// Replicate a 16-bit half precision float value -instruct replicateHF_imm(vReg dst, immH con) %{ +// Replicate an immediate 16-bit half precision float value +instruct replicateHF_imm_le128b(vReg dst, immH con) %{ + predicate(Matcher::vector_length_in_bytes(n) <= 16); match(Set dst (Replicate con)); - format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %} ins_encode %{ - uint length_in_bytes = Matcher::vector_length_in_bytes(this); int imm = (int)($con$$constant) & 0xffff; - if (VM_Version::use_neon_for_vector(length_in_bytes)) { - __ mov($dst$$FloatRegister, get_arrangement(this), imm); - } else { // length_in_bytes must be > 16 and SVE should be enabled - assert(UseSVE > 0, "must be sve"); - __ sve_dup($dst$$FloatRegister, __ H, imm); - } + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + %} + ins_pipe(pipe_slow); +%} + +// Replicate a 16-bit half precision float which is within the limits +// for the operand - immHDupV +instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{ + predicate(Matcher::vector_length_in_bytes(n) > 16); + match(Set dst (Replicate con)); + format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant)); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 4d91e04dc21..28f91204ec3 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -3107,7 +3107,7 @@ instruct replicateB_imm8_gt128b(vReg dst, immI8 con) %{ ins_pipe(pipe_slow); %} -instruct replicateI_imm8_gt128b(vReg dst, immI8_shift8 con) %{ +instruct replicateI_imm8_gt128b(vReg dst, immIDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16 && (Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); @@ -3130,7 +3130,7 @@ instruct replicateL_imm_128b(vReg dst, immL con) %{ ins_pipe(pipe_slow); %} -instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ +instruct replicateL_imm8_gt128b(vReg dst, immLDupV con) %{ predicate(Matcher::vector_length_in_bytes(n) > 16); match(Set dst (Replicate con)); format %{ "replicateL_imm8_gt128b $dst, $con\t# vector > 128 bits" %} @@ -3141,19 +3141,27 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} -// Replicate a 16-bit half precision float value -instruct replicateHF_imm(vReg dst, immH con) %{ +// Replicate an immediate 16-bit half precision float value +instruct replicateHF_imm_le128b(vReg dst, immH con) %{ + predicate(Matcher::vector_length_in_bytes(n) <= 16); match(Set dst (Replicate con)); - format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + format %{ "replicateHF_imm_le128b $dst, $con\t# vector <= 128 bits" %} ins_encode %{ - uint length_in_bytes = Matcher::vector_length_in_bytes(this); int imm = (int)($con$$constant) & 0xffff; - if (VM_Version::use_neon_for_vector(length_in_bytes)) { - __ mov($dst$$FloatRegister, get_arrangement(this), imm); - } else { // length_in_bytes must be > 16 and SVE should be enabled - assert(UseSVE > 0, "must be sve"); - __ sve_dup($dst$$FloatRegister, __ H, imm); - } + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + %} + ins_pipe(pipe_slow); +%} + +// Replicate a 16-bit half precision float which is within the limits +// for the operand - immHDupV +instruct replicateHF_imm8_gt128b(vReg dst, immHDupV con) %{ + predicate(Matcher::vector_length_in_bytes(n) > 16); + match(Set dst (Replicate con)); + format %{ "replicateHF_imm8_gt128b $dst, $con\t# vector > 128 bits" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, (int)($con$$constant)); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index 5e5d6c16b45..fe1792ed1c6 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -434,6 +434,11 @@ int Assembler::operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement return -1; } +bool Assembler::operand_valid_for_sve_dup_immediate(int64_t imm) { + return ((imm >= -128 && imm <= 127) || + (((imm & 0xff) == 0) && imm >= -32768 && imm <= 32512)); +} + bool Assembler::operand_valid_for_sve_logical_immediate(unsigned elembits, uint64_t imm) { return encode_sve_logical_immediate(elembits, imm) != 0xffffffff; } diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 11d302e9026..4b0a0e77915 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -4324,6 +4324,7 @@ public: static bool operand_valid_for_sve_add_sub_immediate(int64_t imm); static bool operand_valid_for_float_immediate(double imm); static int operand_valid_for_movi_immediate(uint64_t imm64, SIMD_Arrangement T); + static bool operand_valid_for_sve_dup_immediate(int64_t imm); void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java new file mode 100644 index 00000000000..ab7808a0401 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java @@ -0,0 +1,136 @@ +/* Copyright (c) 2025, Arm 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +* @test +* @bug 8361582 +* @summary Ensure the correct backend replicate node is being generated for +* half precision float constants on >16B SVE machines +* @modules jdk.incubator.vector +* @library /test/lib / +* @run main/othervm compiler.c2.aarch64.TestFloat16Replicate +*/ + +package compiler.c2.aarch64; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import java.util.Arrays; +import java.util.Random; +import jdk.incubator.vector.Float16; +import jdk.test.lib.*; +import jdk.test.lib.Utils; + +import static java.lang.Float.*; +import static jdk.incubator.vector.Float16.*; + +public class TestFloat16Replicate { + private static short[] input; + private static short[] output; + private static short[] expected; + private static Random rnd; + + // Choose FP16_IMM8 which is within the range of [-128 << 8, 127 << 8] and a multiple of 256 + private static final Float16 FP16_IMM8; + + // Choose a value in the range [-128 << 8, 127 << 8] and a non multiple of 256 for FP16_NON_IMM8 + private static final Float16 FP16_NON_IMM8; + + private static final int LEN = 1024; + + public static void main(String args[]) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation"); + } + + static { + rnd = Utils.getRandomInstance(); + int k = rnd.nextInt(-128, 128); + int b = rnd.nextInt(1, 256); + short bits_imm8 = (short) (k << 8); + short bits_non_imm8 = (short) ((k << 8) + b); + + FP16_IMM8 = Float16.shortBitsToFloat16(bits_imm8); + FP16_NON_IMM8 = Float16.shortBitsToFloat16(bits_non_imm8); + + input = new short[LEN]; + output = new short[LEN]; + expected = new short[LEN]; + + for (int i = 0; i < LEN; i++) { + input[i] = (short) i; + } + } + + // For vectorizable loops containing FP16 operations with an FP16 constant as one of the inputs, the IR + // node `(dst (Replicate con))` is generated to broadcast the constant into all lanes of an SVE register. + // On SVE-capable hardware with vector length > 16B, if the FP16 immediate is a signed value within the + // range [-128, 127] or a signed multiple of 256 in the range [-32768, 32512] for element widths of + // 16 bits or higher then the backend should generate the "replicateHF_imm_gt128b" machnode. + @Test + @Warmup(5000) + @IR(counts = {IRNode.REPLICATE_HF_IMM8, ">0"}, + phase = CompilePhase.FINAL_CODE, + applyIf = {"MaxVectorSize", ">16"}, + applyIfCPUFeature = {"sve", "true"}) + public void TestFloat16AddInRange() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(Float16.add(shortBitsToFloat16(input[i]), FP16_IMM8)); + } + } + + @Check(test="TestFloat16AddInRange") + public void checkResultFloat16AddInRange() { + for (int i = 0; i < LEN; ++i) { + expected[i] = floatToFloat16(float16ToFloat(input[i]) + FP16_IMM8.floatValue()); + } + Verify.checkEQWithRawBits(output, expected); + } + + // For vectorizable loops containing FP16 operations with an FP16 constant as one of the inputs, the IR + // node `(dst (Replicate con))` is generated to broadcast the constant into all lanes of an SVE register. + // On SVE-capable hardware with vector length > 16B, if the FP16 constant falls outside the immediate + // range accepted by the SVE "dup" instruction, the backend must: + // 1. Generate the "loadConH" machnode to load the FP16 constant from the constant pool. + // 2. Emit the "replicateHF" machnode to broadcast this loaded constant into an SVE register. + // In this case, the backend should not generate the "replicateHF_imm8_gt128b" machnode. + @Test + @Warmup(5000) + @IR(counts = {IRNode.REPLICATE_HF, ">0"}, + failOn = {IRNode.REPLICATE_HF_IMM8}, + phase = CompilePhase.FINAL_CODE, + applyIf = {"MaxVectorSize", ">16"}, + applyIfCPUFeature = {"sve", "true"}) + public void TestFloat16AddOutOfRange() { + for (int i = 0; i < LEN; ++i) { + output[i] = float16ToRawShortBits(add(shortBitsToFloat16(input[i]), FP16_NON_IMM8)); + } + } + + @Check(test="TestFloat16AddOutOfRange") + public void checkResultFloat16AddOutOfRange() { + for (int i = 0; i < LEN; ++i) { + expected[i] = floatToFloat16(float16ToFloat(input[i]) + FP16_NON_IMM8.floatValue()); + } + Verify.checkEQWithRawBits(output, expected); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 7fb1eeb800c..16c6d99a64f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2896,6 +2896,16 @@ public class IRNode { vectorNode(SELECT_FROM_TWO_VECTOR_VL, "SelectFromTwoVector", TYPE_LONG); } + public static final String REPLICATE_HF = PREFIX + "REPLICATE_HF" + POSTFIX; + static { + machOnlyNameRegex(REPLICATE_HF, "replicateHF"); + } + + public static final String REPLICATE_HF_IMM8 = PREFIX + "REPLICATE_HF_IMM8" + POSTFIX; + static { + machOnlyNameRegex(REPLICATE_HF_IMM8, "replicateHF_imm8_gt128b"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ From 98af18921aa3c274ef7ece03005337b58df3da96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 1 Sep 2025 09:24:52 +0000 Subject: [PATCH 307/471] 8366456: Allow AllocFailStrategy for RBTree Reviewed-by: cnorrbin, aboldtch --- src/hotspot/share/utilities/rbTree.hpp | 26 +++++++---- test/hotspot/gtest/utilities/test_rbtree.cpp | 46 ++++++++++++-------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 405fa3e9ae9..cc52cec3fe0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -61,7 +61,6 @@ // used for extra validation can optionally be provided. This should return: // - true if a < b // - false otherwise -// ALLOCATOR must check for oom and exit, as RBTree does not handle the allocation failing. // K needs to be of a type that is trivially destructible. // The tree will call a value's destructor when its node is removed. // Nodes are address stable and will not change during its lifetime. @@ -468,13 +467,17 @@ public: RBNode* allocate_node(const K& key) { void* node_place = _allocator.allocate(sizeof(RBNode)); - assert(node_place != nullptr, "rb-tree allocator must exit on failure"); + if (node_place == nullptr) { + return nullptr; + } return new (node_place) RBNode(key); } RBNode* allocate_node(const K& key, const V& val) { void* node_place = _allocator.allocate(sizeof(RBNode)); - assert(node_place != nullptr, "rb-tree allocator must exit on failure"); + if (node_place == nullptr) { + return nullptr; + } return new (node_place) RBNode(key, val); } @@ -485,16 +488,21 @@ public: // Inserts a node with the given key/value into the tree, // if the key already exist, the value is updated instead. - void upsert(const K& key, const V& val, const RBNode* hint_node = nullptr) { + // Returns false if and only if allocation of a new node failed. + bool upsert(const K& key, const V& val, const RBNode* hint_node = nullptr) { Cursor node_cursor = cursor(key, hint_node); RBNode* node = node_cursor.node(); if (node != nullptr) { node->set_val(val); - return; + return true; } node = allocate_node(key, val); + if (node == nullptr) { + return false; + } insert_at_cursor(node, node_cursor); + return true; } // Finds the value of the node associated with the given key. @@ -545,12 +553,12 @@ public: } }; -template +template class RBTreeCHeapAllocator { public: void* allocate(size_t sz) { void* allocation = os::malloc(sz, mem_tag); - if (allocation == nullptr) { + if (allocation == nullptr && strategy == AllocFailStrategy::EXIT_OOM) { vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "red-black tree failed allocation"); } @@ -560,8 +568,8 @@ public: void free(void* ptr) { os::free(ptr); } }; -template -using RBTreeCHeap = RBTree>; +template +using RBTreeCHeap = RBTree>; template using IntrusiveRBTree = AbstractRBTree; diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index e1be83bfd58..d8394de017e 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -986,23 +986,23 @@ struct IntCmp { }; TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { - typedef RBTree > TreeType; - TreeType tree; - const int i1 = 82924; - const char* const s1 = "[82924] = 1"; - const int i2 = -13591; - const char* const s2 = "[-13591] = 2"; - const int i3 = 0; - const char* const s3 = "[0] = 3"; - tree.upsert(i1, 1U); - tree.upsert(i2, 2U); - tree.upsert(i3, 3U); - stringStream ss; - tree.print_on(&ss); - const char* const N = nullptr; - ASSERT_NE(strstr(ss.base(), s1), N); - ASSERT_NE(strstr(ss.base(), s2), N); - ASSERT_NE(strstr(ss.base(), s3), N); + using TreeType = RBTreeCHeap; + TreeType tree; + const int i1 = 82924; + const char* const s1 = "[82924] = 1"; + const int i2 = -13591; + const char* const s2 = "[-13591] = 2"; + const int i3 = 0; + const char* const s3 = "[0] = 3"; + tree.upsert(i1, 1U); + tree.upsert(i2, 2U); + tree.upsert(i3, 3U); + stringStream ss; + tree.print_on(&ss); + const char* const N = nullptr; + ASSERT_NE(strstr(ss.base(), s1), N); + ASSERT_NE(strstr(ss.base(), s2), N); + ASSERT_NE(strstr(ss.base(), s3), N); } TEST_VM_F(RBTreeTest, IntrusiveTest) { @@ -1079,3 +1079,15 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } +struct OomAllocator { + void* allocate(size_t sz) { + return nullptr; + } + void free(void* ptr) {} +}; +TEST_VM_F(RBTreeTest, AllocatorMayReturnNull) { + RBTree rbtree; + bool success = rbtree.upsert(5, 5); + EXPECT_EQ(false, success); + // The test didn't exit the VM, so it was succesful. +} From 5110d54d938b7afbdf9cfbc4501674ef7bc1d518 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 1 Sep 2025 13:08:53 +0000 Subject: [PATCH 308/471] 8365922: Parallel: Group uses of GCTimeRatio to a single location Reviewed-by: tschatzl, phh --- .../gc/parallel/parallelScavengeHeap.cpp | 3 +- .../gc/parallel/psAdaptiveSizePolicy.cpp | 28 +++++++++++++------ .../gc/parallel/psAdaptiveSizePolicy.hpp | 3 +- .../share/gc/shared/adaptiveSizePolicy.cpp | 11 +------- .../share/gc/shared/adaptiveSizePolicy.hpp | 7 +---- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 07ae097c5b8..45c364ab35a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -103,8 +103,7 @@ jint ParallelScavengeHeap::initialize() { double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; _size_policy = new PSAdaptiveSizePolicy(SpaceAlignment, - max_gc_pause_sec, - GCTimeRatio); + max_gc_pause_sec); assert((old_gen()->virtual_space()->high_boundary() == young_gen()->virtual_space()->low_boundary()), diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index 5d99095c1ed..1e4bd6c2868 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -36,10 +36,8 @@ #include PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t space_alignment, - double gc_pause_goal_sec, - uint gc_cost_ratio) : - AdaptiveSizePolicy(gc_pause_goal_sec, - gc_cost_ratio), + double gc_pause_goal_sec) : + AdaptiveSizePolicy(gc_pause_goal_sec), _avg_promoted(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, PromotedPadding)), _space_alignment(space_alignment), _young_gen_size_increment_supplement(YoungGenerationSizeSupplement) {} @@ -73,14 +71,28 @@ void PSAdaptiveSizePolicy::print_stats(bool is_survivor_overflowing) { is_survivor_overflowing ? "true" : "false"); } +// The throughput goal is implemented as +// _throughput_goal = 1 - (1 / (1 + gc_cost_ratio)) +// gc_cost_ratio is the ratio +// application cost / gc cost +// For example a gc_cost_ratio of 4 translates into a +// throughput goal of .80 +static double calculate_throughput_goal(double gc_cost_ratio) { + return 1.0 - (1.0 / (1.0 + gc_cost_ratio)); +} + size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflowing, size_t cur_eden) { // Guard against divide-by-zero; 0.001ms double gc_distance = MAX2(_gc_distance_seconds_seq.last(), 0.000001); double min_gc_distance = MinGCDistanceSecond; - if (mutator_time_percent() < _throughput_goal) { + // Get a local copy and use it inside gc-pause in case the global var gets updated externally. + const uint local_GCTimeRatio = Atomic::load(&GCTimeRatio); + const double throughput_goal = calculate_throughput_goal(local_GCTimeRatio); + + if (mutator_time_percent() < throughput_goal) { size_t new_eden; - const double expected_gc_distance = _trimmed_minor_gc_time_seconds.last() * GCTimeRatio; + const double expected_gc_distance = _trimmed_minor_gc_time_seconds.last() * local_GCTimeRatio; if (gc_distance >= expected_gc_distance) { // The lastest sample already satisfies throughput goal; keep the current size new_eden = cur_eden; @@ -90,7 +102,7 @@ size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflow (double)increase_eden(cur_eden)); } log_debug(gc, ergo)("Adaptive: throughput (actual vs goal): %.3f vs %.3f ; eden delta: + %zu K", - mutator_time_percent(), _throughput_goal, (new_eden - cur_eden)/K); + mutator_time_percent(), throughput_goal, (new_eden - cur_eden)/K); return new_eden; } @@ -118,7 +130,7 @@ size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflow // promoted_bytes_estimate() / (gc_distance + gc_time_lower_estimate) < 1M/s // ==> promoted_bytes_estimate() / M - gc_time_lower_estimate < gc_distance - const double gc_distance_target = MAX3(minor_gc_time_conservative_estimate() * GCTimeRatio, + const double gc_distance_target = MAX3(minor_gc_time_conservative_estimate() * local_GCTimeRatio, promoted_bytes_estimate() / M - gc_time_lower_estimate, min_gc_distance); double predicted_gc_distance = gc_distance * (1 - delta_factor) - _gc_distance_seconds_seq.dsd(); diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp index 68c736d0716..2b4bd2b6807 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp @@ -61,8 +61,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { // NEEDS_CLEANUP this is a singleton object PSAdaptiveSizePolicy(size_t space_alignment, - double gc_pause_goal_sec, - uint gc_time_ratio); + double gc_pause_goal_sec); // Methods indicating events of interest to the adaptive size policy, // called by GC algorithms. It is the responsibility of users of this diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp index 9a699921caa..b048c7dd79a 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp @@ -31,16 +31,7 @@ elapsedTimer AdaptiveSizePolicy::_minor_timer; elapsedTimer AdaptiveSizePolicy::_major_timer; -// The throughput goal is implemented as -// _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio)) -// gc_cost_ratio is the ratio -// application cost / gc cost -// For example a gc_cost_ratio of 4 translates into a -// throughput goal of .80 - -AdaptiveSizePolicy::AdaptiveSizePolicy(double gc_pause_goal_sec, - uint gc_cost_ratio) : - _throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))), +AdaptiveSizePolicy::AdaptiveSizePolicy(double gc_pause_goal_sec) : _gc_distance_timer(), _gc_distance_seconds_seq(seq_default_alpha_value), _trimmed_minor_gc_time_seconds(NumOfGCSample, seq_default_alpha_value), diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp index a3848079a76..89d419c28fa 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp @@ -47,10 +47,6 @@ class AdaptiveSizePolicy : public CHeapObj { static constexpr double MinGCDistanceSecond = 0.100; static_assert(MinGCDistanceSecond >= 0.001, "inv"); - // Goal for the fraction of the total time during which application - // threads run - const double _throughput_goal; - // pause and interval times for collections static elapsedTimer _minor_timer; @@ -170,8 +166,7 @@ class AdaptiveSizePolicy : public CHeapObj { size_t eden_increment(size_t cur_eden, uint percent_change); public: - AdaptiveSizePolicy(double gc_pause_goal_sec, - uint gc_cost_ratio); + AdaptiveSizePolicy(double gc_pause_goal_sec); void record_gc_pause_end_instant() { _gc_distance_timer.reset(); From 99223eea03e2ed714f7a5408c356fdf06efc9200 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Sep 2025 13:48:25 +0000 Subject: [PATCH 309/471] 8366427: C2 SuperWord: refactor VTransform scalar nodes Reviewed-by: mhaessig, chagedorn, kvn --- .../share/opto/superwordVTransformBuilder.cpp | 28 +++-- .../share/opto/superwordVTransformBuilder.hpp | 2 +- src/hotspot/share/opto/vtransform.cpp | 53 +++++++- src/hotspot/share/opto/vtransform.hpp | 117 +++++++++++++----- 4 files changed, 157 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index d178fd4394c..b31f2eda9c0 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -53,7 +53,19 @@ void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { Node* n = _vloop_analyzer.body().body().at(i); if (_packset.get_pack(n) != nullptr) { continue; } - VTransformScalarNode* vtn = new (_vtransform.arena()) VTransformScalarNode(_vtransform, n); + + VTransformNode* vtn = nullptr; + if (n->is_Load() || n->is_Store()) { + MemNode* mem = n->as_Mem(); + const VPointer& mem_p = _vloop_analyzer.vpointers().vpointer(mem); + vtn = new (_vtransform.arena()) VTransformMemopScalarNode(_vtransform, mem, mem_p); + } else if (n->is_Phi()) { + vtn = new (_vtransform.arena()) VTransformLoopPhiNode(_vtransform, n->as_Phi()); + } else if (n->is_CFG()) { + vtn = new (_vtransform.arena()) VTransformCFGNode(_vtransform, n); + } else { + vtn = new (_vtransform.arena()) VTransformDataScalarNode(_vtransform, n); + } map_node_to_vtnode(n, vtn); } } @@ -108,8 +120,8 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies) { for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { Node* n = _vloop_analyzer.body().body().at(i); - VTransformScalarNode* vtn = get_vtnode(n)->isa_Scalar(); - if (vtn == nullptr) { continue; } + VTransformNode* vtn = get_vtnode(n); + if (vtn->isa_Vector() != nullptr) { continue; } vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. if (n->is_Load()) { @@ -178,7 +190,7 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co } void SuperWordVTransformBuilder::init_req_with_scalar(Node* n, VTransformNode* vtn, const int index) { - VTransformNode* req = get_vtnode_or_wrap_as_input_scalar(n->in(index)); + VTransformNode* req = get_vtnode_or_wrap_as_outer(n->in(index)); vtn->init_req(index, req); } @@ -210,7 +222,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i Node* same_input = _packset.same_inputs_at_index_or_null(pack, index); if (same_input == nullptr && p0->in(index) == _vloop.iv()) { // PopulateIndex: [iv+0, iv+1, iv+2, ...] - VTransformNode* iv_vtn = get_vtnode_or_wrap_as_input_scalar(_vloop.iv()); + VTransformNode* iv_vtn = get_vtnode_or_wrap_as_outer(_vloop.iv()); BasicType p0_bt = _vloop_analyzer.types().velt_basic_type(p0); // If we have subword type, take that type directly. If p0 is some ConvI2L/F/D, // then the p0_bt can also be L/F/D but we need to produce ints for the input of @@ -222,7 +234,7 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i } if (same_input != nullptr) { - VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_input_scalar(same_input); + VTransformNode* same_input_vtn = get_vtnode_or_wrap_as_outer(same_input); if (index == 2 && VectorNode::is_shift(p0)) { // Scalar shift count for vector shift operation: vec2 = shiftV(vec1, scalar_count) // Scalar shift operations masks the shift count, but the vector shift does not, so @@ -264,12 +276,12 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i ShouldNotReachHere(); } -VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_input_scalar(Node* n) { +VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_outer(Node* n) { VTransformNode* vtn = get_vtnode_or_null(n); if (vtn != nullptr) { return vtn; } assert(!_vloop.in_bb(n), "only nodes outside the loop can be input nodes to the loop"); - vtn = new (_vtransform.arena()) VTransformInputScalarNode(_vtransform, n); + vtn = new (_vtransform.arena()) VTransformOuterNode(_vtransform, n); map_node_to_vtnode(n, vtn); return vtn; } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index fd85b87f825..ea93bb60ffb 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -76,7 +76,7 @@ private: VTransformVectorNode* make_vector_vtnode_for_pack(const Node_List* pack) const; VTransformNode* get_or_make_vtnode_vector_input_at_index(const Node_List* pack, const int index); - VTransformNode* get_vtnode_or_wrap_as_input_scalar(Node* n); + VTransformNode* get_vtnode_or_wrap_as_outer(Node* n); void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); void set_all_req_with_scalars(Node* n, VTransformNode* vtn); diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index f8efe333941..2882cc2c1a3 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -282,8 +282,8 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { if (visited.test(use->_idx)) { // The use node was already visited, i.e. is higher up in the schedule. // The "out" edge thus points backward, i.e. it is violated. - const VPointer& vp1 = vtn->vpointer(_vloop_analyzer); - const VPointer& vp2 = use->vpointer(_vloop_analyzer); + const VPointer& vp1 = vtn->vpointer(); + const VPointer& vp2 = use->vpointer(); #ifdef ASSERT if (_trace._speculative_aliasing_analysis || _trace._speculative_runtime_checks) { tty->print_cr("\nViolated Weak Edge:"); @@ -630,7 +630,7 @@ bool VTransformGraph::has_store_to_load_forwarding_failure(const VLoopAnalyzer& for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); if (vtn->is_load_or_store_in_loop()) { - const VPointer& p = vtn->vpointer(vloop_analyzer); + const VPointer& p = vtn->vpointer(); if (p.is_valid()) { VTransformVectorNode* vector = vtn->isa_Vector(); bool is_load = vtn->is_load_in_loop(); @@ -708,7 +708,27 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { return n; } -VTransformApplyResult VTransformScalarNode::apply(VTransformApplyState& apply_state) const { +VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { + // This was just wrapped. Now we simply unwap without touching the inputs. + return VTransformApplyResult::make_scalar(_node); +} + +VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { // This was just wrapped. Now we simply unwap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } @@ -861,7 +881,7 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl // Set the memory dependency of the LoadVector as early as possible. // Walk up the memory chain, and ignore any StoreVector that provably // does not have any memory dependency. - const VPointer& load_p = vpointer(apply_state.vloop_analyzer()); + const VPointer& load_p = vpointer(); while (mem->is_StoreVector()) { VPointer store_p(mem->as_Mem(), apply_state.vloop()); if (store_p.never_overlaps_with(load_p)) { @@ -983,7 +1003,24 @@ void VTransformNode::print_node_idx(const VTransformNode* vtn) { } } -void VTransformScalarNode::print_spec() const { +void VTransformMemopScalarNode::print_spec() const { + tty->print("node[%d %s] ", _node->_idx, _node->Name()); + _vpointer.print_on(tty, false); +} + +void VTransformDataScalarNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformLoopPhiNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformCFGNode::print_spec() const { + tty->print("node[%d %s]", _node->_idx, _node->Name()); +} + +void VTransformOuterNode::print_spec() const { tty->print("node[%d %s]", _node->_idx, _node->Name()); } @@ -1011,5 +1048,9 @@ void VTransformVectorNode::print_spec() const { tty->print("%d %s", n->_idx, n->Name()); } tty->print("]"); + if (is_load_or_store_in_loop()) { + tty->print(" "); + vpointer().print_on(tty, false); + } } #endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 74905bc6915..17dd81634ed 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -60,8 +60,11 @@ typedef int VTransformNodeIDX; class VTransformNode; -class VTransformScalarNode; -class VTransformInputScalarNode; +class VTransformMemopScalarNode; +class VTransformDataScalarNode; +class VTransformLoopPhiNode; +class VTransformCFGNode; +class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; class VTransformBoolVectorNode; @@ -422,8 +425,8 @@ public: return false; } - virtual VTransformScalarNode* isa_Scalar() { return nullptr; } - virtual VTransformInputScalarNode* isa_InputScalar() { return nullptr; } + virtual VTransformMemopScalarNode* isa_MemopScalar() { return nullptr; } + virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } @@ -434,7 +437,7 @@ public: virtual bool is_load_in_loop() const { return false; } virtual bool is_load_or_store_in_loop() const { return false; } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const { ShouldNotReachHere(); } + virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const = 0; @@ -448,34 +451,92 @@ public: NOT_PRODUCT(static void print_node_idx(const VTransformNode* vtn);) }; -// Identity transform for scalar nodes. -class VTransformScalarNode : public VTransformNode { +// Identity transform for scalar loads and stores. +class VTransformMemopScalarNode : public VTransformNode { +private: + MemNode* _node; + const VPointer _vpointer; +public: + VTransformMemopScalarNode(VTransform& vtransform, MemNode* n, const VPointer& vpointer) : + VTransformNode(vtransform, n->req()), _node(n), _vpointer(vpointer) + { + assert(node()->is_Load() || node()->is_Store(), "must be memop"); + } + + MemNode* node() const { return _node; } + virtual VTransformMemopScalarNode* isa_MemopScalar() override { return this; } + + virtual bool is_load_in_loop() const override { return _node->is_Load(); } + virtual bool is_load_or_store_in_loop() const override { return true; } + + virtual const VPointer& vpointer() const override { return _vpointer; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "MemopScalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for scalar data nodes. +class VTransformDataScalarNode : public VTransformNode { private: Node* _node; public: - VTransformScalarNode(VTransform& vtransform, Node* n) : - VTransformNode(vtransform, n->req()), _node(n) {} - Node* node() const { return _node; } - virtual VTransformScalarNode* isa_Scalar() override { return this; } - virtual bool is_load_in_loop() const override { return _node->is_Load(); } - virtual bool is_load_or_store_in_loop() const override { return _node->is_Load() || _node->is_Store(); } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return vloop_analyzer.vpointers().vpointer(node()->as_Mem()); } + VTransformDataScalarNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(!_node->is_Mem() && !_node->is_Phi() && !_node->is_CFG(), "must be data node: %s", _node->Name()); + } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; - NOT_PRODUCT(virtual const char* name() const override { return "Scalar"; };) + NOT_PRODUCT(virtual const char* name() const override { return "DataScalar"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for loop head phi nodes. +class VTransformLoopPhiNode : public VTransformNode { +private: + PhiNode* _node; +public: + VTransformLoopPhiNode(VTransform& vtransform, PhiNode* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(_node->in(0)->is_Loop(), "phi ctrl must be Loop: %s", _node->in(0)->Name()); + } + + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "LoopPhi"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// Identity transform for CFG nodes. +class VTransformCFGNode : public VTransformNode { +private: + Node* _node; +public: + VTransformCFGNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) + { + assert(_node->is_CFG(), "must be CFG node: %s", _node->Name()); + } + + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "CFG"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; // Wrapper node for nodes outside the loop that are inputs to nodes in the loop. // Since we want the loop-internal nodes to be able to reference all inputs as vtnodes, // we must wrap the inputs that are outside the loop into special vtnodes, too. -class VTransformInputScalarNode : public VTransformScalarNode { +class VTransformOuterNode : public VTransformNode { +private: + Node* _node; public: - VTransformInputScalarNode(VTransform& vtransform, Node* n) : - VTransformScalarNode(vtransform, n) {} - virtual VTransformInputScalarNode* isa_InputScalar() override { return this; } - virtual bool is_load_in_loop() const override { return false; } - virtual bool is_load_or_store_in_loop() const override { return false; } - NOT_PRODUCT(virtual const char* name() const override { return "InputScalar"; };) + VTransformOuterNode(VTransform& vtransform, Node* n) : + VTransformNode(vtransform, n->req()), _node(n) {} + + virtual VTransformOuterNode* isa_Outer() override { return this; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "Outer"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; // Transform produces a ReplicateNode, replicating the input to all vector lanes. @@ -598,7 +659,7 @@ public: virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } - virtual const VPointer& vpointer(const VLoopAnalyzer& vloop_analyzer) const override { return _vpointer; } + virtual const VPointer& vpointer() const override { return _vpointer; } }; class VTransformLoadVectorNode : public VTransformMemVectorNode { @@ -632,12 +693,12 @@ void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); - // We can ignore input nodes, they are outside the loop. - if (vtn->isa_InputScalar() != nullptr) { continue; } + // We must ignore nodes outside the loop. + if (vtn->isa_Outer() != nullptr) { continue; } - VTransformScalarNode* scalar = vtn->isa_Scalar(); - if (scalar != nullptr && scalar->node()->is_Mem()) { - callback(scalar->node()->as_Mem()); + VTransformMemopScalarNode* scalar = vtn->isa_MemopScalar(); + if (scalar != nullptr) { + callback(scalar->node()); } VTransformVectorNode* vector = vtn->isa_Vector(); From b06459d3a83c13c0fbc7a0a7698435f17265982e Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Mon, 1 Sep 2025 14:21:33 +0000 Subject: [PATCH 310/471] 8364227: MBeanServer registerMBean throws NPE Reviewed-by: alanb --- .../DefaultMBeanServerInterceptor.java | 11 +- .../MBeanServer/ExceptionTestNulls.java | 196 ++++++++++++++++++ 2 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java diff --git a/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index 43606144cd0..161ac1b01fe 100644 --- a/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/src/java.management/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -291,8 +291,13 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - // ------------------------------ - // ------------------------------ + if (object == null) { + final RuntimeException wrapped = + new IllegalArgumentException("Object cannot be null"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register the MBean"); + } + Class theClass = object.getClass(); Introspector.checkCompliance(theClass); diff --git a/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java b/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java new file mode 100644 index 00000000000..e8d534936a0 --- /dev/null +++ b/test/jdk/javax/management/MBeanServer/ExceptionTestNulls.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8364227 + * @summary Test various null parameters and verify Exceptions thrown + * @modules java.management.rmi + * @run main ExceptionTestNulls + */ + +import java.lang.management.ManagementFactory; +import javax.management.AttributeNotFoundException; +import javax.management.ObjectName; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MalformedObjectNameException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationListener; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; + +public class ExceptionTestNulls { + + public interface MyMBean { + } + + public class My implements MyMBean { + } + + private int count; + + public static void main(String args[]) throws Exception { + ExceptionTestNulls test = new ExceptionTestNulls(); + test.run(); + } + + public ExceptionTestNulls() { + count = 0; // Simple index for printing tests, for readability. + } + + public void run() { + + try { + ObjectName name = new ObjectName("a:b=c"); + ObjectName namePattern = new ObjectName("*:type=Foo"); + My myMy = new My(); + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + + try { + // createMBean with null className + mbs.createMBean((String) null, name, name, new Object[0], new String[0]); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // createMBean with ObjectName as a pattern + mbs.createMBean("myMy", namePattern, name, new Object[0], new String[0]); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // registerMBean with null Object + mbs.registerMBean(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // registerMBean with no name available + mbs.registerMBean(myMy, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + // unregisterMBean with null ObjectName + mbs.unregisterMBean(null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.isRegistered(null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttribute(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttribute(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttributes(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.getAttributes(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttribute(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttribute(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttributes(null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.setAttributes(name, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.addNotificationListener(null, (NotificationListener) null, null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + try { + mbs.registerMBean(myMy, name); + mbs.addNotificationListener(null, name, null, null); + } catch (RuntimeOperationsException e) { + checkROEContainsIAE(e); + } + + } catch (MBeanException | MalformedObjectNameException | InstanceAlreadyExistsException + | NotCompliantMBeanException | InstanceNotFoundException | ReflectionException + | AttributeNotFoundException | InvalidAttributeValueException e) { + // Should not reach here. Known Exceptions thrown by methods above. + // These would be a failure, as would other exceptions not caught (e.g. NullPointerException). + throw new RuntimeException(e); + } + } + + public void checkROEContainsIAE(RuntimeOperationsException e) { + System.out.println(++count); + System.out.println("Checking: " + e); + if (e.getCause() instanceof IllegalArgumentException) { + System.out.println("Got expected cause: " + e.getCause()); + System.out.println(); + } else { + throw new RuntimeException("Not the expected cause: " + e); + } + } +} From f58d612b6111658f01fa6b927bb2b2032c685620 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 2 Sep 2025 04:01:32 +0000 Subject: [PATCH 311/471] 8366483: ShowRegistersOnAssertTest uses wrong register pattern string for Windows on AArch64 Reviewed-by: dholmes, shade --- .../runtime/ErrorHandling/ShowRegistersOnAssertTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java index 3b038ebd8a0..b0138625450 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java @@ -76,7 +76,11 @@ public class ShowRegistersOnAssertTest { } else if (Platform.isX86()) { pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("EAX=.*")}; } else if (Platform.isAArch64()) { - pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("R0=.*")}; + if (Platform.isLinux()) { + pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("R0=.*")}; + } else if (Platform.isWindows()) { + pattern = new Pattern[] { Pattern.compile("Registers:"), Pattern.compile("X0 =.*")}; + } } else if (Platform.isS390x()) { pattern = new Pattern[] { Pattern.compile("General Purpose Registers:"), Pattern.compile("^-{26}$"), From 8f11d83a0126f8179d72e714595588b631e6451d Mon Sep 17 00:00:00 2001 From: Philippe Marschall Date: Tue, 2 Sep 2025 05:49:06 +0000 Subject: [PATCH 312/471] 8362893: Improve performance for MemorySegment::getString Reviewed-by: pminborg, mcimadamore --- .../jdk/internal/foreign/StringSupport.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index 6dc104ff323..2f842810aa7 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -33,6 +33,7 @@ import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.ForceInline; import java.lang.foreign.MemorySegment; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import static java.lang.foreign.ValueLayout.*; @@ -71,7 +72,12 @@ public final class StringSupport { final int len = strlenByte(segment, offset, segment.byteSize()); final byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline @@ -85,7 +91,12 @@ public final class StringSupport { int len = strlenShort(segment, offset, segment.byteSize()); byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline @@ -99,7 +110,12 @@ public final class StringSupport { int len = strlenInt(segment, offset, segment.byteSize()); byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); - return new String(bytes, charset); + try { + return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + } catch (CharacterCodingException _) { + // use replacement characters for malformed input + return new String(bytes, charset); + } } @ForceInline From efb81dafaf6da334674e52dbb509208d7d872440 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 2 Sep 2025 06:50:15 +0000 Subject: [PATCH 313/471] 8366031: Mark com/sun/nio/sctp/SctpChannel/CloseDescriptors.java as intermittent Reviewed-by: jpai --- test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java index 0b3ce6ae039..c68abd7a36c 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java @@ -24,6 +24,7 @@ /* * @test * @bug 8238274 + * @key intermittent * @summary Potential leak file descriptor for SCTP * @requires (os.family == "linux") * @library /test/lib From 55e7af0560335ef69af072cee60956cf8e6d00a1 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 07:27:12 +0000 Subject: [PATCH 314/471] 8260555: Change the default TIMEOUT_FACTOR from 4 to 1 Reviewed-by: alanb, sspitsyn, lmesnik, ihse --- doc/testing.html | 11 ++- doc/testing.md | 10 +-- make/RunTests.gmk | 3 +- .../arguments/TestCompileTaskTimeout.java | 2 +- .../arraycopy/stress/TestStressArrayCopy.java | 2 +- .../compiler/c1/TestConcurrentPatching.java | 4 +- .../compiler/c1/TestPinnedIntrinsics.java | 4 +- .../jtreg/compiler/c2/TestMergeStores.java | 6 +- .../c2/TestScalarReplacementMaxLiveNodes.java | 6 +- .../compiler/c2/TestStressRecompilation.java | 4 +- .../TestOverloadCompileQueues.java | 6 +- .../TestAntiDependenciesHighMemUsage2.java | 2 +- .../aes/TestCipherBlockChainingEncrypt.java | 4 +- .../TestLoadBypassesClassCast.java | 2 +- .../floatingpoint/TestFloatSyncJNIArgs.java | 2 +- .../intrinsics/TestLongUnsignedDivMod.java | 4 +- .../ContinuousCallSiteTargetChange.java | 4 +- ...fineMethodUsedByMultipleMethodHandles.java | 2 +- .../vm/ci/runtime/test/RedefineClassTest.java | 4 +- .../runtime/test/TestResolvedJavaMethod.java | 4 +- .../loopopts/TestMaxLoopOptsCountReached.java | 4 +- ...rtialPeelAtUnsignedTestsNegativeLimit.java | 10 +-- .../loopopts/superword/ProdRed_Double.java | 4 +- .../loopopts/superword/ProdRed_Float.java | 4 +- .../loopopts/superword/ProdRed_Int.java | 2 +- .../superword/SumRedAbsNeg_Double.java | 4 +- .../superword/SumRedAbsNeg_Float.java | 2 +- .../loopopts/superword/SumRedSqrt_Double.java | 2 +- .../loopopts/superword/SumRed_Double.java | 2 +- .../loopopts/superword/SumRed_Float.java | 2 +- .../loopopts/superword/SumRed_Int.java | 2 +- .../superword/TestDependencyOffsets.java | 68 +++++++++---------- .../superword/TestEquivalentInvariants.java | 2 +- .../superword/TestMovingLoadBeforeStore.java | 13 ++-- .../loopstripmining/CheckLoopStripMining.java | 2 +- .../profiling/TestProfileCounterOverflow.java | 4 +- .../spectrapredefineclass/Launcher.java | 10 +-- .../Launcher.java | 10 +-- .../tiered/Level2RecompilationTest.java | 5 +- .../compiler/uncommontrap/TestDeoptOOM.java | 6 +- .../vectorapi/TestRawOopAtSafepoint.java | 5 +- .../TestFloat16VectorOperations.java | 2 +- .../vectorization/TestVectorZeroCount.java | 2 +- .../g1/TestGreyReclaimedHumongousObjects.java | 4 +- .../TestHumongousClassLoader.java | 10 +-- .../TestHumongousNonArrayAllocation.java | 12 ++-- .../jtreg/gc/g1/ihop/TestIHOPErgo.java | 4 +- .../gc/stress/TestMultiThreadStressRSet.java | 4 +- .../stress/TestReclaimStringsLeaksMemory.java | 10 +-- .../gc/stress/TestStressG1Humongous.java | 10 +-- .../gc/stress/TestStressRSetCoarsening.java | 14 ++-- .../stress/systemgc/TestSystemGCWithG1.java | 4 +- .../systemgc/TestSystemGCWithParallel.java | 4 +- .../systemgc/TestSystemGCWithSerial.java | 4 +- .../systemgc/TestSystemGCWithShenandoah.java | 8 +-- test/hotspot/jtreg/gc/z/TestUncommit.java | 2 +- test/hotspot/jtreg/gtest/GTestWrapper.java | 2 +- .../jtreg/runtime/8176717/TestInheritFD.java | 9 +-- .../CreateMirror/ArraysNewInstanceBug.java | 4 +- .../ErrorHandling/CreateCoredumpOnCrash.java | 4 +- .../InvocationTests/invocationC1Tests.java | 6 +- .../InvocationTests/invokeinterfaceTests.java | 6 +- .../jtreg/runtime/LoadClass/TestResize.java | 4 +- .../runtime/NMT/VirtualAllocCommitMerge.java | 4 +- .../InvokeInterfaceICCE.java | 2 +- .../InvokeInterfaceSuccessTest.java | 2 +- .../InvokeVirtualICCE.java | 2 +- .../InvokeVirtualSuccessTest.java | 2 +- .../TestThreadDumpMonitorContention.java | 4 +- .../jtreg/runtime/cds/DeterministicDump.java | 2 +- .../cds/appcds/LotsOfSyntheticClasses.java | 2 +- .../jtreg/runtime/cds/appcds/TestCommon.java | 32 ++++----- .../aotCode/AOTCodeCompressedOopsTest.java | 4 +- .../appcds/aotProfile/AOTProfileFlags.java | 2 +- .../sharedStrings/SharedStringsStress.java | 2 +- .../ArrayIndexOutOfBoundsExceptionTest.java | 6 +- .../runtime/logging/RedefineClasses.java | 4 +- .../reflect/ReflectOutOfMemoryError.java | 4 +- .../UnmountedVThreadNativeMethodAtTop.java | 2 +- .../MyPackage/HeapMonitorThreadTest.java | 4 +- .../jvmti/SetTag/TagMapTest.java | 8 +-- .../SuspendResume2/SuspendResume2.java | 6 +- .../serviceability/sa/ClhsdbDumpheap.java | 4 +- .../jtreg/serviceability/sa/ClhsdbFindPC.java | 10 +-- .../sa/ClhsdbJstackXcompStress.java | 4 +- .../sa/ClhsdbThreadContext.java | 4 +- .../sa/TestJhsdbJstackLineNumbers.java | 4 +- .../sa/TestObjectAlignment.java | 4 +- .../sa/sadebugd/SADebugDTest.java | 6 +- .../ir_framework/tests/TestNotCompilable.java | 2 +- .../TestDescription.java | 4 +- .../TestDescription.java | 4 +- .../LargeObjects/large001/large001.java | 4 +- .../large002/TestDescription.java | 4 +- .../large003/TestDescription.java | 4 +- .../large004/TestDescription.java | 4 +- .../large005/TestDescription.java | 4 +- .../SoftReference/soft004/soft004.java | 4 +- .../WeakReference/weak004/weak004.java | 4 +- .../CircularListLow/TestDescription.java | 4 +- .../AdaptiveBlocking001.java | 4 +- .../TestDescription.java | 5 +- .../ShrinkGrowMultiJVM.java | 4 +- .../stressHierarchy001/TestDescription.java | 4 +- .../stressHierarchy002/TestDescription.java | 4 +- .../stressHierarchy003/TestDescription.java | 4 +- .../stressHierarchy004/TestDescription.java | 4 +- .../stressHierarchy005/TestDescription.java | 4 +- .../stressHierarchy006/TestDescription.java | 4 +- .../stressHierarchy007/TestDescription.java | 4 +- .../stressHierarchy008/TestDescription.java | 4 +- .../stressHierarchy009/TestDescription.java | 4 +- .../stressHierarchy010/TestDescription.java | 4 +- .../stressHierarchy011/TestDescription.java | 4 +- .../stressHierarchy012/TestDescription.java | 4 +- .../stressHierarchy013/TestDescription.java | 4 +- .../stressHierarchy014/TestDescription.java | 4 +- .../stressHierarchy015/TestDescription.java | 4 +- .../referringObjects001.java | 4 +- .../_itself_/stepEvent004/stepEvent004.java | 2 +- .../thread/thread001/TestDescription.java | 5 +- .../serial/mixed002/TestDescription.java | 5 +- .../holdevents002/TestDescription.java | 5 +- .../rawmnwait001/TestDescription.java | 5 +- .../SP03/sp03t001/TestDescription.java | 5 +- .../SP03/sp03t002/TestDescription.java | 5 +- .../SP04/sp04t001/TestDescription.java | 5 +- .../SP04/sp04t002/TestDescription.java | 5 +- .../SP07/sp07t001/TestDescription.java | 5 +- .../isSuspended/issuspended002.java | 4 +- .../thread/strace001/TestDescription.java | 5 +- .../thread/strace002/TestDescription.java | 5 +- .../thread/strace003/TestDescription.java | 5 +- .../nsk/stress/strace/strace006.java | 4 +- .../nsk/stress/thread/thread001.java | 4 +- .../nsk/stress/thread/thread002.java | 4 +- .../nsk/stress/thread/thread005.java | 4 +- .../nsk/stress/thread/thread006.java | 4 +- .../nsk/stress/thread/thread007.java | 4 +- .../nsk/stress/thread/thread008.java | 4 +- .../vm/stress/btree/btree001/btree001.java | 9 ++- .../vm/stress/btree/btree002/btree002.java | 9 ++- .../vm/stress/btree/btree003/btree003.java | 9 ++- .../vm/stress/btree/btree004/btree004.java | 9 ++- .../vm/stress/btree/btree005/btree005.java | 9 ++- .../vm/stress/btree/btree006/btree006.java | 9 ++- .../vm/stress/btree/btree007/btree007.java | 9 ++- .../vm/stress/btree/btree008/btree008.java | 9 ++- .../vm/stress/btree/btree009/btree009.java | 9 ++- .../vm/stress/btree/btree010/btree010.java | 9 ++- .../vm/stress/btree/btree011/btree011.java | 9 ++- .../vm/stress/btree/btree012/btree012.java | 9 ++- .../TestDescription.java | 3 +- .../meth/stress/compiler/i2c_c2i/Test.java | 2 +- .../meth/stress/compiler/sequences/Test.java | 4 +- .../provider/KeyFactory/TestProviderLeak.java | 8 +-- test/jdk/com/sun/jdi/InterruptHangTest.java | 7 +- .../com/sun/jdi/MethodEntryExitEvents.java | 8 +-- .../jdk/com/sun/jdi/ThreadMemoryLeakTest.java | 4 +- .../sun/jndi/ldap/LdapPoolTimeoutTest.java | 3 +- .../com/sun/nio/sctp/SctpChannel/Connect.java | 3 +- .../SctpServerChannel/NonBlockingAccept.java | 3 +- .../java/awt/font/NumericShaper/MTTest.java | 4 +- .../XMLDecoder/8028054/TestMethodFinder.java | 4 +- test/jdk/java/foreign/StdLibTest.java | 4 +- test/jdk/java/foreign/TestAccessModes.java | 10 +-- .../java/foreign/TestBufferStackStress2.java | 2 +- .../jdk/java/foreign/TestConcurrentClose.java | 4 +- test/jdk/java/foreign/TestDeadlock.java | 2 +- test/jdk/java/foreign/TestMismatch.java | 4 +- .../java/foreign/TestStringEncodingJumbo.java | 4 +- .../java/foreign/TestStubAllocFailure.java | 4 +- test/jdk/java/foreign/TestUpcallStack.java | 2 +- .../loaderLookup/TestLoaderLookup.java | 2 +- .../UnreferencedFISClosesFd.java | 4 +- .../UnreferencedFOSClosesFd.java | 4 +- .../UnreferencedRAFClosesFd.java | 4 +- .../FieldSetAccessibleTest.java | 4 +- test/jdk/java/lang/Math/IntegralPowTest.java | 2 +- .../ProcessBuilder/FDLeakTest/FDLeakTest.java | 6 +- .../lang/ProcessBuilder/UnblockSignals.java | 10 +-- .../lang/StackWalker/LocalsAndOperands.java | 8 +-- .../CompactString/MaxSizeUTF16String.java | 8 +-- .../StringBuilder/CompactStringBuilder.java | 6 +- .../virtual/CancelTimerWithContention.java | 4 +- .../lang/Thread/virtual/MiscMonitorTests.java | 12 ++-- .../lang/Thread/virtual/MonitorEnterExit.java | 10 +-- .../Thread/virtual/MonitorWaitNotify.java | 10 +-- .../jdk/java/lang/Thread/virtual/Parking.java | 8 +-- .../virtual/RetryMonitorEnterWhenPinned.java | 2 +- .../java/lang/Thread/virtual/Starvation.java | 2 +- .../Thread/virtual/SynchronizedNative.java | 8 +-- .../Thread/virtual/ThreadPollOnYield.java | 4 +- .../stress/GetStackTraceALotWhenBlocking.java | 6 +- .../GetStackTraceALotWithTimedWait.java | 7 +- .../lang/Thread/virtual/stress/ParkALot.java | 6 +- .../lang/Thread/virtual/stress/PinALot.java | 4 +- .../lang/Thread/virtual/stress/Skynet.java | 4 +- .../stress/Skynet100kWithMonitors.java | 4 +- .../lang/Thread/virtual/stress/SleepALot.java | 6 +- .../java/lang/annotation/LoaderLeakTest.java | 4 +- .../invoke/TestLambdaFormCustomization.java | 6 +- .../lang/reflect/IllegalArgumentsTest.java | 4 +- .../math/BigInteger/LargeValueExceptions.java | 4 +- .../UnreferencedDatagramSockets.java | 6 +- .../MulticastSocket/SetLoopbackModeIPv4.java | 4 +- .../UnreferencedMulticastSockets.java | 6 +- .../net/ServerSocket/UnreferencedSockets.java | 6 +- test/jdk/java/net/Socket/CloseAvailable.java | 6 +- .../net/httpclient/AsFileDownloadTest.java | 4 +- .../httpclient/BufferingSubscriberTest.java | 4 +- .../net/httpclient/CancelledResponse.java | 6 +- .../net/httpclient/HttpSlowServerTest.java | 4 +- .../jdk/java/net/httpclient/ManyRequests.java | 8 +-- .../httpclient/ResponseBodyBeforeError.java | 4 +- .../net/httpclient/ResponsePublisher.java | 4 +- .../net/httpclient/SpecialHeadersTest.java | 6 +- .../java/net/httpclient/SplitResponse.java | 4 +- .../net/httpclient/SplitResponseAsync.java | 4 +- .../httpclient/SplitResponseKeepAlive.java | 4 +- .../SplitResponseKeepAliveAsync.java | 4 +- .../java/net/httpclient/SplitResponseSSL.java | 4 +- .../net/httpclient/SplitResponseSSLAsync.java | 4 +- .../httpclient/SplitResponseSSLKeepAlive.java | 4 +- .../SplitResponseSSLKeepAliveAsync.java | 4 +- .../httpclient/whitebox/FlowTestDriver.java | 4 +- .../StressLoopback.java | 4 +- .../nio/channels/Channels/TransferTo.java | 4 +- .../Channels/TransferTo_2GB_transferFrom.java | 4 +- .../Channels/TransferTo_2GB_transferTo.java | 4 +- .../nio/channels/FileChannel/CleanerTest.java | 4 +- .../SocketChannel/CloseDuringConnect.java | 4 +- .../nio/channels/SocketChannel/OpenLeak.java | 4 +- .../nio/channels/unixdomain/IOExchanges.java | 4 +- .../channels/vthread/BlockingChannelOps.java | 8 +-- .../transport/dgcDeadLock/DGCDeadLock.java | 7 +- .../jdk/java/security/SignedObject/Chain.java | 4 +- .../Format/DateFormat/DateFormatTest.java | 2 +- .../java/util/HashMap/WhiteBoxResizeTest.java | 4 +- .../CurrencyNameProviderTest.java | 4 +- .../LocaleNameProviderTest.java | 2 +- .../BasicCancelTest.java | 4 +- .../java/util/logging/FileHandlerPath.java | 4 +- .../HandlersOnComplexResetUpdate.java | 11 ++- .../HandlersOnComplexUpdate.java | 11 ++- .../java/util/stream/TEST.properties | 1 + .../tests/java/util/stream/TEST.properties | 1 + test/jdk/java/util/zip/DeInflate.java | 5 +- .../zip/ZipFile/TestZipFileEncodings.java | 4 +- .../ssl/ciphersuites/DisabledAlgorithms.java | 6 +- .../JFileChooser/6868611/bug6868611.java | 4 +- .../ConcurrentModification.java | 4 +- .../parser/Parser/8078268/bug8078268.java | 6 +- .../xml/crypto/dsig/GenerationTests.java | 2 +- test/jdk/jdk/incubator/vector/AddTest.java | 3 +- .../TestDockerMemoryMetricsSubgroup.java | 2 +- .../docker/TestGetFreeSwapSpaceSize.java | 4 +- .../platform/docker/TestLimitsUpdating.java | 4 +- .../platform/docker/TestPidsLimit.java | 4 +- .../internal/vm/Continuation/BasicExt.java | 6 +- .../jdk/internal/vm/Continuation/Fuzz.java | 13 ++-- .../consumer/recordingstream/TestClose.java | 2 +- .../metadata/annotations/TestStackFilter.java | 4 +- .../oldobject/TestEmergencyDumpAtOOM.java | 2 +- .../oldobject/TestObjectDescription.java | 2 +- .../TestCPUTimeSampleMultipleRecordings.java | 2 +- test/jdk/jdk/jfr/jvm/TestModularImage.java | 2 +- .../MonitoredVm/MonitorVmStartTerminate.java | 1 + .../sun/nio/ch/TestMaxCachedBufferSize.java | 12 ++-- .../sun/nio/cs/TestEncoderReplaceUTF16.java | 4 +- test/jdk/sun/security/ec/ed/EdDSATest.java | 4 +- .../security/krb5/config/IncludeRandom.java | 2 +- .../sun/security/krb5/name/Constructors.java | 4 +- .../jdk/sun/security/pkcs11/KDF/TestHKDF.java | 2 +- .../KeyPairGenerator/TestDefaultSize.java | 4 +- .../pkcs11/KeyStore/ImportKeyToP12.java | 2 +- .../pkcs11/Mac/TestLargeSecretKeys.java | 2 +- .../pkcs12/KeytoolOpensslInteropTest.java | 4 +- .../sun/security/provider/acvp/Launcher.java | 4 +- .../ssl/SSLSocketImpl/SSLSocketCloseHang.java | 7 +- .../ssl/X509KeyManager/CertChecking.java | 8 +-- .../tools/jarsigner/ConciseJarsigner.java | 2 +- .../InsufficientSectionDelimiter.java | 4 +- .../tools/jarsigner/RestrictedAlgo.java | 6 +- .../SectionNameContinuedVsLineBreak.java | 4 +- .../tools/jarsigner/TimestampCheck.java | 2 +- .../security/tools/keytool/GenerateAll.java | 4 +- .../sun/security/tools/keytool/ReadJar.java | 4 +- .../keytool/fakecacerts/TrustedCert.java | 4 +- test/jdk/sun/tools/jcmd/TestJcmdSanity.java | 4 +- .../util/resources/TimeZone/Bug8139107.java | 5 +- test/jdk/tools/jlink/JLink100Modules.java | 4 +- test/jdk/tools/jlink/JLink20000Packages.java | 4 +- test/jdk/tools/jlink/JLinkTest.java | 4 +- .../plugins/IncludeLocalesPluginTest.java | 2 +- .../runtimeImage/JavaSEReproducibleTest.java | 2 +- .../tools/jpackage/macosx/DmgContentTest.java | 2 +- .../macosx/MacFileAssociationsTest.java | 2 +- .../tools/jpackage/share/AddLauncherTest.java | 4 +- .../jpackage/share/AppLauncherSubstTest.java | 2 +- .../tools/jpackage/share/AppVersionTest.java | 2 +- test/jdk/tools/jpackage/share/BasicTest.java | 2 +- test/jdk/tools/jpackage/share/IconTest.java | 2 +- .../tools/jpackage/share/InOutPathTest.java | 2 +- .../tools/jpackage/share/InstallDirTest.java | 4 +- .../tools/jpackage/share/JavaOptionsTest.java | 2 +- .../tools/jpackage/share/MainClassTest.java | 2 +- .../jpackage/share/MultiNameTwoPhaseTest.java | 2 +- .../jpackage/share/PostImageScriptTest.java | 2 +- .../jpackage/windows/WinNoRestartTest.java | 4 +- test/jdk/tools/launcher/InstanceMainTest.java | 4 +- .../testLinkOption/TestRedirectLinks.java | 2 +- test/langtools/jdk/jshell/ClassesTest.java | 4 +- .../jdk/jshell/CompletionSuggestionTest.java | 2 +- .../jdk/jshell/HangingRemoteAgent.java | 6 +- .../JdiHangingLaunchExecutionControlTest.java | 4 +- .../JdiHangingListenExecutionControlTest.java | 2 +- .../jdk/jshell/ToolLocalSimpleTest.java | 4 +- test/langtools/jdk/jshell/ToolSimpleTest.java | 4 +- test/langtools/jdk/jshell/UITesting.java | 13 +--- test/langtools/jdk/jshell/VariablesTest.java | 4 +- .../tools/javac/Paths/MineField.java | 4 +- .../tools/javac/Paths/WildcardMineField.java | 4 +- .../tools/javac/diags/CheckExamples.java | 4 +- .../tools/javac/diags/RunExamples.java | 4 +- .../javac/failover/CheckAttributedTree.java | 4 +- .../MultiReleaseJar/MultiReleaseJarTest.java | 4 +- .../GenericConstructorAndDiamondTest.java | 3 +- .../NegativeCyclicDependencyTest.java | 4 +- .../tools/javac/lambda/LambdaParserTest.java | 4 +- .../bridge/template_tests/TEST.properties | 2 + .../IntersectionTargetTypeTest.java | 3 +- .../CreateSymbolsReproducibleTest.java | 2 +- .../javac/tree/JavacTreeScannerTest.java | 4 +- .../javac/tree/SourceDocTreeScannerTest.java | 4 +- .../javac/tree/SourceTreeScannerTest.java | 4 +- .../tools/javac/types/TestComparisons.java | 3 +- .../tools/javac/util/IteratorsTest.java | 4 +- .../tools/javac/varargs/warning/Warn5.java | 4 +- test/langtools/tools/lib/toolbox/ToolBox.java | 12 +--- test/lib/jdk/test/lib/cds/CDSTestUtils.java | 5 +- test/lib/jdk/test/lib/util/ForceGC.java | 9 +-- 342 files changed, 810 insertions(+), 850 deletions(-) create mode 100644 test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties create mode 100644 test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties diff --git a/doc/testing.html b/doc/testing.html index fa774aa312f..89a9b1b23b7 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -398,7 +398,8 @@ TEST_OPTS keywords.

          JOBS

          Currently only applies to JTReg.

          TIMEOUT_FACTOR

          -

          Currently only applies to JTReg.

          +

          Currently only applies to JTReg +-timeoutFactor.

          JAVA_OPTIONS

          Applies to JTReg, GTest and Micro.

          VM_OPTIONS

          @@ -444,8 +445,12 @@ otherwise it defaults to JOBS, except for Hotspot, where the default is number of CPU cores/2, but never more than memory size in GB/2.

          TIMEOUT_FACTOR

          -

          The timeout factor (-timeoutFactor).

          -

          Defaults to 4.

          +

          The TIMEOUT_FACTOR is forwarded to JTReg framework +itself (-timeoutFactor). Also, some test cases that +programmatically wait a certain amount of time will apply this factor. +If we run in forced compilation mode (-Xcomp), the build +system will automatically adjust this factor to compensate for less +performance. Defaults to 1.

          FAILURE_HANDLER_TIMEOUT

          Sets the argument -timeoutHandlerTimeout for JTReg. The default value is 0. This is only valid if the failure handler is diff --git a/doc/testing.md b/doc/testing.md index 4cfc36c85f9..324f9645c27 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -324,7 +324,7 @@ Currently only applies to JTReg. #### TIMEOUT_FACTOR -Currently only applies to JTReg. +Currently only applies to [JTReg -timeoutFactor](#timeout_factor-1). #### JAVA_OPTIONS @@ -383,9 +383,11 @@ never more than *memory size in GB/2*. #### TIMEOUT_FACTOR -The timeout factor (`-timeoutFactor`). - -Defaults to 4. +The `TIMEOUT_FACTOR` is forwarded to JTReg framework itself +(`-timeoutFactor`). Also, some test cases that programmatically wait a +certain amount of time will apply this factor. If we run in forced +compilation mode (`-Xcomp`), the build system will automatically +adjust this factor to compensate for less performance. Defaults to 1. #### FAILURE_HANDLER_TIMEOUT diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 46f9a2e4047..10f0a2f87ed 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -946,7 +946,8 @@ define SetupRunJtregTestBody JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS) JTREG_AUTO_PROBLEM_LISTS := - JTREG_AUTO_TIMEOUT_FACTOR := 4 + # Please reach consensus before changing this. It was not easy changing it to a `1`. + JTREG_AUTO_TIMEOUT_FACTOR := 1 ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), ) JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java index 4204f7be92e..cb52e5a24a0 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -29,7 +29,7 @@ package compiler.arguments; * @requires vm.debug & vm.flagless & os.name == "Linux" * @summary Check functionality of CompileTaskTimeout * @library /test/lib - * @run driver compiler.arguments.TestCompileTaskTimeout + * @run driver/timeout=480 compiler.arguments.TestCompileTaskTimeout */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java index 55dfb0460a2..8c410c77e5f 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java +++ b/test/hotspot/jtreg/compiler/arraycopy/stress/TestStressArrayCopy.java @@ -51,7 +51,7 @@ import jdk.test.whitebox.cpuinfo.CPUInfo; * jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=7200 + * @run main/othervm/timeout=28800 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * compiler.arraycopy.stress.TestStressArrayCopy */ diff --git a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java index 6a7179d0ce4..dfd719f3a3b 100644 --- a/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java +++ b/test/hotspot/jtreg/compiler/c1/TestConcurrentPatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ import java.util.ArrayList; * @test * @bug 8340313 * @summary Test that concurrent patching of oop immediates is thread-safe in C1. - * @run main/othervm/timeout=480 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching + * @run main/othervm/timeout=1920 -Xcomp -XX:CompileCommand=compileonly,TestConcurrentPatching::* -XX:TieredStopAtLevel=1 TestConcurrentPatching */ class MyClass { } diff --git a/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java b/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java index a1f42a43240..0c47f752eab 100644 --- a/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java +++ b/test/hotspot/jtreg/compiler/c1/TestPinnedIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 8184271 * @summary Test correct scheduling of System.nanoTime C1 intrinsic. - * @run main/othervm -XX:TieredStopAtLevel=1 -Xbatch + * @run main/othervm/timeout=480 -XX:TieredStopAtLevel=1 -Xbatch * -XX:CompileCommand=dontinline,compiler.c1.TestPinnedIntrinsics::checkNanoTime * compiler.c1.TestPinnedIntrinsics */ diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 22920eda828..84329c4a9c8 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -37,7 +37,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores aligned + * @run main/timeout=480 compiler.c2.TestMergeStores aligned */ /* @@ -46,7 +46,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores unaligned + * @run main/timeout=480 compiler.c2.TestMergeStores unaligned */ /* @@ -55,7 +55,7 @@ import java.util.Random; * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run main compiler.c2.TestMergeStores StressIGVN + * @run main/timeout=480 compiler.c2.TestMergeStores StressIGVN */ public class TestMergeStores { diff --git a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java index 60086dba327..f133e91a1ee 100644 --- a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java +++ b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -28,8 +28,8 @@ * @library /test/lib / * @requires vm.debug & vm.compiler2.enabled * @compile -XDstringConcat=inline TestScalarReplacementMaxLiveNodes.java - * @run main/othervm compiler.c2.TestScalarReplacementMaxLiveNodes - * @run main/othervm -Xbatch -XX:-OptimizeStringConcat -XX:-TieredCompilation + * @run main/othervm/timeout=480 compiler.c2.TestScalarReplacementMaxLiveNodes + * @run main/othervm/timeout=480 -Xbatch -XX:-OptimizeStringConcat -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+ReduceAllocationMerges * -XX:CompileCommand=dontinline,compiler.c2.TestScalarReplacementMaxLiveNodes::test * -XX:CompileCommand=compileonly,*TestScalarReplacementMaxLiveNodes*::*test* diff --git a/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java b/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java index 923323beb75..3572b6137f0 100644 --- a/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java +++ b/test/hotspot/jtreg/compiler/c2/TestStressRecompilation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8245801 * @requires vm.debug * @summary Test running with StressRecompilation enabled. - * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressRecompilation + * @run main/othervm/timeout=480 -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressRecompilation * compiler.c2.TestStressRecompilation */ diff --git a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java index 04906954090..db5f31d8c77 100644 --- a/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java +++ b/test/hotspot/jtreg/compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -26,9 +26,9 @@ * @bug 8163511 8230402 * @summary Test overloading the C1 and C2 compile queues with tasks. * @requires !vm.graal.enabled - * @run main/othervm/timeout=300 -XX:-TieredCompilation -XX:CompileThreshold=2 -XX:CICompilerCount=1 + * @run main/othervm/timeout=1200 -XX:-TieredCompilation -XX:CompileThreshold=2 -XX:CICompilerCount=1 * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues - * @run main/othervm/timeout=300 -XX:TieredCompileTaskTimeout=1000 -XX:CompileThresholdScaling=0.001 -XX:CICompilerCount=2 + * @run main/othervm/timeout=1200 -XX:TieredCompileTaskTimeout=1000 -XX:CompileThresholdScaling=0.001 -XX:CICompilerCount=2 * compiler.classUnloading.methodUnloading.TestOverloadCompileQueues */ diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java index d5f220f4628..cfe884c269f 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java @@ -25,7 +25,7 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining + * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining * -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement TestAntiDependenciesHighMemUsage2 */ diff --git a/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java b/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java index 46d09b42425..b80a4ecdf5c 100644 --- a/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java +++ b/test/hotspot/jtreg/compiler/codegen/aes/TestCipherBlockChainingEncrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -Xbatch + * @run main/othervm/timeout=480 -Xbatch * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * compiler.codegen.aes.TestCipherBlockChainingEncrypt */ diff --git a/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java b/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java index f5608c3a51a..127206f9b0e 100644 --- a/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java +++ b/test/hotspot/jtreg/compiler/controldependency/TestLoadBypassesClassCast.java @@ -26,7 +26,7 @@ * @summary C2: Load can bypass subtype check that enforces it's from the right object type * @requires vm.gc.Parallel * @requires vm.compiler2.enabled - * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileOnly=TestLoadBypassesClassCast::test + * @run main/othervm/timeout=480 -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileOnly=TestLoadBypassesClassCast::test * -XX:CompileThreshold=20000 -XX:LoopMaxUnroll=1 -XX:-LoopUnswitching -XX:+UseParallelGC TestLoadBypassesClassCast * */ diff --git a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java index d9699062952..cd596c337b7 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatSyncJNIArgs.java @@ -27,7 +27,7 @@ * @summary Regression test for passing float args to a synchronized jni function. * * - * @run main/othervm/native compiler.floatingpoint.TestFloatSyncJNIArgs + * @run main/othervm/native/timeout=480 compiler.floatingpoint.TestFloatSyncJNIArgs */ package compiler.floatingpoint; diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java index 88fd46c4325..ce9444823da 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestLongUnsignedDivMod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @summary Test intrinsic for divideUnsigned() and remainderUnsigned() methods for Long * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="riscv64" | os.arch=="aarch64" * @library /test/lib / -* @run driver compiler.intrinsics.TestLongUnsignedDivMod +* @run driver/timeout=480 compiler.intrinsics.TestLongUnsignedDivMod */ package compiler.intrinsics; diff --git a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java index 2b501064b76..5964341e816 100644 --- a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java +++ b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver/timeout=180 compiler.jsr292.ContinuousCallSiteTargetChange + * @run driver/timeout=720 compiler.jsr292.ContinuousCallSiteTargetChange */ package compiler.jsr292; diff --git a/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java b/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java index 93f21164bf5..769863880f2 100644 --- a/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java +++ b/test/hotspot/jtreg/compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java @@ -32,7 +32,7 @@ * jdk.attach * @requires vm.jvmti * - * @run main/othervm -Djdk.attach.allowAttachSelf compiler.jsr292.RedefineMethodUsedByMultipleMethodHandles + * @run main/othervm/timeout=480 -Djdk.attach.allowAttachSelf compiler.jsr292.RedefineMethodUsedByMultipleMethodHandles */ package compiler.jsr292; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java index 6aeaf4eec7e..a6f58fd1375 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * jdk.internal.vm.ci/jdk.vm.ci.runtime * jdk.attach * java.base/jdk.internal.misc - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Djdk.attach.allowAttachSelf jdk.vm.ci.runtime.test.RedefineClassTest + * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -Djdk.attach.allowAttachSelf jdk.vm.ci.runtime.test.RedefineClassTest */ package jdk.vm.ci.runtime.test; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 6151ae68ce7..58612aa0da1 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -40,7 +40,7 @@ * java.base/jdk.internal.misc * java.base/jdk.internal.vm * java.base/sun.reflect.annotation - * @run junit/othervm/timeout=240 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod + * @run junit/othervm/timeout=960 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod */ package jdk.vm.ci.runtime.test; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java index d8a56e1b51b..a529c69dae8 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8284944 * @requires vm.compiler2.enabled * @summary triggers the loop optimization phase `LoopOptsCount` many times - * @run main/othervm -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached + * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached */ import java.lang.System.Logger.Level; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java index 7809f79ce9d..34f0411f4ed 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test id=Xbatch * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xbatch -XX:-TieredCompilation + * @run main/othervm/timeout=480 -Xbatch -XX:-TieredCompilation * -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ @@ -34,7 +34,7 @@ * @test id=Xcomp-run-inline * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xcomp -XX:-TieredCompilation + * @run main/othervm/timeout=480 -Xcomp -XX:-TieredCompilation * -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::run*,*TestPartialPeel*::test* * -XX:CompileCommand=inline,*TestPartialPeelAtUnsignedTestsNegativeLimit::test* * -XX:CompileCommand=dontinline,*TestPartialPeelAtUnsignedTestsNegativeLimit::check @@ -45,7 +45,7 @@ * @test id=Xcomp-compile-test * @bug 8332920 * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". - * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* + * @run main/othervm/timeout=480 -Xcomp -XX:-TieredCompilation -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test* * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ @@ -55,7 +55,7 @@ * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". * Only run this test with C2 since it is time-consuming and only tests a C2 issue. - * @run main compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + * @run main/timeout=480 compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit */ package compiler.loopopts; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java index 41284c0d61e..4eebe6a80fe 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Double + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java index 603530f7fb2..116a69f6bbf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Float + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java index 9ca670117cf..433a4b6f3a3 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test * @library /test/lib / - * @run driver compiler.loopopts.superword.ProdRed_Int + * @run driver/timeout=480 compiler.loopopts.superword.ProdRed_Int */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java index 0122f1c34cd..2dd720ad1f0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : double abs & neg test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedAbsNeg_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRedAbsNeg_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java index 6e2d304c149..3ada72c402b 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java @@ -26,7 +26,7 @@ * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : float abs & neg test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedAbsNeg_Float + * @run driver/timeout=480 compiler.loopopts.superword.SumRedAbsNeg_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java index 2965af2a63b..ab99fd4adef 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java @@ -26,7 +26,7 @@ * @bug 8135028 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRedSqrt_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRedSqrt_Double */ diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java index 0b81ae59bf0..89a396f43af 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Double + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Double */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java index f667f2d05c1..db3ccf1a0b2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Float + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Float */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java index 098dc2a7d1e..8c7e69247c5 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java @@ -26,7 +26,7 @@ * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test * @library /test/lib / - * @run driver compiler.loopopts.superword.SumRed_Int + * @run driver/timeout=480 compiler.loopopts.superword.SumRed_Int */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index d760c87ad19..e2aca036474 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -27,7 +27,7 @@ * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vanilla-A */ /* @@ -36,7 +36,7 @@ * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vanilla-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vanilla-U */ /* @@ -48,7 +48,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v016-A */ /* @@ -60,7 +60,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v016-U */ /* @@ -72,7 +72,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v008-A */ /* @@ -84,7 +84,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v008-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v008-U */ /* @@ -96,7 +96,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v004-A */ /* @@ -108,7 +108,7 @@ * @requires vm.cpu.features ~= ".*sse4.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets sse4-v004-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets sse4-v004-U */ /* @@ -120,7 +120,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v032-A */ /* @@ -132,7 +132,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v032-U */ /* @@ -144,7 +144,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v016-A */ /* @@ -156,7 +156,7 @@ * @requires vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx1-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx1-v016-U */ /* @@ -168,7 +168,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v032-A */ /* @@ -180,7 +180,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v032-U */ /* @@ -192,7 +192,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v016-A */ /* @@ -204,7 +204,7 @@ * @requires vm.cpu.features ~= ".*avx2.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx2-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx2-v016-U */ /* @@ -216,7 +216,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v064-A */ /* @@ -228,7 +228,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v064-U */ /* @@ -240,7 +240,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v032-A */ /* @@ -252,7 +252,7 @@ * @requires vm.cpu.features ~= ".*avx512.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512-v032-U */ /* @@ -264,7 +264,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-A */ /* @@ -276,7 +276,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v064-U */ /* @@ -288,7 +288,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-A */ /* @@ -300,7 +300,7 @@ * @requires vm.cpu.features ~= ".*avx512bw.*" * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets avx512bw-v032-U */ /* @@ -311,7 +311,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v064-A */ /* @@ -322,7 +322,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v064-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v064-U */ /* @@ -333,7 +333,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v032-A */ /* @@ -344,7 +344,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v032-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v032-U */ /* @@ -355,7 +355,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v016-A */ /* @@ -366,7 +366,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v016-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v016-U */ /* @@ -377,7 +377,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v008-A */ /* @@ -388,7 +388,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v008-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v008-U */ /* @@ -399,7 +399,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-A + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v004-A */ /* @@ -410,7 +410,7 @@ * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java - * @run driver compiler.loopopts.superword.TestDependencyOffsets vec-v004-U + * @run driver/timeout=480 compiler.loopopts.superword.TestDependencyOffsets vec-v004-U */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index 7cec26d6532..91d1ee9666a 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java @@ -39,7 +39,7 @@ import java.lang.foreign.*; * i.e. where the invariants have the same summands, but in a different order. * @modules java.base/jdk.internal.misc * @library /test/lib / - * @run driver/timeout=1200 compiler.loopopts.superword.TestEquivalentInvariants + * @run driver/timeout=4800 compiler.loopopts.superword.TestEquivalentInvariants */ public class TestEquivalentInvariants { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java index 72ca2cee341..18fb0019fa5 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java @@ -29,12 +29,13 @@ * @key randomness * @modules java.base/jdk.internal.misc * @library /test/lib - * @run main/othervm -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestMovingLoadBeforeStore::test* - * --add-modules java.base --add-exports java.base/jdk.internal.misc=ALL-UNNAMED - * -Xbatch - * -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM - * -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=100 - * compiler.loopopts.superword.TestMovingLoadBeforeStore + * @run main/othervm/timeout=480 + * -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestMovingLoadBeforeStore::test* + * --add-modules java.base --add-exports java.base/jdk.internal.misc=ALL-UNNAMED + * -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM + * -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=100 + * compiler.loopopts.superword.TestMovingLoadBeforeStore */ package compiler.loopopts.superword; diff --git a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java index 9e8ac6b013a..cdbf5affd01 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java @@ -28,7 +28,7 @@ * @requires vm.compiler2.enabled * * @library /test/lib - * @run driver compiler.loopstripmining.CheckLoopStripMining + * @run driver/timeout=480 compiler.loopstripmining.CheckLoopStripMining */ package compiler.loopstripmining; diff --git a/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java b/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java index b4c4d2d4a4a..bcd48698d13 100644 --- a/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java +++ b/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Loongson Technology Co. Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,7 +27,7 @@ * @bug 8224162 * @summary Profile counter for a call site may overflow. * @requires vm.compMode != "Xcomp" - * @run main/othervm -Xbatch -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:MaxTrivialSize=0 -XX:C1MaxTrivialSize=0 compiler.profiling.TestProfileCounterOverflow + * @run main/othervm/timeout=480 -Xbatch -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:MaxTrivialSize=0 -XX:C1MaxTrivialSize=0 compiler.profiling.TestProfileCounterOverflow */ package compiler.profiling; diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java index bdf4b3fb852..297c0312069 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -32,10 +32,10 @@ * @build compiler.profiling.spectrapredefineclass.Agent * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass.Agent * @run driver compiler.profiling.spectrapredefineclass.Launcher - * @run main/othervm -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 - * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 - * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf - * compiler.profiling.spectrapredefineclass.Agent + * @run main/othervm/timeout=480 -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 + * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 + * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf + * compiler.profiling.spectrapredefineclass.Agent */ package compiler.profiling.spectrapredefineclass; diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java index 6fdbca00523..e7f5736889c 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -35,10 +35,10 @@ * compiler.profiling.spectrapredefineclass_classloaders.B * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass_classloaders.Agent * @run driver compiler.profiling.spectrapredefineclass_classloaders.Launcher - * @run main/othervm -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 - * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 - * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf - * compiler.profiling.spectrapredefineclass_classloaders.Agent + * @run main/othervm/timeout=480 -XX:CompilationMode=high-only -XX:-BackgroundCompilation -XX:CompileThreshold=10000 + * -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 + * -XX:ReservedCodeCacheSize=3M -Djdk.attach.allowAttachSelf + * compiler.profiling.spectrapredefineclass_classloaders.Agent */ package compiler.profiling.spectrapredefineclass_classloaders; diff --git a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java index 9cdba8c7bea..5bf031b7c4a 100644 --- a/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java +++ b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation + * @run main/othervm/timeout=960 -Xbootclasspath/a:. -XX:+TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCaseHelper::* * -XX:CompileCommand=print,compiler.whitebox.SimpleTestCaseHelper::* @@ -101,4 +101,3 @@ public class Level2RecompilationTest extends CompLevelsTest { super.checkLevel(expected, actual); } } - diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java index 3dc9df2d73e..1f5fc3d36bd 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestDeoptOOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary failed reallocations of scalar replaced objects during deoptimization causes crash * * @requires !vm.graal.enabled - * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack + * @run main/othervm/timeout=480 -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 * compiler.uncommontrap.TestDeoptOOM @@ -38,7 +38,7 @@ * @bug 8273456 * @summary Test that ttyLock is ranked above StackWatermark_lock * @requires !vm.graal.enabled & vm.gc.Z - * @run main/othervm -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack + * @run main/othervm/timeout=480 -XX:-BackgroundCompilation -Xmx128M -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::main * -XX:CompileCommand=exclude,compiler.uncommontrap.TestDeoptOOM::m9_1 * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java b/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java index 7af6296d16b..c9c574771c5 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestRawOopAtSafepoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,8 @@ import jdk.test.lib.Asserts; * @summary Verify that CheckCastPPs with raw oop inputs are not floating below a safepoint. * @library /test/lib * @modules jdk.incubator.vector - * @run main/othervm -XX:-TieredCompilation -Xbatch + * @run main/othervm/timeout=480 + * -XX:-TieredCompilation -Xbatch * -XX:CompileCommand=compileonly,compiler.vectorapi.TestRawOopAtSafepoint::test* * -XX:CompileCommand=dontinline,compiler.vectorapi.TestRawOopAtSafepoint::safepoint * compiler.vectorapi.TestRawOopAtSafepoint diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java index 9c342574632..f3c27c4d278 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -29,7 +29,7 @@ * @modules jdk.incubator.vector * @library /test/lib / * @compile TestFloat16VectorOperations.java -* @run driver compiler.vectorization.TestFloat16VectorOperations +* @run driver/timeout=480 compiler.vectorization.TestFloat16VectorOperations */ package compiler.vectorization; diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java index f4c8845b857..c30a28c46f9 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java @@ -26,7 +26,7 @@ * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Ensure that vectorization of numberOfLeadingZeros and numberOfTrailingZeros outputs correct values * @library /test/lib / - * @run main/othervm compiler.vectorization.TestVectorZeroCount + * @run main/othervm/timeout=480 compiler.vectorization.TestVectorZeroCount */ package compiler.vectorization; diff --git a/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java b/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java index 0ee8cfdbaa4..1dee119401b 100644 --- a/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java +++ b/test/hotspot/jtreg/gc/g1/TestGreyReclaimedHumongousObjects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -29,7 +29,7 @@ package gc.g1; * @requires vm.gc.G1 * @summary Test handling of marked but unscanned reclaimed humongous objects. * @modules jdk.management - * @run main/othervm -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m + * @run main/othervm/timeout=480 -XX:+UseG1GC -Xss32m -Xmx128m -XX:G1HeapRegionSize=1m * gc.g1.TestGreyReclaimedHumongousObjects 1048576 90 */ diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java index 813b002a8ea..5ade1fbee93 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -48,20 +48,20 @@ import java.nio.file.Paths; * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=240 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=960 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * gc.g1.humongousObjects.ClassLoaderGenerator 1 * - * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC.log * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC * - * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC_Mem_Pressure.log * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC_MEMORY_PRESSURE * - *@run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + *@run main/othervm/timeout=480 -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_CMC.log * -XX:G1HeapRegionSize=1M -XX:MaxTenuringThreshold=1 * gc.g1.humongousObjects.TestHumongousClassLoader CMC diff --git a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java index c9bc1e0f14e..692e5017157 100644 --- a/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java +++ b/test/hotspot/jtreg/gc/g1/humongousObjects/TestHumongousNonArrayAllocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -44,23 +44,23 @@ import java.nio.file.Paths; * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation LARGEST_NON_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation SMALLEST_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation ONE_REGION_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation TWO_REGION_HUMONGOUS * - * @run main/othervm -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -Xms128M -Xmx128M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:G1HeapRegionSize=1M * gc.g1.humongousObjects.TestHumongousNonArrayAllocation MORE_THAN_TWO_REGION_HUMONGOUS * diff --git a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java index b0adb1d489f..83080175a15 100644 --- a/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java +++ b/test/hotspot/jtreg/gc/g1/ihop/TestIHOPErgo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * @modules java.management - * @run driver/timeout=480 gc.g1.ihop.TestIHOPErgo + * @run driver/timeout=1920 gc.g1.ihop.TestIHOPErgo */ package gc.g1.ihop; diff --git a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java index 0c742b7b4ef..a323ebd945a 100644 --- a/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java +++ b/test/hotspot/jtreg/gc/stress/TestMultiThreadStressRSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -51,7 +51,7 @@ import jdk.test.lib.Utils; * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc * -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 60 16 * - * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * @run main/othervm/timeout=1200 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 gc.stress.TestMultiThreadStressRSet 600 32 */ diff --git a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java index 645583ec450..80ab9e21667 100644 --- a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java +++ b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -31,10 +31,10 @@ package gc.stress; * @requires !vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver gc.stress.TestReclaimStringsLeaksMemory - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC - * @run driver gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java index 9f3c4286c0f..f92a562aa31 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 4 3 1.1 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 4 3 1.1 120 */ /* @@ -40,7 +40,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 16 5 2.1 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 16 5 2.1 120 */ /* @@ -49,7 +49,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=180 gc.stress.TestStressG1Humongous 32 4 0.6 120 + * @run driver/timeout=240 gc.stress.TestStressG1Humongous 32 4 0.6 120 */ /* @@ -58,7 +58,7 @@ package gc.stress; * @requires !vm.flightRecorder * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=900 gc.stress.TestStressG1Humongous 1 7 0.6 600 + * @run driver/timeout=1200 gc.stress.TestStressG1Humongous 1 7 0.6 600 */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java b/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java index f7b6c77fdf3..7f91714d709 100644 --- a/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java +++ b/test/hotspot/jtreg/gc/stress/TestStressRSetCoarsening.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -38,7 +38,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 1 0 300 @@ -53,7 +53,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=8m gc.stress.TestStressRSetCoarsening 1 10 300 @@ -68,7 +68,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=32m gc.stress.TestStressRSetCoarsening 42 10 300 @@ -83,7 +83,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx500m -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 2 0 300 @@ -98,7 +98,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=1800 + * @run main/othervm/timeout=7200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx1G -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 500 0 1800 @@ -113,7 +113,7 @@ import jdk.test.whitebox.WhiteBox; * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm/timeout=1800 + * @run main/othervm/timeout=7200 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000 * -Xmx1G -XX:G1HeapRegionSize=1m gc.stress.TestStressRSetCoarsening 10 10 1800 diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java index 64a090025ac..a3bb0944dd5 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.G1 * @summary Stress the G1 GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC gc.stress.systemgc.TestSystemGCWithG1 270 + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC gc.stress.systemgc.TestSystemGCWithG1 270 */ public class TestSystemGCWithG1 { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java index 07a510c7a4e..2b4bca5cf4b 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.Parallel * @summary Stress the Parallel GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC gc.stress.systemgc.TestSystemGCWithParallel 270 + * @run main/othervm/timeout=540 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC gc.stress.systemgc.TestSystemGCWithParallel 270 */ public class TestSystemGCWithParallel { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java index 1db15b76e18..8571aee84c0 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ package gc.stress.systemgc; * @library / * @requires vm.gc.Serial * @summary Stress the Serial GC full GC by allocating objects of different lifetimes concurrently with System.gc(). - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC gc.stress.systemgc.TestSystemGCWithSerial 270 + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC gc.stress.systemgc.TestSystemGCWithSerial 270 */ public class TestSystemGCWithSerial { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java index 13129552873..ea475d42e0c 100644 --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithShenandoah.java @@ -32,12 +32,12 @@ package gc.stress.systemgc; * @requires vm.gc.Shenandoah * @summary Stress the Shenandoah GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC * -XX:+ShenandoahVerify * gc.stress.systemgc.TestSystemGCWithShenandoah 270 * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC * gc.stress.systemgc.TestSystemGCWithShenandoah 270 */ @@ -49,12 +49,12 @@ package gc.stress.systemgc; * @requires vm.gc.Shenandoah * @summary Stress the Shenandoah GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * gc.stress.systemgc.TestSystemGCWithShenandoah 270 * - * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=540 -Xlog:gc*=info -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * gc.stress.systemgc.TestSystemGCWithShenandoah 270 */ diff --git a/test/hotspot/jtreg/gc/z/TestUncommit.java b/test/hotspot/jtreg/gc/z/TestUncommit.java index afb736501dd..0e674358be5 100644 --- a/test/hotspot/jtreg/gc/z/TestUncommit.java +++ b/test/hotspot/jtreg/gc/z/TestUncommit.java @@ -27,7 +27,7 @@ package gc.z; * @test TestUncommit * @requires vm.gc.Z * @summary Test ZGC uncommit unused memory - * @run main/othervm -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=5 gc.z.TestUncommit + * @run main/othervm/timeout=480 -XX:+UseZGC -Xlog:gc*,gc+heap=debug,gc+stats=off -Xms128M -Xmx512M -XX:ZUncommitDelay=5 gc.z.TestUncommit */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/gtest/GTestWrapper.java b/test/hotspot/jtreg/gtest/GTestWrapper.java index 1bd9734e48c..2ee174b11be 100644 --- a/test/hotspot/jtreg/gtest/GTestWrapper.java +++ b/test/hotspot/jtreg/gtest/GTestWrapper.java @@ -27,7 +27,7 @@ * @modules java.base/jdk.internal.misc * java.xml * @requires vm.flagless - * @run main/native GTestWrapper + * @run main/native/timeout=480 GTestWrapper */ import jdk.test.lib.Platform; diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index f2a17acdd64..8130ff65792 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -56,7 +56,7 @@ import java.util.stream.Stream; * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver TestInheritFD + * @run driver/timeout=480 TestInheritFD */ /** @@ -78,6 +78,8 @@ import java.util.stream.Stream; * the third VM. */ +import jdk.test.lib.Utils; + public class TestInheritFD { public static final String LEAKS_FD = "VM RESULT => LEAKS FD"; @@ -90,8 +92,7 @@ public class TestInheritFD { public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; - public static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - public static long subProcessTimeout = (long)(15L * timeoutFactor); + public static long subProcessTimeout = (long)(15L * Utils.TIMEOUT_FACTOR); // Extract a pid from the specified String at the specified start offset. private static long extractPidFromStringOffset(String str, int start) { diff --git a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java index cb45f00d666..743e0372ab1 100644 --- a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java +++ b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8182397 * @summary race in setting array_klass field for component mirror with mirror update for klass * @modules java.base/jdk.internal.misc - * @run main/othervm -Xcomp ArraysNewInstanceBug + * @run main/othervm/timeout=480 -Xcomp ArraysNewInstanceBug */ // This test crashes in compiled code with race, because the compiler generates code that assumes this ordering. diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java index 2fb42e230a5..12755cba243 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/CreateCoredumpOnCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * java.compiler * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run driver CreateCoredumpOnCrash + * @run driver/timeout=480 CreateCoredumpOnCrash * @requires vm.flagless * @requires !vm.asan */ diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java index 0e4f01bb55f..a21c6b2b233 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invocationC1Tests.java @@ -32,7 +32,7 @@ * @modules java.base/jdk.internal.misc * @compile invokespecial/Checker.java invokespecial/ClassGenerator.java invokespecial/Generator.java * - * @run driver/timeout=1800 invocationC1Tests special + * @run driver/timeout=7200 invocationC1Tests special */ /* @@ -45,7 +45,7 @@ * @modules java.base/jdk.internal.misc * @compile invokevirtual/Checker.java invokevirtual/ClassGenerator.java invokevirtual/Generator.java * - * @run driver/timeout=1800 invocationC1Tests virtual + * @run driver/timeout=7200 invocationC1Tests virtual */ /* @@ -58,7 +58,7 @@ * @modules java.base/jdk.internal.misc * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java invokeinterface/Generator.java * - * @run driver/timeout=1800 invocationC1Tests interface + * @run driver/timeout=7200 invocationC1Tests interface */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java index 1cf175030be..fdbffb3afcf 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java @@ -33,7 +33,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests current-int + * @run driver/timeout=5400 invokeinterfaceTests current-int */ /* @@ -47,7 +47,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests current-comp + * @run driver/timeout=5400 invokeinterfaceTests current-comp */ /* @@ -61,7 +61,7 @@ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java * invokeinterface/Generator.java * - * @run driver/timeout=1800 invokeinterfaceTests old-int + * @run driver/timeout=5400 invokeinterfaceTests old-int */ import jdk.test.lib.process.ProcessTools; diff --git a/test/hotspot/jtreg/runtime/LoadClass/TestResize.java b/test/hotspot/jtreg/runtime/LoadClass/TestResize.java index 9177ede52da..bb4ebe358e4 100644 --- a/test/hotspot/jtreg/runtime/LoadClass/TestResize.java +++ b/test/hotspot/jtreg/runtime/LoadClass/TestResize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * @modules java.base/jdk.internal.misc * java.management * @compile TriggerResize.java - * @run driver TestResize + * @run driver/timeout=480 TestResize */ import jdk.test.lib.Platform; diff --git a/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java b/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java index 4d691eb920a..fd4444ccd88 100644 --- a/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java +++ b/test/hotspot/jtreg/runtime/NMT/VirtualAllocCommitMerge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * java.management * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -Xint -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitMerge + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -Xint -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocCommitMerge * */ diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java index 9212b2d0032..f00ed1636e2 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceICCE.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceICCE + * @run main/othervm/timeout=2000 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceICCE */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java index 4eb3c06e637..f27c03308e9 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeInterfaceSuccessTest.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceSuccessTest + * @run main/othervm/timeout=1200 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeInterfaceSuccessTest */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java index c041bca153d..1a0e67aeeab 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualICCE.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=1200 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualICCE + * @run main/othervm/timeout=4800 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualICCE */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java index a20e934d651..821b11169ab 100644 --- a/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java +++ b/test/hotspot/jtreg/runtime/SelectionResolution/InvokeVirtualSuccessTest.java @@ -28,7 +28,7 @@ * @requires vm.opt.final.ClassUnloading * @library /testlibrary/asm * @library /runtime/SelectionResolution/classes - * @run main/othervm/timeout=400 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualSuccessTest + * @run main/othervm/timeout=1600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies InvokeVirtualSuccessTest */ import java.util.Arrays; diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java index a8f8660272d..6dc6d04a737 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpMonitorContention.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * * @library /test/lib * @modules java.base/jdk.internal.misc - * @run main/othervm TestThreadDumpMonitorContention + * @run main/othervm/timeout=480 TestThreadDumpMonitorContention */ import java.io.BufferedReader; diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 202262a8117..d26ca8cc7cf 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -29,7 +29,7 @@ * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI DeterministicDump */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java index 3c3db7d0397..bb3d33218a2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java @@ -37,7 +37,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @summary Try to archive lots and lots of classes. * @requires vm.cds * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @run driver/timeout=500 LotsOfSyntheticClasses + * @run driver/timeout=8000 LotsOfSyntheticClasses */ public class LotsOfSyntheticClasses { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java index 5d1e3831d86..16e691c9a13 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java @@ -22,30 +22,22 @@ * */ -import jdk.test.lib.Utils; -import jdk.test.lib.BuildHelper; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.Platform; -import jdk.test.lib.cds.CDSOptions; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.cds.CDSTestUtils.Result; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; +import cdsutils.DynamicDumpHelper; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.nio.file.DirectoryStream; -import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.regex.Matcher; @@ -53,8 +45,17 @@ import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; +import jdk.test.lib.BuildHelper; +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.Utils; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils.Result; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; import jtreg.SkippedException; -import cdsutils.DynamicDumpHelper; /** @@ -76,9 +77,6 @@ public class TestCommon extends CDSTestUtils { private static final SimpleDateFormat timeStampFormat = new SimpleDateFormat("HH'h'mm'm'ss's'SSS"); - private static final String timeoutFactor = - System.getProperty("test.timeout.factor", "1.0"); - private static String currentArchiveName; // Call this method to start new archive with new unique name @@ -420,7 +418,7 @@ public class TestCommon extends CDSTestUtils { cmd.add("-Xshare:" + opts.xShareMode); cmd.add("-showversion"); cmd.add("-XX:SharedArchiveFile=" + getCurrentArchiveName()); - cmd.add("-Dtest.timeout.factor=" + timeoutFactor); + cmd.add("-Dtest.timeout.factor=" + Utils.TIMEOUT_FACTOR); if (opts.appJar != null) { cmd.add("-cp"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 4587eeae5e5..e1d132dd984 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -32,12 +32,12 @@ * subtests with this flag. * @library /test/lib /test/setup_aot * @build AOTCodeCompressedOopsTest JavacBenchApp - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * @run driver/timeout=480 jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * JavacBenchApp * JavacBenchApp$ClassFile * JavacBenchApp$FileManager * JavacBenchApp$SourceFile - * @run driver AOTCodeCompressedOopsTest + * @run driver/timeout=480 AOTCodeCompressedOopsTest */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java index fe9c7e7bbb7..4dc4512e01c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java @@ -36,7 +36,7 @@ * JavacBenchApp$FileManager * JavacBenchApp$SourceFile * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello - * @run driver AOTProfileFlags + * @run driver/timeout=480 AOTProfileFlags */ import jdk.test.lib.cds.CDSTestUtils; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java index 5871305139e..1114870d1d3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsStress.java @@ -28,7 +28,7 @@ * @requires vm.cds.write.archived.java.heap * @library /test/hotspot/jtreg/runtime/cds/appcds /test/lib * @build HelloString - * @run driver/timeout=650 SharedStringsStress + * @run driver/timeout=2600 SharedStringsStress */ import java.io.File; import java.io.FileOutputStream; diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java index 434864ff3bf..cf316a8bfd6 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,8 +34,8 @@ * @test * @requires !vm.graal.enabled * @comment These test C1 and C2 so make no sense when Graal is enabled. - * @run testng/othervm -Xcomp -XX:-TieredCompilation ArrayIndexOutOfBoundsExceptionTest - * @run testng/othervm -Xcomp -XX:TieredStopAtLevel=1 ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm/timeout=480 -Xcomp -XX:-TieredCompilation ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 ArrayIndexOutOfBoundsExceptionTest */ import java.io.ByteArrayInputStream; diff --git a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java index 8b75802cd3b..a013ebdea54 100644 --- a/test/hotspot/jtreg/runtime/logging/RedefineClasses.java +++ b/test/hotspot/jtreg/runtime/logging/RedefineClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * java.instrument * @requires vm.jvmti * @run main RedefineClassHelper - * @run main/othervm -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses + * @run main/othervm/timeout=480 -Xmx256m -XX:MaxMetaspaceSize=64m -javaagent:redefineagent.jar -Xlog:all=trace:file=all.log RedefineClasses */ // package access top-level class to avoid problem with RedefineClassHelper diff --git a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java index 09646d07358..69cfade4521 100644 --- a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 8297977 * @summary Test that throwing OOM from reflected method gets InvocationTargetException - * @run main/othervm -Xmx128m ReflectOutOfMemoryError + * @run main/othervm/timeout=480 -Xmx128m ReflectOutOfMemoryError */ import java.lang.reflect.*; diff --git a/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java b/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java index 7980b5ae28d..04086c49a4d 100644 --- a/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java +++ b/test/hotspot/jtreg/serviceability/HeapDump/UnmountedVThreadNativeMethodAtTop.java @@ -29,7 +29,7 @@ * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run junit/othervm/native -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI --enable-native-access=ALL-UNNAMED UnmountedVThreadNativeMethodAtTop + * @run junit/othervm/native/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI --enable-native-access=ALL-UNNAMED UnmountedVThreadNativeMethodAtTop */ import java.lang.management.ManagementFactory; diff --git a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java index 38fd16808cd..17565899a64 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,7 +30,7 @@ package MyPackage; * @summary Verifies the JVMTI Heap Monitor Thread information sanity. * @requires vm.jvmti * @compile HeapMonitorThreadTest.java - * @run main/othervm/native -Xmx512m -agentlib:HeapMonitorTest MyPackage.HeapMonitorThreadTest + * @run main/othervm/native/timeout=480 -Xmx512m -agentlib:HeapMonitorTest MyPackage.HeapMonitorThreadTest */ import java.util.List; diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java b/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java index d75f56714a4..136381e2111 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/SetTag/TagMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,9 +26,9 @@ * @bug 8306843 * @summary Test that 10M tags doesn't time out. * @requires vm.jvmti - * @run main/othervm/native -agentlib:TagMapTest - * -Xlog:jvmti+table - * TagMapTest + * @run main/othervm/native/timeout=480 -agentlib:TagMapTest + * -Xlog:jvmti+table + * TagMapTest */ import java.util.ArrayList; diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java index b773cf3fa0a..80dd42c480a 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume2/SuspendResume2.java @@ -28,7 +28,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -Djdk.virtualThreadScheduler.maxPoolSize=1 * -agentlib:SuspendResume2 * SuspendResume2 @@ -40,7 +40,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -Djdk.virtualThreadScheduler.maxPoolSize=1 * -agentlib:SuspendResume2 * -XX:-VerifyContinuations @@ -53,7 +53,7 @@ * @library /test/lib * @compile SuspendResume2.java * @run driver jdk.test.lib.FileInstaller . . - * @run main/othervm/native + * @run main/othervm/native/timeout=700 * -agentlib:SuspendResume2 * -XX:+UnlockExperimentalVMOptions * -XX:-VMContinuations diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java index fef7c827eb7..ee9872867ac 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpheap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -46,7 +46,7 @@ import jtreg.SkippedException; * timeouts. As there is no known direct benefit from running the test * with -Xcomp, we disable such testing. * @library /test/lib - * @run main/othervm/timeout=240 ClhsdbDumpheap + * @run main/othervm/timeout=960 ClhsdbDumpheap */ public class ClhsdbDumpheap { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java index c75a38490d5..7ced4c9515b 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ import jtreg.SkippedException; * @requires vm.compiler1.enabled * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC true false + * @run main/othervm/timeout=1920 ClhsdbFindPC true false */ /** @@ -53,7 +53,7 @@ import jtreg.SkippedException; * @requires vm.compiler1.enabled * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC true true + * @run main/othervm/timeout=1920 ClhsdbFindPC true true */ /** @@ -64,7 +64,7 @@ import jtreg.SkippedException; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @requires vm.compiler1.enabled * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC false false + * @run main/othervm/timeout=1920 ClhsdbFindPC false false */ /** @@ -74,7 +74,7 @@ import jtreg.SkippedException; * @requires vm.hasSA * @requires vm.compiler1.enabled * @library /test/lib - * @run main/othervm/timeout=480 ClhsdbFindPC false true + * @run main/othervm/timeout=1920 ClhsdbFindPC false true */ public class ClhsdbFindPC { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java index 7e06cb3af95..bb35e6c5aff 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstackXcompStress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,7 +39,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @requires vm.opt.DeoptimizeALot != true * @library /test/lib - * @run driver/timeout=300 ClhsdbJstackXcompStress + * @run driver/timeout=1200 ClhsdbJstackXcompStress */ public class ClhsdbJstackXcompStress { diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java index 988227f3961..5c3092a139d 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbThreadContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ import jtreg.SkippedException; * @requires vm.hasSA * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @library /test/lib - * @run main/othervm ClhsdbThreadContext + * @run main/othervm/timeout=480 ClhsdbThreadContext */ public class ClhsdbThreadContext { diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java index 87e664ef308..15b9aa9ccae 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLineNumbers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ import jdk.test.lib.SA.SATestUtils; * @requires os.family=="windows" | os.family == "linux" | os.family == "mac" * @requires vm.flagless * @library /test/lib - * @run driver TestJhsdbJstackLineNumbers + * @run driver/timeout=480 TestJhsdbJstackLineNumbers */ /* diff --git a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java index 28d6f74c689..62fe2f5d7aa 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java +++ b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ import jdk.test.lib.Utils; * @requires (os.arch != "riscv64" | !(vm.cpu.features ~= ".*qemu.*")) * @modules jdk.hotspot.agent/sun.jvm.hotspot * jdk.hotspot.agent/sun.jvm.hotspot.runtime - * @run driver TestObjectAlignment + * @run driver/timeout=480 TestObjectAlignment */ public class TestObjectAlignment { diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java index ebdd69e7d40..69f4c9eb454 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/SADebugDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * @modules java.base/jdk.internal.misc * @library /test/lib * - * @run driver SADebugDTest + * @run driver/timeout=480 SADebugDTest */ import java.util.concurrent.TimeUnit; @@ -125,7 +125,7 @@ public class SADebugDTest { // The startProcess will block until the 'golden' string appears in either process' stdout or stderr // In case of timeout startProcess kills the debugd process - Process debugd = startProcess("debugd", pb, null, l -> checkOutput(l, useRmiPort, rmiPort), 20, TimeUnit.SECONDS); + Process debugd = startProcess("debugd", pb, null, l -> checkOutput(l, useRmiPort, rmiPort), 80, TimeUnit.SECONDS); // If we are here, this means we have received the golden line and the test has passed // The debugd remains running, we have to kill it diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java index 8ba72f1bd86..bf8de679dfa 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java @@ -33,7 +33,7 @@ import compiler.lib.ir_framework.driver.irmatching.IRViolationException; * @requires vm.compiler2.enabled & vm.flagless & vm.debug == true * @summary Test the functionality of allowNotCompilable. * @library /test/lib / - * @run driver ir_framework.tests.TestNotCompilable + * @run driver/timeout=480 ir_framework.tests.TestNotCompilable */ public class TestNotCompilable { diff --git a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java index 51d787ec218..10bafe26ae4 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_class/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ * @requires vm.opt.ClassUnloadingWithConcurrentMark != false * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java index 4d681af1e28..03108809ebd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/tests/unloading_redefinition_inMemoryCompilation_keep_obj/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ * @requires vm.opt.ClassUnloadingWithConcurrentMark != false * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index 4d93785e5c6..8f8cfdcd541 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. 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 @@ -59,7 +59,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index c96b47cf1cd..c207b80c059 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -60,7 +60,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index adfa8879153..fd7e1e5e8dd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index 7b09a18d798..2301daba8d3 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index d2943ff90ab..abf91f48dea 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm/timeout=300 + * @run main/othervm/timeout=1200 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java index ba9b6d75750..f57e0888268 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/SoftReference/soft004/soft004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.SoftReference.soft004.soft004 -t 1 + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.SoftReference.soft004.soft004 -t 1 */ package gc.gctests.SoftReference.soft004; diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java index bf86f5d8045..29390ae02d5 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/WeakReference/weak004/weak004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.WeakReference.weak004.weak004 -t 1 + * @run main/othervm/timeout=480 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.gctests.WeakReference.weak004.weak004 -t 1 */ package gc.gctests.WeakReference.weak004; diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java index 2e4cfcb9992..68fe6779e99 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,5 +31,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) + * @run main/othervm/timeout=480 gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) */ diff --git a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java index e2d04c6745a..17e88aeebb0 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java +++ b/test/hotspot/jtreg/vmTestbase/jit/escape/AdaptiveBlocking/AdaptiveBlocking001/AdaptiveBlocking001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001 - * @run driver/timeout=300 ExecDriver --java -server -Xcomp -XX:+DoEscapeAnalysis + * @run driver/timeout=1200 ExecDriver --java -server -Xcomp -XX:+DoEscapeAnalysis * jit.escape.AdaptiveBlocking.AdaptiveBlocking001.AdaptiveBlocking001 -numRounds 10 */ diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java index 577bb5f1a92..3fb8241191d 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/CompressedClassSpaceSize/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,11 +31,10 @@ * * @requires vm.opt.final.ClassUnloading * @library /vmTestbase /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -DrequiresCompressedClassSpace=true * -XX:MaxMetaspaceSize=100m * -XX:CompressedClassSpaceSize=10m * -Xlog:gc*:gc.log * metaspace.shrink_grow.ShrinkGrowTest.ShrinkGrowTest */ - diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java index c59f8cd9e9e..dc7881dc8f7 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowMultiJVM/ShrinkGrowMultiJVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * @requires vm.opt.final.ClassUnloading * @library /vmTestbase /test/lib * @build metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM - * @run driver metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM + * @run driver/timeout=480 metaspace.shrink_grow.ShrinkGrowMultiJVM.ShrinkGrowMultiJVM */ package metaspace.shrink_grow.ShrinkGrowMultiJVM; diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java index 32f5c0c55e8..2b4082d215f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java index 75faa8d14e3..e936c3fe73e 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java index 743de7b4e7d..48fa6fe5392 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java index bc6287eaf60..ada43b47c59 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java index 030f07fbaea..e66673d3316 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java index f294a4ecc6a..288ea9d2105 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy006/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java index f3238d787c2..651da5c2955 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java index a37231429c3..03b8f77cfaf 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java index dd28f1665a7..247abdfaa3d 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java index ab11ba48647..2c9acbbbf01 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java index ce304df4041..755869c92d2 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=450m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java index a37eda53cfa..71a61a92ede 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @comment generate and compile metaspace.stressHierarchy.common.HumongousClass * @run driver metaspace.stressHierarchy.common.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:MaxMetaspaceSize=250m * -Xss10m * -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java index a10d9b2d50b..c9cf9ee88cb 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy013/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java index c0ceceb1e50..181a526e97f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy014/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java index a0c73e6dd0c..11eba8b2b1f 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy015/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * @library /vmTestbase /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm + * @run main/othervm/timeout=480 * -Xss10m * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java index 7e73bace342..b5ea8c34cbd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects001/referringObjects001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -57,7 +57,7 @@ * /test/lib * @build nsk.jdi.ObjectReference.referringObjects.referringObjects001.referringObjects001 * nsk.share.jdi.TestClass1 - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.jdi.ObjectReference.referringObjects.referringObjects001.referringObjects001 * -verbose * -arch=${os.family}-${os.simpleArch} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java index ff303d4c52d..14c0ebf74f5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/StepEvent/_itself_/stepEvent004/stepEvent004.java @@ -62,7 +62,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdi.StepEvent._itself_.stepEvent004.stepEvent004 - * @run driver + * @run driver/timeout=480 * nsk.jdi.StepEvent._itself_.stepEvent004.stepEvent004 * -verbose * -arch=${os.family}-${os.simpleArch} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java index b638a58976f..269aaec8226 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathEvent/thread/thread001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -82,7 +82,7 @@ * /test/lib * @build nsk.jdi.ThreadDeathEvent.thread.thread001 * nsk.jdi.ThreadDeathEvent.thread.thread001a - * @run driver + * @run driver/timeout=480 * nsk.jdi.ThreadDeathEvent.thread.thread001 * -verbose * -arch=${os.family}-${os.simpleArch} @@ -91,4 +91,3 @@ * -transport.address=dynamic * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java index 938673e2284..e5d77e0263b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -63,7 +63,7 @@ * nsk.share.jdi.MonitorEventsDebuggee * * @build nsk.share.jdi.SerialExecutionDebugger - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.share.jdi.SerialExecutionDebugger * -verbose * -arch=${os.family}-${os.simpleArch} @@ -76,4 +76,3 @@ * -configFile ${test.src}/mixed002.tests * -testWorkDir . */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java index e41efd46bb4..32cf223dda7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/HoldEvents/holdevents002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -53,7 +53,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.jdwp.VirtualMachine.HoldEvents.holdevents002a - * @run main/othervm/timeout=420 + * @run main/othervm/timeout=1680 * nsk.jdwp.VirtualMachine.HoldEvents.holdevents002 * -arch=${os.family}-${os.simpleArch} * -verbose @@ -62,4 +62,3 @@ * -transport.address=dynamic * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java index 7705260e802..93b59229f14 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -37,6 +37,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native -agentlib:rawmnwait001 nsk.jvmti.RawMonitorWait.rawmnwait001 + * @run main/othervm/native/timeout=480 -agentlib:rawmnwait001 nsk.jvmti.RawMonitorWait.rawmnwait001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java index 9c5f23d0c43..cf472a079c2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -59,8 +59,7 @@ * @build nsk.jvmti.scenarios.sampling.SP03.sp03t001 * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp03t001=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP03.sp03t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java index ba4d3f332ce..7c9f0773788 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP03/sp03t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -59,8 +59,7 @@ * @build nsk.jvmti.scenarios.sampling.SP03.sp03t002 * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp03t002=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP03.sp03t002 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java index 730cfa104e5..dbb8f30873f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -58,8 +58,7 @@ * /test/lib * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp04t001=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP04.sp04t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java index e03a343e381..da08316bfd2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP04/sp04t002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -58,8 +58,7 @@ * /test/lib * @comment see JDK-8243962 for background on requires expression * @requires !(vm.flightRecorder & vm.debug & os.family == "windows") - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp04t002=-waittime=5,threads=10 * nsk.jvmti.scenarios.sampling.SP04.sp04t002 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java index 79ccb9c8e70..182cf4494ff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -38,8 +38,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * -agentlib:sp07t001=-waittime=5 * nsk.jvmti.scenarios.sampling.SP07.sp07t001 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java index 411d70f6e91..e8b855b5ce6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isSuspended/issuspended002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. 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 @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * /testlibrary - * @run main/othervm nsk.monitoring.ThreadInfo.isSuspended.issuspended002 + * @run main/othervm/timeout=480 nsk.monitoring.ThreadInfo.isSuspended.issuspended002 */ package nsk.monitoring.ThreadInfo.isSuspended; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java index 53b73954af5..5732f319bc9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -60,6 +60,5 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native nsk.monitoring.stress.thread.strace001 -threadCount=50 -depth=200 + * @run main/othervm/native/timeout=480 nsk.monitoring.stress.thread.strace001 -threadCount=50 -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java index b41fb5f76f8..6548e27c779 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -58,10 +58,9 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.monitoring.stress.thread.strace001 * -testMode=server * -threadCount=50 * -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java index c39f4dde2af..fc0174092e0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -58,11 +58,10 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native + * @run main/othervm/native/timeout=480 * nsk.monitoring.stress.thread.strace001 * -testMode=server * -MBeanServer=custom * -threadCount=50 * -depth=200 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java index ef27aa57bfa..accfae7e4bd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/strace/strace006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -43,7 +43,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm/native nsk.stress.strace.strace006 + * @run main/othervm/native/timeout=480 nsk.stress.strace.strace006 */ package nsk.stress.strace; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java index 4fdab351c79..a047824ffbb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * lower than the main thread. * * @library /test/lib - * @run main/othervm nsk.stress.thread.thread001 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread001 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java index a574533581f..f4d48b9eaa7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * Try to start the given number of threads of the same * priority that the main thread. * - * @run main/othervm nsk.stress.thread.thread002 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread002 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java index 0a5e33441cb..06afa1d2154 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * DESCRIPTION * Try many threads starting simultaneously. * - * @run main/othervm nsk.stress.thread.thread005 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread005 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java index 6adda1929d2..b6e5115e153 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * Try many threads of lower priority * starting simultaneously. * - * @run main/othervm nsk.stress.thread.thread006 500 2m 5s + * @run main/othervm/timeout=480 nsk.stress.thread.thread006 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java index 26388c28d0a..04b3784ce11 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * Try to start the given number of threads starting simultaneously * when notifyall() is signaled at the stopLine object. * - * @run main/othervm/timeout=300 nsk.stress.thread.thread007 500 2m 5s + * @run main/othervm/timeout=1200 nsk.stress.thread.thread007 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java index 2cbc198a693..a6a64bc9ce9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/thread008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * starting simultaneously when notifyall() is signaled at the * stopLine object. * - * @run main/othervm/timeout=300 nsk.stress.thread.thread008 500 2m 5s + * @run main/othervm/timeout=1200 nsk.stress.thread.thread008 500 2m 5s */ package nsk.stress.thread; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java index db6ebf0a446..d00b965cce2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree001/btree001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -40,14 +40,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java index 5a4a9fae0d6..e2b161f6f47 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree002/btree002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -39,15 +39,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java index b915e0d716c..7fedad20e90 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree003/btree003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -39,15 +39,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java index 14094d6a5a1..dc8170c80e9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree004/btree004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -40,13 +40,12 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java index 42041c94fcf..55b20419d17 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree005/btree005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -39,14 +39,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java index 49b55e39456..ed15893686f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree006/btree006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -39,14 +39,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java index 6c74967dd22..dd58953d323 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree007/btree007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -42,15 +42,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -t 1 * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java index 9861f3c051f..a0dff733054 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree008/btree008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -41,11 +41,11 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar @@ -53,4 +53,3 @@ * -stressHeap * -t 1 */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java index 273fceebb81..6f70b64178b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree009/btree009.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -41,11 +41,11 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar @@ -53,4 +53,3 @@ * -stressHeap * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java index 1e9f3e8813f..27d6166776b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree010/btree010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -42,14 +42,13 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java index 507abcef278..0a46ed3d80c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree011/btree011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -41,15 +41,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -useSingleLoader * -stressHeap */ - diff --git a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java index 45ce9150457..cdc22cbb399 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/sysdict/vm/stress/btree/btree012/btree012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -41,15 +41,14 @@ * @comment btree classes import nsk.sysdict.share.* * @build nsk.sysdict.share.* * @comment build btree.jar - * @run driver nsk.sysdict.share.GenClassesBuilder btree + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder btree * @comment build fats.jar - * @run driver nsk.sysdict.share.GenClassesBuilder fats + * @run driver/timeout=480 nsk.sysdict.share.GenClassesBuilder fats * @build nsk.sysdict.share.BTreeTest - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * nsk.sysdict.share.BTreeTest * -jarpath btree.jar${path.separator}fats.jar * -stressHeap * -useFatClass */ - diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java index 5afb841f141..e0be5f1adb5 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -59,4 +59,3 @@ * vm.mlvm.indy.func.jvmti.share.IndyRedefineTest * -dummyClassName=vm.mlvm.indy.func.jvmti.mergeCP_indy2manyDiff_a.INDIFY_Dummy0 */ - diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java index 146db0dfa80..72212757a8e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java @@ -50,7 +50,7 @@ * @build vm.mlvm.meth.stress.compiler.i2c_c2i.Test * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm -XX:CompileCommand=MemLimit,*.*,0 vm.mlvm.meth.stress.compiler.i2c_c2i.Test + * @run main/othervm/timeout=480 -XX:CompileCommand=MemLimit,*.*,0 vm.mlvm.meth.stress.compiler.i2c_c2i.Test */ package vm.mlvm.meth.stress.compiler.i2c_c2i; diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java index 9a34a2b7b3d..daf5aa19609 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ * @build vm.mlvm.meth.stress.compiler.sequences.Test * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=480 * vm.mlvm.meth.stress.compiler.sequences.Test * -threadsPerCpu 1 * -threadsExtra 2 diff --git a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java index b2122d5691b..3b817325bcf 100644 --- a/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java +++ b/test/jdk/com/sun/crypto/provider/KeyFactory/TestProviderLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -28,6 +28,7 @@ * @summary com.sun.crypto.provider.SunJCE instance leak using KRB5 and * LoginContext * @author Brad Wetmore + * @library /test/lib * * @run main/othervm -Xmx20m TestProviderLeak * @@ -47,6 +48,7 @@ import javax.crypto.spec.*; import java.util.*; import java.util.concurrent.*; import jdk.test.lib.security.SecurityUtils; +import jdk.test.lib.Utils; public class TestProviderLeak { private static final int MB = 1024 * 1024; @@ -59,9 +61,7 @@ public class TestProviderLeak { static { int timeout = 5; try { - double timeoutFactor = Double.parseDouble( - System.getProperty("test.timeout.factor", "1.0")); - timeout = (int) (timeout * timeoutFactor); + timeout = (int) (timeout * Utils.TIMEOUT_FACTOR); } catch (Exception e) { System.out.println("Warning: " + e); } diff --git a/test/jdk/com/sun/jdi/InterruptHangTest.java b/test/jdk/com/sun/jdi/InterruptHangTest.java index 5dcb5efef31..07af07e3c02 100644 --- a/test/jdk/com/sun/jdi/InterruptHangTest.java +++ b/test/jdk/com/sun/jdi/InterruptHangTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. 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 @@ -24,12 +24,14 @@ import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; +import jdk.test.lib.Utils; /** * @test * @bug 6459476 * @summary Test interrupting debuggee with single stepping enable * @author jjh + * @library /test/lib * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g InterruptHangTest.java @@ -284,8 +286,7 @@ public class InterruptHangTest extends TestScaffold { timerThread = new Thread("test timer") { public void run() { int mySteps = 0; - float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - long sleepSeconds = (long)(20 * timeoutFactor); + long sleepSeconds = (long)(20 * Utils.TIMEOUT_FACTOR); println("Timer watching for steps every " + sleepSeconds + " seconds"); while (true) { try { diff --git a/test/jdk/com/sun/jdi/MethodEntryExitEvents.java b/test/jdk/com/sun/jdi/MethodEntryExitEvents.java index abdb0ff7c75..075d2044240 100644 --- a/test/jdk/com/sun/jdi/MethodEntryExitEvents.java +++ b/test/jdk/com/sun/jdi/MethodEntryExitEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -29,9 +29,9 @@ * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g MethodEntryExitEvents.java - * @run driver MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee - * @run driver MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee - * @run driver MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_EVENT_THREAD MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_NONE MethodEntryExitEventsDebugee + * @run driver/timeout=480 MethodEntryExitEvents SUSPEND_ALL MethodEntryExitEventsDebugee */ import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java index ef44829f1f7..59168a4de7e 100644 --- a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java +++ b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g ThreadMemoryLeakTest.java * @comment run with -Xmx7m so any leak will quickly produce OOME - * @run main/othervm -Xmx7m ThreadMemoryLeakTest + * @run main/othervm/timeout=480 -Xmx7m ThreadMemoryLeakTest */ import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java index 123c5120daf..294e0f5f1a8 100644 --- a/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java +++ b/test/jdk/com/sun/jndi/ldap/LdapPoolTimeoutTest.java @@ -27,7 +27,7 @@ * @summary Multi-threaded client timeout tests for ldap pool * @library /test/lib * lib/ - * @run testng/othervm LdapPoolTimeoutTest + * @run testng/othervm/timeout=480 LdapPoolTimeoutTest */ import org.testng.annotations.Test; @@ -144,4 +144,3 @@ public class LdapPoolTimeoutTest { } } - diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java index fccc12a9f06..b73db200ee2 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,7 @@ * @bug 4927640 * @summary Tests the SCTP protocol implementation * @author chegar + * @run main/timeout=480 Connect */ import java.net.InetSocketAddress; diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java index 49ba4d64b5b..6d62aa6c154 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,7 @@ * @bug 4927640 * @summary Tests the SCTP protocol implementation * @author chegar + * @run main/timeout=480 NonBlockingAccept */ import java.net.InetSocketAddress; diff --git a/test/jdk/java/awt/font/NumericShaper/MTTest.java b/test/jdk/java/awt/font/NumericShaper/MTTest.java index 08a218dfc0d..a152f552dd1 100644 --- a/test/jdk/java/awt/font/NumericShaper/MTTest.java +++ b/test/jdk/java/awt/font/NumericShaper/MTTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 6843181 6943963 * @summary Confirm that NumericShaper is thread-safe. - * @run main/timeout=300/othervm MTTest + * @run main/timeout=400/othervm MTTest */ import java.awt.font.NumericShaper; diff --git a/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java b/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java index 1f6dc09550c..dc3384a3572 100644 --- a/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java +++ b/test/jdk/java/beans/XMLDecoder/8028054/TestMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ import java.util.List; * @author Sergey Malenkov * @modules java.desktop/com.sun.beans.finder * @compile -XDignore.symbol.file TestMethodFinder.java - * @run main TestMethodFinder + * @run main/timeout=480 TestMethodFinder */ public class TestMethodFinder { diff --git a/test/jdk/java/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index 7bb8a29b0c0..f1e35b53a39 100644 --- a/test/jdk/java/foreign/StdLibTest.java +++ b/test/jdk/java/foreign/StdLibTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm --enable-native-access=ALL-UNNAMED StdLibTest + * @run testng/othervm/timeout=480 --enable-native-access=ALL-UNNAMED StdLibTest */ import java.lang.invoke.MethodHandle; diff --git a/test/jdk/java/foreign/TestAccessModes.java b/test/jdk/java/foreign/TestAccessModes.java index a721c87484d..e54d4f1ae9e 100644 --- a/test/jdk/java/foreign/TestAccessModes.java +++ b/test/jdk/java/foreign/TestAccessModes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -23,10 +23,10 @@ /* * @test - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes - * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes + * @run testng/othervm/timeout=480 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes */ import java.lang.foreign.*; diff --git a/test/jdk/java/foreign/TestBufferStackStress2.java b/test/jdk/java/foreign/TestBufferStackStress2.java index cefdbb725d1..402ce6bbe94 100644 --- a/test/jdk/java/foreign/TestBufferStackStress2.java +++ b/test/jdk/java/foreign/TestBufferStackStress2.java @@ -30,7 +30,7 @@ * @bug 8356114 8356658 * @modules java.base/jdk.internal.foreign * @build NativeTestHelper TestBufferStackStress2 - * @run junit TestBufferStackStress2 + * @run junit/timeout=480 TestBufferStackStress2 */ import jdk.internal.foreign.BufferStack; diff --git a/test/jdk/java/foreign/TestConcurrentClose.java b/test/jdk/java/foreign/TestConcurrentClose.java index 06dc7375cda..82bb2492acf 100644 --- a/test/jdk/java/foreign/TestConcurrentClose.java +++ b/test/jdk/java/foreign/TestConcurrentClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run testng/othervm + * @run testng/othervm/timeout=480 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/jdk/java/foreign/TestDeadlock.java b/test/jdk/java/foreign/TestDeadlock.java index 8511a01d2f5..f333727d4ce 100644 --- a/test/jdk/java/foreign/TestDeadlock.java +++ b/test/jdk/java/foreign/TestDeadlock.java @@ -23,7 +23,7 @@ /* * @test id=Arena_allocateFrom - * @run main/othervm/timeout=10 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena + * @run main/othervm/timeout=60 --enable-native-access=ALL-UNNAMED -Xlog:class+init TestDeadlock Arena */ /* diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index f50621e3415..fa01f1553eb 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test * @bug 8323552 - * @run testng TestMismatch + * @run testng/timeout=480 TestMismatch */ import java.lang.foreign.Arena; diff --git a/test/jdk/java/foreign/TestStringEncodingJumbo.java b/test/jdk/java/foreign/TestStringEncodingJumbo.java index 8ef86e72efc..bdae83bbd8b 100644 --- a/test/jdk/java/foreign/TestStringEncodingJumbo.java +++ b/test/jdk/java/foreign/TestStringEncodingJumbo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ import static org.testng.Assert.*; * @requires sun.arch.data.model == "64" * @requires vm.flavor != "zero" * - * @run testng/othervm -Xmx6G TestStringEncodingJumbo + * @run testng/othervm/timeout=480 -Xmx6G TestStringEncodingJumbo */ public class TestStringEncodingJumbo { diff --git a/test/jdk/java/foreign/TestStubAllocFailure.java b/test/jdk/java/foreign/TestStubAllocFailure.java index b3b327e788c..8cd4a61626e 100644 --- a/test/jdk/java/foreign/TestStubAllocFailure.java +++ b/test/jdk/java/foreign/TestStubAllocFailure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" * @requires vm.compMode != "Xcomp" - * @run testng/othervm/native + * @run testng/othervm/native/timeout=480 * --enable-native-access=ALL-UNNAMED * TestStubAllocFailure */ diff --git a/test/jdk/java/foreign/TestUpcallStack.java b/test/jdk/java/foreign/TestUpcallStack.java index 726373b9e27..4552cbef734 100644 --- a/test/jdk/java/foreign/TestUpcallStack.java +++ b/test/jdk/java/foreign/TestUpcallStack.java @@ -27,7 +27,7 @@ * @modules java.base/jdk.internal.foreign * @build NativeTestHelper CallGeneratorHelper TestUpcallBase * - * @run testng/othervm/native -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run testng/othervm/native/timeout=480 -Xcheck:jni -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies * --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 * TestUpcallStack */ diff --git a/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java index cc44d194174..204f4038144 100644 --- a/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java +++ b/test/jdk/java/foreign/loaderLookup/TestLoaderLookup.java @@ -25,7 +25,7 @@ * @test * @compile lookup/Lookup.java * @compile invoker/Invoker.java - * @run main/othervm/native --enable-native-access=ALL-UNNAMED TestLoaderLookup + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED TestLoaderLookup */ import java.lang.foreign.*; diff --git a/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java b/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java index ac5d6c6a329..e0aeb76f93f 100644 --- a/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java +++ b/test/jdk/java/io/FileInputStream/UnreferencedFISClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * @bug 6524062 * @summary Test to ensure that FIS.finalize() invokes the close() method as per * the specification. - * @run main/othervm UnreferencedFISClosesFd + * @run main/othervm/timeout=480 UnreferencedFISClosesFd */ import java.io.File; import java.io.FileDescriptor; diff --git a/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java b/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java index 3ff817085bd..ada39a2803a 100644 --- a/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java +++ b/test/jdk/java/io/FileOutputStream/UnreferencedFOSClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -29,7 +29,7 @@ * @build jdk.test.lib.util.FileUtils UnreferencedFOSClosesFd * @bug 6524062 * @summary Test to ensure that the fd is closed if left unreferenced - * @run main/othervm UnreferencedFOSClosesFd + * @run main/othervm/timeout=480 UnreferencedFOSClosesFd */ import java.io.File; import java.io.FileDescriptor; diff --git a/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java b/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java index c5b73a07c7d..99212b9a837 100644 --- a/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java +++ b/test/jdk/java/io/RandomAccessFile/UnreferencedRAFClosesFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -48,7 +48,7 @@ import jdk.test.lib.util.FileUtils; * @build jdk.test.lib.util.FileUtils UnreferencedRAFClosesFd * @modules java.base/java.io:open * @summary Test to ensure that an unclosed and unreferenced RandomAccessFile closes the fd - * @run main/othervm UnreferencedRAFClosesFd + * @run main/othervm/timeout=480 UnreferencedRAFClosesFd */ public class UnreferencedRAFClosesFd { diff --git a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 51ce41d837b..4f700df33dc 100644 --- a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -57,7 +57,7 @@ import jdk.internal.module.Modules; * loads all classes and get their declared fields * and call setAccessible(false) followed by setAccessible(true); * @modules java.base/jdk.internal.module - * @run main/othervm --add-modules=ALL-SYSTEM FieldSetAccessibleTest + * @run main/othervm/timeout=480 --add-modules=ALL-SYSTEM FieldSetAccessibleTest * * @author danielfuchs */ diff --git a/test/jdk/java/lang/Math/IntegralPowTest.java b/test/jdk/java/lang/Math/IntegralPowTest.java index b0aadcc8d3b..ffbb499e0c8 100644 --- a/test/jdk/java/lang/Math/IntegralPowTest.java +++ b/test/jdk/java/lang/Math/IntegralPowTest.java @@ -25,7 +25,7 @@ * @test * @bug 8355992 * @summary Tests for StrictMath.*PowExact and .*unsignedMultiplyExact - * @run junit IntegralPowTest + * @run junit/timeout=480 IntegralPowTest */ import org.junit.jupiter.api.Test; diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java index 146c2be563f..02f3583f0b3 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java @@ -27,7 +27,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest */ /** @@ -35,7 +35,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest */ /** @@ -43,7 +43,7 @@ * @summary Check that we don't leak FDs * @requires os.family == "linux" * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest */ import jdk.test.lib.process.ProcessTools; diff --git a/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java b/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java index d2625518b6d..5f310ff7df4 100644 --- a/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java +++ b/test/jdk/java/lang/ProcessBuilder/UnblockSignals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -30,8 +30,8 @@ import java.io.IOException; * @requires (os.family == "linux" | os.family == "mac") * @comment Don't allow -Xcomp, it disturbs the relative timing of the sleep and kill commands * @requires (vm.compMode != "Xcomp") - * @run main/othervm -Djdk.lang.Process.launchMechanism=POSIX_SPAWN UnblockSignals - * @run main/othervm -Djdk.lang.Process.launchMechanism=POSIX_SPAWN -Xrs UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=POSIX_SPAWN UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=POSIX_SPAWN -Xrs UnblockSignals */ /* @@ -41,8 +41,8 @@ import java.io.IOException; * @requires (os.family == "linux" | os.family == "mac") * @comment Don't allow -Xcomp, it disturbs the relative timing of the sleep and kill commands * @requires (vm.compMode != "Xcomp") - * @run main/othervm -Djdk.lang.Process.launchMechanism=FORK UnblockSignals - * @run main/othervm -Djdk.lang.Process.launchMechanism=FORK -Xrs UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=FORK UnblockSignals + * @run main/othervm/timeout=480 -Djdk.lang.Process.launchMechanism=FORK -Xrs UnblockSignals */ public class UnblockSignals { diff --git a/test/jdk/java/lang/StackWalker/LocalsAndOperands.java b/test/jdk/java/lang/StackWalker/LocalsAndOperands.java index 900cad1246a..445a4efe649 100644 --- a/test/jdk/java/lang/StackWalker/LocalsAndOperands.java +++ b/test/jdk/java/lang/StackWalker/LocalsAndOperands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,8 +26,8 @@ * @bug 8020968 8147039 8156073 * @summary Tests for locals and operands * @modules java.base/java.lang:open - * @run testng/othervm -Xint -DtestUnused=true LocalsAndOperands - * @run testng/othervm -Xcomp LocalsAndOperands + * @run testng/othervm/timeout=480 -Xint -DtestUnused=true LocalsAndOperands + * @run testng/othervm/timeout=480 -Xcomp LocalsAndOperands */ /* @@ -35,7 +35,7 @@ * @bug 8020968 8147039 8156073 * @modules java.base/java.lang:open * @requires !vm.graal.enabled - * @run testng/othervm -Xcomp -XX:-TieredCompilation LocalsAndOperands + * @run testng/othervm/timeout=480 -Xcomp -XX:-TieredCompilation LocalsAndOperands */ import org.testng.annotations.*; diff --git a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java index 3511a870f39..076e3c53faf 100644 --- a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java +++ b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -32,9 +32,9 @@ import java.nio.charset.StandardCharsets; * @summary Tests Compact String for maximum size strings * @requires os.maxMemory >= 8g & vm.bits == 64 * @requires vm.flagless - * @run junit/othervm -XX:+CompactStrings -Xmx8g MaxSizeUTF16String - * @run junit/othervm -XX:-CompactStrings -Xmx8g MaxSizeUTF16String - * @run junit/othervm -Xcomp -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -XX:+CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -XX:-CompactStrings -Xmx8g MaxSizeUTF16String + * @run junit/othervm/timeout=480 -Xcomp -Xmx8g MaxSizeUTF16String */ public class MaxSizeUTF16String { diff --git a/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java b/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java index 49eb3b28ff3..2a6e92e9402 100644 --- a/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java +++ b/test/jdk/java/lang/StringBuilder/CompactStringBuilder.java @@ -33,9 +33,9 @@ import static org.testng.Assert.assertTrue; * @bug 8054307 8077559 8351443 * @summary Tests Compact String. This test is testing StringBuilder * behavior related to Compact String. - * @run testng/othervm -XX:+CompactStrings CompactStringBuilder - * @run testng/othervm -XX:-CompactStrings CompactStringBuilder - * @run testng/othervm -Xcomp CompactStringBuilder + * @run testng/othervm/timeout=480 -XX:+CompactStrings CompactStringBuilder + * @run testng/othervm/timeout=480 -XX:-CompactStrings CompactStringBuilder + * @run testng/othervm/timeout=480 -Xcomp CompactStringBuilder */ public class CompactStringBuilder { diff --git a/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java b/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java index 840e40453c6..9c8e37e8c6d 100644 --- a/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java +++ b/test/jdk/java/lang/Thread/virtual/CancelTimerWithContention.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * contention on the timer queue * @requires vm.continuations * @key randomness - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.virtualThreadScheduler.parallelism=2 * -Djdk.virtualThreadScheduler.timerQueues=1 * CancelTimerWithContention diff --git a/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java b/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java index b512aa75789..32586812614 100644 --- a/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java +++ b/test/jdk/java/lang/Thread/virtual/MiscMonitorTests.java @@ -27,7 +27,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm MiscMonitorTests + * @run junit/othervm/timeout=480 MiscMonitorTests */ /* @@ -35,7 +35,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xint MiscMonitorTests + * @run junit/othervm/timeout=480 -Xint MiscMonitorTests */ /* @@ -43,7 +43,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp MiscMonitorTests */ /* @@ -51,7 +51,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp -XX:TieredStopAtLevel=3 MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp -XX:TieredStopAtLevel=3 MiscMonitorTests */ /* @@ -60,7 +60,7 @@ * @library /test/lib * @requires vm.continuations * @modules java.base/java.lang:+open - * @run junit/othervm -Xcomp -XX:-TieredCompilation MiscMonitorTests + * @run junit/othervm/timeout=480 -Xcomp -XX:-TieredCompilation MiscMonitorTests */ /* @@ -68,7 +68,7 @@ * @requires vm.debug == true & vm.continuations * @library /test/lib * @modules java.base/java.lang:+open - * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=1000 MiscMonitorTests + * @run junit/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=1000 MiscMonitorTests */ import java.util.concurrent.atomic.AtomicInteger; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java index 3a7eecd054e..14b8ffc1949 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java @@ -26,35 +26,35 @@ * @summary Test virtual thread with monitor enter/exit * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp-TieredStopAtLevel1 * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorEnterExit */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorEnterExit + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorEnterExit */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java index d5df8eb97d0..47089d9d6df 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java @@ -26,35 +26,35 @@ * @summary Test virtual threads using Object.wait/notifyAll * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp-TieredStopAtLevel1 * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorWaitNotify + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ import java.util.ArrayList; diff --git a/test/jdk/java/lang/Thread/virtual/Parking.java b/test/jdk/java/lang/Thread/virtual/Parking.java index 574707e637c..c337f36e7c2 100644 --- a/test/jdk/java/lang/Thread/virtual/Parking.java +++ b/test/jdk/java/lang/Thread/virtual/Parking.java @@ -26,28 +26,28 @@ * @summary Test virtual threads using park/unpark * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit Parking + * @run junit/timeout=480 Parking */ /* * @test id=Xint * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xint Parking + * @run junit/othervm/timeout=480 -Xint Parking */ /* * @test id=Xcomp * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xcomp Parking + * @run junit/othervm/timeout=480 -Xcomp Parking */ /* * @test id=Xcomp-noTieredCompilation * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm -Xcomp -XX:-TieredCompilation Parking + * @run junit/othervm/timeout=480 -Xcomp -XX:-TieredCompilation Parking */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java b/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java index 1c7177d9f38..464259ecb86 100644 --- a/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/RetryMonitorEnterWhenPinned.java @@ -29,7 +29,7 @@ * can't continue because there are no carriers available. * @modules java.base/java.lang:+open * @library /test/lib - * @run main/othervm/native --enable-native-access=ALL-UNNAMED RetryMonitorEnterWhenPinned + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED RetryMonitorEnterWhenPinned */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/Starvation.java b/test/jdk/java/lang/Thread/virtual/Starvation.java index 2b8da5fbca8..c55ad3c2494 100644 --- a/test/jdk/java/lang/Thread/virtual/Starvation.java +++ b/test/jdk/java/lang/Thread/virtual/Starvation.java @@ -25,7 +25,7 @@ * @requires vm.continuations * @library /test/lib * @bug 8345294 - * @run main/othervm/timeout=200/native --enable-native-access=ALL-UNNAMED Starvation 100000 + * @run main/othervm/timeout=800/native --enable-native-access=ALL-UNNAMED Starvation 100000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java b/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java index c894944aa25..7a3da0ac334 100644 --- a/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java +++ b/test/jdk/java/lang/Thread/virtual/SynchronizedNative.java @@ -28,7 +28,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -36,7 +36,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xint --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xint --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -44,7 +44,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xcomp -XX:TieredStopAtLevel=1 --enable-native-access=ALL-UNNAMED SynchronizedNative */ /* @@ -52,7 +52,7 @@ * @requires vm.continuations * @modules java.base/java.lang:+open jdk.management * @library /test/lib - * @run junit/othervm/native -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED SynchronizedNative + * @run junit/othervm/native/timeout=480 -Xcomp -XX:-TieredCompilation --enable-native-access=ALL-UNNAMED SynchronizedNative */ import java.util.concurrent.CountDownLatch; diff --git a/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java b/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java index 4e6c3c12269..56257b8847e 100644 --- a/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java +++ b/test/jdk/java/lang/Thread/virtual/ThreadPollOnYield.java @@ -27,7 +27,7 @@ * @summary Test that Thread.yield loop polls for safepoints * @requires vm.continuations * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED ThreadPollOnYield + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED ThreadPollOnYield */ /* @@ -36,7 +36,7 @@ * @summary Test that Thread.yield loop polls for safepoints * @requires vm.continuations & vm.compMode != "Xcomp" * @library /test/lib - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED -Xcomp -XX:-TieredCompilation + * @run junit/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED -Xcomp -XX:-TieredCompilation * -XX:CompileCommand=inline,*::yield* -XX:CompileCommand=inline,*::*Yield ThreadPollOnYield */ diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java index 17b63573d85..fa4d16d9f82 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * @requires vm.debug != true * @modules jdk.management * @library /test/lib - * @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 100000 + * @run main/othervm/timeout=1200 GetStackTraceALotWhenBlocking 100000 */ /* @@ -36,7 +36,7 @@ * @requires vm.debug == true & vm.continuations * @modules jdk.management * @library /test/lib - * @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 50000 + * @run main/othervm/timeout=1200 GetStackTraceALotWhenBlocking 50000 */ import java.time.Instant; diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java index ad3fbdf0565..0e8693756e5 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWithTimedWait.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -25,13 +25,13 @@ * @test * @summary Stress test Thread.getStackTrace on a virtual thread in timed-Object.wait * @requires vm.debug != true - * @run main GetStackTraceALotWithTimedWait 100000 + * @run main/timeout=480 GetStackTraceALotWithTimedWait 100000 */ /* * @test * @requires vm.debug == true - * @run main GetStackTraceALotWithTimedWait 50000 + * @run main/timeout=480 GetStackTraceALotWithTimedWait 50000 */ import java.time.Instant; @@ -88,4 +88,3 @@ public class GetStackTraceALotWithTimedWait { } } } - diff --git a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java index c30193bc121..29704fd8975 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,14 +26,14 @@ * @summary Stress test parking and unparking * @requires vm.debug != true * @library /test/lib - * @run main/othervm/timeout=300 ParkALot 300000 + * @run main/othervm/timeout=1200 ParkALot 300000 */ /* * @test * @requires vm.debug == true * @library /test/lib - * @run main/othervm/timeout=300 ParkALot 100000 + * @run main/othervm/timeout=1200 ParkALot 100000 */ import java.time.Instant; diff --git a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java index ff45ea837ae..2da43388a85 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/PinALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/PinALot.java @@ -26,14 +26,14 @@ * @summary Stress test timed park when pinned * @requires vm.debug != true * @library /test/lib - * @run main/othervm/native --enable-native-access=ALL-UNNAMED PinALot 500000 + * @run main/othervm/native/timeout=480 --enable-native-access=ALL-UNNAMED PinALot 500000 */ /* * @test * @requires vm.debug == true * @library /test/lib - * @run main/othervm/native/timeout=300 --enable-native-access=ALL-UNNAMED PinALot 200000 + * @run main/othervm/native/timeout=1200 --enable-native-access=ALL-UNNAMED PinALot 200000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java index 1d9a5b7104b..06f3b5ff235 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet.java @@ -26,13 +26,13 @@ * @summary Stress test virtual threads with a variation of the Skynet 1M benchmark * @requires vm.continuations * @requires !vm.debug | vm.gc != "Z" - * @run main/othervm/timeout=400 -Xmx1500m Skynet + * @run main/othervm/timeout=1600 -Xmx1500m Skynet */ /* * @test id=Z * @requires vm.debug == true & vm.continuations * @requires vm.gc.Z - * @run main/othervm/timeout=400 -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=1600 -XX:+UnlockDiagnosticVMOptions * -XX:+UseZGC * -XX:+ZVerifyOops -XX:ZCollectionInterval=0.01 -Xmx1500m Skynet */ diff --git a/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java b/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java index 7949529af60..77eed59c88d 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java +++ b/test/jdk/java/lang/Thread/virtual/stress/Skynet100kWithMonitors.java @@ -27,13 +27,13 @@ * a channel implementation based on object monitors. This variant uses a reduced number of * 100k virtual threads at the final level. * @requires vm.debug != true & vm.continuations - * @run main/othervm/timeout=300 Skynet100kWithMonitors 50 + * @run main/othervm/timeout=1200 Skynet100kWithMonitors 50 */ /* * @test * @requires vm.debug == true & vm.continuations - * @run main/othervm/timeout=300 Skynet100kWithMonitors 10 + * @run main/othervm/timeout=1200 Skynet100kWithMonitors 10 */ public class Skynet100kWithMonitors { diff --git a/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java b/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java index d10897629c4..fadc5c3446b 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/SleepALot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -25,13 +25,13 @@ * @test * @summary Stress test Thread.sleep * @requires vm.debug != true & vm.continuations - * @run main SleepALot 500000 + * @run main/timeout=480 SleepALot 500000 */ /* * @test * @requires vm.debug == true & vm.continuations - * @run main/othervm/timeout=300 SleepALot 200000 + * @run main/othervm/timeout=1200 SleepALot 200000 */ import java.time.Duration; diff --git a/test/jdk/java/lang/annotation/LoaderLeakTest.java b/test/jdk/java/lang/annotation/LoaderLeakTest.java index 762a08f9990..6b31add49a4 100644 --- a/test/jdk/java/lang/annotation/LoaderLeakTest.java +++ b/test/jdk/java/lang/annotation/LoaderLeakTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary annotations cause memory leak * @library /test/lib * @build jdk.test.lib.process.* - * @run testng LoaderLeakTest + * @run testng/timeout=480 LoaderLeakTest */ import jdk.test.lib.Utils; diff --git a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java index 60ba4af590e..7635851724e 100644 --- a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java +++ b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -29,8 +29,8 @@ import java.util.ArrayList; * @test * @bug 8340812 * @summary Verify that LambdaForm customization via MethodHandle::updateForm is thread safe. - * @run main TestLambdaFormCustomization - * @run main/othervm -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization + * @run main/timeout=480 TestLambdaFormCustomization + * @run main/othervm/timeout=480 -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization */ public class TestLambdaFormCustomization { diff --git a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java index bb9efe29e51..7260c04c10a 100644 --- a/test/jdk/java/lang/reflect/IllegalArgumentsTest.java +++ b/test/jdk/java/lang/reflect/IllegalArgumentsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 8277964 * @summary Test IllegalArgumentException be thrown when an argument is invalid - * @run testng/othervm/timeout=180 IllegalArgumentsTest + * @run testng/othervm/timeout=720 IllegalArgumentsTest */ import java.lang.reflect.Constructor; diff --git a/test/jdk/java/math/BigInteger/LargeValueExceptions.java b/test/jdk/java/math/BigInteger/LargeValueExceptions.java index bba3a23b438..4c85281a5c0 100644 --- a/test/jdk/java/math/BigInteger/LargeValueExceptions.java +++ b/test/jdk/java/math/BigInteger/LargeValueExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8200698 * @summary Tests that exceptions are thrown for ops which would overflow * @requires (sun.arch.data.model == "64" & os.maxMemory >= 4g) - * @run testng/othervm -Xmx4g LargeValueExceptions + * @run testng/othervm/timeout=480 -Xmx4g LargeValueExceptions */ import java.math.BigInteger; import static java.math.BigInteger.ONE; diff --git a/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java b/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java index c8a1659368a..dff8b38d3c1 100644 --- a/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java +++ b/test/jdk/java/net/DatagramSocket/UnreferencedDatagramSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -26,8 +26,8 @@ * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open * java.base/sun.net java.base/sun.nio.ch:+open - * @run main/othervm UnreferencedDatagramSockets - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedDatagramSockets + * @run main/othervm/timeout=480 UnreferencedDatagramSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedDatagramSockets * @summary Check that unreferenced datagram sockets are closed */ diff --git a/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java b/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java index 87d62fdd685..13383a397f9 100644 --- a/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java +++ b/test/jdk/java/net/MulticastSocket/SetLoopbackModeIPv4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -42,5 +42,3 @@ public class SetLoopbackModeIPv4 { SetLoopbackMode.main(args); } } - - diff --git a/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java b/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java index 6e318dd77d7..2a87207c961 100644 --- a/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java +++ b/test/jdk/java/net/MulticastSocket/UnreferencedMulticastSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -26,8 +26,8 @@ * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open * java.base/sun.net java.base/sun.nio.ch:+open - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets - * @run main/othervm UnreferencedMulticastSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets + * @run main/othervm/timeout=480 UnreferencedMulticastSockets * @summary Check that unreferenced multicast sockets are closed */ diff --git a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java index baed6c156d5..61e1bbfc21d 100644 --- a/test/jdk/java/net/ServerSocket/UnreferencedSockets.java +++ b/test/jdk/java/net/ServerSocket/UnreferencedSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,8 +25,8 @@ * @test * @library /test/lib * @modules java.management java.base/java.io:+open java.base/java.net:+open - * @run main/othervm UnreferencedSockets - * @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedSockets + * @run main/othervm/timeout=480 UnreferencedSockets + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedSockets * @summary Check that unreferenced sockets are closed */ diff --git a/test/jdk/java/net/Socket/CloseAvailable.java b/test/jdk/java/net/Socket/CloseAvailable.java index 5ff7e0c03a3..dfaf92d9219 100644 --- a/test/jdk/java/net/Socket/CloseAvailable.java +++ b/test/jdk/java/net/Socket/CloseAvailable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -26,8 +26,8 @@ * @bug 4091859 8189366 * @library /test/lib * @summary Test Socket.getInputStream().available() - * @run main CloseAvailable - * @run main/othervm -Djava.net.preferIPv4Stack=true CloseAvailable + * @run main/timeout=480 CloseAvailable + * @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true CloseAvailable */ import java.net.*; diff --git a/test/jdk/java/net/httpclient/AsFileDownloadTest.java b/test/jdk/java/net/httpclient/AsFileDownloadTest.java index 1ec26777696..31d919230a4 100644 --- a/test/jdk/java/net/httpclient/AsFileDownloadTest.java +++ b/test/jdk/java/net/httpclient/AsFileDownloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -76,7 +76,7 @@ import static org.testng.Assert.fail; * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform jdk.test.lib.util.FileUtils * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run testng/othervm AsFileDownloadTest + * @run testng/othervm/timeout=480 AsFileDownloadTest */ public class AsFileDownloadTest { diff --git a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java index c35c62c062a..6d15ba5d3a8 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -54,7 +54,7 @@ import static org.testng.Assert.*; * @key randomness * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm -Djdk.internal.httpclient.debug=true BufferingSubscriberTest + * @run testng/othervm/timeout=480 -Djdk.internal.httpclient.debug=true BufferingSubscriberTest */ public class BufferingSubscriberTest { diff --git a/test/jdk/java/net/httpclient/CancelledResponse.java b/test/jdk/java/net/httpclient/CancelledResponse.java index f69bf066ba2..44be38317dc 100644 --- a/test/jdk/java/net/httpclient/CancelledResponse.java +++ b/test/jdk/java/net/httpclient/CancelledResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -59,8 +59,8 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; * @modules java.net.http/jdk.internal.net.http.common * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer ReferenceTracker - * @run main/othervm CancelledResponse - * @run main/othervm CancelledResponse SSL + * @run main/othervm/timeout=480 CancelledResponse + * @run main/othervm/timeout=480 CancelledResponse SSL */ /** diff --git a/test/jdk/java/net/httpclient/HttpSlowServerTest.java b/test/jdk/java/net/httpclient/HttpSlowServerTest.java index 85db9bba563..a71eaf746ad 100644 --- a/test/jdk/java/net/httpclient/HttpSlowServerTest.java +++ b/test/jdk/java/net/httpclient/HttpSlowServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -61,7 +61,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer HttpSlowServerTest * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run main/othervm -Dtest.requiresHost=true + * @run main/othervm/timeout=480 -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.debug=false * HttpSlowServerTest diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java index 493c2c3a504..c196ef76466 100644 --- a/test/jdk/java/net/httpclient/ManyRequests.java +++ b/test/jdk/java/net/httpclient/ManyRequests.java @@ -33,10 +33,10 @@ * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests - * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests * @summary Send a large number of requests asynchronously */ // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests diff --git a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java index d1cffff72cf..beed8f86fa6 100644 --- a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java +++ b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * @modules java.net.http/jdk.internal.net.http.common * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm ResponseBodyBeforeError + * @run testng/othervm/timeout=480 ResponseBodyBeforeError */ import java.io.Closeable; diff --git a/test/jdk/java/net/httpclient/ResponsePublisher.java b/test/jdk/java/net/httpclient/ResponsePublisher.java index e8d76430946..3d6cf601b2f 100644 --- a/test/jdk/java/net/httpclient/ResponsePublisher.java +++ b/test/jdk/java/net/httpclient/ResponsePublisher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * immediately with a Publisher> * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run testng/othervm ResponsePublisher + * @run testng/othervm/timeout=480 ResponsePublisher */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/SpecialHeadersTest.java b/test/jdk/java/net/httpclient/SpecialHeadersTest.java index 37cb47a6872..d3e1f37b592 100644 --- a/test/jdk/java/net/httpclient/SpecialHeadersTest.java +++ b/test/jdk/java/net/httpclient/SpecialHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -31,10 +31,10 @@ * jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.SimpleSSLContext * @requires (vm.compMode != "Xcomp") - * @run testng/othervm + * @run testng/othervm/timeout=480 * -Djdk.httpclient.HttpClient.log=requests,headers,errors * SpecialHeadersTest - * @run testng/othervm -Djdk.httpclient.allowRestrictedHeaders=Host + * @run testng/othervm/timeout=480 -Djdk.httpclient.allowRestrictedHeaders=Host * -Djdk.httpclient.HttpClient.log=requests,headers,errors * SpecialHeadersTest */ diff --git a/test/jdk/java/net/httpclient/SplitResponse.java b/test/jdk/java/net/httpclient/SplitResponse.java index 48f958047b7..ad04e8a1627 100644 --- a/test/jdk/java/net/httpclient/SplitResponse.java +++ b/test/jdk/java/net/httpclient/SplitResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -52,7 +52,7 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString; * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:CLOSE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseAsync.java b/test/jdk/java/net/httpclient/SplitResponseAsync.java index caed3dc8d67..dfb3843561a 100644 --- a/test/jdk/java/net/httpclient/SplitResponseAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:CLOSE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java b/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java index f805f26a1e4..a8477e8b289 100644 --- a/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java +++ b/test/jdk/java/net/httpclient/SplitResponseKeepAlive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:KEEP_ALIVE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java b/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java index c8d034444b6..7d46989f976 100644 --- a/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseKeepAliveAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTP connection:KEEP_ALIVE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSL.java b/test/jdk/java/net/httpclient/SplitResponseSSL.java index ba030d74efa..31c3f4f8f61 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSL.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:CLOSE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java b/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java index e78b6703d59..e54a0314d2d 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:CLOSE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java index 9892370cdef..a707c6c3921 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAlive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:KEEP_ALIVE mode:SYNC diff --git a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java index 96dbb5f5bc0..740baabd714 100644 --- a/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java +++ b/test/jdk/java/net/httpclient/SplitResponseSSLKeepAliveAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer SplitResponse - * @run main/othervm + * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all * SplitResponse HTTPS connection:KEEP_ALIVE mode:ASYNC diff --git a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java index aea81fb0a0b..a0130de5a67 100644 --- a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -24,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.FlowTest + * @run testng/timeout=480 java.net.http/jdk.internal.net.http.FlowTest */ diff --git a/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java index 8f8f816cad6..331da97845a 100644 --- a/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java +++ b/test/jdk/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @bug 6834246 6842687 * @summary Stress test connections through the loopback interface * @run main StressLoopback - * @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback + * @run main/othervm/timeout=480 -Djdk.net.useFastTcpLoopback StressLoopback * @key randomness */ diff --git a/test/jdk/java/nio/channels/Channels/TransferTo.java b/test/jdk/java/nio/channels/Channels/TransferTo.java index bc0dc01fdb0..b02bf7b3649 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -47,7 +47,7 @@ import static org.testng.Assert.assertThrows; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo + * @run testng/othervm/timeout=720 TransferTo * @bug 8265891 * @summary Tests whether sun.nio.ChannelInputStream.transferTo conforms to the * InputStream.transferTo specification diff --git a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java index 4829cc63f70..f57d6cca963 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferFrom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -36,7 +36,7 @@ import org.testng.annotations.Test; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo_2GB_transferFrom + * @run testng/othervm/timeout=720 TransferTo_2GB_transferFrom * @bug 8278268 * @summary Tests if ChannelInputStream.transferFrom correctly * transfers 2GB+ using FileChannel.transferFrom(ReadableByteChannel). diff --git a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java index 34b4e504b05..fdd3bddb126 100644 --- a/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java +++ b/test/jdk/java/nio/channels/Channels/TransferTo_2GB_transferTo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ import org.testng.annotations.Test; * @test * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run testng/othervm/timeout=180 TransferTo_2GB_transferTo + * @run testng/othervm/timeout=720 TransferTo_2GB_transferTo * @bug 8265891 * @summary Tests if ChannelInputStream.transferTo correctly * transfers 2GB+ using FileChannel.transferTo(WritableByteChannel). diff --git a/test/jdk/java/nio/channels/FileChannel/CleanerTest.java b/test/jdk/java/nio/channels/FileChannel/CleanerTest.java index c999684a56d..48b00deabb9 100644 --- a/test/jdk/java/nio/channels/FileChannel/CleanerTest.java +++ b/test/jdk/java/nio/channels/FileChannel/CleanerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * @library /test/lib * @build jdk.test.lib.util.FileUtils CleanerTest * @modules java.management java.base/sun.nio.ch:+open - * @run main/othervm CleanerTest + * @run main/othervm/timeout=480 CleanerTest */ import com.sun.management.UnixOperatingSystemMXBean; diff --git a/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java b/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java index c42db8f485f..2ec77d97958 100644 --- a/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java +++ b/test/jdk/java/nio/channels/SocketChannel/CloseDuringConnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @bug 8198928 * @library /test/lib * @build jdk.test.lib.Utils - * @run main CloseDuringConnect + * @run main/timeout=480 CloseDuringConnect * @summary Attempt to cause a deadlock by closing a SocketChannel in one thread * where another thread is closing the channel after a connect fail */ diff --git a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java index c7eed1f27a0..cbfe4c9b7fb 100644 --- a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java +++ b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * connection cannot be established * @requires vm.flagless * @build OpenLeak - * @run junit/othervm OpenLeak + * @run junit/othervm/timeout=480 OpenLeak */ import java.io.IOException; diff --git a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java index 96478b2b20f..33a7b5ef3c4 100644 --- a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java +++ b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /** * @test * @bug 8245194 - * @run testng/othervm IOExchanges + * @run testng/othervm/timeout=480 IOExchanges */ import java.io.IOException; diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index 1cdd090d1be..f04bece07b6 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -26,22 +26,22 @@ * @bug 8284161 * @summary Test virtual threads doing blocking I/O on NIO channels * @library /test/lib - * @run junit BlockingChannelOps + * @run junit/timeout=480 BlockingChannelOps */ /* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib - * @run junit/othervm -Djdk.pollerMode=1 BlockingChannelOps - * @run junit/othervm -Djdk.pollerMode=2 BlockingChannelOps + * @run junit/othervm/timeout=480 -Djdk.pollerMode=1 BlockingChannelOps + * @run junit/othervm/timeout=480 -Djdk.pollerMode=2 BlockingChannelOps */ /* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingChannelOps + * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingChannelOps */ import java.io.Closeable; diff --git a/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java b/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java index 2137cfb3721..baa20ff2b9c 100644 --- a/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java +++ b/test/jdk/java/rmi/transport/dgcDeadLock/DGCDeadLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp * @build TestLibrary Test TestImpl RegistryVM RegistryRunner - * @run main/othervm/timeout=360 DGCDeadLock + * @run main/othervm/timeout=1440 DGCDeadLock */ /* This test attempts to cause a deadlock between the rmi leaseChecker @@ -56,8 +56,7 @@ import java.io.*; public class DGCDeadLock implements Runnable { final static public int HOLD_TARGET_TIME = 25000; - public static final double TEST_FAIL_TIME = - (HOLD_TARGET_TIME + 30000) * TestLibrary.getTimeoutFactor(); + public static final double TEST_FAIL_TIME = (HOLD_TARGET_TIME + 30000) * Math.max(TestLibrary.getTimeoutFactor(), 4); public static volatile boolean finished = false; static final DGCDeadLock test = new DGCDeadLock(); static volatile int registryPort = -1; diff --git a/test/jdk/java/security/SignedObject/Chain.java b/test/jdk/java/security/SignedObject/Chain.java index 883ac13890d..c4b83d1ec5b 100644 --- a/test/jdk/java/security/SignedObject/Chain.java +++ b/test/jdk/java/security/SignedObject/Chain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ import static jdk.test.lib.SigTestUtil.SignatureType; * @summary Verify a chain of signed objects * @library /test/lib * @build jdk.test.lib.SigTestUtil - * @run main Chain + * @run main/timeout=480 Chain */ public class Chain { diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java index f0b30fa1065..06cb4fe7df4 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatTest.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatTest.java @@ -27,7 +27,7 @@ * 8190748 8216969 8174269 8347841 8347955 * @summary test DateFormat and SimpleDateFormat. * @modules jdk.localedata - * @run junit DateFormatTest + * @run junit/timeout=480 DateFormatTest */ import java.time.ZoneId; diff --git a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java index e517d5570d0..f17d9194c14 100644 --- a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java +++ b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, Red Hat, Inc. All rights reserved. - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -57,7 +57,7 @@ import static org.testng.Assert.assertThrows; * @summary White box tests for HashMap-related internals around table sizing * @comment skip running this test on 32 bit VM * @requires vm.bits == "64" - * @run testng/othervm -Xmx2g WhiteBoxResizeTest + * @run testng/othervm/timeout=960 -Xmx2g WhiteBoxResizeTest */ public class WhiteBoxResizeTest { diff --git a/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java b/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java index bc1df961a57..46bee98a810 100644 --- a/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java +++ b/test/jdk/java/util/PluggableLocale/CurrencyNameProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * java.base/sun.util.resources * @build com.foobar.Utils * com.bar.* - * @run main/othervm -Djava.locale.providers=CLDR,SPI CurrencyNameProviderTest + * @run main/othervm/timeout=480 -Djava.locale.providers=CLDR,SPI CurrencyNameProviderTest */ import java.text.DecimalFormat; diff --git a/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java b/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java index 9d44dd79c02..fcec85a945b 100644 --- a/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java +++ b/test/jdk/java/util/PluggableLocale/LocaleNameProviderTest.java @@ -31,7 +31,7 @@ * java.base/sun.util.resources * @build com.foobar.Utils * com.bar.* - * @run junit/othervm -Djava.locale.providers=CLDR,SPI LocaleNameProviderTest + * @run junit/othervm/timeout=960 -Djava.locale.providers=CLDR,SPI LocaleNameProviderTest */ import java.util.ArrayList; diff --git a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java index 5ca755fc362..43490a711b2 100644 --- a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java +++ b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/BasicCancelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test * @bug 6602600 - * @run main/othervm -Xmx64m BasicCancelTest + * @run main/othervm/timeout=480 -Xmx64m BasicCancelTest * @summary Check effectiveness of RemoveOnCancelPolicy */ diff --git a/test/jdk/java/util/logging/FileHandlerPath.java b/test/jdk/java/util/logging/FileHandlerPath.java index 85ec52a0619..a4d23dbf458 100644 --- a/test/jdk/java/util/logging/FileHandlerPath.java +++ b/test/jdk/java/util/logging/FileHandlerPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -39,7 +39,7 @@ import java.util.logging.LogManager; * @bug 8059269 * @summary tests that using a simple (non composite) pattern does not lead * to NPE when the lock file already exists. - * @run main/othervm FileHandlerPath + * @run main/othervm/timeout=480 FileHandlerPath * @author danielfuchs * @key randomness */ diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java index f24bb2e22ec..64fd22362ca 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -40,6 +40,7 @@ import java.util.function.Function; import java.util.logging.FileHandler; import java.util.logging.LogManager; import java.util.logging.Logger; +import jdk.test.lib.Utils; /** * @test @@ -49,6 +50,7 @@ import java.util.logging.Logger; * Test a complex reconfiguration where a logger with handlers * suddenly appears in the hierarchy between a child logger and the * root logger. + * @library /test/lib * @run main/othervm HandlersOnComplexResetUpdate * @author danielfuchs */ @@ -60,13 +62,8 @@ public class HandlersOnComplexResetUpdate { test(properties); } - public static final double TIMEOUT_FACTOR; - static { - String toFactor = System.getProperty("test.timeout.factor", "1.0"); - TIMEOUT_FACTOR = Double.parseDouble(toFactor); - } static int adjustCount(int count) { - return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); + return Math.min(count, (int) Math.ceil(Utils.TIMEOUT_FACTOR * count)); } private static final String PREFIX = diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java index 8735c34aa98..146cfea1af8 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -40,6 +40,7 @@ import java.util.function.Function; import java.util.logging.FileHandler; import java.util.logging.LogManager; import java.util.logging.Logger; +import jdk.test.lib.Utils; /** * @test @@ -49,6 +50,7 @@ import java.util.logging.Logger; * Test a complex reconfiguration where a logger with handlers * suddenly appears in the hierarchy between a child logger and the * root logger. + * @library /test/lib * @run main/othervm HandlersOnComplexUpdate * @author danielfuchs */ @@ -60,13 +62,8 @@ public class HandlersOnComplexUpdate { test(properties); } - public static final double TIMEOUT_FACTOR; - static { - String toFactor = System.getProperty("test.timeout.factor", "1.0"); - TIMEOUT_FACTOR = Double.parseDouble(toFactor); - } static int adjustCount(int count) { - return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); + return Math.min(count, (int) Math.ceil(Utils.TIMEOUT_FACTOR * count)); } private static final String PREFIX = diff --git a/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties b/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties new file mode 100644 index 00000000000..64710ba44a1 --- /dev/null +++ b/test/jdk/java/util/stream/boottest/java.base/java/util/stream/TEST.properties @@ -0,0 +1 @@ +timeout.default.seconds=480 diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties new file mode 100644 index 00000000000..64710ba44a1 --- /dev/null +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/TEST.properties @@ -0,0 +1 @@ +timeout.default.seconds=480 diff --git a/test/jdk/java/util/zip/DeInflate.java b/test/jdk/java/util/zip/DeInflate.java index 226d4ed4ae3..83ed417fed1 100644 --- a/test/jdk/java/util/zip/DeInflate.java +++ b/test/jdk/java/util/zip/DeInflate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -24,8 +24,9 @@ /* * @test * @bug 7110149 8184306 6341887 8357145 - * @summary Test basic deflater & inflater functionality + * @summary Test basic deflater and inflater functionality * @key randomness + * @run main/timeout=480 DeInflate */ import java.io.*; diff --git a/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java b/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java index d8d474ae8d4..4e271912345 100644 --- a/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java +++ b/test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8243254 * @summary Tests a simple set of operations on Zip files in various encodings * focusing on ensuring metadata is properly encoded and read. - * @run testng TestZipFileEncodings + * @run testng/timeout=480 TestZipFileEncodings */ import org.testng.annotations.AfterClass; import org.testng.annotations.DataProvider; diff --git a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java index 8db1dfdeac8..946951dfc98 100644 --- a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java +++ b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,8 +27,8 @@ * @summary Check if weak cipher suites are disabled * @library /javax/net/ssl/templates * @modules jdk.crypto.ec - * @run main/othervm DisabledAlgorithms default - * @run main/othervm DisabledAlgorithms empty + * @run main/othervm/timeout=480 DisabledAlgorithms default + * @run main/othervm/timeout=480 DisabledAlgorithms empty */ import java.io.BufferedInputStream; diff --git a/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java b/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java index 28ed114b807..07d24115218 100644 --- a/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java +++ b/test/jdk/javax/swing/JFileChooser/6868611/bug6868611.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 6868611 8198004 * @summary FileSystemView throws NullPointerException * @author Pavel Porvatov - * @run main bug6868611 + * @run main/timeout=480 bug6868611 */ import javax.swing.*; diff --git a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java index 0c23ee23b5b..8b4d9ab8e69 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java +++ b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ import javax.swing.JFileChooser; * @bug 8323670 8307091 8240690 * @requires os.family == "mac" | os.family == "linux" * @summary Verifies thread-safety of BasicDirectoryModel (JFileChooser) - * @run main/othervm -Djava.awt.headless=true ConcurrentModification + * @run main/othervm/timeout=480 -Djava.awt.headless=true ConcurrentModification */ public final class ConcurrentModification extends ThreadGroup { /** Initial number of files. */ diff --git a/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java b/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java index 0de35fbdaa9..363cb94d924 100644 --- a/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java +++ b/test/jdk/javax/swing/text/html/parser/Parser/8078268/bug8078268.java @@ -30,16 +30,18 @@ import javax.swing.SwingUtilities; import javax.swing.text.Document; import javax.swing.text.html.HTMLEditorKit; +import jdk.test.lib.Utils; + import static java.util.concurrent.TimeUnit.MILLISECONDS; /* @test @bug 8078268 @summary javax.swing.text.html.parser.Parser parseScript incorrectly optimized + @library /test/lib @run main bug8078268 */ public class bug8078268 { - private static final float tf = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - private static final long TIMEOUT = 10_000 * (long)tf; + private static final long TIMEOUT = (long) (10_000 * Utils.TIMEOUT_FACTOR); private static final String FILENAME = "slowparse.html"; diff --git a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java index ac24ceb476c..0ecc40a8819 100644 --- a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java +++ b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java @@ -34,7 +34,7 @@ * @build jdk.test.lib.Asserts * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java GenerationTests.java - * @run main/othervm/timeout=300 -Dsun.net.httpserver.nodelay=true GenerationTests + * @run main/othervm/timeout=1200 -Dsun.net.httpserver.nodelay=true GenerationTests * @author Sean Mullan */ diff --git a/test/jdk/jdk/incubator/vector/AddTest.java b/test/jdk/jdk/incubator/vector/AddTest.java index bd11f0092be..8d0d7080c49 100644 --- a/test/jdk/jdk/incubator/vector/AddTest.java +++ b/test/jdk/jdk/incubator/vector/AddTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,7 @@ * @test * @modules jdk.incubator.vector * @requires vm.compiler2.enabled + * @run main/timeout=480 AddTest */ import jdk.incubator.vector.FloatVector; diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index 0587d5a6bfb..53f11f22d79 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -44,7 +44,7 @@ import jtreg.SkippedException; * @library /test/lib * @modules java.base/jdk.internal.platform * @build MetricsMemoryTester - * @run main TestDockerMemoryMetricsSubgroup + * @run main/timeout=480 TestDockerMemoryMetricsSubgroup */ public class TestDockerMemoryMetricsSubgroup { diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index b9d031f0309..dc70fe32b16 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2020, 2022, Tencent. All rights reserved. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * @requires !vm.asan * @library /test/lib * @build GetFreeSwapSpaceSize - * @run driver TestGetFreeSwapSpaceSize + * @run driver/timeout=480 TestGetFreeSwapSpaceSize */ import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index 31e90e8802a..e4decb7f903 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,7 +34,7 @@ * @library /test/lib * @modules java.base/jdk.internal.platform * @build LimitUpdateChecker - * @run driver TestLimitsUpdating + * @run driver/timeout=480 TestLimitsUpdating */ import java.io.File; diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 6b19bb475f1..033562b3951 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,7 +31,7 @@ * @requires !vm.asan * @library /test/lib * @build TestPidsLimit - * @run driver TestPidsLimit + * @run driver/timeout=480 TestPidsLimit */ import java.util.ArrayList; import java.util.List; diff --git a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java index 530bcb54f34..254583bf18b 100644 --- a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java +++ b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java @@ -153,7 +153,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* @@ -173,7 +173,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* @@ -193,7 +193,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -Xbatch -XX:-TieredCompilation * -XX:CompileCommand=dontinline,*::*dontinline* * -XX:CompileCommand=dontinline,*::*dontjit* diff --git a/test/jdk/jdk/internal/vm/Continuation/Fuzz.java b/test/jdk/jdk/internal/vm/Continuation/Fuzz.java index 5f4f8c85f61..8d522cc83e1 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Fuzz.java +++ b/test/jdk/jdk/internal/vm/Continuation/Fuzz.java @@ -34,8 +34,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * Fuzz + * @run main/othervm/timeout=1200 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * Fuzz */ /* @@ -51,9 +51,9 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * - * @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -XX:+PreserveFramePointer - * Fuzz + * @run main/othervm/timeout=1200 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+PreserveFramePointer + * Fuzz */ import jdk.internal.vm.Continuation; @@ -84,8 +84,7 @@ public class Fuzz implements Runnable { static final boolean RANDOM = true; static final boolean VERBOSE = false; - static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - static int COMPILATION_TIMEOUT = (int)(5_000 * timeoutFactor); // ms + static int COMPILATION_TIMEOUT = (int)(5_000 * Utils.TIMEOUT_FACTOR); // ms static final Path TEST_DIR = Path.of(System.getProperty("test.src", ".")); diff --git a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java index c7e6c6e5922..512f6b39ef9 100644 --- a/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java +++ b/test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java @@ -38,7 +38,7 @@ import jdk.jfr.consumer.RecordingStream; * @requires vm.flagless * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm -Xlog:jfr+streaming+system=trace jdk.jfr.api.consumer.recordingstream.TestClose + * @run main/othervm/timeout=480 -Xlog:jfr+streaming+system=trace jdk.jfr.api.consumer.recordingstream.TestClose */ public class TestClose { diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java index b7c3a67ae68..43abc9cefff 100644 --- a/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestStackFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -51,7 +51,7 @@ import jdk.test.lib.jfr.TestClassLoader; * @requires vm.hasJFR * @modules jdk.jfr/jdk.jfr.events * @library /test/lib /test/jdk - * @run main/othervm -Xlog:jfr=warning jdk.jfr.api.metadata.annotations.TestStackFilter + * @run main/othervm/timeout=480 -Xlog:jfr=warning jdk.jfr.api.metadata.annotations.TestStackFilter */ public class TestStackFilter { private static class Quux { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java index a86229c65e3..fd09db01482 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java @@ -44,7 +44,7 @@ import jdk.test.lib.process.ProcessTools; * @requires vm.flagless * @requires vm.hasJFR * @library /test/lib -* @run main/othervm jdk.jfr.event.oldobject.TestEmergencyDumpAtOOM +* @run main/othervm/timeout=480 jdk.jfr.event.oldobject.TestEmergencyDumpAtOOM */ public class TestEmergencyDumpAtOOM { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java index 60f85e6ba72..56f48a810c3 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java @@ -46,7 +46,7 @@ import jdk.test.lib.jfr.Events; * @comment Marked as flagless until JDK-8344015 is fixed * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription + * @run main/othervm/timeout=960 -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription */ public class TestObjectDescription { diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java index 133df36684c..976d08f1250 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java @@ -36,7 +36,7 @@ import jdk.test.lib.jfr.EventNames; * @requires vm.hasJFR & os.family == "linux" * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal - * @run main jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings + * @run main/timeout=480 jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings */ public class TestCPUTimeSampleMultipleRecordings { diff --git a/test/jdk/jdk/jfr/jvm/TestModularImage.java b/test/jdk/jdk/jfr/jvm/TestModularImage.java index fe49b460f18..41e8dc0fa5b 100644 --- a/test/jdk/jdk/jfr/jvm/TestModularImage.java +++ b/test/jdk/jdk/jfr/jvm/TestModularImage.java @@ -49,7 +49,7 @@ import jdk.test.lib.process.ProcessTools; * module java.base to add java.lang.JTRegModuleHelper. If then a * jlink run is attempted in-process - using the ToolProvider API - * on a JEP 493 enabled JDK, the test fails. - * @run main/othervm jdk.jfr.jvm.TestModularImage + * @run main/othervm/timeout=480 jdk.jfr.jvm.TestModularImage */ public class TestModularImage { private static final String STARTED_RECORDING = "Started recording"; diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index b4291645007..2dc2b2b4587 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -35,6 +35,7 @@ import java.util.concurrent.Semaphore; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; diff --git a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java index ef73a15256a..986fc338c71 100644 --- a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java +++ b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -44,11 +44,11 @@ import jdk.test.lib.RandomFactory; * @modules java.management * @library /test/lib * @build TestMaxCachedBufferSize - * @run main/othervm/timeout=150 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize - * @run main/othervm/timeout=150 -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=0 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=2000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=100000 TestMaxCachedBufferSize + * @run main/othervm/timeout=600 -Djdk.nio.maxCachedBufferSize=10000000 TestMaxCachedBufferSize * @summary Test the implementation of the jdk.nio.maxCachedBufferSize property * (use -Dseed=X to set PRNG seed) * @key randomness diff --git a/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java index c61e85d6698..a93dac16ab6 100644 --- a/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java +++ b/test/jdk/sun/nio/cs/TestEncoderReplaceUTF16.java @@ -45,8 +45,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @modules java.base/jdk.internal.access * java.base/sun.nio.cs * @build TestEncoderReplaceLatin1 - * @run junit/timeout=10 TestEncoderReplaceUTF16 - * @run junit/timeout=10/othervm -XX:-CompactStrings TestEncoderReplaceUTF16 + * @run junit/timeout=40 TestEncoderReplaceUTF16 + * @run junit/timeout=40/othervm -XX:-CompactStrings TestEncoderReplaceUTF16 */ class TestEncoderReplaceUTF16 { diff --git a/test/jdk/sun/security/ec/ed/EdDSATest.java b/test/jdk/sun/security/ec/ed/EdDSATest.java index c154bca4252..bebb9d2359e 100644 --- a/test/jdk/sun/security/ec/ed/EdDSATest.java +++ b/test/jdk/sun/security/ec/ed/EdDSATest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -57,7 +57,7 @@ import java.util.HexFormat; * @summary Test Signature with variation of serialized EDDSA Keys. * @library /test/lib * @build jdk.test.lib.Convert - * @run main EdDSATest + * @run main/timeout=480 EdDSATest */ public class EdDSATest { diff --git a/test/jdk/sun/security/krb5/config/IncludeRandom.java b/test/jdk/sun/security/krb5/config/IncludeRandom.java index fe05917fd4c..5ee0e485d82 100644 --- a/test/jdk/sun/security/krb5/config/IncludeRandom.java +++ b/test/jdk/sun/security/krb5/config/IncludeRandom.java @@ -27,7 +27,7 @@ * @summary Support "include" anywhere * @modules java.security.jgss/sun.security.krb5 * @library /test/lib - * @run main/othervm IncludeRandom + * @run main/othervm/timeout=480 IncludeRandom */ import jdk.test.lib.Asserts; import jdk.test.lib.security.SeededSecureRandom; diff --git a/test/jdk/sun/security/krb5/name/Constructors.java b/test/jdk/sun/security/krb5/name/Constructors.java index 733a9e421f8..d2b04726bb1 100644 --- a/test/jdk/sun/security/krb5/name/Constructors.java +++ b/test/jdk/sun/security/krb5/name/Constructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @bug 6966259 * @summary Make PrincipalName and Realm immutable * @modules java.security.jgss/sun.security.krb5 - * @run main/othervm Constructors + * @run main/othervm/timeout=480 Constructors */ import java.util.Arrays; diff --git a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java index aaaa8373f44..5cf0491cd7d 100644 --- a/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java +++ b/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java @@ -43,7 +43,7 @@ import java.util.List; * @bug 8328119 * @summary test HKDF key derivation in SunPKCS11 * @library /test/lib .. - * @run main/othervm/timeout=30 TestHKDF + * @run main/othervm/timeout=120 TestHKDF */ public final class TestHKDF extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java index a359ff7a13c..cee8f235f9f 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -29,7 +29,7 @@ * @library /test/lib .. * @modules java.base/sun.security.util * jdk.crypto.cryptoki - * @run main TestDefaultSize + * @run main/timeout=480 TestDefaultSize */ import java.security.InvalidParameterException; diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java index 395fe416858..0e8cb36659f 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java @@ -42,7 +42,7 @@ import javax.crypto.spec.SecretKeySpec; * applied to PKCS #12 keystores * @library /test/lib .. * @modules java.base/sun.security.util - * @run main/othervm/timeout=30 ImportKeyToP12 + * @run main/othervm/timeout=120 ImportKeyToP12 */ public final class ImportKeyToP12 extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java b/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java index dc263cfdb2b..948270d10d9 100644 --- a/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java +++ b/test/jdk/sun/security/pkcs11/Mac/TestLargeSecretKeys.java @@ -31,7 +31,7 @@ import java.security.Provider; * @test * @bug 8328556 * @library /test/lib .. - * @run main/othervm/timeout=30 -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt TestLargeSecretKeys + * @run main/othervm/timeout=120 -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt TestLargeSecretKeys */ public final class TestLargeSecretKeys extends PKCS11Test { diff --git a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java index facdbc8a187..4974ba06649 100644 --- a/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java +++ b/test/jdk/sun/security/pkcs12/KeytoolOpensslInteropTest.java @@ -36,7 +36,7 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * @library /test/lib /sun/security/pkcs11/ - * @run main/othervm KeytoolOpensslInteropTest true + * @run main/othervm/timeout=480 KeytoolOpensslInteropTest true */ /* @@ -48,7 +48,7 @@ * @modules java.base/sun.security.pkcs * java.base/sun.security.util * @library /test/lib /sun/security/pkcs11/ - * @run main/othervm KeytoolOpensslInteropTest false + * @run main/othervm/timeout=480 KeytoolOpensslInteropTest false */ import jdk.test.lib.Asserts; diff --git a/test/jdk/sun/security/provider/acvp/Launcher.java b/test/jdk/sun/security/provider/acvp/Launcher.java index c07b7929d89..f420b61d6f4 100644 --- a/test/jdk/sun/security/provider/acvp/Launcher.java +++ b/test/jdk/sun/security/provider/acvp/Launcher.java @@ -37,7 +37,7 @@ import java.util.zip.ZipFile; * @bug 8342442 8345057 * @library /test/lib * @modules java.base/sun.security.provider - * @run main Launcher + * @run main/timeout=480 Launcher */ /* @@ -46,7 +46,7 @@ import java.util.zip.ZipFile; * @bug 8342442 8345057 * @library /test/lib * @modules java.base/sun.security.provider - * @run main/othervm -Xcomp Launcher + * @run main/othervm/timeout=480 -Xcomp Launcher */ /// This test runs on `internalProjection.json`-style files generated by NIST's diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java index 3f69ae2d120..75a790bfd27 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,6 +25,7 @@ * @test * @bug 8184328 8253368 8260923 * @summary JDK8u131-b34-socketRead0 hang at SSL read + * @library /test/lib * @run main/othervm SSLSocketCloseHang TLSv1.2 * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownInput * @run main/othervm SSLSocketCloseHang TLSv1.2 shutdownOutput @@ -39,6 +40,7 @@ import java.net.*; import java.util.*; import java.security.*; import javax.net.ssl.*; +import jdk.test.lib.Utils; public class SSLSocketCloseHang { /* @@ -137,8 +139,7 @@ public class SSLSocketCloseHang { System.out.println("server ready"); Socket baseSocket = new Socket("localhost", serverPort); - float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - baseSocket.setSoTimeout((int)(1000 * timeoutFactor)); + baseSocket.setSoTimeout((int)(1000 * Utils.TIMEOUT_FACTOR)); SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault(); diff --git a/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java b/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java index 81e16b925fc..a6963e314f3 100644 --- a/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java +++ b/test/jdk/sun/security/ssl/X509KeyManager/CertChecking.java @@ -62,10 +62,10 @@ import sun.security.x509.X500Name; * @modules java.base/sun.security.x509 * java.base/sun.security.util * @library /test/lib - * @run main/othervm CertChecking false SunX509 - * @run main/othervm CertChecking true SunX509 - * @run main/othervm CertChecking false PKIX - * @run main/othervm CertChecking true PKIX + * @run main/othervm/timeout=480 CertChecking false SunX509 + * @run main/othervm/timeout=480 CertChecking true SunX509 + * @run main/othervm/timeout=480 CertChecking false PKIX + * @run main/othervm/timeout=480 CertChecking true PKIX */ /* diff --git a/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java b/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java index e81a25712a6..ef440cb3358 100644 --- a/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java +++ b/test/jdk/sun/security/tools/jarsigner/ConciseJarsigner.java @@ -26,7 +26,7 @@ * @bug 6802846 8172529 8227758 8260960 * @summary jarsigner needs enhanced cert validation(options) * @library /test/lib - * @run main/timeout=240 ConciseJarsigner + * @run main/timeout=960 ConciseJarsigner */ import jdk.test.lib.Asserts; diff --git a/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java b/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java index 4c201a6baf3..dbc0ec1d203 100644 --- a/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java +++ b/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -44,7 +44,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @test * @bug 8217375 * @library /test/lib - * @run testng InsufficientSectionDelimiter + * @run testng/timeout=480 InsufficientSectionDelimiter * @summary Checks some cases signing a jar the manifest of which has no or * only one line break at the end and no proper delimiting blank line does not * result in an invalid signed jar without jarsigner noticing and failing. diff --git a/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java b/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java index 65fb1374bdc..46a787f7798 100644 --- a/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java +++ b/test/jdk/sun/security/tools/jarsigner/RestrictedAlgo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -39,8 +39,8 @@ import jdk.test.lib.process.OutputAnalyzer; * key sizes, with and without entries in jdk.jar.disabledAlgorithms, * jdk.certpath.disabledAlgorithms * @library /test/lib - * @run main/othervm RestrictedAlgo RESTRICT - * @run main/othervm RestrictedAlgo NO_RESTRICT + * @run main/othervm/timeout=480 RestrictedAlgo RESTRICT + * @run main/othervm/timeout=480 RestrictedAlgo NO_RESTRICT */ public class RestrictedAlgo { diff --git a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java index 4464314bf28..d17b2743857 100644 --- a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java +++ b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -43,7 +43,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @bug 8217375 8267319 * @library /test/lib * @modules jdk.jartool/jdk.security.jarsigner - * @run testng SectionNameContinuedVsLineBreak + * @run testng/timeout=480 SectionNameContinuedVsLineBreak * @summary Checks some specific line break character sequences in section name * continuation line breaks. */ diff --git a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java index 1c81543e435..889ff3208e4 100644 --- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java +++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java @@ -75,7 +75,7 @@ import sun.security.timestamp.TimestampToken; * jdk.test.lib.Platform * jdk.test.lib.process.* * @compile -XDignore.symbol.file TimestampCheck.java - * @run main/timeout=600 TimestampCheck + * @run main/timeout=2400 TimestampCheck */ public class TimestampCheck { diff --git a/test/jdk/sun/security/tools/keytool/GenerateAll.java b/test/jdk/sun/security/tools/keytool/GenerateAll.java index 5435372cdcf..e9a653eabe9 100644 --- a/test/jdk/sun/security/tools/keytool/GenerateAll.java +++ b/test/jdk/sun/security/tools/keytool/GenerateAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary keytool and jarsigner for all algorithms * @library /test/lib * @modules java.base/sun.security.util - * @run testng/timeout=300 GenerateAll + * @run testng/timeout=1200 GenerateAll */ import jdk.test.lib.SecurityTools; diff --git a/test/jdk/sun/security/tools/keytool/ReadJar.java b/test/jdk/sun/security/tools/keytool/ReadJar.java index 97c65e1fb3b..00f6c7b3f8c 100644 --- a/test/jdk/sun/security/tools/keytool/ReadJar.java +++ b/test/jdk/sun/security/tools/keytool/ReadJar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * jdk.test.lib.JDKToolLauncher * jdk.test.lib.Platform * jdk.test.lib.process.* - * @run main ReadJar + * @run main/timeout=480 ReadJar */ import java.nio.file.Files; diff --git a/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java b/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java index c90b3f37eaa..5c0694887fd 100644 --- a/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java +++ b/test/jdk/sun/security/tools/keytool/fakecacerts/TrustedCert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * @build java.base/sun.security.util.FilePaths * @modules java.base/sun.security.util * java.base/jdk.internal.misc - * @run main TrustedCert + * @run main/timeout=480 TrustedCert */ import jdk.test.lib.SecurityTools; diff --git a/test/jdk/sun/tools/jcmd/TestJcmdSanity.java b/test/jdk/sun/tools/jcmd/TestJcmdSanity.java index 017392565dd..92f73597ce6 100644 --- a/test/jdk/sun/tools/jcmd/TestJcmdSanity.java +++ b/test/jdk/sun/tools/jcmd/TestJcmdSanity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -43,7 +43,7 @@ import jdk.test.lib.Utils; * * @library /test/lib * - * @run main/othervm -XX:+UsePerfData TestJcmdSanity + * @run main/othervm/timeout=480 -XX:+UsePerfData TestJcmdSanity */ public class TestJcmdSanity { diff --git a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java index 1320d228793..3a65569ad98 100644 --- a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java +++ b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary Test that date parsing with DateTimeFormatter pattern * that contains timezone field doesn't trigger NPE. All supported * locales are tested. - * @run testng Bug8139107 + * @run testng/timeout=480 Bug8139107 */ import java.time.format.DateTimeFormatter; import java.util.Locale; @@ -56,4 +56,3 @@ public class Bug8139107 { // Pattern with time zone field static final String pattern = "dd-MM-yyyy HH:mm:ss z"; } - diff --git a/test/jdk/tools/jlink/JLink100Modules.java b/test/jdk/tools/jlink/JLink100Modules.java index 1ce63aec9e6..7927a2de2b4 100644 --- a/test/jdk/tools/jlink/JLink100Modules.java +++ b/test/jdk/tools/jlink/JLink100Modules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink100Modules + * @run main/othervm/timeout=480 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink100Modules */ public class JLink100Modules { private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") diff --git a/test/jdk/tools/jlink/JLink20000Packages.java b/test/jdk/tools/jlink/JLink20000Packages.java index 865cf7ca98c..d592cbc112b 100644 --- a/test/jdk/tools/jlink/JLink20000Packages.java +++ b/test/jdk/tools/jlink/JLink20000Packages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -45,7 +45,7 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages + * @run main/othervm/timeout=1920 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages */ public class JLink20000Packages { private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index 0b7de201ac9..bc4d2a08800 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -55,7 +55,7 @@ import tests.JImageGenerator; * jdk.jlink/jdk.tools.jimage * jdk.compiler * @build tests.* - * @run main/othervm -Xmx1g JLinkTest + * @run main/othervm/timeout=480 -Xmx1g JLinkTest */ public class JLinkTest { static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") diff --git a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java index 008b4a175a9..d2c3f2800a8 100644 --- a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -68,7 +68,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @build tests.* * @build jdk.test.lib.Platform * @build tools.jlink.plugins.GetAvailableLocales - * @run junit/othervm/timeout=180 -Xmx1g IncludeLocalesPluginTest + * @run junit/othervm/timeout=720 -Xmx1g IncludeLocalesPluginTest */ public class IncludeLocalesPluginTest { diff --git a/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java b/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java index d923358aed9..49ce65b08ed 100644 --- a/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java +++ b/test/jdk/tools/jlink/runtimeImage/JavaSEReproducibleTest.java @@ -40,7 +40,7 @@ import tests.Helper; * jdk.jlink/jdk.tools.jimage * @build tests.* jdk.test.lib.process.OutputAnalyzer * jdk.test.lib.process.ProcessTools - * @run main/othervm -Xmx1g JavaSEReproducibleTest + * @run main/othervm/timeout=480 -Xmx1g JavaSEReproducibleTest */ public class JavaSEReproducibleTest extends AbstractLinkableRuntimeTest { diff --git a/test/jdk/tools/jpackage/macosx/DmgContentTest.java b/test/jdk/tools/jpackage/macosx/DmgContentTest.java index c670d111e20..f6c2fe63671 100644 --- a/test/jdk/tools/jpackage/macosx/DmgContentTest.java +++ b/test/jdk/tools/jpackage/macosx/DmgContentTest.java @@ -42,7 +42,7 @@ import java.util.List; * @build jdk.jpackage.test.* * @build DmgContentTest * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=DmgContentTest */ public class DmgContentTest { diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 889a5bb374e..81831f59da3 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -44,7 +44,7 @@ import jdk.jpackage.test.Annotations.Test; * @build jdk.jpackage.test.* * @build MacFileAssociationsTest * @requires (os.family == "mac") - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MacFileAssociationsTest */ public class MacFileAssociationsTest { diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index 8d5f0de28f2..a7bfbf376ed 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -50,7 +50,7 @@ import jdk.jpackage.test.CfgFile; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AddLauncherTest.java - * @run main/othervm/timeout=360 -Xmx512m + * @run main/othervm/timeout=1440 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest.test */ @@ -63,7 +63,7 @@ import jdk.jpackage.test.CfgFile; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AddLauncherTest.java - * @run main/othervm/timeout=540 -Xmx512m + * @run main/othervm/timeout=2160 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=AddLauncherTest */ diff --git a/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java index abd1288e024..3cbb14e4015 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherSubstTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @build AppLauncherSubstTest - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppLauncherSubstTest */ public class AppLauncherSubstTest { diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index c9e66cbd7a1..ad96a9b9e0c 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -39,7 +39,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AppVersionTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppVersionTest */ diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index b55f7bb87ad..7dcd9f73d2d 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -57,7 +57,7 @@ import jdk.tools.jlink.internal.LinkableRuntimeImage; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror BasicTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=BasicTest */ diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index df207d1c30a..a2a9e67bd91 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.Annotations.Test; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror IconTest.java - * @run main/othervm/timeout=720 -Xmx512m + * @run main/othervm/timeout=2880 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=IconTest */ diff --git a/test/jdk/tools/jpackage/share/InOutPathTest.java b/test/jdk/tools/jpackage/share/InOutPathTest.java index f5fe3c618ae..f7c597d2ed3 100644 --- a/test/jdk/tools/jpackage/share/InOutPathTest.java +++ b/test/jdk/tools/jpackage/share/InOutPathTest.java @@ -50,7 +50,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InOutPathTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InOutPathTest */ public final class InOutPathTest { diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index bbdc118d60b..5106eed3fc6 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -66,7 +66,7 @@ import jdk.jpackage.test.TKit.TextStreamVerifier; * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InstallDirTest.java * @requires (jpackage.test.SQETest != null) - * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=4000 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InstallDirTest.testCommon */ @@ -78,7 +78,7 @@ import jdk.jpackage.test.TKit.TextStreamVerifier; * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InstallDirTest.java * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=4000 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InstallDirTest */ public class InstallDirTest { diff --git a/test/jdk/tools/jpackage/share/JavaOptionsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsTest.java index cb720dfb2a3..d1a0dbccf83 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsTest.java @@ -37,7 +37,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror JavaOptionsTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2840 -Xmx512m jdk.jpackage.test.Main * --jpt-run=JavaOptionsTest * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault */ diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index dd89d84e46d..bc813c4ec15 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -58,7 +58,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror MainClassTest.java - * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MainClassTest */ diff --git a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java index 8becb6f3dc3..de8412c2839 100644 --- a/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiNameTwoPhaseTest.java @@ -46,7 +46,7 @@ import jdk.jpackage.test.JPackageCommand; * @requires (jpackage.test.SQETest == null) * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror MultiNameTwoPhaseTest.java - * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2160 -Xmx512m jdk.jpackage.test.Main * --jpt-run=MultiNameTwoPhaseTest */ diff --git a/test/jdk/tools/jpackage/share/PostImageScriptTest.java b/test/jdk/tools/jpackage/share/PostImageScriptTest.java index bbdd0b7c581..68ded999e4a 100644 --- a/test/jdk/tools/jpackage/share/PostImageScriptTest.java +++ b/test/jdk/tools/jpackage/share/PostImageScriptTest.java @@ -52,7 +52,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror PostImageScriptTest.java - * @run main/othervm/timeout=720 -Xmx512m + * @run main/othervm/timeout=2880 -Xmx512m * jdk.jpackage.test.Main * --jpt-run=PostImageScriptTest */ diff --git a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java index c76f68476db..7f04ee2bd2e 100644 --- a/test/jdk/tools/jpackage/windows/WinNoRestartTest.java +++ b/test/jdk/tools/jpackage/windows/WinNoRestartTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; * @requires os.family == "windows" * @build jdk.jpackage.test.* * @build WinNoRestartTest - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=480 -Xmx512m jdk.jpackage.test.Main * --jpt-run=WinNoRestartTest */ diff --git a/test/jdk/tools/launcher/InstanceMainTest.java b/test/jdk/tools/launcher/InstanceMainTest.java index 699db27d7bb..273d56a86bd 100644 --- a/test/jdk/tools/launcher/InstanceMainTest.java +++ b/test/jdk/tools/launcher/InstanceMainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ import java.util.function.Consumer; * @test * @bug 8329420 * @summary test execution priority and behavior of main methods - * @run main InstanceMainTest + * @run main/timeout=480 InstanceMainTest */ public class InstanceMainTest extends TestHelper { diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index 9a80ca4d089..3c51b938396 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -34,7 +34,7 @@ * @build toolbox.ToolBox toolbox.JavacTask javadoc.tester.* * @build jtreg.SkippedException * @build jdk.test.lib.Platform jdk.test.lib.net.SimpleSSLContext jdk.test.lib.net.URIBuilder - * @run main TestRedirectLinks + * @run main/timeout=480 TestRedirectLinks */ import java.io.File; diff --git a/test/langtools/jdk/jshell/ClassesTest.java b/test/langtools/jdk/jshell/ClassesTest.java index 8c17c8072f8..3da389e5059 100644 --- a/test/langtools/jdk/jshell/ClassesTest.java +++ b/test/langtools/jdk/jshell/ClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 8282160 8292755 8319532 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng ClassesTest + * @run testng/timeout=480 ClassesTest */ import java.util.ArrayList; diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index fb9e8eacc4a..cfbe874e6f2 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng CompletionSuggestionTest + * @run testng/timeout=480 CompletionSuggestionTest */ import java.io.IOException; diff --git a/test/langtools/jdk/jshell/HangingRemoteAgent.java b/test/langtools/jdk/jshell/HangingRemoteAgent.java index 515f98731a3..141499b0cfd 100644 --- a/test/langtools/jdk/jshell/HangingRemoteAgent.java +++ b/test/langtools/jdk/jshell/HangingRemoteAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -35,9 +35,7 @@ import jdk.jshell.spi.ExecutionControlProvider; */ class HangingRemoteAgent extends RemoteExecutionControl { - private static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); - - private static final int TIMEOUT = (int)(2000 * timeoutFactor); + private static final int TIMEOUT = (int)(2000 * Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"))); private static final long DELAY = TIMEOUT * 2L; private static final boolean INFRA_VERIFY = false; diff --git a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java index 577228d4820..cb8fc2ea408 100644 --- a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng JdiHangingLaunchExecutionControlTest + * @run testng/timeout=480 JdiHangingLaunchExecutionControlTest */ import org.testng.annotations.Test; diff --git a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java index 2e9b04a634b..d43c3f170bd 100644 --- a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java @@ -27,7 +27,7 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng JdiHangingListenExecutionControlTest + * @run testng/timeout=480 JdiHangingListenExecutionControlTest * @key intermittent */ diff --git a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java index bb6f4588968..6af4b82dbb9 100644 --- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream ToolSimpleTest - * @run testng/othervm ToolLocalSimpleTest + * @run testng/othervm/timeout=480 ToolLocalSimpleTest */ import java.util.Locale; diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 62ea2451fb4..4ed0e741d49 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ * jdk.jshell/jdk.internal.jshell.tool * java.desktop * @build KullaTesting TestingInputStream - * @run testng ToolSimpleTest + * @run testng/timeout=480 ToolSimpleTest */ import java.util.ArrayList; diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index cc821b1874b..e7daa4df8e6 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -145,18 +145,7 @@ public class UITesting { public void test(Writer inputSink, StringBuilder out) throws Exception; } - private static final long TIMEOUT; - - static { - long factor; - - try { - factor = (long) Double.parseDouble(System.getProperty("test.timeout.factor", "1")); - } catch (NumberFormatException ex) { - factor = 1; - } - TIMEOUT = 60_000 * factor; - } + private static final long TIMEOUT = (long) (60_000 * Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"))); protected void waitOutput(StringBuilder out, String expected) { waitOutput(out, expected, null); diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index a7aabc0ead6..64d25e8a63c 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng VariablesTest + * @run testng/timeout=480 VariablesTest */ import java.nio.file.Path; diff --git a/test/langtools/tools/javac/Paths/MineField.java b/test/langtools/tools/javac/Paths/MineField.java index ee8ead00027..f01afeef3aa 100644 --- a/test/langtools/tools/javac/Paths/MineField.java +++ b/test/langtools/tools/javac/Paths/MineField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * @summary Test that javac and java find files in similar ways * @library /tools/lib * @build toolbox.ToolBox Util MineField - * @run main MineField + * @run main/timeout=480 MineField */ /* diff --git a/test/langtools/tools/javac/Paths/WildcardMineField.java b/test/langtools/tools/javac/Paths/WildcardMineField.java index ad1362080b1..c47337923f6 100644 --- a/test/langtools/tools/javac/Paths/WildcardMineField.java +++ b/test/langtools/tools/javac/Paths/WildcardMineField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary Test classpath wildcards for javac and java -classpath option. * @library /tools/lib * @build toolbox.ToolBox Util WildcardMineField - * @run main WildcardMineField + * @run main/timeout=480 WildcardMineField */ /* diff --git a/test/langtools/tools/javac/diags/CheckExamples.java b/test/langtools/tools/javac/diags/CheckExamples.java index dd763f3d3da..502f5fa8b88 100644 --- a/test/langtools/tools/javac/diags/CheckExamples.java +++ b/test/langtools/tools/javac/diags/CheckExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * jdk.compiler/com.sun.tools.javac.resources:open * jdk.compiler/com.sun.tools.javac.util * @build Example CheckExamples DocCommentProcessor - * @run main/othervm CheckExamples + * @run main/othervm/timeout=480 CheckExamples */ /* diff --git a/test/langtools/tools/javac/diags/RunExamples.java b/test/langtools/tools/javac/diags/RunExamples.java index 7e956aefb36..7805efa734b 100644 --- a/test/langtools/tools/javac/diags/RunExamples.java +++ b/test/langtools/tools/javac/diags/RunExamples.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * jdk.compiler/com.sun.tools.javac.parser * jdk.compiler/com.sun.tools.javac.util * @build ArgTypeCompilerFactory Example HTMLWriter RunExamples DocCommentProcessor - * @run main/othervm RunExamples + * @run main/othervm/timeout=480 RunExamples */ /* * See CR 7127924 for info on why othervm is used. diff --git a/test/langtools/tools/javac/failover/CheckAttributedTree.java b/test/langtools/tools/javac/failover/CheckAttributedTree.java index 1969a97df05..9b28d2bebd4 100644 --- a/test/langtools/tools/javac/failover/CheckAttributedTree.java +++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main CheckAttributedTree -q -r -et ERRONEOUS . + * @run main/timeout=480 CheckAttributedTree -q -r -et ERRONEOUS . */ import java.awt.BorderLayout; diff --git a/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java b/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java index ce2ce4530f8..09209e14c9d 100644 --- a/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java +++ b/test/langtools/tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng MultiReleaseJarTest + * @run testng/timeout=480 MultiReleaseJarTest */ import org.testng.annotations.AfterClass; diff --git a/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java b/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java index 727f749c1c9..4c4775ed744 100644 --- a/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java +++ b/test/langtools/tools/javac/generics/diamond/7030150/GenericConstructorAndDiamondTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -26,6 +26,7 @@ * @bug 7030150 7039931 * @summary Type inference for generic instance creation failed for formal type parameter * @modules jdk.compiler + * @run main/timeout=480 GenericConstructorAndDiamondTest */ import com.sun.source.util.JavacTask; diff --git a/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java b/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java index cf204264367..83ff216ef7a 100644 --- a/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java +++ b/test/langtools/tools/javac/importscope/NegativeCyclicDependencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -29,7 +29,7 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox NegativeCyclicDependencyTest - * @run main NegativeCyclicDependencyTest + * @run main/timeout=480 NegativeCyclicDependencyTest */ import javax.tools.JavaCompiler; diff --git a/test/langtools/tools/javac/lambda/LambdaParserTest.java b/test/langtools/tools/javac/lambda/LambdaParserTest.java index e3440d3b17f..53578d9c40d 100644 --- a/test/langtools/tools/javac/lambda/LambdaParserTest.java +++ b/test/langtools/tools/javac/lambda/LambdaParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. 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 @@ -33,7 +33,7 @@ * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main LambdaParserTest + * @run main/timeout=480 LambdaParserTest */ import java.io.IOException; diff --git a/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties b/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties index 90f2fe459c2..9acbe8f1700 100644 --- a/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties +++ b/test/langtools/tools/javac/lambda/bridge/template_tests/TEST.properties @@ -6,3 +6,5 @@ lib.dirs = /lib/combo modules = \ jdk.compiler/com.sun.tools.javac.util + +timeout.default.seconds=480 diff --git a/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java b/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java index e702ea3e75a..27a902fcb32 100644 --- a/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java +++ b/test/langtools/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -26,6 +26,7 @@ * @bug 8002099 8010822 * @summary Add support for intersection types in cast expression * @modules jdk.compiler/com.sun.tools.javac.util + * @run main/timeout=480 IntersectionTargetTypeTest */ import com.sun.source.util.JavacTask; diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java index a6298bfa8ce..ee3bb8c897d 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Test; * * @compile ${test.root}/../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java * - * @run junit CreateSymbolsReproducibleTest + * @run junit/timeout=480 CreateSymbolsReproducibleTest */ public class CreateSymbolsReproducibleTest { diff --git a/test/langtools/tools/javac/tree/JavacTreeScannerTest.java b/test/langtools/tools/javac/tree/JavacTreeScannerTest.java index 590cdb849c4..8e9c0501f8e 100644 --- a/test/langtools/tools/javac/tree/JavacTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/JavacTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest JavacTreeScannerTest - * @run main JavacTreeScannerTest -q -r . + * @run main/timeout=480 JavacTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java b/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java index 72cc2d2e9d1..da069f4f911 100644 --- a/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/SourceDocTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -40,7 +40,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest SourceDocTreeScannerTest - * @run main SourceDocTreeScannerTest -q -r . + * @run main/timeout=480 SourceDocTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java index bf50f298871..de68377a3c6 100644 --- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -41,7 +41,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest SourceTreeScannerTest - * @run main SourceTreeScannerTest -q -r . + * @run main/timeout=480 SourceTreeScannerTest -q -r . */ import java.io.*; diff --git a/test/langtools/tools/javac/types/TestComparisons.java b/test/langtools/tools/javac/types/TestComparisons.java index 9835e1271f5..8b15edd6715 100644 --- a/test/langtools/tools/javac/types/TestComparisons.java +++ b/test/langtools/tools/javac/types/TestComparisons.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -26,6 +26,7 @@ * @bug 8013357 * @summary javac should correctly enforce binary comparison rules. * @modules jdk.compiler + * @run main/timeout=480 TestComparisons */ import java.io.*; diff --git a/test/langtools/tools/javac/util/IteratorsTest.java b/test/langtools/tools/javac/util/IteratorsTest.java index cbfde59b1e1..bd05bebeb09 100644 --- a/test/langtools/tools/javac/util/IteratorsTest.java +++ b/test/langtools/tools/javac/util/IteratorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8303882 * @summary Verify that Iterators method work as expected * @modules jdk.compiler/com.sun.tools.javac.util - * @run junit IteratorsTest + * @run junit/timeout=480 IteratorsTest */ import com.sun.tools.javac.util.Iterators; diff --git a/test/langtools/tools/javac/varargs/warning/Warn5.java b/test/langtools/tools/javac/varargs/warning/Warn5.java index af8c045e62b..114f94ebc91 100644 --- a/test/langtools/tools/javac/varargs/warning/Warn5.java +++ b/test/langtools/tools/javac/varargs/warning/Warn5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main/othervm Warn5 + * @run main/othervm/timeout=480 Warn5 */ import java.io.IOException; diff --git a/test/langtools/tools/lib/toolbox/ToolBox.java b/test/langtools/tools/lib/toolbox/ToolBox.java index 0763da16ee5..ee217ab2c0c 100644 --- a/test/langtools/tools/lib/toolbox/ToolBox.java +++ b/test/langtools/tools/lib/toolbox/ToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -102,12 +102,6 @@ public class ToolBox { public static final String testSrc = System.getProperty("test.src"); /** The location of the test JDK for this test, or null if not set. */ public static final String testJDK = System.getProperty("test.jdk"); - /** The timeout factor for slow systems. */ - public static final float timeoutFactor; - static { - String ttf = System.getProperty("test.timeout.factor"); - timeoutFactor = (ttf == null) ? 1.0f : Float.parseFloat(ttf); - } /** The current directory. */ public static final Path currDir = Path.of("."); @@ -482,8 +476,8 @@ public class ToolBox { throw new IOException("File not deleted: " + path); } - private static final int RETRY_DELETE_MILLIS = isWindows() ? (int)(500 * timeoutFactor): 0; - private static final int MAX_RETRY_DELETE_MILLIS = isWindows() ? (int)(15 * 1000 * timeoutFactor) : 0; + private static final int RETRY_DELETE_MILLIS = isWindows() ? 500 : 0; + private static final int MAX_RETRY_DELETE_MILLIS = isWindows() ? 60 * 1000 : 0; /** * Moves a file. diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index 56e3baa2e25..13ac2e4e97a 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -228,9 +228,6 @@ public class CDSTestUtils { public static final boolean copyChildStdoutToMainStdout = Boolean.getBoolean("test.cds.copy.child.stdout"); - // This property is passed to child test processes - public static final String TestTimeoutFactor = System.getProperty("test.timeout.factor", "1.0"); - public static final String UnableToMapMsg = "Unable to map shared archive: test did not complete"; @@ -433,7 +430,7 @@ public class CDSTestUtils { ArrayList cmd = new ArrayList(); cmd.addAll(opts.prefix); cmd.add("-Xshare:" + opts.xShareMode); - cmd.add("-Dtest.timeout.factor=" + TestTimeoutFactor); + cmd.add("-Dtest.timeout.factor=" + Utils.TIMEOUT_FACTOR); if (!opts.useSystemArchive) { if (opts.archiveName == null) diff --git a/test/lib/jdk/test/lib/util/ForceGC.java b/test/lib/jdk/test/lib/util/ForceGC.java index e3587b9a2be..b1517d38175 100644 --- a/test/lib/jdk/test/lib/util/ForceGC.java +++ b/test/lib/jdk/test/lib/util/ForceGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -27,15 +27,12 @@ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.function.BooleanSupplier; +import jdk.test.lib.Utils; /** * Utility class to invoke System.gc() */ public class ForceGC { - // The jtreg testing timeout factor. - private static final double TIMEOUT_FACTOR = Double.valueOf( - System.getProperty("test.timeout.factor", "1.0")); - /** * Causes the current thread to wait until the {@code booleanSupplier} * returns true, or the waiting time elapses. The waiting time @@ -57,7 +54,7 @@ public class ForceGC { */ public static boolean wait(BooleanSupplier booleanSupplier) { - return waitFor(booleanSupplier, Math.round(1000L * TIMEOUT_FACTOR)); + return waitFor(booleanSupplier, Math.round(1000L * Utils.TIMEOUT_FACTOR)); } /** From 3fb9246af9a006c0b3a1f9c41d60dff74f7bf140 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 07:54:36 +0000 Subject: [PATCH 315/471] 8366544: Parallel: Inline PSParallelCompact::invoke_no_policy Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 10 +--------- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index b549c61e1c0..5a0dbe3d4e6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -969,19 +969,11 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); + assert(ref_processor() != nullptr, "Sanity"); SvcGCMarker sgcm(SvcGCMarker::FULL); IsSTWGCActiveMark mark; - return PSParallelCompact::invoke_no_policy(clear_all_soft_refs); -} - -// This method contains no policy. You should probably -// be calling invoke() instead. -bool PSParallelCompact::invoke_no_policy(bool clear_all_soft_refs) { - assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - assert(ref_processor() != nullptr, "Sanity"); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCIdMark gc_id_mark; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index a0118717f9d..874c72d5671 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -762,7 +762,6 @@ public: static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); static bool invoke(bool clear_all_soft_refs); - static bool invoke_no_policy(bool clear_all_soft_refs); template static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); From d19eab4f08592140229de43689c7d20ff7fbf4ee Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Tue, 2 Sep 2025 07:57:03 +0000 Subject: [PATCH 316/471] 8366556: Sort share/runtime includes Reviewed-by: dholmes, ayang --- src/hotspot/share/runtime/basicLock.inline.hpp | 1 + src/hotspot/share/runtime/continuationFreezeThaw.cpp | 6 +++--- src/hotspot/share/runtime/continuationHelper.inline.hpp | 1 - src/hotspot/share/runtime/continuationWrapper.inline.hpp | 2 +- src/hotspot/share/runtime/cpuTimeCounters.cpp | 2 +- src/hotspot/share/runtime/deoptimization.cpp | 4 +--- src/hotspot/share/runtime/fieldDescriptor.cpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.hpp | 3 ++- src/hotspot/share/runtime/flags/jvmFlagAccess.cpp | 2 +- .../share/runtime/flags/jvmFlagConstraintsCompiler.cpp | 4 ++-- .../share/runtime/flags/jvmFlagConstraintsRuntime.cpp | 2 +- src/hotspot/share/runtime/flags/jvmFlagLimit.cpp | 7 +++---- src/hotspot/share/runtime/flags/jvmFlagLookup.hpp | 2 +- src/hotspot/share/runtime/frame.cpp | 2 +- src/hotspot/share/runtime/frame.inline.hpp | 2 +- src/hotspot/share/runtime/handles.inline.hpp | 2 +- src/hotspot/share/runtime/handshake.cpp | 2 +- src/hotspot/share/runtime/interfaceSupport.cpp | 1 - src/hotspot/share/runtime/java.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 6 +++--- src/hotspot/share/runtime/javaThread.hpp | 2 +- src/hotspot/share/runtime/keepStackGCProcessed.cpp | 2 +- src/hotspot/share/runtime/objectMonitor.cpp | 1 - src/hotspot/share/runtime/os.cpp | 4 ++-- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/signature.cpp | 1 - src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp | 2 +- src/hotspot/share/runtime/stubCodeGenerator.cpp | 1 - src/hotspot/share/runtime/stubRoutines.cpp | 2 +- src/hotspot/share/runtime/synchronizer.cpp | 1 - src/hotspot/share/runtime/threadSMR.inline.hpp | 2 +- src/hotspot/share/runtime/threads.cpp | 6 +++--- src/hotspot/share/runtime/vframe.cpp | 3 +-- src/hotspot/share/runtime/vframeArray.cpp | 2 +- src/hotspot/share/runtime/vframe_hp.cpp | 2 +- src/hotspot/share/runtime/vmOperations.cpp | 2 +- src/hotspot/share/runtime/vmOperations.hpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 5 ++--- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 39 files changed, 45 insertions(+), 53 deletions(-) diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index ee4791edecf..773d8a1c848 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_BASICLOCK_INLINE_HPP #include "runtime/basicLock.hpp" + #include "runtime/objectMonitor.inline.hpp" inline markWord BasicLock::displaced_header() const { diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 1027b4447c5..40a8987e139 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -28,9 +28,9 @@ #include "code/nmethod.inline.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.inline.hpp" +#include "gc/shared/barrierSet.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gc_globals.hpp" -#include "gc/shared/barrierSet.hpp" #include "gc/shared/memAllocator.hpp" #include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "interpreter/interpreter.hpp" @@ -39,8 +39,8 @@ #include "logging/logStream.hpp" #include "oops/access.inline.hpp" #include "oops/method.inline.hpp" -#include "oops/oopsHierarchy.hpp" #include "oops/objArrayOop.inline.hpp" +#include "oops/oopsHierarchy.hpp" #include "oops/stackChunkOop.inline.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/arguments.hpp" @@ -57,8 +57,8 @@ #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" -#include "runtime/smallRegisterMap.inline.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/smallRegisterMap.inline.hpp" #include "runtime/stackChunkFrameStream.inline.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackOverflow.hpp" diff --git a/src/hotspot/share/runtime/continuationHelper.inline.hpp b/src/hotspot/share/runtime/continuationHelper.inline.hpp index 279e2a5ffd5..9aadfd8a388 100644 --- a/src/hotspot/share/runtime/continuationHelper.inline.hpp +++ b/src/hotspot/share/runtime/continuationHelper.inline.hpp @@ -28,7 +28,6 @@ #include "runtime/continuationHelper.hpp" #include "code/scopeDesc.hpp" -#include "compiler/oopMap.hpp" #include "compiler/oopMap.inline.hpp" #include "interpreter/oopMapCache.hpp" #include "runtime/frame.inline.hpp" diff --git a/src/hotspot/share/runtime/continuationWrapper.inline.hpp b/src/hotspot/share/runtime/continuationWrapper.inline.hpp index 0215f765c5d..ddf5e0be02d 100644 --- a/src/hotspot/share/runtime/continuationWrapper.inline.hpp +++ b/src/hotspot/share/runtime/continuationWrapper.inline.hpp @@ -28,8 +28,8 @@ // There is no continuationWrapper.hpp file #include "classfile/javaClasses.inline.hpp" -#include "oops/oop.inline.hpp" #include "memory/allocation.hpp" +#include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/stackChunkOop.hpp" #include "runtime/continuationEntry.inline.hpp" diff --git a/src/hotspot/share/runtime/cpuTimeCounters.cpp b/src/hotspot/share/runtime/cpuTimeCounters.cpp index 0248db8fec3..c6bcffbd024 100644 --- a/src/hotspot/share/runtime/cpuTimeCounters.cpp +++ b/src/hotspot/share/runtime/cpuTimeCounters.cpp @@ -23,8 +23,8 @@ * */ -#include "runtime/cpuTimeCounters.hpp" #include "runtime/atomic.hpp" +#include "runtime/cpuTimeCounters.hpp" const char* CPUTimeGroups::to_string(CPUTimeType val) { switch (val) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index efc7bfde3dd..521ac5454ea 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -35,7 +35,6 @@ #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/memAllocator.hpp" -#include "interpreter/bytecode.hpp" #include "interpreter/bytecode.inline.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/interpreter.hpp" @@ -68,7 +67,6 @@ #include "runtime/continuationEntry.inline.hpp" #include "runtime/deoptimization.hpp" #include "runtime/escapeBarrier.hpp" -#include "runtime/fieldDescriptor.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" @@ -91,8 +89,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "runtime/vframe.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" #include "runtime/vmOperations.hpp" #include "utilities/checkedCast.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 28f44d4de8d..c5c3bdbd4bc 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -26,10 +26,10 @@ #include "memory/resourceArea.hpp" #include "oops/annotations.hpp" #include "oops/constantPool.hpp" +#include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/fieldStreams.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp index 5bd5c2bdb4f..a9dace1e19c 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp @@ -25,10 +25,11 @@ #ifndef SHARE_RUNTIME_FLAGS_JVMFLAG_HPP #define SHARE_RUNTIME_FLAGS_JVMFLAG_HPP -#include "utilities/globalDefinitions.hpp" #include "utilities/enumIterator.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/vmEnums.hpp" + #include class outputStream; diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp index dead6e632ef..2db9f198ddd 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp @@ -26,8 +26,8 @@ #include "memory/allocation.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagAccess.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 17dc71bc59d..4e28135dccf 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -25,14 +25,14 @@ #include "code/relocInfo.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "compiler/compilerDirectives.hpp" -#include "oops/metadata.hpp" -#include "runtime/os.hpp" #include "interpreter/invocationCounter.hpp" +#include "oops/metadata.hpp" #include "runtime/arguments.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagConstraintsCompiler.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/os.hpp" #include "utilities/powerOfTwo.hpp" /** diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 6a618cd7fea..1e6efd893c8 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -23,8 +23,8 @@ */ #include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "runtime/safepointMechanism.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp index 3d5faa85a0d..b5507c07ee7 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp @@ -22,16 +22,15 @@ * */ -#include "memory/allocation.inline.hpp" #include "gc/shared/jvmFlagConstraintsGC.hpp" +#include "memory/allocation.inline.hpp" +#include "oops/markWord.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/flags/jvmFlagAccess.hpp" -#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/flags/jvmFlagConstraintsCompiler.hpp" #include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagLimit.hpp" #include "runtime/globals_extension.hpp" -#include "gc/shared/referenceProcessor.hpp" -#include "oops/markWord.hpp" #include "runtime/task.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp b/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp index 128025b8e22..256f674f19c 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLookup.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_RUNTIME_FLAGS_JVMFLAGLOOKUP_HPP #define SHARE_RUNTIME_FLAGS_JVMFLAGLOOKUP_HPP -#include "runtime/globals_extension.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals_extension.hpp" // This is a hashtable that maps from (const char*) to (JVMFlag*) to speed up // the processing of JVM command-line arguments at runtime. diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index ba9aa3eb29a..75c6e388b0d 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -50,8 +50,8 @@ #include "runtime/javaThread.hpp" #include "runtime/monitorChunk.hpp" #include "runtime/os.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/safefetch.hpp" +#include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stackValue.hpp" #include "runtime/stubCodeGenerator.hpp" diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index aa2de69a739..449abddd443 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -30,8 +30,8 @@ #include "code/codeBlob.inline.hpp" #include "code/nmethod.inline.hpp" #include "interpreter/interpreter.hpp" -#include "oops/stackChunkOop.inline.hpp" #include "oops/method.hpp" +#include "oops/stackChunkOop.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/registerMap.hpp" #include "runtime/stubRoutines.hpp" diff --git a/src/hotspot/share/runtime/handles.inline.hpp b/src/hotspot/share/runtime/handles.inline.hpp index 4d3dd527c0d..15b06315823 100644 --- a/src/hotspot/share/runtime/handles.inline.hpp +++ b/src/hotspot/share/runtime/handles.inline.hpp @@ -27,9 +27,9 @@ #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" +#include "runtime/javaThread.hpp" // these inline functions are in a separate file to break an include cycle // between Thread and Handle diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index e6a12677a19..f9e48b7f711 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -40,8 +40,8 @@ #include "runtime/task.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vmThread.hpp" -#include "utilities/formatBuffer.hpp" #include "utilities/filterQueue.inline.hpp" +#include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/systemMemoryBarrier.hpp" diff --git a/src/hotspot/share/runtime/interfaceSupport.cpp b/src/hotspot/share/runtime/interfaceSupport.cpp index 42dc37f4ccb..53216f14f24 100644 --- a/src/hotspot/share/runtime/interfaceSupport.cpp +++ b/src/hotspot/share/runtime/interfaceSupport.cpp @@ -22,7 +22,6 @@ * */ -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 2aaf020d6d6..b3b46e5a9ab 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -75,9 +75,9 @@ #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/trimNativeHeap.hpp" +#include "runtime/vm_version.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" -#include "runtime/vm_version.hpp" #include "sanitizers/leak.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index a0ac7bd4768..5ea2a4e4385 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -32,8 +32,8 @@ #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "code/scopeDesc.hpp" -#include "compiler/compileTask.hpp" #include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/tlab_globals.hpp" @@ -88,10 +88,10 @@ #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" -#include "runtime/vmThread.hpp" +#include "runtime/vframeArray.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "services/threadService.hpp" #include "utilities/copy.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index fac263d9048..bf72fac5737 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -38,8 +38,8 @@ #include "runtime/lockStack.hpp" #include "runtime/park.hpp" #include "runtime/safepointMechanism.hpp" -#include "runtime/stackWatermarkSet.hpp" #include "runtime/stackOverflow.hpp" +#include "runtime/stackWatermarkSet.hpp" #include "runtime/suspendResumeManager.hpp" #include "runtime/thread.hpp" #include "runtime/threadHeapSampler.hpp" diff --git a/src/hotspot/share/runtime/keepStackGCProcessed.cpp b/src/hotspot/share/runtime/keepStackGCProcessed.cpp index d928e689fea..01029b6b977 100644 --- a/src/hotspot/share/runtime/keepStackGCProcessed.cpp +++ b/src/hotspot/share/runtime/keepStackGCProcessed.cpp @@ -22,10 +22,10 @@ * */ +#include "runtime/keepStackGCProcessed.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" -#include "runtime/keepStackGCProcessed.hpp" KeepStackGCProcessedMark::KeepStackGCProcessedMark(JavaThread* jt) : _active(true), diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 39ba328b0d0..9e3638ddadc 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -45,7 +45,6 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 3152f734dfa..f2a7587d364 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -65,8 +65,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/threadCrashProtection.hpp" #include "runtime/threadSMR.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "sanitizers/address.hpp" #include "services/attachListener.hpp" #include "services/threadService.hpp" @@ -89,8 +89,8 @@ # include #endif -# include # include +# include OSThread* os::_starting_thread = nullptr; volatile unsigned int os::_rand_seed = 1234567; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 13612496fbd..044359eba8d 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -42,8 +42,8 @@ #include "gc/shared/collectedHeap.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" -#include "jvm.h" #include "jfr/jfrEvents.hpp" +#include "jvm.h" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index fb649b8c872..9ae5b3df415 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -39,7 +39,6 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" -#include "runtime/sharedRuntime.hpp" // Implementation of SignatureIterator diff --git a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp index 734d31d3390..09c267b408b 100644 --- a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp +++ b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp @@ -31,10 +31,10 @@ #include "compiler/oopMap.hpp" #include "interpreter/interpreter.hpp" #include "logging/log.hpp" +#include "oops/instanceStackChunkKlass.inline.hpp" #include "oops/method.hpp" #include "oops/oop.hpp" #include "oops/stackChunkOop.inline.hpp" -#include "oops/instanceStackChunkKlass.inline.hpp" #include "runtime/frame.inline.hpp" #include "utilities/debug.hpp" #include "utilities/devirtualizer.inline.hpp" diff --git a/src/hotspot/share/runtime/stubCodeGenerator.cpp b/src/hotspot/share/runtime/stubCodeGenerator.cpp index 4e5f1635e42..43250c004ca 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.cpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp @@ -22,7 +22,6 @@ * */ -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "code/codeCache.hpp" #include "compiler/disassembler.hpp" diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 82608737be8..5246613738e 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -31,9 +31,9 @@ #include "prims/vectorSupport.hpp" #include "runtime/continuation.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/timerTrace.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #ifdef COMPILER2 diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 221e7dd71ec..f3e3072978b 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -44,7 +44,6 @@ #include "runtime/lightweightSynchronizer.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" diff --git a/src/hotspot/share/runtime/threadSMR.inline.hpp b/src/hotspot/share/runtime/threadSMR.inline.hpp index 3bca94a82e5..a78fbf48761 100644 --- a/src/hotspot/share/runtime/threadSMR.inline.hpp +++ b/src/hotspot/share/runtime/threadSMR.inline.hpp @@ -29,8 +29,8 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shared/tlab_globals.hpp" -#include "runtime/atomic.hpp" #include "memory/iterator.hpp" +#include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/debug.hpp" diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 1ac44b8a2f5..5ba3499efbe 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -37,8 +37,8 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" -#include "compiler/compileTask.hpp" #include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/gcVMOperations.hpp" @@ -91,13 +91,13 @@ #include "runtime/stackWatermarkSet.inline.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.inline.hpp" #include "runtime/threads.hpp" +#include "runtime/threadSMR.inline.hpp" #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "runtime/trimNativeHeap.hpp" -#include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmOperations.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" #include "services/threadIdTable.hpp" diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index a3c0c41b1b1..74d42b7dc9d 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -43,7 +43,6 @@ #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.inline.hpp" -#include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/signature.hpp" @@ -51,8 +50,8 @@ #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" vframe::vframe(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) : _reg_map(reg_map), _thread(thread), diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 224bce4513a..a68a0adf299 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -40,8 +40,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/synchronizer.hpp" #include "runtime/vframe.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" #include "utilities/copy.hpp" #include "utilities/events.hpp" diff --git a/src/hotspot/share/runtime/vframe_hp.cpp b/src/hotspot/share/runtime/vframe_hp.cpp index 5e3ef80a2ca..c901dd9f23a 100644 --- a/src/hotspot/share/runtime/vframe_hp.cpp +++ b/src/hotspot/share/runtime/vframe_hp.cpp @@ -42,8 +42,8 @@ #include "runtime/signature.hpp" #include "runtime/stackValue.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" +#include "runtime/vframeArray.hpp" // ------------- compiledVFrame -------------- diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 2cfc84376af..c5539fd5e50 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -31,8 +31,8 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logStream.hpp" #include "memory/heapInspection.hpp" #include "memory/metaspace/metaspaceReporter.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index baeea722dce..2ed9626652c 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -27,8 +27,8 @@ #include "oops/oop.hpp" #include "runtime/javaThread.hpp" -#include "runtime/vmOperation.hpp" #include "runtime/threadSMR.hpp" +#include "runtime/vmOperation.hpp" class ObjectMonitorsView; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index b95c1aaf60c..3575ef70d19 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -46,7 +46,6 @@ #include "interpreter/interpreter.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" #include "logging/logAsyncWriter.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/heap.hpp" #include "memory/padded.hpp" @@ -56,8 +55,8 @@ #include "oops/array.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" -#include "oops/constMethod.hpp" #include "oops/constantPool.hpp" +#include "oops/constMethod.hpp" #include "oops/cpCache.hpp" #include "oops/fieldInfo.hpp" #include "oops/instanceClassLoaderKlass.hpp" @@ -99,8 +98,8 @@ #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" #include "runtime/vframeArray.hpp" -#include "runtime/vmStructs.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmStructs.hpp" #include "services/attachListener.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index e2724a93890..be35f8fa2b2 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -61,6 +61,7 @@ public class TestIncludesAreSorted { "share/opto", "share/precompiled", "share/prims", + "share/runtime", "share/services", "share/utilities" }; From af532cc1b227c56cd03caca7d7558d58687d8584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nordstr=C3=B6m?= Date: Tue, 2 Sep 2025 07:58:38 +0000 Subject: [PATCH 317/471] 8365913: Support latest MSC_VER in abstract_vm_version.cpp Reviewed-by: dholmes --- src/hotspot/share/runtime/abstract_vm_version.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 97d4f7f228d..7d460d83e1b 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -271,6 +271,18 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.7 (VS2022)" #elif _MSC_VER == 1938 #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.8 (VS2022)" + #elif _MSC_VER == 1939 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.9 (VS2022)" + #elif _MSC_VER == 1940 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.10 (VS2022)" + #elif _MSC_VER == 1941 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.11 (VS2022)" + #elif _MSC_VER == 1942 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.12 (VS2022)" + #elif _MSC_VER == 1943 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.13 (VS2022)" + #elif _MSC_VER == 1944 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 17.14 (VS2022)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif From 523bc77981cfe82956d2176f74917c41788da6db Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Tue, 2 Sep 2025 08:15:27 +0000 Subject: [PATCH 318/471] 8364816: GetLastError() in os_windows.cpp should not store value to errno Reviewed-by: dholmes, jsikstro --- src/hotspot/os/windows/os_windows.cpp | 51 ++++++++++++---------- src/hotspot/share/cds/aotClassLocation.cpp | 6 --- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 3f3d9f6ac63..09d8b542a10 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -4700,13 +4700,13 @@ static bool is_symbolic_link(const wchar_t* wide_path) { if (f != INVALID_HANDLE_VALUE) { const bool result = fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fd.dwReserved0 == IO_REPARSE_TAG_SYMLINK; if (::FindClose(f) == 0) { - errno = ::GetLastError(); - log_debug(os)("is_symbolic_link() failed to FindClose: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindClose: GetLastError->%lu.", errcode); } return result; } else { - errno = ::GetLastError(); - log_debug(os)("is_symbolic_link() failed to FindFirstFileW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindFirstFileW: GetLastError->%lu.", errcode); return false; } } @@ -4716,8 +4716,8 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { HANDLE hFile = CreateFileW(wide_path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to CreateFileW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CreateFileW: GetLastError->%lu.", errcode); return nullptr; } @@ -4725,8 +4725,8 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { const size_t target_path_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED); if (target_path_size == 0) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%lu.", errcode); return nullptr; } @@ -4736,14 +4736,14 @@ static WCHAR* get_path_to_target(const wchar_t* wide_path) { const size_t res = ::GetFinalPathNameByHandleW(hFile, path_to_target, static_cast(target_path_size), FILE_NAME_NORMALIZED); if (res != target_path_size - 1) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%lu.", errcode); return nullptr; } if (::CloseHandle(hFile) == 0) { - errno = ::GetLastError(); - log_debug(os)("get_path_to_target() failed to CloseHandle: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CloseHandle: GetLastError->%lu.", errcode); return nullptr; } @@ -4824,9 +4824,8 @@ int os::stat(const char *path, struct stat *sbuf) { if (is_symlink) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { - // it is a symbolic link, but we failed to resolve it, - // errno has been set in the call to get_path_to_target(), - // no need to overwrite it + // it is a symbolic link, but we failed to resolve it + errno = ENOENT; os::free(wide_path); return -1; } @@ -4837,8 +4836,13 @@ int os::stat(const char *path, struct stat *sbuf) { // if getting attributes failed, GetLastError should be called immediately after that if (!bret) { - errno = ::GetLastError(); - log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%ld.", errno); + DWORD errcode = ::GetLastError(); + if (errcode == ERROR_FILE_NOT_FOUND || errcode == ERROR_PATH_NOT_FOUND) { + errno = ENOENT; + } else { + errno = 0; + } + log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); os::free(wide_path); os::free(path_to_target); return -1; @@ -5038,9 +5042,8 @@ int os::open(const char *path, int oflag, int mode) { if (is_symlink) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { - // it is a symbolic link, but we failed to resolve it, - // errno has been set in the call to get_path_to_target(), - // no need to overwrite it + // it is a symbolic link, but we failed to resolve it + errno = ENOENT; os::free(wide_path); return -1; } @@ -5048,10 +5051,9 @@ int os::open(const char *path, int oflag, int mode) { int fd = ::_wopen(is_symlink ? path_to_target : wide_path, oflag | O_BINARY | O_NOINHERIT, mode); - // if opening files failed, GetLastError should be called immediately after that + // if opening files failed, errno has been set to indicate the problem if (fd == -1) { - errno = ::GetLastError(); - log_debug(os)("os::open() failed to _wopen: GetLastError->%ld.", errno); + log_debug(os)("os::open() failed to _wopen: errno->%s.", strerror(errno)); } os::free(wide_path); os::free(path_to_target); @@ -5119,7 +5121,8 @@ bool os::dir_is_empty(const char* path) { } FindClose(f); } else { - errno = ::GetLastError(); + DWORD errcode = ::GetLastError(); + log_debug(os)("os::dir_is_empty() failed to FindFirstFileW: GetLastError->%lu.", errcode); } return is_empty; diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 4119b9236e1..f04c601ac86 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -241,12 +241,6 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa // The timestamp of $JAVA_HOME/lib/modules is not checked at runtime. check_time = !is_jrt; } -#ifdef _WINDOWS - } else if (errno == ERROR_FILE_NOT_FOUND || errno == ERROR_PATH_NOT_FOUND) { - // On Windows, the errno could be ERROR_PATH_NOT_FOUND (3) in case the directory - // path doesn't exist. - type = FileType::NOT_EXIST; -#endif } else if (errno == ENOENT) { // We allow the file to not exist, as long as it also doesn't exist during runtime. type = FileType::NOT_EXIST; From ef7872cc31d4d7c0a9f311eafc28132ead3476b6 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 2 Sep 2025 09:08:26 +0000 Subject: [PATCH 319/471] 8365163: [ubsan] left-shift issue in globalDefinitions.hpp Reviewed-by: kbarrett, stefank, aph --- .../share/utilities/globalDefinitions.hpp | 16 +++-------- .../utilities/test_globalDefinitions.cpp | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 2a179f5814f..1ef548d6510 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -641,19 +641,11 @@ inline jdouble jdouble_cast (jlong x) { return ((DoubleLongConv*)&x)->d; } inline jint low (jlong value) { return jint(value); } inline jint high(jlong value) { return jint(value >> 32); } -// the fancy casts are a hopefully portable way -// to do unsigned 32 to 64 bit type conversion -inline void set_low (jlong* value, jint low ) { *value &= (jlong)0xffffffff << 32; - *value |= (jlong)(julong)(juint)low; } - -inline void set_high(jlong* value, jint high) { *value &= (jlong)(julong)(juint)0xffffffff; - *value |= (jlong)high << 32; } - inline jlong jlong_from(jint h, jint l) { - jlong result = 0; // initialization to avoid warning - set_high(&result, h); - set_low(&result, l); - return result; + // First cast jint values to juint, so cast to julong will zero-extend. + julong high = (julong)(juint)h << 32; + julong low = (julong)(juint)l; + return (jlong)(high | low); } union jlong_accessor { diff --git a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp index 38aa7aa477b..4c04b77a51b 100644 --- a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp +++ b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp @@ -295,3 +295,30 @@ TEST(globalDefinitions, format_specifiers) { // Check all platforms print this compatibly without leading 0x. check_format(UINT64_FORMAT_0, (u8)0x123, "0000000000000123"); } + +TEST(globalDefinitions, jlong_from) { + jlong val = jlong_from(0xFF, 0); + EXPECT_EQ(val, CONST64(0x00000000FF00000000)); + + val = jlong_from(0, 0xFF); + EXPECT_EQ(val, CONST64(0x00000000000000FF)); + + val = jlong_from(0xFFFFFFFF, 0); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFF00000000)); + + val = jlong_from(0, 0xFFFFFFFF); + EXPECT_EQ(val, CONST64(0x00000000FFFFFFFF)); + + val = jlong_from(0, -1); + EXPECT_EQ(val, CONST64(0x00000000FFFFFFFF)); + + val = jlong_from(-1, 0); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFF00000000)); + + val = jlong_from(-1, -1); + EXPECT_EQ((julong)val, UCONST64(0xFFFFFFFFFFFFFFFF)); + EXPECT_EQ(val, CONST64(-1)); + + val = jlong_from(0xABCD, 0xEFEF); + EXPECT_EQ(val, CONST64(0x0000ABCD0000EFEF)); +} From e66ed4d72948a56863f2979b976ef81c0fc43f75 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 09:30:29 +0000 Subject: [PATCH 320/471] 8366666: Bump timeout on StressAsyncUL Reviewed-by: stefank --- test/hotspot/jtreg/runtime/logging/StressAsyncUL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index e14cad6cc65..2967507fa64 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -28,7 +28,7 @@ * @requires vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver StressAsyncUL + * @run driver/timeout=480 StressAsyncUL */ import jdk.test.lib.process.OutputAnalyzer; From 31847149c1956b23c19a99309982660b4bbdd2d6 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Tue, 2 Sep 2025 11:17:56 +0000 Subject: [PATCH 321/471] 8325766: Extend CertificateBuilder to create trust and end entity certificates programmatically Reviewed-by: mullan, abarashev --- .../HttpsURLConnection/IPIdentities.java | 708 +++--------------- .../https/HttpsURLConnection/TEST.properties | 3 + .../test/lib/security/CertificateBuilder.java | 95 ++- 3 files changed, 202 insertions(+), 604 deletions(-) create mode 100644 test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java index 6ea62526566..9ce71064b54 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java @@ -34,379 +34,41 @@ * @author Xuelei Fan */ -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; + +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.security.KeyStore; -import java.security.KeyFactory; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; + import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; import java.math.BigInteger; import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.security.CertificateBuilder; +import jdk.test.lib.security.CertificateBuilder.KeyUsage; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; -/* - * Certificates and key used in the test. - * - * TLS server certificate: - * server private key: - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,D9AE407F6D0E389A - * - * WPrA7TFol/cQCcp9oHnXWNpYlvRbbIcQj0m+RKT2Iuzfus+DHt3Zadf8nJpKfX2e - * h2rnhlzCN9M7djRDooZKDOPCsdBn51Au7HlZF3S3Opgo7D8XFM1a8t1Je4ke14oI - * nw6QKYsBblRziPnP2PZ0zvX24nOv7bbY8beynlJHGs00VWSFdoH2DS0aE1p6D+3n - * ptJuJ75dVfZFK4X7162APlNXevX8D6PEQpSiRw1rjjGGcnvQ4HdWk3BxDVDcCNJb - * Y1aGNRxsjTDvPi3R9Qx2M+W03QzEPx4SR3ZHVskeSJHaetM0TM/w/45Paq4GokXP - * ZeTnbEx1xmjkA7h+t4doLL4watx5F6yLsJzu8xB3lt/1EtmkYtLz1t7X4BetPAXz - * zS69X/VwhKfsOI3qXBWuL2oHPyhDmT1gcaUQwEPSV6ogHEEQEDXdiUS8heNK13KF - * TCQYFkETvV2BLxUhV1hypPzRQ6tUpJiAbD5KmoK2lD9slshG2QtvKQq0/bgkDY5J - * LhDHV2dtcZ3kDPkkZXpbcJQvoeH3d09C5sIsuTFo2zgNR6oETHUc5TzP6FY2YYRa - * QcK5HcmtsRRiXFm01ac+aMejJUIujjFt84SiKWT/73vC8AmY4tYcJBLjCg4XIxSH - * fdDFLL1YZENNO5ivlp8mdiHqcawx+36L7DrEZQ8RZt6cqST5t/+XTdM74s6k81GT - * pNsa82P2K2zmIUZ/DL2mKjW1vfRByw1NQFEBkN3vdyZxYfM/JyUzX4hbjXBEkh9Q - * QYrcwLKLjis2QzSvK04B3bvRzRb+4ocWiso8ZPAXAIxZFBWDpTMM2A== - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICXAIBAAKBgQClrFscN6LdmYktsnm4j9VIpecchBeNaZzGrG358h0fORna03Ie - * buxEzHCk3LoAMPagTz1UemFqzFfQCn+VKBg/mtmU8hvIJIh+/p0PPftXUwizIDPU - * PxdHFNHN6gjYDnVOr77M0uyvqXpJ38LZrLgkQJCmA1Yq0DAFQCxPq9l0iQIDAQAB - * AoGAbqcbg1E1mkR99uOJoNeQYKFOJyGiiXTMnXV1TseC4+PDfQBU7Dax35GcesBi - * CtapIpFKKS5D+ozY6b7ZT8ojxuQ/uHLPAvz0WDR3ds4iRF8tyu71Q1ZHcQsJa17y - * yO7UbkSSKn/Mp9Rb+/dKqftUGNXVFLqgHBOzN2s3We3bbbECQQDYBPKOg3hkaGHo - * OhpHKqtQ6EVkldihG/3i4WejRonelXN+HRh1KrB2HBx0M8D/qAzP1i3rNSlSHer4 - * 59YRTJnHAkEAxFX/sVYSn07BHv9Zhn6XXct/Cj43z/tKNbzlNbcxqQwQerw3IH51 - * 8UH2YOA+GD3lXbKp+MytoFLWv8zg4YT/LwJAfqan75Z1R6lLffRS49bIiq8jwE16 - * rTrUJ+kv8jKxMqc9B3vXkxpsS1M/+4E8bqgAmvpgAb8xcsvHsBd9ErdukQJBAKs2 - * j67W75BrPjBI34pQ1LEfp56IGWXOrq1kF8IbCjxv3+MYRT6Z6UJFkpRymNPNDjsC - * dgUYgITiGJHUGXuw3lMCQHEHqo9ZtXz92yFT+VhsNc29B8m/sqUJdtCcMd/jGpAF - * u6GHufjqIZBpQsk63wbwESAPZZ+kk1O1kS5GIRLX608= - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * publicExponent: 65537 (0x10001) - * privateExponent: - * 6e:a7:1b:83:51:35:9a:44:7d:f6:e3:89:a0:d7:90: - * 60:a1:4e:27:21:a2:89:74:cc:9d:75:75:4e:c7:82: - * e3:e3:c3:7d:00:54:ec:36:b1:df:91:9c:7a:c0:62: - * 0a:d6:a9:22:91:4a:29:2e:43:fa:8c:d8:e9:be:d9: - * 4f:ca:23:c6:e4:3f:b8:72:cf:02:fc:f4:58:34:77: - * 76:ce:22:44:5f:2d:ca:ee:f5:43:56:47:71:0b:09: - * 6b:5e:f2:c8:ee:d4:6e:44:92:2a:7f:cc:a7:d4:5b: - * fb:f7:4a:a9:fb:54:18:d5:d5:14:ba:a0:1c:13:b3: - * 37:6b:37:59:ed:db:6d:b1 - * prime1: - * 00:d8:04:f2:8e:83:78:64:68:61:e8:3a:1a:47:2a: - * ab:50:e8:45:64:95:d8:a1:1b:fd:e2:e1:67:a3:46: - * 89:de:95:73:7e:1d:18:75:2a:b0:76:1c:1c:74:33: - * c0:ff:a8:0c:cf:d6:2d:eb:35:29:52:1d:ea:f8:e7: - * d6:11:4c:99:c7 - * prime2: - * 00:c4:55:ff:b1:56:12:9f:4e:c1:1e:ff:59:86:7e: - * 97:5d:cb:7f:0a:3e:37:cf:fb:4a:35:bc:e5:35:b7: - * 31:a9:0c:10:7a:bc:37:20:7e:75:f1:41:f6:60:e0: - * 3e:18:3d:e5:5d:b2:a9:f8:cc:ad:a0:52:d6:bf:cc: - * e0:e1:84:ff:2f - * exponent1: - * 7e:a6:a7:ef:96:75:47:a9:4b:7d:f4:52:e3:d6:c8: - * 8a:af:23:c0:4d:7a:ad:3a:d4:27:e9:2f:f2:32:b1: - * 32:a7:3d:07:7b:d7:93:1a:6c:4b:53:3f:fb:81:3c: - * 6e:a8:00:9a:fa:60:01:bf:31:72:cb:c7:b0:17:7d: - * 12:b7:6e:91 - * exponent2: - * 00:ab:36:8f:ae:d6:ef:90:6b:3e:30:48:df:8a:50: - * d4:b1:1f:a7:9e:88:19:65:ce:ae:ad:64:17:c2:1b: - * 0a:3c:6f:df:e3:18:45:3e:99:e9:42:45:92:94:72: - * 98:d3:cd:0e:3b:02:76:05:18:80:84:e2:18:91:d4: - * 19:7b:b0:de:53 - * coefficient: - * 71:07:aa:8f:59:b5:7c:fd:db:21:53:f9:58:6c:35: - * cd:bd:07:c9:bf:b2:a5:09:76:d0:9c:31:df:e3:1a: - * 90:05:bb:a1:87:b9:f8:ea:21:90:69:42:c9:3a:df: - * 06:f0:11:20:0f:65:9f:a4:93:53:b5:91:2e:46:21: - * 12:d7:eb:4f - * - * - * server certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 7 (0x7) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:57 2008 GMT - * Not After : Aug 25 03:27:57 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Server, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:a5:ac:5b:1c:37:a2:dd:99:89:2d:b2:79:b8:8f: - * d5:48:a5:e7:1c:84:17:8d:69:9c:c6:ac:6d:f9:f2: - * 1d:1f:39:19:da:d3:72:1e:6e:ec:44:cc:70:a4:dc: - * ba:00:30:f6:a0:4f:3d:54:7a:61:6a:cc:57:d0:0a: - * 7f:95:28:18:3f:9a:d9:94:f2:1b:c8:24:88:7e:fe: - * 9d:0f:3d:fb:57:53:08:b3:20:33:d4:3f:17:47:14: - * d1:cd:ea:08:d8:0e:75:4e:af:be:cc:d2:ec:af:a9: - * 7a:49:df:c2:d9:ac:b8:24:40:90:a6:03:56:2a:d0: - * 30:05:40:2c:4f:ab:d9:74:89 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * ED:6E:DB:F4:B5:56:C8:FB:1A:06:61:3F:0F:08:BB:A6:04:D8:16:54 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3 - * ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6 - * YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS - * 7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva - * cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h - * pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun - * nZif - * -----END CERTIFICATE----- - * - * - * TLS client certificate: - * client private key: - * ----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,FA2A435CD35A9390 - * - * Z+Y2uaETbsUWIyJUyVu1UV2G4rgFYJyACZT6Tp1KjRtxflSh2kXkJ9MpuXMXA0V4 - * Yy3fDzPqCL9NJmQAYRlAx/W/+j4F5EyMWDIx8fUxzONRZyoiwF7jLm+KscAfv6Pf - * q7ItWOdj3z7IYrwlB8YIGd3F2cDKT3S+lYRk7rKb/qT7itbuHnY4Ardh3yl+MZak - * jBp+ELUlRsUqSr1V0LoM+0rCCykarpyfhpxEcqsrl0v9Cyi5uhU50/oKv5zql3SH - * l2ImgDjp3batAs8+Bd4NF2aqi0a7Hy44JUHxRm4caZryU/i/D9N1MbuM6882HLat - * 5N0G+NaIUfywa8mjwq2D5aiit18HqKA6XeRRYeJ5Dvu9DCO4GeFSwcUFIBMI0L46 - * 7s114+oDodg57pMgITi+04vmUxvqlN9aiyd7f5Fgd7PeHGeOdbMz1NaJLJaPI9++ - * NakK8eK9iwT/Gdq0Uap5/CHW7vCT5PO+h3HY0STH0lWStXhdWnFO04zTdywsbSp+ - * DLpHeFT66shfeUlxR0PsCbG9vPRt/QmGLeYQZITppWo/ylSq4j+pRIuXvuWHdBRN - * rTZ8QF4Y7AxQUXVz1j1++s6ZMHTzaK2i9HrhmDs1MbJl+QwWre3Xpv3LvTVz3k5U - * wX8kuY1m3STt71QCaRWENq5sRaMImLxZbxc/ivFl9RAzUqo4NCxLod/QgA4iLqtO - * ztnlpzwlC/F8HbQ1oqYWwnZAPhzU/cULtstl+Yrws2c2atO323LbPXZqbASySgig - * sNpFXQMObdfP6LN23bY+1SvtK7V4NUTNhpdIc6INQAQ= - * -----END RSA PRIVATE KEY----- - * - * -----BEGIN RSA PRIVATE KEY----- - * MIICWwIBAAKBgQC78EA2rCZUTvSjWgAvaSFvuXo6k+yi9uGOx2PYLxIwmS6w8o/4 - * Jy0keCiE9wG/jUR53TvSVfPOPLJbIX3v/TNKsaP/xsibuQ98QTWX+ds6BWAFFa9Z - * F5KjEK0WHOQHU6+odqJWKpLT+SjgeM9eH0irXBnd4WdDunWN9YKsQ5JEGwIDAQAB - * AoGAEbdqNj0wN85hnWyEi/ObJU8UyKTdL9eaF72QGfcF/fLSxfd3vurihIeXOkGW - * tpn4lIxYcVGM9CognhqgJpl11jFTQzn1KqZ+NEJRKkCHA4hDabKJbSC9fXHvRwrf - * BsFpZqgiNxp3HseUTiwnaUVeyPgMt/jAj5nB5Sib+UyUxrECQQDnNQBiF2aifEg6 - * zbJOOC7he5CHAdkFxSxWVFVHL6EfXfqdLVkUohMbgZv+XxyIeU2biOExSg49Kds3 - * FOKgTau1AkEA0Bd1haj6QuCo8I0AXm2WO+MMTZMTvtHD/bGjKNM+fT4I8rKYnQRX - * 1acHdqS9Xx2rNJqZgkMmpESIdPR2fc4yjwJALFeM6EMmqvj8/VIf5UJ/Mz14fXwM - * PEARfckUxd9LnnFutCBTWlKvKXJVEZb6KO5ixPaegc57Jp3Vbh3yTN44lQJADD/1 - * SSMDaIB1MYP7a5Oj7m6VQNPRq8AJe5vDcRnOae0G9dKRrVyeFxO4GsHj6/+BHp2j - * P8nYMn9eURQ7DXjf/QJAAQzMlWnKGSO8pyTDtnQx3hRMoUkOEhmNq4bQhLkYqtnY - * FcqpUQ2qMjW+NiNWk5HnTrMS3L9EdJobMUzaNZLy4w== - * -----END RSA PRIVATE KEY----- - * - * Private-Key: (1024 bit) - * modulus: - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * publicExponent: 65537 (0x10001) - * privateExponent: - * 11:b7:6a:36:3d:30:37:ce:61:9d:6c:84:8b:f3:9b: - * 25:4f:14:c8:a4:dd:2f:d7:9a:17:bd:90:19:f7:05: - * fd:f2:d2:c5:f7:77:be:ea:e2:84:87:97:3a:41:96: - * b6:99:f8:94:8c:58:71:51:8c:f4:2a:20:9e:1a:a0: - * 26:99:75:d6:31:53:43:39:f5:2a:a6:7e:34:42:51: - * 2a:40:87:03:88:43:69:b2:89:6d:20:bd:7d:71:ef: - * 47:0a:df:06:c1:69:66:a8:22:37:1a:77:1e:c7:94: - * 4e:2c:27:69:45:5e:c8:f8:0c:b7:f8:c0:8f:99:c1: - * e5:28:9b:f9:4c:94:c6:b1 - * prime1: - * 00:e7:35:00:62:17:66:a2:7c:48:3a:cd:b2:4e:38: - * 2e:e1:7b:90:87:01:d9:05:c5:2c:56:54:55:47:2f: - * a1:1f:5d:fa:9d:2d:59:14:a2:13:1b:81:9b:fe:5f: - * 1c:88:79:4d:9b:88:e1:31:4a:0e:3d:29:db:37:14: - * e2:a0:4d:ab:b5 - * prime2: - * 00:d0:17:75:85:a8:fa:42:e0:a8:f0:8d:00:5e:6d: - * 96:3b:e3:0c:4d:93:13:be:d1:c3:fd:b1:a3:28:d3: - * 3e:7d:3e:08:f2:b2:98:9d:04:57:d5:a7:07:76:a4: - * bd:5f:1d:ab:34:9a:99:82:43:26:a4:44:88:74:f4: - * 76:7d:ce:32:8f - * exponent1: - * 2c:57:8c:e8:43:26:aa:f8:fc:fd:52:1f:e5:42:7f: - * 33:3d:78:7d:7c:0c:3c:40:11:7d:c9:14:c5:df:4b: - * 9e:71:6e:b4:20:53:5a:52:af:29:72:55:11:96:fa: - * 28:ee:62:c4:f6:9e:81:ce:7b:26:9d:d5:6e:1d:f2: - * 4c:de:38:95 - * exponent2: - * 0c:3f:f5:49:23:03:68:80:75:31:83:fb:6b:93:a3: - * ee:6e:95:40:d3:d1:ab:c0:09:7b:9b:c3:71:19:ce: - * 69:ed:06:f5:d2:91:ad:5c:9e:17:13:b8:1a:c1:e3: - * eb:ff:81:1e:9d:a3:3f:c9:d8:32:7f:5e:51:14:3b: - * 0d:78:df:fd - * coefficient: - * 01:0c:cc:95:69:ca:19:23:bc:a7:24:c3:b6:74:31: - * de:14:4c:a1:49:0e:12:19:8d:ab:86:d0:84:b9:18: - * aa:d9:d8:15:ca:a9:51:0d:aa:32:35:be:36:23:56: - * 93:91:e7:4e:b3:12:dc:bf:44:74:9a:1b:31:4c:da: - * 35:92:f2:e3 - * - * client certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 6 (0x6) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 03:27:34 2008 GMT - * Not After : Aug 25 03:27:34 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org, OU=SSL-Client, CN=localhost - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:bb:f0:40:36:ac:26:54:4e:f4:a3:5a:00:2f:69: - * 21:6f:b9:7a:3a:93:ec:a2:f6:e1:8e:c7:63:d8:2f: - * 12:30:99:2e:b0:f2:8f:f8:27:2d:24:78:28:84:f7: - * 01:bf:8d:44:79:dd:3b:d2:55:f3:ce:3c:b2:5b:21: - * 7d:ef:fd:33:4a:b1:a3:ff:c6:c8:9b:b9:0f:7c:41: - * 35:97:f9:db:3a:05:60:05:15:af:59:17:92:a3:10: - * ad:16:1c:e4:07:53:af:a8:76:a2:56:2a:92:d3:f9: - * 28:e0:78:cf:5e:1f:48:ab:5c:19:dd:e1:67:43:ba: - * 75:8d:f5:82:ac:43:92:44:1b - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Basic Constraints: - * CA:FALSE - * X509v3 Key Usage: - * Digital Signature, Non Repudiation, Key Encipherment - * X509v3 Subject Key Identifier: - * CD:BB:C8:85:AA:91:BD:FD:1D:BE:CD:67:7C:FF:B3:E9:4C:A8:22:E6 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * - * X509v3 Subject Alternative Name: critical - * IP Address:127.0.0.1 - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD - * VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas - * JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV - * 8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq - * ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw - * CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV - * HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB - * MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx - * HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP - * i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC - * I9aw - * -----END CERTIFICATE----- - * - * - * - * Trusted CA certificate: - * Certificate: - * Data: - * Version: 3 (0x2) - * Serial Number: 0 (0x0) - * Signature Algorithm: md5WithRSAEncryption - * Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Validity - * Not Before: Dec 8 02:43:36 2008 GMT - * Not After : Aug 25 02:43:36 2028 GMT - * Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org - * Subject Public Key Info: - * Public Key Algorithm: rsaEncryption - * RSA Public Key: (1024 bit) - * Modulus (1024 bit): - * 00:cb:c4:38:20:07:be:88:a7:93:b0:a1:43:51:2d: - * d7:8e:85:af:54:dd:ad:a2:7b:23:5b:cf:99:13:53: - * 99:45:7d:ee:6d:ba:2d:bf:e3:ad:6e:3d:9f:1a:f9: - * 03:97:e0:17:55:ae:11:26:57:de:01:29:8e:05:3f: - * 21:f7:e7:36:e8:2e:37:d7:48:ac:53:d6:60:0e:c7: - * 50:6d:f6:c5:85:f7:8b:a6:c5:91:35:72:3c:94:ee: - * f1:17:f0:71:e3:ec:1b:ce:ca:4e:40:42:b0:6d:ee: - * 6a:0e:d6:e5:ad:3c:0f:c9:ba:82:4f:78:f8:89:97: - * 89:2a:95:12:4c:d8:09:2a:e9 - * Exponent: 65537 (0x10001) - * X509v3 extensions: - * X509v3 Subject Key Identifier: - * FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * X509v3 Authority Key Identifier: - * keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14 - * DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org - * serial:00 - * - * X509v3 Basic Constraints: - * CA:TRUE - * Signature Algorithm: md5WithRSAEncryption - * - * -----BEGIN CERTIFICATE----- - * MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET - * MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK - * EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ - * BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp - * dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB - * gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX - * 4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj - * 7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G - * A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ - * hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt - * U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw - * DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA - * ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ - * LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P - * 6Mvf0r1PNTY2hwTJLJmKtg== - * -----END CERTIFICATE--- - */ +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; public class IPIdentities { - static Map cookies; - ServerSocket ss; /* * ============================================================= @@ -421,208 +83,14 @@ public class IPIdentities { */ static boolean separateServerThread = true; - /* - * Where do we find the keystores? - */ - static String trusedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + - "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" + - "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" + - "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" + - "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" + - "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" + - "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" + - "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" + - "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" + - "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" + - "6Mvf0r1PNTY2hwTJLJmKtg==\n" + - "-----END CERTIFICATE-----"; + static X509Certificate trustedCert; - static String serverCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBzANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3NTdaFw0yODA4MjUwMzI3NTdaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtU2VydmVyMRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKWsWxw3\n" + - "ot2ZiS2yebiP1Uil5xyEF41pnMasbfnyHR85GdrTch5u7ETMcKTcugAw9qBPPVR6\n" + - "YWrMV9AKf5UoGD+a2ZTyG8gkiH7+nQ89+1dTCLMgM9Q/F0cU0c3qCNgOdU6vvszS\n" + - "7K+peknfwtmsuCRAkKYDVirQMAVALE+r2XSJAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTtbtv0tVbI+xoGYT8PCLumBNgWVDAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBAFJjItCtCBZcjD69wdqfIbKmRFa6eJAjR6LcoDva\n" + - "cKC/sDOLelpspiZ66Zb0Xdv5qQ7QrfOXt3K8QqJKRMdZLF9WfUfy0gJDM32ub91h\n" + - "pu+TmcGPs+6RdrAQcuvU1ZDV9X8SMj7BtKaim4d5sqFw1npncKiA5xFn8vOYwdun\n" + - "nZif\n" + - "-----END CERTIFICATE-----"; + static X509Certificate serverCert; - static String clientCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICnzCCAgigAwIBAgIBBjANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" + - "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" + - "EwhTb21lLU9yZzAeFw0wODEyMDgwMzI3MzRaFw0yODA4MjUwMzI3MzRaMHIxCzAJ\n" + - "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" + - "dHkxETAPBgNVBAoTCFNvbWUtT3JnMRMwEQYDVQQLEwpTU0wtQ2xpZW50MRIwEAYD\n" + - "VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALvwQDas\n" + - "JlRO9KNaAC9pIW+5ejqT7KL24Y7HY9gvEjCZLrDyj/gnLSR4KIT3Ab+NRHndO9JV\n" + - "8848slshfe/9M0qxo//GyJu5D3xBNZf52zoFYAUVr1kXkqMQrRYc5AdTr6h2olYq\n" + - "ktP5KOB4z14fSKtcGd3hZ0O6dY31gqxDkkQbAgMBAAGjbjBsMAkGA1UdEwQCMAAw\n" + - "CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTNu8iFqpG9/R2+zWd8/7PpTKgi5jAfBgNV\n" + - "HSMEGDAWgBT6uVG/TOfZhpgz+efLHvEzSfeoFDASBgNVHREBAf8ECDAGhwR/AAAB\n" + - "MA0GCSqGSIb3DQEBBAUAA4GBACjj9PS+W6XOF7toFMwMOv/AemZeBOpcEF1Ei1Hx\n" + - "HjvB6EOHkMY8tFm5OPzkiWiK3+s3awpSW0jWdzMYwrQJ3/klMsPDpI7PEuirqwHP\n" + - "i5Wyl/vk7jmfWVcBO9MVhPUo4BYl4vS9aj6JA5QbkbkB95LOgT/BowY0WmHeVsXC\n" + - "I9aw\n" + - "-----END CERTIFICATE-----"; + static X509Certificate clientCert; - - static byte serverPrivateExponent[] = { - (byte)0x6e, (byte)0xa7, (byte)0x1b, (byte)0x83, - (byte)0x51, (byte)0x35, (byte)0x9a, (byte)0x44, - (byte)0x7d, (byte)0xf6, (byte)0xe3, (byte)0x89, - (byte)0xa0, (byte)0xd7, (byte)0x90, (byte)0x60, - (byte)0xa1, (byte)0x4e, (byte)0x27, (byte)0x21, - (byte)0xa2, (byte)0x89, (byte)0x74, (byte)0xcc, - (byte)0x9d, (byte)0x75, (byte)0x75, (byte)0x4e, - (byte)0xc7, (byte)0x82, (byte)0xe3, (byte)0xe3, - (byte)0xc3, (byte)0x7d, (byte)0x00, (byte)0x54, - (byte)0xec, (byte)0x36, (byte)0xb1, (byte)0xdf, - (byte)0x91, (byte)0x9c, (byte)0x7a, (byte)0xc0, - (byte)0x62, (byte)0x0a, (byte)0xd6, (byte)0xa9, - (byte)0x22, (byte)0x91, (byte)0x4a, (byte)0x29, - (byte)0x2e, (byte)0x43, (byte)0xfa, (byte)0x8c, - (byte)0xd8, (byte)0xe9, (byte)0xbe, (byte)0xd9, - (byte)0x4f, (byte)0xca, (byte)0x23, (byte)0xc6, - (byte)0xe4, (byte)0x3f, (byte)0xb8, (byte)0x72, - (byte)0xcf, (byte)0x02, (byte)0xfc, (byte)0xf4, - (byte)0x58, (byte)0x34, (byte)0x77, (byte)0x76, - (byte)0xce, (byte)0x22, (byte)0x44, (byte)0x5f, - (byte)0x2d, (byte)0xca, (byte)0xee, (byte)0xf5, - (byte)0x43, (byte)0x56, (byte)0x47, (byte)0x71, - (byte)0x0b, (byte)0x09, (byte)0x6b, (byte)0x5e, - (byte)0xf2, (byte)0xc8, (byte)0xee, (byte)0xd4, - (byte)0x6e, (byte)0x44, (byte)0x92, (byte)0x2a, - (byte)0x7f, (byte)0xcc, (byte)0xa7, (byte)0xd4, - (byte)0x5b, (byte)0xfb, (byte)0xf7, (byte)0x4a, - (byte)0xa9, (byte)0xfb, (byte)0x54, (byte)0x18, - (byte)0xd5, (byte)0xd5, (byte)0x14, (byte)0xba, - (byte)0xa0, (byte)0x1c, (byte)0x13, (byte)0xb3, - (byte)0x37, (byte)0x6b, (byte)0x37, (byte)0x59, - (byte)0xed, (byte)0xdb, (byte)0x6d, (byte)0xb1 - }; - - static byte serverModulus[] = { - (byte)0x00, - (byte)0xa5, (byte)0xac, (byte)0x5b, (byte)0x1c, - (byte)0x37, (byte)0xa2, (byte)0xdd, (byte)0x99, - (byte)0x89, (byte)0x2d, (byte)0xb2, (byte)0x79, - (byte)0xb8, (byte)0x8f, (byte)0xd5, (byte)0x48, - (byte)0xa5, (byte)0xe7, (byte)0x1c, (byte)0x84, - (byte)0x17, (byte)0x8d, (byte)0x69, (byte)0x9c, - (byte)0xc6, (byte)0xac, (byte)0x6d, (byte)0xf9, - (byte)0xf2, (byte)0x1d, (byte)0x1f, (byte)0x39, - (byte)0x19, (byte)0xda, (byte)0xd3, (byte)0x72, - (byte)0x1e, (byte)0x6e, (byte)0xec, (byte)0x44, - (byte)0xcc, (byte)0x70, (byte)0xa4, (byte)0xdc, - (byte)0xba, (byte)0x00, (byte)0x30, (byte)0xf6, - (byte)0xa0, (byte)0x4f, (byte)0x3d, (byte)0x54, - (byte)0x7a, (byte)0x61, (byte)0x6a, (byte)0xcc, - (byte)0x57, (byte)0xd0, (byte)0x0a, (byte)0x7f, - (byte)0x95, (byte)0x28, (byte)0x18, (byte)0x3f, - (byte)0x9a, (byte)0xd9, (byte)0x94, (byte)0xf2, - (byte)0x1b, (byte)0xc8, (byte)0x24, (byte)0x88, - (byte)0x7e, (byte)0xfe, (byte)0x9d, (byte)0x0f, - (byte)0x3d, (byte)0xfb, (byte)0x57, (byte)0x53, - (byte)0x08, (byte)0xb3, (byte)0x20, (byte)0x33, - (byte)0xd4, (byte)0x3f, (byte)0x17, (byte)0x47, - (byte)0x14, (byte)0xd1, (byte)0xcd, (byte)0xea, - (byte)0x08, (byte)0xd8, (byte)0x0e, (byte)0x75, - (byte)0x4e, (byte)0xaf, (byte)0xbe, (byte)0xcc, - (byte)0xd2, (byte)0xec, (byte)0xaf, (byte)0xa9, - (byte)0x7a, (byte)0x49, (byte)0xdf, (byte)0xc2, - (byte)0xd9, (byte)0xac, (byte)0xb8, (byte)0x24, - (byte)0x40, (byte)0x90, (byte)0xa6, (byte)0x03, - (byte)0x56, (byte)0x2a, (byte)0xd0, (byte)0x30, - (byte)0x05, (byte)0x40, (byte)0x2c, (byte)0x4f, - (byte)0xab, (byte)0xd9, (byte)0x74, (byte)0x89 - }; - - static byte clientPrivateExponent[] = { - (byte)0x11, (byte)0xb7, (byte)0x6a, (byte)0x36, - (byte)0x3d, (byte)0x30, (byte)0x37, (byte)0xce, - (byte)0x61, (byte)0x9d, (byte)0x6c, (byte)0x84, - (byte)0x8b, (byte)0xf3, (byte)0x9b, (byte)0x25, - (byte)0x4f, (byte)0x14, (byte)0xc8, (byte)0xa4, - (byte)0xdd, (byte)0x2f, (byte)0xd7, (byte)0x9a, - (byte)0x17, (byte)0xbd, (byte)0x90, (byte)0x19, - (byte)0xf7, (byte)0x05, (byte)0xfd, (byte)0xf2, - (byte)0xd2, (byte)0xc5, (byte)0xf7, (byte)0x77, - (byte)0xbe, (byte)0xea, (byte)0xe2, (byte)0x84, - (byte)0x87, (byte)0x97, (byte)0x3a, (byte)0x41, - (byte)0x96, (byte)0xb6, (byte)0x99, (byte)0xf8, - (byte)0x94, (byte)0x8c, (byte)0x58, (byte)0x71, - (byte)0x51, (byte)0x8c, (byte)0xf4, (byte)0x2a, - (byte)0x20, (byte)0x9e, (byte)0x1a, (byte)0xa0, - (byte)0x26, (byte)0x99, (byte)0x75, (byte)0xd6, - (byte)0x31, (byte)0x53, (byte)0x43, (byte)0x39, - (byte)0xf5, (byte)0x2a, (byte)0xa6, (byte)0x7e, - (byte)0x34, (byte)0x42, (byte)0x51, (byte)0x2a, - (byte)0x40, (byte)0x87, (byte)0x03, (byte)0x88, - (byte)0x43, (byte)0x69, (byte)0xb2, (byte)0x89, - (byte)0x6d, (byte)0x20, (byte)0xbd, (byte)0x7d, - (byte)0x71, (byte)0xef, (byte)0x47, (byte)0x0a, - (byte)0xdf, (byte)0x06, (byte)0xc1, (byte)0x69, - (byte)0x66, (byte)0xa8, (byte)0x22, (byte)0x37, - (byte)0x1a, (byte)0x77, (byte)0x1e, (byte)0xc7, - (byte)0x94, (byte)0x4e, (byte)0x2c, (byte)0x27, - (byte)0x69, (byte)0x45, (byte)0x5e, (byte)0xc8, - (byte)0xf8, (byte)0x0c, (byte)0xb7, (byte)0xf8, - (byte)0xc0, (byte)0x8f, (byte)0x99, (byte)0xc1, - (byte)0xe5, (byte)0x28, (byte)0x9b, (byte)0xf9, - (byte)0x4c, (byte)0x94, (byte)0xc6, (byte)0xb1 - }; - - static byte clientModulus[] = { - (byte)0x00, - (byte)0xbb, (byte)0xf0, (byte)0x40, (byte)0x36, - (byte)0xac, (byte)0x26, (byte)0x54, (byte)0x4e, - (byte)0xf4, (byte)0xa3, (byte)0x5a, (byte)0x00, - (byte)0x2f, (byte)0x69, (byte)0x21, (byte)0x6f, - (byte)0xb9, (byte)0x7a, (byte)0x3a, (byte)0x93, - (byte)0xec, (byte)0xa2, (byte)0xf6, (byte)0xe1, - (byte)0x8e, (byte)0xc7, (byte)0x63, (byte)0xd8, - (byte)0x2f, (byte)0x12, (byte)0x30, (byte)0x99, - (byte)0x2e, (byte)0xb0, (byte)0xf2, (byte)0x8f, - (byte)0xf8, (byte)0x27, (byte)0x2d, (byte)0x24, - (byte)0x78, (byte)0x28, (byte)0x84, (byte)0xf7, - (byte)0x01, (byte)0xbf, (byte)0x8d, (byte)0x44, - (byte)0x79, (byte)0xdd, (byte)0x3b, (byte)0xd2, - (byte)0x55, (byte)0xf3, (byte)0xce, (byte)0x3c, - (byte)0xb2, (byte)0x5b, (byte)0x21, (byte)0x7d, - (byte)0xef, (byte)0xfd, (byte)0x33, (byte)0x4a, - (byte)0xb1, (byte)0xa3, (byte)0xff, (byte)0xc6, - (byte)0xc8, (byte)0x9b, (byte)0xb9, (byte)0x0f, - (byte)0x7c, (byte)0x41, (byte)0x35, (byte)0x97, - (byte)0xf9, (byte)0xdb, (byte)0x3a, (byte)0x05, - (byte)0x60, (byte)0x05, (byte)0x15, (byte)0xaf, - (byte)0x59, (byte)0x17, (byte)0x92, (byte)0xa3, - (byte)0x10, (byte)0xad, (byte)0x16, (byte)0x1c, - (byte)0xe4, (byte)0x07, (byte)0x53, (byte)0xaf, - (byte)0xa8, (byte)0x76, (byte)0xa2, (byte)0x56, - (byte)0x2a, (byte)0x92, (byte)0xd3, (byte)0xf9, - (byte)0x28, (byte)0xe0, (byte)0x78, (byte)0xcf, - (byte)0x5e, (byte)0x1f, (byte)0x48, (byte)0xab, - (byte)0x5c, (byte)0x19, (byte)0xdd, (byte)0xe1, - (byte)0x67, (byte)0x43, (byte)0xba, (byte)0x75, - (byte)0x8d, (byte)0xf5, (byte)0x82, (byte)0xac, - (byte)0x43, (byte)0x92, (byte)0x44, (byte)0x1b - }; + static KeyPair serverKeys; + static KeyPair clientKeys; static char passphrase[] = "passphrase".toCharArray(); @@ -639,7 +107,7 @@ public class IPIdentities { /* * Turn on SSL debugging? */ - static boolean debug = false; + static boolean debug = Boolean.getBoolean("test.debug"); private SSLServerSocket sslServerSocket = null; @@ -650,8 +118,8 @@ public class IPIdentities { * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLContext context = getSSLContext(trusedCertStr, serverCertStr, - serverModulus, serverPrivateExponent, passphrase); + SSLContext context = getSSLContext(trustedCert, serverCert, + serverKeys, passphrase); SSLServerSocketFactory sslssf = context.getServerSocketFactory(); // doClientSide() connects to the loopback address @@ -706,8 +174,8 @@ public class IPIdentities { void doClientSide() throws Exception { SSLContext reservedSSLContext = SSLContext.getDefault(); try { - SSLContext context = getSSLContext(trusedCertStr, clientCertStr, - clientModulus, clientPrivateExponent, passphrase); + SSLContext context = getSSLContext(trustedCert, clientCert, + clientKeys, passphrase); SSLContext.setDefault(context); /* @@ -755,6 +223,65 @@ public class IPIdentities { volatile Exception serverException = null; volatile Exception clientException = null; + private static X509Certificate createTrustedCert(KeyPair caKeys) throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name( + "O=Some-Org, L=Some-City, ST=Some-State, C=US")); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf(random.nextLong(1000000)+1); + return CertificateBuilder.newCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .setOneHourValidity() + .build(null, caKeys.getPrivate(), "MD5WithRSA"); + } + + private static void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + clientKeys = kpg.generateKeyPair(); + + trustedCert = createTrustedCert(caKeys); + if (debug) { + System.out.println("----------- Trusted Cert -----------"); + CertificateBuilder.printCertificate(trustedCert, System.out); + } + + serverCert = CertificateBuilder.newCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + serverKeys.getPublic(), caKeys.getPublic(), + KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) + .addBasicConstraintsExt(false, false, -1) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) + .setOneHourValidity() + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + if (debug) { + System.out.println("----------- Server Cert -----------"); + CertificateBuilder.printCertificate(serverCert, System.out); + } + + clientCert = CertificateBuilder.newCertificateBuilder( + "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", + clientKeys.getPublic(), caKeys.getPublic(), + KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NONREPUDIATION, KeyUsage.KEY_ENCIPHERMENT) + .addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1")) + .addBasicConstraintsExt(false, false, -1) + .setOneHourValidity() + .build(trustedCert, caKeys.getPrivate(), "MD5WithRSA"); + if (debug) { + System.out.println("----------- Client Cert -----------"); + CertificateBuilder.printCertificate(clientCert, System.out); + } + } + public static void main(String args[]) throws Exception { // MD5 is used in this test case, don't disable MD5 algorithm. Security.setProperty("jdk.certpath.disabledAlgorithms", @@ -762,8 +289,11 @@ public class IPIdentities { Security.setProperty("jdk.tls.disabledAlgorithms", "SSLv3, RC4, DH keySize < 768"); - if (debug) + if (debug) { System.setProperty("javax.net.debug", "all"); + } + + setupCertificates(); /* * Start the tests. @@ -855,45 +385,23 @@ public class IPIdentities { } // get the ssl context - private static SSLContext getSSLContext(String trusedCertStr, - String keyCertStr, byte[] modulus, - byte[] privateExponent, char[] passphrase) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - ByteArrayInputStream is = - new ByteArrayInputStream(trusedCertStr.getBytes()); - Certificate trusedCert = cf.generateCertificate(is); - is.close(); + private static SSLContext getSSLContext(X509Certificate trustedCert, + X509Certificate keyCert, KeyPair key, char[] passphrase) throws Exception { // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(null, null); // import the trused cert - ks.setCertificateEntry("RSA Export Signer", trusedCert); - - if (keyCertStr != null) { - // generate the private key. - RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec( - new BigInteger(modulus), - new BigInteger(privateExponent)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); + ks.setCertificateEntry("RSA Export Signer", trustedCert); + if (keyCert != null) { Certificate[] chain = new Certificate[2]; chain[0] = keyCert; - chain[1] = trusedCert; + chain[1] = trustedCert; // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); + ks.setKeyEntry("Whatever", key.getPrivate(), passphrase, chain); } // create SSL context @@ -902,7 +410,7 @@ public class IPIdentities { SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - if (keyCertStr != null) { + if (keyCert != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties new file mode 100644 index 00000000000..e1ed216f21d --- /dev/null +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TEST.properties @@ -0,0 +1,3 @@ +modules = \ + java.base/sun.security.util \ + java.base/sun.security.x509 diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index 857d585f029..e5044d46b0f 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -24,12 +24,10 @@ package jdk.test.lib.security; import java.io.*; +import java.security.cert.*; +import java.security.cert.Extension; import java.util.*; import java.security.*; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.Extension; import java.time.temporal.ChronoUnit; import java.time.Instant; import javax.security.auth.x500.X500Principal; @@ -56,6 +54,7 @@ import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; + /** * Helper class that builds and signs X.509 certificates. * @@ -100,6 +99,89 @@ public class CertificateBuilder { private byte[] tbsCertBytes; private byte[] signatureBytes; + public enum KeyUsage { + DIGITAL_SIGNATURE, + NONREPUDIATION, + KEY_ENCIPHERMENT, + DATA_ENCIPHERMENT, + KEY_AGREEMENT, + KEY_CERT_SIGN, + CRL_SIGN, + ENCIPHER_ONLY, + DECIPHER_ONLY; + } + + /** + * Create a new CertificateBuilder instance. This method sets the subject name, + * public key, authority key id, and serial number. + * + * @param subjectName entity associated with the public key + * @param publicKey the entity's public key + * @param caKey public key of certificate signer + * @param keyUsages list of key uses + * @return + * @throws CertificateException + * @throws IOException + */ + public static CertificateBuilder newCertificateBuilder(String subjectName, + PublicKey publicKey, PublicKey caKey, KeyUsage... keyUsages) + throws CertificateException, IOException { + SecureRandom random = new SecureRandom(); + + boolean [] keyUsage = new boolean[KeyUsage.values().length]; + for (KeyUsage ku : keyUsages) { + keyUsage[ku.ordinal()] = true; + } + + CertificateBuilder builder = new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setSerialNumber(BigInteger.valueOf(random.nextLong(1000000)+1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey); + if (keyUsages.length != 0) { + builder.addKeyUsageExt(keyUsage); + } + return builder; + } + + /** + * Create a Subject Alternative Name extension for the given DNS name + * @param critical Sets the extension to critical or non-critical + * @param dnsName DNS name to use in the extension + * @throws IOException + */ + public static SubjectAlternativeNameExtension createDNSSubjectAltNameExt( + boolean critical, String dnsName) throws IOException { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new DNSName(dnsName))); + return new SubjectAlternativeNameExtension(critical, gns); + } + + /** + * Create a Subject Alternative Name extension for the given IP address + * @param critical Sets the extension to critical or non-critical + * @param ipAddress IP address to use in the extension + * @throws IOException + */ + public static SubjectAlternativeNameExtension createIPSubjectAltNameExt( + boolean critical, String ipAddress) throws IOException { + GeneralNames gns = new GeneralNames(); + gns.add(new GeneralName(new IPAddressName(ipAddress))); + return new SubjectAlternativeNameExtension(critical, gns); + } + + public static void printCertificate(X509Certificate certificate, PrintStream ps) { + try { + Base64.Encoder encoder = Base64.getEncoder(); + ps.println("-----BEGIN CERTIFICATE-----"); + ps.println(encoder.encodeToString(certificate.getEncoded())); + ps.println("-----END CERTIFICATE-----"); + } catch (CertificateEncodingException exc) { + exc.printStackTrace(ps); + } + } + /** * Default constructor for a {@code CertificateBuilder} object. * @@ -177,6 +259,11 @@ public class CertificateBuilder { return setNotBefore(nbDate).setNotAfter(naDate); } + public CertificateBuilder setOneHourValidity() { + return setNotBefore(Date.from(Instant.now().minus(5, ChronoUnit.MINUTES))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))); + } + /** * Set the serial number on the certificate. * From eea50fbc1b24710b18eff4b59dc90dee3736cd95 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 2 Sep 2025 12:42:46 +0000 Subject: [PATCH 322/471] 8356439: Rename JavaLangAccess::*NoRepl methods Reviewed-by: alanb, liach, rriggs --- .../share/classes/java/lang/String.java | 332 ++++++++++++------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 24 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{NoReplTest.java => OrThrowTest.java} | 20 +- 7 files changed, 265 insertions(+), 145 deletions(-) rename test/jdk/java/lang/String/{NoReplTest.java => OrThrowTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 15b8e98369e..8acb8d8514b 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -689,12 +689,24 @@ public final class String } /* - * Throws iae, instead of replacing, if malformed or unmappable. - * The byte array can be exclusively used to construct - * the string and is not modified or used for any other purpose. + * {@return a new string by decoding from the given UTF-8 bytes array} + *

          + * WARNING: The caller of this method is assumed to have relinquished + * and transferred the ownership of the byte array. It can thus be + * exclusively used to construct the {@code String}. + * + * @param bytes byte array containing UTF-8 encoded characters + * @param offset the index of the first byte to decode + * @param length the number of bytes to decode + * @throws NullPointerException If {@code bytes} is null + * @throws StringIndexOutOfBoundsException If {@code offset} is negative, + * {@code length} is negative, or {@code offset} is greater than + * {@code bytes.length - length} + * @throws CharacterCodingException for malformed input or unmappable characters */ - private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { - checkBoundsOffCount(offset, length, bytes.length); + private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) + throws CharacterCodingException { + checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` if (length == 0) { return ""; } @@ -745,10 +757,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -784,26 +796,13 @@ public final class String * * @throws CharacterCodingException for malformed input or unmappable characters */ - static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { - try { - return newStringNoRepl1(src, cs); - } catch (IllegalArgumentException e) { - //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof MalformedInputException mie) { - throw mie; - } - throw (CharacterCodingException)cause; - } - } - - private static String newStringNoRepl1(byte[] src, Charset cs) { + static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { int len = src.length; if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8NoRepl(src, 0, src.length); + return newStringUTF8OrThrow(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -816,7 +815,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throwMalformed(src); + throw malformedASCII(src); } } @@ -831,13 +830,7 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen; - try { - caLen = decodeWithDecoder(cd, ca, src, 0, src.length); - } catch (CharacterCodingException x) { - // throw via IAE - throw new IllegalArgumentException(x); - } + int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -874,7 +867,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val, true); + return encodeUTF8(coder, val); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -882,13 +875,30 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, true); + return encodeWithEncoder(cs, coder, val, null); } - private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with the encoder of {@code + * cs}} + * + * @param cs a charset to obtain the encoder from + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeWithEncoder( + Charset cs, byte coder, byte[] val, Class exClass) + throws E { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); + boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -930,7 +940,9 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - throw new IllegalArgumentException(x); + @SuppressWarnings("unchecked") + E cce = (E) x; + throw cce; } else { throw new Error(x); } @@ -938,60 +950,69 @@ public final class String return trimArray(ba, bb.position()); } - /* - * Throws iae, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * + * @param s the string to encode + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesUTF8NoRepl(String s) { - return encodeUTF8(s.coder(), s.value(), false); + static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /* - * Throws CCE, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} + *

          + * WARNING: This method returns the {@code byte[]} backing the provided + * {@code String}, if the input is ASCII. Hence, the returned byte array + * must not be modified. + * + * @param s the string to encode + * @param cs the charset + * @throws NullPointerException If {@code s} or {@code cs} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - try { - return getBytesNoRepl1(s, cs); - } catch (IllegalArgumentException e) { - //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof UnmappableCharacterException) { - throw (UnmappableCharacterException)cause; - } - throw (CharacterCodingException)cause; - } - } - - private static byte[] getBytesNoRepl1(String s, Charset cs) { - byte[] val = s.value(); + static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + byte[] val = s.value(); // Implicit null check on `s` byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8(coder, val, false); + return encodeUTF8OrThrow(coder, val); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1(coder, val, false); + return encode8859_1OrThrow(coder, val); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throwUnmappable(val); + throw unmappableASCII(val); } } } - return encodeWithEncoder(cs, coder, val, false); + return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); } + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with US-ASCII} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1031,10 +1052,26 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, true); + return encode8859_1(coder, val, null); } - private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { + private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encode8859_1(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with ISO-8859-1} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { if (coder == LATIN1) { return val.clone(); } @@ -1048,8 +1085,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (!doReplace) { - throwUnmappable(sp); + if (exClass != null) { + throw String.unmappableCharacterException(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1143,7 +1180,26 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); + } + + private static int decodeUTF8_UTF16OrThrow( + byte[] src, int sp, int sl, byte[] dst, int dp) + throws MalformedInputException { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); + } + + /** + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static int decodeUTF8_UTF16( + byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) + throws E { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1152,8 +1208,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1162,8 +1218,8 @@ public final class String } continue; } - if (!doReplace) { - throwMalformed(sp, 1); // underflow() + if (exClass != null) { + throw String.malformedInputException(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1172,8 +1228,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1181,8 +1237,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1192,14 +1248,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (!doReplace) { - throwMalformed(sp - 1, 2); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp, 1); + if (exClass != null) { + throw String.malformedInputException(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1211,8 +1267,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (!doReplace) { - throwMalformed(sp - 4, 4); + if (exClass != null) { + throw String.malformedInputException(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1225,14 +1281,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); // or 2 + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1241,8 +1297,8 @@ public final class String } break; } else { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1284,29 +1340,76 @@ public final class String return 3; } - private static void throwMalformed(int off, int nb) { - String msg = "malformed input off : " + off + ", length : " + nb; - throw new IllegalArgumentException(msg, new MalformedInputException(nb)); + /** + * {@return a new {@link MalformedInputException} for the sub-range denoted + * by specified {@code offset} and {@code length}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E malformedInputException(int offset, int length) throws E { + MalformedInputException mie = new MalformedInputException(length); + String msg = "malformed input offset : " + offset + ", length : " + length; + mie.initCause(new IllegalArgumentException(msg)); + return (E) mie; } - private static void throwMalformed(byte[] val) { + /** + * {@return a new {@link MalformedInputException} for the given malformed + * ASCII string} + */ + private static MalformedInputException malformedASCII(byte[] val) throws MalformedInputException { int dp = StringCoding.countPositives(val, 0, val.length); - throwMalformed(dp, 1); + return malformedInputException(dp, 1); } - private static void throwUnmappable(int off) { - String msg = "malformed input off : " + off + ", length : 1"; - throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); + /** + * {@return a new {@link UnmappableCharacterException} at given {@code offset}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E unmappableCharacterException(int offset) throws E { + UnmappableCharacterException uce = new UnmappableCharacterException(1); + String msg = "malformed input offset : " + offset + ", length : 1"; + uce.initCause(new IllegalArgumentException(msg, uce)); + return (E) uce; } - private static void throwUnmappable(byte[] val) { + /** + * {@return a new {@link UnmappableCharacterException} for the given + * malformed ASCII string} + */ + private static UnmappableCharacterException unmappableASCII(byte[] val) throws UnmappableCharacterException { int dp = StringCoding.countPositives(val, 0, val.length); - throwUnmappable(dp); + return unmappableCharacterException(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { + private static byte[] encodeUTF8(byte coder, byte[] val) { + return encodeUTF8(coder, val, null); + } + + private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encodeUTF8(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with UTF-8} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { if (coder == UTF16) { - return encodeUTF8_UTF16(val, doReplace); + return encodeUTF8_UTF16(val, exClass); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1334,13 +1437,24 @@ public final class String return Arrays.copyOf(dst, dp); } - private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * UTF-16, and then encoding the result with UTF-8} + * + * @param val a string byte array encoded with UTF-16 + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1369,10 +1483,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dst[dp++] = '?'; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1396,10 +1510,14 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * @param val UTF16 encoded byte array - * @param doReplace true to replace unmappable characters + * + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting discarded. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception */ - private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { + private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1418,10 +1536,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dp++; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index a40c27bbf47..bb1775fbc6b 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,6 +2124,7 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2132,21 +2133,24 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringNoRepl(bytes, cs); + public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringOrThrow(bytes, cs); } + public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } + public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - return String.getBytesNoRepl(s, cs); + + public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + return String.getBytesOrThrow(s, cs); } - public byte[] getBytesUTF8NoRepl(String s) { - return String.getBytesUTF8NoRepl(s); + public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return String.getBytesUTF8OrThrow(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index f8278fa2642..80c771f5306 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringNoRepl(ba, cs); + return JLA.uncheckedNewStringOrThrow(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 8b812eba202..b9906d348e3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,7 +264,11 @@ class ZipCoder { @Override byte[] getBytes(String s) { - return JLA.getBytesUTF8NoRepl(s); + try { + return JLA.getBytesUTF8OrThrow(s); + } catch (CharacterCodingException cce) { + throw new IllegalArgumentException(cce); + } } @Override @@ -278,8 +282,6 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. - // We use the JLA.newStringUTF8NoRepl variant to throw - // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -296,7 +298,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index aa5b6e438f5..c7d7c86b932 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,7 +45,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; -import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -332,7 +331,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@linkplain java.nio.charset.Charset charset}. + * using the specified {@code Charset}. *

          * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -343,25 +342,22 @@ public interface JavaLangAccess { * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes */ - String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * Encode the given string into a sequence of bytes using the specified - * {@linkplain java.nio.charset.Charset charset}. + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} *

          * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. - *

          - * This method throws {@code CharacterCodingException} instead of replacing - * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @return the encoded bytes + * @throws NullPointerException If {@code s} or {@code cs} is null * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -387,13 +383,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * Encode the given string into a sequence of bytes using utf8. + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} * * @param s the string to encode - * @return the encoded bytes in utf8 - * @throws IllegalArgumentException for malformed surrogates + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - byte[] getBytesUTF8NoRepl(String s); + byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5dfc73f57aa..5a77bb0b935 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/NoReplTest.java b/test/jdk/java/lang/String/OrThrowTest.java similarity index 79% rename from test/jdk/java/lang/String/NoReplTest.java rename to test/jdk/java/lang/String/OrThrowTest.java index 1817a1ffe73..340a190b4eb 100644 --- a/test/jdk/java/lang/String/NoReplTest.java +++ b/test/jdk/java/lang/String/OrThrowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -24,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *NoRepl() shared secret methods. - * @run testng NoReplTest + * @summary Tests for *OrThrow() shared secret methods. + * @run testng OrThrowTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class NoReplTest { +public class OrThrowTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies newStringNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.readString()` method. + * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.readString()} method. */ @Test - public void newStringNoReplTest() throws IOException { + public void uncheckedNewStringOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class NoReplTest { } /** - * Verifies getBytesNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.writeString()` method. + * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.writeString()} method. */ @Test - public void getBytesNoReplTest() throws IOException { + public void uncheckedGetBytesOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From 1feb9bd55946cad8a37745b0c9ceef16f408afd8 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 12:46:59 +0000 Subject: [PATCH 323/471] 8365557: Parallel: Refactor ParallelScavengeHeap::mem_allocate_work Reviewed-by: tschatzl, iwalulya --- .../gc/parallel/parallelScavengeHeap.cpp | 50 +++++++------------ src/hotspot/share/gc/parallel/psOldGen.hpp | 3 +- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 45c364ab35a..3b530895eb1 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -279,17 +279,23 @@ HeapWord* ParallelScavengeHeap::mem_allocate(size_t size, HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded) { - { + for (uint loop_count = 0; /* empty */; ++loop_count) { + // Try young-gen first. HeapWord* result = young_gen()->allocate(size); if (result != nullptr) { return result; } - } - uint loop_count = 0; - uint gc_count = 0; + // Try allocating from the old gen for non-TLAB in certain scenarios. + if (!is_tlab) { + if (!should_alloc_in_eden(size) || _is_heap_almost_full) { + result = old_gen()->cas_allocate_noexpand(size); + if (result != nullptr) { + return result; + } + } + } - while (true) { // We don't want to have multiple collections for a single filled generation. // To prevent this, each thread tracks the total_collections() value, and if // the count has changed, does not do a new collection. @@ -301,49 +307,31 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, // the collection count has already changed. To prevent duplicate collections, // The policy MUST attempt allocations during the same period it reads the // total_collections() value! + uint gc_count; { MutexLocker ml(Heap_lock); gc_count = total_collections(); - - HeapWord* result = young_gen()->allocate(size); - if (result != nullptr) { - return result; - } - - // Try allocating from the old gen for non-TLAB in certain scenarios. - if (!is_tlab) { - if (!should_alloc_in_eden(size) || _is_heap_almost_full) { - result = old_gen()->cas_allocate_noexpand(size); - if (result != nullptr) { - return result; - } - } - } } { VM_ParallelCollectForAllocation op(size, is_tlab, gc_count); VMThread::execute(&op); - // Did the VM operation execute? If so, return the result directly. - // This prevents us from looping until time out on requests that can - // not be satisfied. if (op.gc_succeeded()) { assert(is_in_or_null(op.result()), "result not in heap"); - return op.result(); } - // Was the gc-overhead reached inside the safepoint? If so, this mutator should return null as well for global consistency. - if (_gc_overhead_counter >= GCOverheadLimitThreshold) { - return nullptr; - } } - loop_count++; + // Was the gc-overhead reached inside the safepoint? If so, this mutator + // should return null as well for global consistency. + if (_gc_overhead_counter >= GCOverheadLimitThreshold) { + return nullptr; + } + if ((QueuedAllocationWarningCount > 0) && (loop_count % QueuedAllocationWarningCount == 0)) { - log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count); - log_warning(gc)("\tsize=%zu", size); + log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times, size=%zu", loop_count, size); } } } diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index 23fde1f2fe0..77ae5510b31 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -108,7 +108,7 @@ class PSOldGen : public CHeapObj { void shrink(size_t bytes); - // Invoked by mutators and GC-workers. + // Used by GC-workers during GC or for CDS at startup. HeapWord* allocate(size_t word_size) { HeapWord* res; do { @@ -120,7 +120,6 @@ class PSOldGen : public CHeapObj { // Invoked by mutators before attempting GC. HeapWord* cas_allocate_noexpand(size_t word_size) { - assert_locked_or_safepoint(Heap_lock); HeapWord* res = object_space()->cas_allocate(word_size); if (res != nullptr) { _start_array->update_for_block(res, res + word_size); From 710354369e0131e900afc4ced706a9ed0e23ab9c Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 2 Sep 2025 13:09:33 +0000 Subject: [PATCH 324/471] 8366063: Parallel: Refactor copy_unmarked_to_survivor_space Reviewed-by: tschatzl, iwalulya --- .../share/gc/parallel/psPromotionManager.hpp | 7 + .../gc/parallel/psPromotionManager.inline.hpp | 148 ++++++++++-------- 2 files changed, 87 insertions(+), 68 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 78bb7dde66a..f1169c8ad63 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -113,6 +113,13 @@ class PSPromotionManager { template oop copy_unmarked_to_survivor_space(oop o, markWord m); + inline HeapWord* allocate_in_young_gen(Klass* klass, + size_t obj_size, + uint age); + inline HeapWord* allocate_in_old_gen(Klass* klass, + size_t obj_size, + uint age); + public: // Static static void initialize(); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 451a7dae189..6154abf1b1c 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -153,6 +153,80 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { } } +inline HeapWord* PSPromotionManager::allocate_in_young_gen(Klass* klass, + size_t obj_size, + uint age) { + HeapWord* result = _young_lab.allocate(obj_size); + if (result != nullptr) { + return result; + } + if (_young_gen_is_full) { + return nullptr; + } + // Do we allocate directly, or flush and refill? + if (obj_size > (YoungPLABSize / 2)) { + // Allocate this object directly + result = young_space()->cas_allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, false, nullptr); + } else { + // Flush and fill + _young_lab.flush(); + + HeapWord* lab_base = young_space()->cas_allocate(YoungPLABSize); + if (lab_base != nullptr) { + _young_lab.initialize(MemRegion(lab_base, YoungPLABSize)); + // Try the young lab allocation again. + result = _young_lab.allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, false, &_young_lab); + } else { + _young_gen_is_full = true; + } + } + if (result == nullptr && !_young_gen_is_full && !_young_gen_has_alloc_failure) { + _young_gen_has_alloc_failure = true; + } + return result; +} + +inline HeapWord* PSPromotionManager::allocate_in_old_gen(Klass* klass, + size_t obj_size, + uint age) { +#ifndef PRODUCT + if (ParallelScavengeHeap::heap()->promotion_should_fail()) { + return nullptr; + } +#endif // #ifndef PRODUCT + + HeapWord* result = _old_lab.allocate(obj_size); + if (result != nullptr) { + return result; + } + if (_old_gen_is_full) { + return nullptr; + } + // Do we allocate directly, or flush and refill? + if (obj_size > (OldPLABSize / 2)) { + // Allocate this object directly + result = old_gen()->allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, true, nullptr); + } else { + // Flush and fill + _old_lab.flush(); + + HeapWord* lab_base = old_gen()->allocate(OldPLABSize); + if (lab_base != nullptr) { + _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); + // Try the old lab allocation again. + result = _old_lab.allocate(obj_size); + promotion_trace_event(cast_to_oop(result), klass, obj_size, age, true, &_old_lab); + } + } + if (result == nullptr) { + _old_gen_is_full = true; + } + return result; +} + // // This method is pretty bulky. It would be nice to split it up // into smaller submethods, but we need to be careful not to hurt @@ -186,77 +260,17 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, if (!promote_immediately) { // Try allocating obj in to-space (unless too old) if (age < PSScavenge::tenuring_threshold()) { - new_obj = cast_to_oop(_young_lab.allocate(new_obj_size)); - if (new_obj == nullptr && !_young_gen_is_full) { - // Do we allocate directly, or flush and refill? - if (new_obj_size > (YoungPLABSize / 2)) { - // Allocate this object directly - new_obj = cast_to_oop(young_space()->cas_allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, false, nullptr); - } else { - // Flush and fill - _young_lab.flush(); - - HeapWord* lab_base = young_space()->cas_allocate(YoungPLABSize); - if (lab_base != nullptr) { - _young_lab.initialize(MemRegion(lab_base, YoungPLABSize)); - // Try the young lab allocation again. - new_obj = cast_to_oop(_young_lab.allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, false, &_young_lab); - } else { - _young_gen_is_full = true; - } - } - if (new_obj == nullptr && !_young_gen_is_full && !_young_gen_has_alloc_failure) { - _young_gen_has_alloc_failure = true; - } - } + new_obj = cast_to_oop(allocate_in_young_gen(klass, new_obj_size, age)); } } // Otherwise try allocating obj tenured if (new_obj == nullptr) { -#ifndef PRODUCT - if (ParallelScavengeHeap::heap()->promotion_should_fail()) { + new_obj = cast_to_oop(allocate_in_old_gen(klass, new_obj_size, age)); + if (new_obj == nullptr) { return oop_promotion_failed(o, test_mark); } -#endif // #ifndef PRODUCT - - new_obj = cast_to_oop(_old_lab.allocate(new_obj_size)); new_obj_is_tenured = true; - - if (new_obj == nullptr) { - if (!_old_gen_is_full) { - // Do we allocate directly, or flush and refill? - if (new_obj_size > (OldPLABSize / 2)) { - // Allocate this object directly - new_obj = cast_to_oop(old_gen()->allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, true, nullptr); - } else { - // Flush and fill - _old_lab.flush(); - - HeapWord* lab_base = old_gen()->allocate(OldPLABSize); - if(lab_base != nullptr) { - _old_lab.initialize(MemRegion(lab_base, OldPLABSize)); - // Try the old lab allocation again. - new_obj = cast_to_oop(_old_lab.allocate(new_obj_size)); - promotion_trace_event(new_obj, klass, new_obj_size, age, true, &_old_lab); - } - } - } - - // This is the promotion failed test, and code handling. - // The code belongs here for two reasons. It is slightly - // different than the code below, and cannot share the - // CAS testing code. Keeping the code here also minimizes - // the impact on the common case fast path code. - - if (new_obj == nullptr) { - _old_gen_is_full = true; - return oop_promotion_failed(o, test_mark); - } - } } assert(new_obj != nullptr, "allocation should have succeeded"); @@ -287,17 +301,16 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, // Do the size comparison first with new_obj_size, which we // already have. Hopefully, only a few objects are larger than // _min_array_size_for_chunking, and most of them will be arrays. - // So, the is->objArray() test would be very infrequent. + // So, the objArray test would be very infrequent. if (new_obj_size > _min_array_size_for_chunking && - new_obj->is_objArray() && + klass->is_objArray_klass() && PSChunkLargeArrays) { push_objArray(o, new_obj); } else { // we'll just push its contents push_contents(new_obj); - if (StringDedup::is_enabled() && - java_lang_String::is_instance(new_obj) && + if (StringDedup::is_enabled_string(klass) && psStringDedup::is_candidate_from_evacuation(new_obj, new_obj_is_tenured)) { _string_dedup_requests.add(o); } @@ -305,7 +318,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, return new_obj; } else { // We lost, someone else "owns" this object. - assert(o->is_forwarded(), "Object must be forwarded if the cas failed."); assert(o->forwardee() == forwardee, "invariant"); From a029245a4e1f04052fa0f0a5af16ae0e770bd822 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 2 Sep 2025 13:25:32 +0000 Subject: [PATCH 325/471] 8365983: Tests should throw SkippedException when SCTP not supported Reviewed-by: jpai --- test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java | 15 ++++++++------- .../nio/sctp/SctpChannel/CloseDescriptors.java | 6 ++++-- .../jdk/com/sun/nio/sctp/SctpChannel/CommUp.java | 15 ++++++++------- .../com/sun/nio/sctp/SctpChannel/Connect.java | 13 +++++++------ .../com/sun/nio/sctp/SctpChannel/Receive.java | 16 ++++++++-------- .../nio/sctp/SctpChannel/ReceiveIntoDirect.java | 15 ++++++++------- test/jdk/com/sun/nio/sctp/SctpChannel/Send.java | 15 ++++++++------- .../com/sun/nio/sctp/SctpChannel/Shutdown.java | 15 ++++++++------- .../nio/sctp/SctpChannel/SocketOptionTests.java | 15 ++++++++------- .../sun/nio/sctp/SctpMultiChannel/Branch.java | 15 ++++++++------- .../sctp/SctpMultiChannel/CloseDescriptors.java | 13 ++++++------- .../com/sun/nio/sctp/SctpMultiChannel/Send.java | 15 ++++++++------- .../nio/sctp/SctpMultiChannel/SendFailed.java | 15 ++++++++------- .../sctp/SctpMultiChannel/SocketOptionTests.java | 15 ++++++++------- .../sun/nio/sctp/SctpServerChannel/Accept.java | 15 ++++++++------- .../SctpServerChannel/NonBlockingAccept.java | 13 +++++++------ 16 files changed, 120 insertions(+), 106 deletions(-) diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java index 027f31695ae..ff5ca00846c 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Bind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,18 +49,14 @@ import com.sun.nio.sctp.SctpServerChannel; import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; +import jtreg.SkippedException; + /** * Tests bind, bindAddress, unbindAddress, getLocalAddress, and * getAllLocalAddresses. */ public class Bind { void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - /* Simply bind tests */ testBind(); @@ -341,6 +338,10 @@ public class Bind { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java index c68abd7a36c..5d62b88f23e 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java @@ -46,6 +46,8 @@ import java.util.Optional; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpServerChannel; +import jtreg.SkippedException; + public class CloseDescriptors { private static Selector selector; private static final int LOOP = 10; @@ -55,7 +57,7 @@ public class CloseDescriptors { public static void main(String[] args) throws Exception { if (!Util.isSCTPSupported()) { - throw new jtreg.SkippedException("SCTP protocol is not supported"); + throw new SkippedException("SCTP protocol is not supported"); } List lsofDirs = List.of("/usr/bin", "/usr/sbin"); @@ -64,7 +66,7 @@ public class CloseDescriptors { .filter(f -> Files.isExecutable(f)) .findFirst(); if (!lsof.isPresent()) { - throw new jtreg.SkippedException("Cannot locate lsof in " + lsofDirs); + throw new SkippedException("Cannot locate lsof in " + lsofDirs); } try (ServerSocket ss = new ServerSocket(0)) { diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java index 8cbe034b00d..320e556f800 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CommUp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 6863110 + * @library /test/lib * @summary Newly connected/accepted SctpChannel should fire OP_READ if registered with a Selector * @author chegar */ @@ -49,6 +50,8 @@ import static java.lang.System.err; import static java.nio.channels.SelectionKey.OP_CONNECT; import static java.nio.channels.SelectionKey.OP_READ; +import jtreg.SkippedException; + public class CommUp { static CountDownLatch acceptLatch = new CountDownLatch(1); static final int TIMEOUT = 10000; @@ -61,12 +64,6 @@ public class CommUp { void test(String[] args) { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -355,6 +352,10 @@ public class CommUp { void sleep(long millis) { try { Thread.currentThread().sleep(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java index b73db200ee2..79b9453a595 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Connect.java @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar * @run main/timeout=480 Connect @@ -44,6 +45,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + /** * Tests connect, finishConnect, isConnectionPending, * getRemoteAddresses and association. @@ -51,12 +54,6 @@ import static java.lang.System.err; public class Connect { void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - doTest(); } @@ -236,6 +233,10 @@ public class Connect { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java index 23005bbf849..48eb413a9ca 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Receive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Receive { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -61,13 +64,6 @@ public class Receive { SocketAddress address = null; Server server; - - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -349,6 +345,10 @@ public class Receive { void debug(String message) {if(debug) { System.out.println(Thread.currentThread() + " " + message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java b/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java index e7b23d0aaed..48d89c34ca4 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/ReceiveIntoDirect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 8034181 + * @library /test/lib * @summary SIGBUS in SctpChannelImpl receive * @author chegar */ @@ -45,6 +46,8 @@ import static java.lang.System.out; import static java.lang.System.err; import static java.nio.charset.StandardCharsets.US_ASCII; +import jtreg.SkippedException; + public class ReceiveIntoDirect { /* suitably small message to NOT overrun small buffers */ final byte[] msgBytes = "Hello".getBytes(US_ASCII); @@ -56,12 +59,6 @@ public class ReceiveIntoDirect { SocketAddress address = null; Server server; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -264,6 +261,10 @@ public class ReceiveIntoDirect { void debug(String message) {if(debug) { System.out.println(Thread.currentThread() + " " + message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java index 93e462a1820..35a28f4eb38 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Send.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Send { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -60,12 +63,6 @@ public class Send { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -451,6 +448,10 @@ public class Send { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java b/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java index 41ba744315c..0891851fe86 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/Shutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -43,6 +44,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Shutdown { static CountDownLatch finishedLatch = new CountDownLatch(1); static CountDownLatch sentLatch = new CountDownLatch(1); @@ -51,12 +54,6 @@ public class Shutdown { SocketAddress address = null; ShutdownServer server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -272,6 +269,10 @@ public class Shutdown { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java b/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java index 052f9999e57..857efbb63f5 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -43,6 +44,8 @@ import java.security.PrivilegedAction; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; import static java.lang.System.out; +import jtreg.SkippedException; + public class SocketOptionTests { final String osName = AccessController.doPrivileged( (PrivilegedAction)() -> System.getProperty("os.name")); @@ -66,12 +69,6 @@ public class SocketOptionTests { } void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - try (SctpChannel sc = SctpChannel.open()) { /* check supported options */ @@ -190,6 +187,10 @@ public class SocketOptionTests { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java index ffd8eb361c3..9beb8c74c3e 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Branch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -48,6 +49,8 @@ import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Branch { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -58,12 +61,6 @@ public class Branch { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -277,6 +274,10 @@ public class Branch { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java index 08340312532..fdafec80745 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/CloseDescriptors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 8269481 + * @library /test/lib * @summary Tests that file descriptors are closed * @requires (os.family == "linux") * @run main/othervm CloseDescriptors @@ -38,6 +39,8 @@ import java.util.Optional; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.SctpMultiChannel; +import jtreg.SkippedException; + public class CloseDescriptors { private static final int NUM = 5; @@ -46,9 +49,7 @@ public class CloseDescriptors { public static void main(String[] args) throws Exception { if (!Util.isSCTPSupported()) { - System.out.println("SCTP protocol is not supported"); - System.out.println("Test cannot be run"); - return; + throw new SkippedException("SCTP protocol is not supported"); } List lsofDirs = List.of("/usr/bin", "/usr/sbin"); @@ -57,9 +58,7 @@ public class CloseDescriptors { .filter(f -> Files.isExecutable(f)) .findFirst(); if (!lsof.isPresent()) { - System.out.println("Cannot locate lsof in " + lsofDirs); - System.out.println("Test cannot be run"); - return; + throw new SkippedException("Cannot locate lsof in " + lsofDirs); } try (ServerSocket ss = new ServerSocket(0)) { diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java index feb914a410e..8fb551dd8f4 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/Send.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -42,6 +43,8 @@ import com.sun.nio.sctp.SctpMultiChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Send { /* Latches used to synchronize between the client and server so that * connections without any IO may not be closed without being accepted */ @@ -52,12 +55,6 @@ public class Send { SocketAddress address = null; Server server = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -355,6 +352,10 @@ public class Send { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java index 7ebbcfb6079..a64d4d58270 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SendFailed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 8067846 + * @library /test/lib * @summary Test for send failed notification */ @@ -35,6 +36,8 @@ import java.nio.ByteBuffer; import static java.lang.System.out; import static java.nio.ByteBuffer.*; +import jtreg.SkippedException; + public class SendFailed { static final SocketAddress remoteAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 3000); @@ -45,12 +48,6 @@ public class SendFailed { void test(String[] args) throws IOException { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - System.out.println("remote address: " + remoteAddress); System.out.println("Note, remote address should not be up"); @@ -186,6 +183,10 @@ public class SendFailed { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message, Object... args) {if(debug) { out.printf(message, args); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java index 2da35d6eda5..3a681884b9a 100644 --- a/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java +++ b/test/jdk/com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -51,6 +52,8 @@ import java.security.PrivilegedAction; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; import static java.lang.System.out; +import jtreg.SkippedException; + public class SocketOptionTests { final String osName = AccessController.doPrivileged( (PrivilegedAction)() -> System.getProperty("os.name")); @@ -74,12 +77,6 @@ public class SocketOptionTests { } void test(String[] args) { - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - try { SctpMultiChannel smc = SctpMultiChannel.open(); @@ -244,6 +241,10 @@ public class SocketOptionTests { void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java index 99d6e26c939..56522a85f6b 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/Accept.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. 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 @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar */ @@ -41,6 +42,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class Accept { static CountDownLatch acceptLatch = new CountDownLatch(1); static CountDownLatch closeByIntLatch = new CountDownLatch(1); @@ -50,12 +53,6 @@ public class Accept { void test(String[] args) { SocketAddress address = null; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -262,6 +259,10 @@ public class Accept { void join(Thread thread, long millis) { try { thread.join(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} diff --git a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java index 6d62aa6c154..abf35bf779d 100644 --- a/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java +++ b/test/jdk/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java @@ -23,6 +23,7 @@ /* @test * @bug 4927640 + * @library /test/lib * @summary Tests the SCTP protocol implementation * @author chegar * @run main/timeout=480 NonBlockingAccept @@ -43,6 +44,8 @@ import com.sun.nio.sctp.SctpServerChannel; import static java.lang.System.out; import static java.lang.System.err; +import jtreg.SkippedException; + public class NonBlockingAccept { static CountDownLatch acceptLatch = new CountDownLatch(1); static final int SEL_TIMEOUT = 10000; @@ -52,12 +55,6 @@ public class NonBlockingAccept { SocketAddress address = null; NonblockingServer server; - if (!Util.isSCTPSupported()) { - out.println("SCTP protocol is not supported"); - out.println("Test cannot be run"); - return; - } - if (args.length == 2) { /* requested to connecct to a specific address */ try { @@ -219,6 +216,10 @@ public class NonBlockingAccept { void sleep(long millis) { try { Thread.currentThread().sleep(millis); } catch(InterruptedException ie) { unexpected(ie); }} public static void main(String[] args) throws Throwable { + if (!Util.isSCTPSupported()) { + throw new SkippedException("SCTP protocol is not supported"); + } + Class k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} From 444a8fa14e8ab016b8aae018054c5dc1eb843fee Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 2 Sep 2025 14:54:50 +0000 Subject: [PATCH 326/471] 8365501: Remove special AdapterHandlerEntry for abstract methods Reviewed-by: kvn, adinn --- src/hotspot/share/cds/archiveBuilder.cpp | 7 +---- src/hotspot/share/oops/method.cpp | 19 ++++++++++---- src/hotspot/share/runtime/javaCalls.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 29 +-------------------- src/hotspot/share/runtime/sharedRuntime.hpp | 4 --- 5 files changed, 17 insertions(+), 44 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 1c807776e3c..7ffbf0151d2 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -563,12 +563,7 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref ref->msotype() == MetaspaceObj::CompileTrainingDataType) { return (TrainingData::need_data() || TrainingData::assembling_data()) ? make_a_copy : set_to_null; } else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) { - if (CDSConfig::is_dumping_adapters()) { - AdapterHandlerEntry* entry = (AdapterHandlerEntry*)ref->obj(); - return AdapterHandlerLibrary::is_abstract_method_adapter(entry) ? set_to_null : make_a_copy; - } else { - return set_to_null; - } + return CDSConfig::is_dumping_adapters() ? make_a_copy : set_to_null; } else { if (ref->msotype() == MetaspaceObj::ClassType) { Klass* klass = (Klass*)ref->obj(); diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 595b4e52882..40c44e07e37 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -152,11 +152,17 @@ void Method::release_C_heap_structures() { } address Method::get_i2c_entry() { + if (is_abstract()) { + return SharedRuntime::throw_AbstractMethodError_entry(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_i2c_entry(); } address Method::get_c2i_entry() { + if (is_abstract()) { + return SharedRuntime::get_handle_wrong_method_abstract_stub(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_entry(); } @@ -1165,9 +1171,9 @@ void Method::clear_code() { // this may be null if c2i adapters have not been made yet // Only should happen at allocate time. if (adapter() == nullptr) { - _from_compiled_entry = nullptr; + _from_compiled_entry = nullptr; } else { - _from_compiled_entry = adapter()->get_c2i_entry(); + _from_compiled_entry = adapter()->get_c2i_entry(); } OrderAccess::storestore(); _from_interpreted_entry = _i2i_entry; @@ -1196,7 +1202,7 @@ void Method::unlink_code() { void Method::unlink_method() { assert(CDSConfig::is_dumping_archive(), "sanity"); _code = nullptr; - if (!CDSConfig::is_dumping_adapters() || AdapterHandlerLibrary::is_abstract_method_adapter(_adapter)) { + if (!CDSConfig::is_dumping_adapters()) { _adapter = nullptr; } _i2i_entry = nullptr; @@ -1277,9 +1283,12 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // called from the vtable. We need adapters on such methods that get loaded // later. Ditto for mega-morphic itable calls. If this proves to be a // problem we'll make these lazily later. - if (_adapter == nullptr) { + if (is_abstract()) { + h_method->_from_compiled_entry = SharedRuntime::get_handle_wrong_method_abstract_stub(); + } else if (_adapter == nullptr) { (void) make_adapters(h_method, CHECK); assert(adapter()->is_linked(), "Adapter must have been linked"); + h_method->_from_compiled_entry = adapter()->get_c2i_entry(); } // ONLY USE the h_method now as make_adapter may have blocked @@ -1300,6 +1309,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { } address Method::make_adapters(const methodHandle& mh, TRAPS) { + assert(!mh->is_abstract(), "abstract methods do not have adapters"); PerfTraceTime timer(ClassLoader::perf_method_adapters_time()); // Adapters for compiled code are made eagerly here. They are fairly @@ -1318,7 +1328,6 @@ address Method::make_adapters(const methodHandle& mh, TRAPS) { } mh->set_adapter_entry(adapter); - mh->_from_compiled_entry = adapter->get_c2i_entry(); return adapter->get_c2i_entry(); } diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 04bd0871073..f237886c128 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -406,7 +406,7 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC address verified_entry_point = (address) HotSpotJVMCI::InstalledCode::entryPoint(nullptr, alternative_target()); if (verified_entry_point != nullptr) { thread->set_jvmci_alternate_call_target(verified_entry_point); - entry_point = method->adapter()->get_i2c_entry(); + entry_point = method->get_i2c_entry(); } } #endif diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 044359eba8d..dc25fec9de7 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2510,7 +2510,6 @@ static void print_table_statistics() { // --------------------------------------------------------------------------- // Implementation of AdapterHandlerLibrary -AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_no_arg_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_int_arg_handler = nullptr; AdapterHandlerEntry* AdapterHandlerLibrary::_obj_arg_handler = nullptr; @@ -2546,28 +2545,11 @@ static void post_adapter_creation(const AdapterBlob* new_adapter, } } -void AdapterHandlerLibrary::create_abstract_method_handler() { - assert_lock_strong(AdapterHandlerLibrary_lock); - // Create a special handler for abstract methods. Abstract methods - // are never compiled so an i2c entry is somewhat meaningless, but - // throw AbstractMethodError just in case. - // Pass wrong_method_abstract for the c2i transitions to return - // AbstractMethodError for invalid invocations. - address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub(); - _abstract_method_handler = AdapterHandlerLibrary::new_entry(AdapterFingerPrint::allocate(0, nullptr)); - _abstract_method_handler->set_entry_points(SharedRuntime::throw_AbstractMethodError_entry(), - wrong_method_abstract, - wrong_method_abstract, - nullptr); -} - void AdapterHandlerLibrary::initialize() { { ResourceMark rm; - MutexLocker mu(AdapterHandlerLibrary_lock); _adapter_handler_table = new (mtCode) AdapterHandlerTable(); _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size); - create_abstract_method_handler(); } #if INCLUDE_CDS @@ -2627,9 +2609,6 @@ AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* finger } AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) { - if (method->is_abstract()) { - return _abstract_method_handler; - } int total_args_passed = method->size_of_parameters(); // All args on stack if (total_args_passed == 0) { return _no_arg_handler; @@ -2727,6 +2706,7 @@ void AdapterHandlerLibrary::verify_adapter_sharing(int total_args_passed, BasicT #endif /* ASSERT*/ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { + assert(!method->is_abstract(), "abstract methods do not have adapters"); // Use customized signature handler. Need to lock around updates to // the _adapter_handler_table (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a @@ -3497,13 +3477,6 @@ void AdapterHandlerLibrary::print_statistics() { #endif /* PRODUCT */ -bool AdapterHandlerLibrary::is_abstract_method_adapter(AdapterHandlerEntry* entry) { - if (entry == _abstract_method_handler) { - return true; - } - return false; -} - JRT_LEAF(void, SharedRuntime::enable_stack_reserved_zone(JavaThread* current)) assert(current == JavaThread::current(), "pre-condition"); StackOverflow* overflow_state = current->stack_overflow_state(); diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 41e4fc1fb3f..288bc0adc52 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -783,7 +783,6 @@ class AdapterHandlerLibrary: public AllStatic { friend class SharedRuntime; private: static BufferBlob* _buffer; // the temporary code buffer in CodeCache - static AdapterHandlerEntry* _abstract_method_handler; static AdapterHandlerEntry* _no_arg_handler; static AdapterHandlerEntry* _int_arg_handler; static AdapterHandlerEntry* _obj_arg_handler; @@ -801,7 +800,6 @@ class AdapterHandlerLibrary: public AllStatic { int total_args_passed, BasicType* sig_bt, bool is_transient = false); - static void create_abstract_method_handler(); static void lookup_simple_adapters() NOT_CDS_RETURN; #ifndef PRODUCT static void print_adapter_handler_info(outputStream* st, AdapterHandlerEntry* handler, AdapterBlob* adapter_blob); @@ -831,8 +829,6 @@ class AdapterHandlerLibrary: public AllStatic { static void print_statistics(); #endif // PRODUCT - static bool is_abstract_method_adapter(AdapterHandlerEntry* adapter); - static AdapterBlob* link_aot_adapter_handler(AdapterHandlerEntry* handler) NOT_CDS_RETURN_(nullptr); static void dump_aot_adapter_table() NOT_CDS_RETURN; static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN; From ecf05ca541b32736ab8e8a38d4be4f037a56361d Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Tue, 2 Sep 2025 15:26:48 +0000 Subject: [PATCH 327/471] 8366693: Backout recent JavaLangAccess changes breaking the build Reviewed-by: jpai, serb, alanb, syan, rriggs, jwaters --- .../share/classes/java/lang/String.java | 332 ++++++------------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 24 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{OrThrowTest.java => NoReplTest.java} | 20 +- 7 files changed, 145 insertions(+), 265 deletions(-) rename test/jdk/java/lang/String/{OrThrowTest.java => NoReplTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 8acb8d8514b..15b8e98369e 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -689,24 +689,12 @@ public final class String } /* - * {@return a new string by decoding from the given UTF-8 bytes array} - *

          - * WARNING: The caller of this method is assumed to have relinquished - * and transferred the ownership of the byte array. It can thus be - * exclusively used to construct the {@code String}. - * - * @param bytes byte array containing UTF-8 encoded characters - * @param offset the index of the first byte to decode - * @param length the number of bytes to decode - * @throws NullPointerException If {@code bytes} is null - * @throws StringIndexOutOfBoundsException If {@code offset} is negative, - * {@code length} is negative, or {@code offset} is greater than - * {@code bytes.length - length} - * @throws CharacterCodingException for malformed input or unmappable characters + * Throws iae, instead of replacing, if malformed or unmappable. + * The byte array can be exclusively used to construct + * the string and is not modified or used for any other purpose. */ - private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) - throws CharacterCodingException { - checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` + private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { + checkBoundsOffCount(offset, length, bytes.length); if (length == 0) { return ""; } @@ -757,10 +745,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); + dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); + dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -796,13 +784,26 @@ public final class String * * @throws CharacterCodingException for malformed input or unmappable characters */ - static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { + static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { + try { + return newStringNoRepl1(src, cs); + } catch (IllegalArgumentException e) { + //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause + Throwable cause = e.getCause(); + if (cause instanceof MalformedInputException mie) { + throw mie; + } + throw (CharacterCodingException)cause; + } + } + + private static String newStringNoRepl1(byte[] src, Charset cs) { int len = src.length; if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8OrThrow(src, 0, src.length); + return newStringUTF8NoRepl(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -815,7 +816,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throw malformedASCII(src); + throwMalformed(src); } } @@ -830,7 +831,13 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + int caLen; + try { + caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + } catch (CharacterCodingException x) { + // throw via IAE + throw new IllegalArgumentException(x); + } if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -867,7 +874,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val); + return encodeUTF8(coder, val, true); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -875,30 +882,13 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, null); + return encodeWithEncoder(cs, coder, val, true); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with the encoder of {@code - * cs}} - * - * @param cs a charset to obtain the encoder from - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeWithEncoder( - Charset cs, byte coder, byte[] val, Class exClass) - throws E { + private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); - boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -940,9 +930,7 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - @SuppressWarnings("unchecked") - E cce = (E) x; - throw cce; + throw new IllegalArgumentException(x); } else { throw new Error(x); } @@ -950,69 +938,60 @@ public final class String return trimArray(ba, bb.position()); } - /** - * {@return the sequence of bytes obtained by encoding the given string in UTF-8} - * - * @param s the string to encode - * @throws NullPointerException If {@code s} is null - * @throws CharacterCodingException For malformed input or unmappable characters + /* + * Throws iae, instead of replacing, if unmappable. */ - static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { - return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` + static byte[] getBytesUTF8NoRepl(String s) { + return encodeUTF8(s.coder(), s.value(), false); } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /** - * {@return the sequence of bytes obtained by encoding the given string in - * the specified {@code Charset}} - *

          - * WARNING: This method returns the {@code byte[]} backing the provided - * {@code String}, if the input is ASCII. Hence, the returned byte array - * must not be modified. - * - * @param s the string to encode - * @param cs the charset - * @throws NullPointerException If {@code s} or {@code cs} is null - * @throws CharacterCodingException For malformed input or unmappable characters + /* + * Throws CCE, instead of replacing, if unmappable. */ - static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { - Objects.requireNonNull(cs); - byte[] val = s.value(); // Implicit null check on `s` + static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { + try { + return getBytesNoRepl1(s, cs); + } catch (IllegalArgumentException e) { + //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause + Throwable cause = e.getCause(); + if (cause instanceof UnmappableCharacterException) { + throw (UnmappableCharacterException)cause; + } + throw (CharacterCodingException)cause; + } + } + + private static byte[] getBytesNoRepl1(String s, Charset cs) { + byte[] val = s.value(); byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8OrThrow(coder, val); + return encodeUTF8(coder, val, false); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1OrThrow(coder, val); + return encode8859_1(coder, val, false); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throw unmappableASCII(val); + throwUnmappable(val); } } } - return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); + return encodeWithEncoder(cs, coder, val, false); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with US-ASCII} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1052,26 +1031,10 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, null); + return encode8859_1(coder, val, true); } - private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { - return encode8859_1(coder, val, UnmappableCharacterException.class); - } - - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with ISO-8859-1} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { + private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { if (coder == LATIN1) { return val.clone(); } @@ -1085,8 +1048,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (exClass != null) { - throw String.unmappableCharacterException(sp); + if (!doReplace) { + throwUnmappable(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1180,26 +1143,7 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { - return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); - } - - private static int decodeUTF8_UTF16OrThrow( - byte[] src, int sp, int sl, byte[] dst, int dp) - throws MalformedInputException { - return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); - } - - /** - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static int decodeUTF8_UTF16( - byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) - throws E { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1208,8 +1152,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1218,8 +1162,8 @@ public final class String } continue; } - if (exClass != null) { - throw String.malformedInputException(sp, 1); // underflow() + if (!doReplace) { + throwMalformed(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1228,8 +1172,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (exClass != null) { - throw String.malformedInputException(sp - 3, 3); + if (!doReplace) { + throwMalformed(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1237,8 +1181,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (exClass != null) { - throw String.malformedInputException(sp - 3, 3); + if (!doReplace) { + throwMalformed(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1248,14 +1192,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 2); + if (!doReplace) { + throwMalformed(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (exClass != null) { - throw String.malformedInputException(sp, 1); + if (!doReplace) { + throwMalformed(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1267,8 +1211,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (exClass != null) { - throw String.malformedInputException(sp - 4, 4); + if (!doReplace) { + throwMalformed(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1281,14 +1225,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); // or 2 + if (!doReplace) { + throwMalformed(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1297,8 +1241,8 @@ public final class String } break; } else { - if (exClass != null) { - throw String.malformedInputException(sp - 1, 1); + if (!doReplace) { + throwMalformed(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1340,76 +1284,29 @@ public final class String return 3; } - /** - * {@return a new {@link MalformedInputException} for the sub-range denoted - * by specified {@code offset} and {@code length}} - * - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - @SuppressWarnings("unchecked") - private static E malformedInputException(int offset, int length) throws E { - MalformedInputException mie = new MalformedInputException(length); - String msg = "malformed input offset : " + offset + ", length : " + length; - mie.initCause(new IllegalArgumentException(msg)); - return (E) mie; + private static void throwMalformed(int off, int nb) { + String msg = "malformed input off : " + off + ", length : " + nb; + throw new IllegalArgumentException(msg, new MalformedInputException(nb)); } - /** - * {@return a new {@link MalformedInputException} for the given malformed - * ASCII string} - */ - private static MalformedInputException malformedASCII(byte[] val) throws MalformedInputException { + private static void throwMalformed(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - return malformedInputException(dp, 1); + throwMalformed(dp, 1); } - /** - * {@return a new {@link UnmappableCharacterException} at given {@code offset}} - * - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - @SuppressWarnings("unchecked") - private static E unmappableCharacterException(int offset) throws E { - UnmappableCharacterException uce = new UnmappableCharacterException(1); - String msg = "malformed input offset : " + offset + ", length : 1"; - uce.initCause(new IllegalArgumentException(msg, uce)); - return (E) uce; + private static void throwUnmappable(int off) { + String msg = "malformed input off : " + off + ", length : 1"; + throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); } - /** - * {@return a new {@link UnmappableCharacterException} for the given - * malformed ASCII string} - */ - private static UnmappableCharacterException unmappableASCII(byte[] val) throws UnmappableCharacterException { + private static void throwUnmappable(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - return unmappableCharacterException(dp); + throwUnmappable(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val) { - return encodeUTF8(coder, val, null); - } - - private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { - return encodeUTF8(coder, val, UnmappableCharacterException.class); - } - - /** - * {@return the byte array obtained by first decoding {@code val} with - * {@code coder}, and then encoding the result with UTF-8} - * - * @param coder a coder to decode {@code val} with - * @param val a string byte array encoded with {@code coder} - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { + private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { if (coder == UTF16) { - return encodeUTF8_UTF16(val, exClass); + return encodeUTF8_UTF16(val, doReplace); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1437,24 +1334,13 @@ public final class String return Arrays.copyOf(dst, dp); } - /** - * {@return the byte array obtained by first decoding {@code val} with - * UTF-16, and then encoding the result with UTF-8} - * - * @param val a string byte array encoded with UTF-16 - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting replaced. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception - */ - private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { + private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1483,10 +1369,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (exClass == null) { + if (doReplace) { dst[dp++] = '?'; } else { - throw String.unmappableCharacterException(sp - 1); + throwUnmappable(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1510,14 +1396,10 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * - * @param exClass The exception class where any non-null value indicates - * malformed or unmappable bytes will result in an exception - * to be thrown instead of getting discarded. - * @param The exception type parameter to enable callers to avoid - * having to declare the exception + * @param val UTF16 encoded byte array + * @param doReplace true to replace unmappable characters */ - private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { + private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1536,10 +1418,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (exClass == null) { + if (doReplace) { dp++; } else { - throw String.unmappableCharacterException(sp - 1); + throwUnmappable(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index bb1775fbc6b..a40c27bbf47 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,7 +2124,6 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } - public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2133,24 +2132,21 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringOrThrow(bytes, cs); + public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringNoRepl(bytes, cs); } - public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } - public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - - public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { - return String.getBytesOrThrow(s, cs); + public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { + return String.getBytesNoRepl(s, cs); } - public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { - return String.getBytesUTF8OrThrow(s); + public byte[] getBytesUTF8NoRepl(String s) { + return String.getBytesUTF8NoRepl(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 80c771f5306..f8278fa2642 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringOrThrow(ba, cs); + return JLA.uncheckedNewStringNoRepl(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index b9906d348e3..8b812eba202 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,11 +264,7 @@ class ZipCoder { @Override byte[] getBytes(String s) { - try { - return JLA.getBytesUTF8OrThrow(s); - } catch (CharacterCodingException cce) { - throw new IllegalArgumentException(cce); - } + return JLA.getBytesUTF8NoRepl(s); } @Override @@ -282,6 +278,8 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. + // We use the JLA.newStringUTF8NoRepl variant to throw + // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -298,7 +296,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index c7d7c86b932..aa5b6e438f5 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,6 +45,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; +import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -331,7 +332,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@code Charset}. + * using the specified {@linkplain java.nio.charset.Charset charset}. *

          * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -342,22 +343,25 @@ public interface JavaLangAccess { * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes */ - String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * {@return the sequence of bytes obtained by encoding the given string in - * the specified {@code Charset}} + * Encode the given string into a sequence of bytes using the specified + * {@linkplain java.nio.charset.Charset charset}. *

          * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. + *

          + * This method throws {@code CharacterCodingException} instead of replacing + * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @throws NullPointerException If {@code s} or {@code cs} is null + * @return the encoded bytes * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -383,13 +387,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * Encode the given string into a sequence of bytes using utf8. * * @param s the string to encode - * @throws NullPointerException If {@code s} is null - * @throws CharacterCodingException For malformed input or unmappable characters + * @return the encoded bytes in utf8 + * @throws IllegalArgumentException for malformed surrogates */ - byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; + byte[] getBytesUTF8NoRepl(String s); /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5a77bb0b935..5dfc73f57aa 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/OrThrowTest.java b/test/jdk/java/lang/String/NoReplTest.java similarity index 79% rename from test/jdk/java/lang/String/OrThrowTest.java rename to test/jdk/java/lang/String/NoReplTest.java index 340a190b4eb..1817a1ffe73 100644 --- a/test/jdk/java/lang/String/OrThrowTest.java +++ b/test/jdk/java/lang/String/NoReplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, Oracle and/or its affiliates. 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 @@ -24,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *OrThrow() shared secret methods. - * @run testng OrThrowTest + * @summary Tests for *NoRepl() shared secret methods. + * @run testng NoReplTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class OrThrowTest { +public class NoReplTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. - * The method is invoked by {@code Files.readString()} method. + * Verifies newStringNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.readString()` method. */ @Test - public void uncheckedNewStringOrThrowTest() throws IOException { + public void newStringNoReplTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class OrThrowTest { } /** - * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. - * The method is invoked by {@code Files.writeString()} method. + * Verifies getBytesNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.writeString()` method. */ @Test - public void uncheckedGetBytesOrThrowTest() throws IOException { + public void getBytesNoReplTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From 48ba8ed2439f9a4a5cdca8715ffddad377366347 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 2 Sep 2025 17:00:33 +0000 Subject: [PATCH 328/471] 8366704: Bump timeout on TestInheritFD Reviewed-by: lmesnik --- test/hotspot/jtreg/runtime/8176717/TestInheritFD.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index 8130ff65792..7cb0efac897 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -92,7 +92,7 @@ public class TestInheritFD { public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; - public static long subProcessTimeout = (long)(15L * Utils.TIMEOUT_FACTOR); + public static long subProcessTimeout = (long)(60L * Utils.TIMEOUT_FACTOR); // Extract a pid from the specified String at the specified start offset. private static long extractPidFromStringOffset(String str, int start) { From c935d1ce1c42ce98cc6ceffaa4f47eb2dba24dfd Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 2 Sep 2025 17:11:34 +0000 Subject: [PATCH 329/471] 8366375: Collator example for SECONDARY uses wrong code point Reviewed-by: jlu, joehw, smarks --- src/java.base/share/classes/java/text/Collator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index 7f6db310366..276a66cdc07 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -138,7 +138,7 @@ public abstract class Collator * Collator strength value. When set, only SECONDARY and above differences are * considered significant during comparison. The assignment of strengths * to language features is locale dependent. A common example is for - * different accented forms of the same base letter ("a" vs "ä" (U+00E9)) to be + * different accented forms of the same base letter ("a" vs "ä" (U+00E4)) to be * considered a SECONDARY difference. * @see java.text.Collator#setStrength * @see java.text.Collator#getStrength @@ -161,8 +161,8 @@ public abstract class Collator * characters ("\u0001" vs "\u0002") to be considered equal at the * PRIMARY, SECONDARY, and TERTIARY levels but different at the IDENTICAL * level. Additionally, differences between pre-composed accents such as - * "\u00C0" (A-grave) and combining accents such as "A\u0300" - * (A, combining-grave) will be considered significant at the IDENTICAL + * "\u00E4" (a-diaeresis) and combining accents such as "a\u0308" + * (a, combining-diaeresis) will be considered significant at the IDENTICAL * level if decomposition is set to NO_DECOMPOSITION. */ public static final int IDENTICAL = 3; From 0d85f076cc32494c1162baea3ea6b0db67136d41 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Tue, 2 Sep 2025 18:03:09 +0000 Subject: [PATCH 330/471] 8359174: tools/jlink/JLink20000Packages.java timed out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vicente Romero Co-authored-by: Eirik Bjørsnøs Reviewed-by: jpai, liach --- test/jdk/tools/jlink/JLink20000Packages.java | 135 ++++++++++-------- test/jdk/tools/lib/tests/JImageGenerator.java | 6 +- 2 files changed, 76 insertions(+), 65 deletions(-) diff --git a/test/jdk/tools/jlink/JLink20000Packages.java b/test/jdk/tools/jlink/JLink20000Packages.java index d592cbc112b..08e6141a267 100644 --- a/test/jdk/tools/jlink/JLink20000Packages.java +++ b/test/jdk/tools/jlink/JLink20000Packages.java @@ -21,14 +21,28 @@ * questions. */ +import tests.JImageGenerator; + +import java.io.BufferedOutputStream; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.StringJoiner; -import java.util.spi.ToolProvider; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; -import tests.JImageGenerator; +import static java.lang.classfile.ClassFile.ACC_MANDATED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; /* * @test @@ -36,79 +50,57 @@ import tests.JImageGenerator; * pagination is in place, the limitation is on the constant pool size, not number * of packages. * @bug 8321413 - * @library ../lib - * @enablePreview + * @library ../lib /test/lib * @modules java.base/jdk.internal.jimage - * jdk.jlink/jdk.tools.jlink.internal - * jdk.jlink/jdk.tools.jlink.plugin - * jdk.jlink/jdk.tools.jmod * jdk.jlink/jdk.tools.jimage - * jdk.compiler * @build tests.* - * @run main/othervm/timeout=1920 -Xmx1g -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages + * @run main/othervm -Xlog:init=debug -XX:+UnlockDiagnosticVMOptions -XX:+BytecodeVerificationLocal JLink20000Packages */ public class JLink20000Packages { - private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") - .orElseThrow(() -> new RuntimeException("javac tool not found")); - - static void report(String command, String[] args) { - System.out.println(command + " " + String.join(" ", Arrays.asList(args))); - } - - static void javac(String[] args) { - report("javac", args); - JAVAC_TOOL.run(System.out, System.err, args); - } + private static final ClassDesc CD_System = ClassDesc.of("java.lang.System"); + private static final ClassDesc CD_PrintStream = ClassDesc.of("java.io.PrintStream"); + private static final MethodTypeDesc MTD_void_String = MethodTypeDesc.of(CD_void, CD_String); public static void main(String[] args) throws Exception { - Path src = Paths.get("bug8321413"); + String moduleName = "bug8321413x"; + Path src = Paths.get(moduleName); + Files.createDirectories(src); + Path jarPath = src.resolve(moduleName +".jar"); Path imageDir = src.resolve("out-jlink"); - Path mainModulePath = src.resolve("bug8321413x"); - StringJoiner mainModuleInfoContent = new StringJoiner(";\n exports ", "module bug8321413x {\n exports ", ";\n}"); + // Generate module with 20000 classes in unique packages + try (JarOutputStream out = new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(jarPath)))) { + Set packageNames = new HashSet<>(); + for (int i = 0; i < 20_000; i++) { + String packageName = "p" + i; + packageNames.add(packageName); - for (int i = 0; i < 20000; i++) { - String packageName = "p" + i; - String className = "C" + i; + // Generate a class file for this package + String className = "C" + i; + byte[] classData = ClassFile.of().build(ClassDesc.of(packageName, className), cb -> {}); + out.putNextEntry(new JarEntry(packageName + "/" + className +".class")); + out.write(classData); + } - Path packagePath = Files.createDirectories(mainModulePath.resolve(packageName)); + // Write the main class + out.putNextEntry(new JarEntry("testpackage/JLink20000PackagesTest.class")); + out.write(generateMainClass()); + packageNames.add("testpackage"); - StringBuilder classContent = new StringBuilder("package "); - classContent.append(packageName).append(";\n"); - classContent.append("class ").append(className).append(" {}\n"); - Files.writeString(packagePath.resolve(className + ".java"), classContent.toString()); - - mainModuleInfoContent.add(packageName); + // Write the module descriptor + byte[] moduleInfo = ClassFile.of().buildModule(ModuleAttribute.of( + ModuleDesc.of(moduleName), mab -> { + mab.requires(ModuleDesc.of("java.base"), ACC_MANDATED, null); + packageNames.forEach(pkgName -> mab.exports(PackageDesc.of(pkgName), 0)); + })); + out.putNextEntry(new JarEntry("module-info.class")); + out.write(moduleInfo); } - // create module reading the generated modules - Path mainModuleInfo = mainModulePath.resolve("module-info.java"); - Files.writeString(mainModuleInfo, mainModuleInfoContent.toString()); - - Path mainClassDir = mainModulePath.resolve("testpackage"); - Files.createDirectories(mainClassDir); - - Files.writeString(mainClassDir.resolve("JLink20000PackagesTest.java"), """ - package testpackage; - - public class JLink20000PackagesTest { - public static void main(String[] args) throws Exception { - System.out.println("JLink20000PackagesTest started."); - } - } - """); - - String out = src.resolve("out").toString(); - javac(new String[]{ - "-d", out, - "--module-source-path", src.toString(), - "--module", "bug8321413x" - }); - JImageGenerator.getJLinkTask() - .modulePath(out) .output(imageDir) - .addMods("bug8321413x") + .addJars(jarPath) + .addMods(moduleName) .call() .assertSuccess(); @@ -117,8 +109,9 @@ public class JLink20000Packages { ProcessBuilder processBuilder = new ProcessBuilder(bin.toString(), "-XX:+UnlockDiagnosticVMOptions", + // Option is useful to verify build image "-XX:+BytecodeVerificationLocal", - "-m", "bug8321413x/testpackage.JLink20000PackagesTest"); + "-m", moduleName + "/testpackage.JLink20000PackagesTest"); processBuilder.inheritIO(); processBuilder.directory(binDir.toFile()); Process process = processBuilder.start(); @@ -126,4 +119,22 @@ public class JLink20000Packages { if (exitCode != 0) throw new AssertionError("JLink20000PackagesTest failed to launch"); } + + /** + * Generate test class with main() does + * System.out.println("JLink20000PackagesTest started."); + */ + private static byte[] generateMainClass() { + return ClassFile.of().build(ClassDesc.of("testpackage", "JLink20000PackagesTest"), + cb -> { + cb.withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), + ACC_PUBLIC | ACC_STATIC, mb -> { + mb.withCode(cob -> cob.getstatic(CD_System, "out", CD_PrintStream) + .ldc("JLink20000PackagesTest started.") + .invokevirtual(CD_PrintStream, "println", MTD_void_String) + .return_() + ); + }); + }); + } } diff --git a/test/jdk/tools/lib/tests/JImageGenerator.java b/test/jdk/tools/lib/tests/JImageGenerator.java index b872ca4f584..5e006459101 100644 --- a/test/jdk/tools/lib/tests/JImageGenerator.java +++ b/test/jdk/tools/lib/tests/JImageGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -423,7 +423,7 @@ public class JImageGenerator { // This is expect FIRST jmods THEN jars, if you change this, some tests could fail String jmods = toPath(this.jmods); String jars = toPath(this.jars); - return linkableRuntime ? jars : jmods + File.pathSeparator + jars; + return (linkableRuntime || jmods.isEmpty()) ? jars : jmods + File.pathSeparator + jars; } private String toPath(List paths) { @@ -654,7 +654,7 @@ public class JImageGenerator { // This is expect FIRST jmods THEN jars, if you change this, some tests could fail String jmods = toPath(this.jmods); String jars = toPath(this.jars); - return jmods + File.pathSeparator + jars; + return jmods.isEmpty() ? jars : jmods + File.pathSeparator + jars; } private String toPath(List paths) { From 80fb7088a10136080d23ea93b4840f17d738500c Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 2 Sep 2025 20:43:38 +0000 Subject: [PATCH 331/471] 8365175: Replace Unicode extension anchor elements with link tag Reviewed-by: liach, iris, naoto --- .../share/classes/java/text/DateFormat.java | 4 ++-- .../classes/java/text/DateFormatSymbols.java | 4 ++-- .../java/text/DecimalFormatSymbols.java | 4 ++-- .../share/classes/java/text/NumberFormat.java | 6 +++--- .../text/spi/DecimalFormatSymbolsProvider.java | 6 +++--- .../java/time/format/DateTimeFormatter.java | 8 ++++---- .../time/format/DateTimeFormatterBuilder.java | 4 ++-- .../classes/java/time/format/DecimalStyle.java | 4 ++-- .../classes/java/time/temporal/WeekFields.java | 4 ++-- .../share/classes/java/util/Calendar.java | 18 +++++++++--------- .../classes/java/util/ResourceBundle.java | 4 ++-- .../java/util/spi/LocaleNameProvider.java | 6 +++--- 12 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/text/DateFormat.java b/src/java.base/share/classes/java/text/DateFormat.java index af756289086..19835dff7c4 100644 --- a/src/java.base/share/classes/java/text/DateFormat.java +++ b/src/java.base/share/classes/java/text/DateFormat.java @@ -101,8 +101,8 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * * *

          If the specified locale contains "ca" (calendar), "rg" (region override), - * and/or "tz" (timezone) Unicode - * extensions, the calendar, the country and/or the time zone for formatting + * and/or "tz" (timezone) {@linkplain Locale##def_locale_extension Unicode + * extensions}, the calendar, the country and/or the time zone for formatting * are overridden. If both "ca" and "rg" are specified, the calendar from the "ca" * extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index f08f5e78338..9fff6a7c4d4 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. 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 @@ -84,7 +84,7 @@ import sun.util.locale.provider.TimeZoneNameUtility; * * *

          If the locale contains "rg" (region override) - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * the symbols are overridden for the designated region. * *

          diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index dfb344f26a7..ccb6c02535c 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -60,8 +60,8 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * your {@code DecimalFormat} and modify it. * *

          The "rg" (region override), "nu" (numbering system), and "cu" (currency) - * {@code Locale} Unicode - * extensions are supported which may override values within the symbols. + * {@code Locale} {@linkplain Locale##def_locale_extension Unicode + * extensions} are supported which may override values within the symbols. * For both "nu" and "cu", if they are specified in addition to "rg" by the * backing {@code Locale}, the respective values from the "nu" and "cu" extension * supersede the implicit ones from the "rg" extension. diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 759ed7ae5ea..afdba76d1ed 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -92,7 +92,7 @@ import sun.util.locale.provider.LocaleServiceProviderPool; * *

          Locale Extensions

          * Formatting behavior can be changed when using a locale that contains any of the following - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, *
            *
          • "nu" * ( @@ -110,7 +110,7 @@ import sun.util.locale.provider.LocaleServiceProviderPool; *

            * For both "nu" and "cu", if they are specified in addition to "rg", the respective * values from the "nu" and "cu" extension supersede the implicit ones from the "rg" extension. - * Although Unicode extensions + * Although {@linkplain Locale##def_locale_extension Unicode extensions} * defines various keys and values, actual locale-sensitive service implementations * in a Java Runtime Environment might not support any particular Unicode locale * attributes or key/type pairs. @@ -691,7 +691,7 @@ public abstract class NumberFormat extends Format { *

            If the specified locale contains the "{@code cf}" ( * * currency format style) - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * the returned currency format uses the style if it is available. * Otherwise, the style uses the default "{@code standard}" currency format. * For example, if the style designates "{@code account}", negative diff --git a/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java b/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java index ffb149bcb8a..2524cc3aa61 100644 --- a/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java +++ b/src/java.base/share/classes/java/text/spi/DecimalFormatSymbolsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -34,8 +34,8 @@ import java.util.spi.LocaleServiceProvider; * provide instances of the * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} class. * - *

            The requested {@code Locale} may contain an extension for + *

            The requested {@code Locale} may contain an {@linkplain + * Locale##def_locale_extension extension} for * specifying the desired numbering system. For example, {@code "ar-u-nu-arab"} * (in the BCP 47 language tag form) specifies Arabic with the Arabic-Indic * digits and symbols, while {@code "ar-u-nu-latn"} specifies Arabic with the diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 108f1e1eef8..26192b8e178 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -1508,9 +1508,9 @@ public final class DateTimeFormatter { * localization, such as the text or localized pattern. *

            * The locale is stored as passed in, without further processing. - * If the locale has - * Unicode extensions, they may be used later in text - * processing. To set the chronology, time-zone and decimal style from + * If the locale has {@linkplain Locale##def_locale_extension Unicode extensions}, + * they may be used later in text processing. + * To set the chronology, time-zone and decimal style from * unicode extensions, see {@link #localizedBy localizedBy()}. *

            * This instance is immutable and unaffected by this method call. @@ -1535,7 +1535,7 @@ public final class DateTimeFormatter { * localization, such as the text or localized pattern. If the locale contains the * "ca" (calendar), "nu" (numbering system), "rg" (region override), and/or * "tz" (timezone) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the chronology, numbering system and/or the zone are overridden. If both "ca" * and "rg" are specified, the chronology from the "ca" extension supersedes the * implicit one from the "rg" extension. Same is true for the "nu" extension. diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 43a79cd85ee..7a2142e5113 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -205,7 +205,7 @@ public final class DateTimeFormatterBuilder { * for the requested dateStyle and/or timeStyle. *

            * If the locale contains the "rg" (region override) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the formatting pattern is overridden with the one appropriate for the region. * * @param dateStyle the FormatStyle for the date, null for time-only pattern @@ -235,7 +235,7 @@ public final class DateTimeFormatterBuilder { * for the requested template. *

            * If the locale contains the "rg" (region override) - * Unicode extensions, + * {@linkplain Locale##def_locale_extension Unicode extensions}, * the formatting pattern is overridden with the one appropriate for the region. *

            * Refer to {@link #appendLocalized(String)} for the detail of {@code requestedTemplate} diff --git a/src/java.base/share/classes/java/time/format/DecimalStyle.java b/src/java.base/share/classes/java/time/format/DecimalStyle.java index a9ad8a4e273..94d6a700ce3 100644 --- a/src/java.base/share/classes/java/time/format/DecimalStyle.java +++ b/src/java.base/share/classes/java/time/format/DecimalStyle.java @@ -150,8 +150,8 @@ public final class DecimalStyle { *

            * This method provides access to locale sensitive decimal style symbols. * If the locale contains "nu" (Numbering System) and/or "rg" - * (Region Override) - * Unicode extensions, returned instance will reflect the values specified with + * (Region Override) {@linkplain Locale##def_locale_extension Unicode extensions}, + * returned instance will reflect the values specified with * those extensions. If both "nu" and "rg" are specified, the value from * the "nu" extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/time/temporal/WeekFields.java b/src/java.base/share/classes/java/time/temporal/WeekFields.java index bbad365553d..fc72b806601 100644 --- a/src/java.base/share/classes/java/time/temporal/WeekFields.java +++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java @@ -289,8 +289,8 @@ public final class WeekFields implements Serializable { *

            * This will look up appropriate values from the provider of localization data. * If the locale contains "fw" (First day of week) and/or "rg" - * (Region Override) - * Unicode extensions, returned instance will reflect the values specified with + * (Region Override) {@linkplain Locale##def_locale_extension Unicode extensions}, + * returned instance will reflect the values specified with * those extensions. If both "fw" and "rg" are specified, the value from * the "fw" extension supersedes the implicit one from the "rg" extension. * diff --git a/src/java.base/share/classes/java/util/Calendar.java b/src/java.base/share/classes/java/util/Calendar.java index 7cf389df42b..e9183ae17da 100644 --- a/src/java.base/share/classes/java/util/Calendar.java +++ b/src/java.base/share/classes/java/util/Calendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. 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 @@ -129,8 +129,8 @@ import sun.util.spi.CalendarProvider; * parameters: the first day of the week and the minimal days in first week * (from 1 to 7). These numbers are taken from the locale resource data or the * locale itself when a {@code Calendar} is constructed. If the designated - * locale contains "fw" and/or "rg" - * Unicode extensions, the first day of the week will be obtained according to + * locale contains "fw" and/or "rg" {@linkplain Locale##def_locale_extension + * Unicode extensions}, the first day of the week will be obtained according to * those extensions. If both "fw" and "rg" are specified, the value from the "fw" * extension supersedes the implicit one from the "rg" extension. * They may also be specified explicitly through the methods for setting their @@ -1454,7 +1454,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * and time zone hasn't been given explicitly, time zone in the locale * is used. * @@ -1615,7 +1615,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * that time zone is used instead. * * @return a Calendar. @@ -1647,7 +1647,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable * If the locale contains the time zone with "tz" - * Unicode extension, + * {@linkplain Locale##def_locale_extension Unicode extension}, * that time zone is used instead. * * @param aLocale the locale for the week data @@ -2632,8 +2632,8 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableUnicode locale extensions. + * calendar types can be used for the {@linkplain Locale##def_locale_extension + * Unicode locale extensions}. * The {@code Set} returned contains at least {@code "gregory"}. The * calendar types don't include aliases, such as {@code "gregorian"} for * {@code "gregory"}. @@ -2667,7 +2667,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableLocale extensions + * @see Locale##def_locale_extension Locale extensions * @see Locale.Builder#setLocale(Locale) * @see Locale.Builder#setUnicodeLocaleKeyword(String, String) */ diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index b3807ac770a..b375a8ba941 100644 --- a/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/src/java.base/share/classes/java/util/ResourceBundle.java @@ -3052,8 +3052,8 @@ public abstract class ResourceBundle { * {@code IllegalArgumentException} is thrown.

          • * *
          • If the {@code locale}'s language is one of the - * Legacy language - * codes, either old or new, then repeat the loading process + * {@linkplain Locale##legacy_language_codes Legacy language + * codes}, either old or new, then repeat the loading process * if needed, with the bundle name with the other language. * For example, "iw" for "he" and vice versa. * diff --git a/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java b/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java index 76712257117..2109a4cead1 100644 --- a/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java +++ b/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -145,7 +145,7 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { /** * Returns a localized name for the given - * Unicode extension key, + * {@linkplain Locale##def_locale_extension Unicode extension} key, * and the given locale that is appropriate for display to the user. * If the name returned cannot be localized according to {@code locale}, * this method returns null. @@ -169,7 +169,7 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { /** * Returns a localized name for the given - * Unicode extension type, + * {@linkplain Locale##def_locale_extension Unicode extension} type, * and the given locale that is appropriate for display to the user. * If the name returned cannot be localized according to {@code locale}, * this method returns null. From 991ac9e6168b2573f78772e2d7936792a43fe336 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Tue, 2 Sep 2025 21:28:22 +0000 Subject: [PATCH 332/471] 8365407: Race condition in MethodTrainingData::verify() Reviewed-by: kvn, vlivanov, iklam --- .../share/compiler/compilationPolicy.cpp | 24 ++++---- .../share/compiler/compilationPolicy.hpp | 26 ++++---- src/hotspot/share/oops/trainingData.cpp | 59 ++++++++++++------- src/hotspot/share/oops/trainingData.hpp | 10 ++-- src/hotspot/share/runtime/init.cpp | 5 +- src/hotspot/share/runtime/java.cpp | 7 +++ 6 files changed, 73 insertions(+), 58 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 9c49d941bbc..80223a4e5cb 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -138,7 +138,7 @@ void CompilationPolicy::compile_if_required(const methodHandle& m, TRAPS) { } } -void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS) { +void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, JavaThread* current) { if (!klass->has_init_deps_processed()) { ResourceMark rm; log_debug(training)("Replay training: %s", klass->external_name()); @@ -150,11 +150,11 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS assert(klass->has_init_deps_processed(), ""); if (AOTCompileEagerly) { ktd->iterate_comp_deps([&](CompileTrainingData* ctd) { - if (ctd->init_deps_left() == 0) { + if (ctd->init_deps_left_acquire() == 0) { MethodTrainingData* mtd = ctd->method(); if (mtd->has_holder()) { - const methodHandle mh(THREAD, const_cast(mtd->holder())); - CompilationPolicy::maybe_compile_early(mh, THREAD); + const methodHandle mh(current, const_cast(mtd->holder())); + CompilationPolicy::maybe_compile_early(mh, current); } } }); @@ -163,10 +163,10 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS } } -void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, TRAPS) { +void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, JavaThread* current) { assert(klass->is_initialized(), ""); if (TrainingData::have_data() && klass->is_shared()) { - _training_replay_queue.push(klass, TrainingReplayQueue_lock, THREAD); + _training_replay_queue.push(klass, TrainingReplayQueue_lock, current); } } @@ -181,11 +181,11 @@ void CompilationPolicyUtils::Queue::print_on(outputStream* st) { } } -void CompilationPolicy::replay_training_at_init_loop(TRAPS) { +void CompilationPolicy::replay_training_at_init_loop(JavaThread* current) { while (!CompileBroker::is_compilation_disabled_forever()) { - InstanceKlass* ik = _training_replay_queue.pop(TrainingReplayQueue_lock, THREAD); + InstanceKlass* ik = _training_replay_queue.pop(TrainingReplayQueue_lock, current); if (ik != nullptr) { - replay_training_at_init_impl(ik, THREAD); + replay_training_at_init_impl(ik, current); } } } @@ -446,7 +446,7 @@ void CompilationPolicy::print_training_data_on(outputStream* st, const char* pr if (ctd == nullptr) { st->print("null"); } else { - st->print("%d", ctd->init_deps_left()); + st->print("%d", ctd->init_deps_left_acquire()); } } } @@ -1172,7 +1172,7 @@ CompLevel CompilationPolicy::trained_transition_from_none(const methodHandle& me CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); assert(ctd != nullptr, "Should have CTD for CompLevel_full_optimization"); // With SkipTier2IfPossible and all deps satisfied, go to level 4 immediately - if (SkipTier2IfPossible && ctd->init_deps_left() == 0) { + if (SkipTier2IfPossible && ctd->init_deps_left_acquire() == 0) { if (method->method_data() == nullptr) { create_mdo(method, THREAD); } @@ -1200,7 +1200,7 @@ CompLevel CompilationPolicy::trained_transition_from_limited_profile(const metho assert(training_has_profile, "Have to have a profile to be here"); // Check if the method is ready CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); - if (ctd != nullptr && ctd->init_deps_left() == 0) { + if (ctd != nullptr && ctd->init_deps_left_acquire() == 0) { if (method->method_data() == nullptr) { create_mdo(method, THREAD); } diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index f4a7c4c249b..d950ba418f9 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -74,32 +74,28 @@ class Queue { } public: Queue() : _head(nullptr), _tail(nullptr) { } - void push(T* value, Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); + void push(T* value, Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); push_unlocked(value); locker.notify_all(); } bool is_empty_unlocked() const { return _head == nullptr; } - T* pop(Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); - while(is_empty_unlocked() && !CompileBroker::is_compilation_disabled_forever()) { + T* pop(Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); + while (is_empty_unlocked() && !CompileBroker::is_compilation_disabled_forever()) { locker.wait(); } T* value = pop_unlocked(); return value; } - T* try_pop(Monitor* lock, TRAPS) { - MonitorLocker locker(THREAD, lock); - T* value = nullptr; - if (!is_empty_unlocked()) { - value = pop_unlocked(); - } + T* try_pop(Monitor* lock, JavaThread* current) { + MonitorLocker locker(current, lock); + T* value = pop_unlocked(); return value; } - void print_on(outputStream* st); }; } // namespace CompilationPolicyUtils @@ -342,7 +338,7 @@ class CompilationPolicy : AllStatic { // m must be compiled before executing it static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); static void maybe_compile_early(const methodHandle& m, TRAPS); - static void replay_training_at_init_impl(InstanceKlass* klass, TRAPS); + static void replay_training_at_init_impl(InstanceKlass* klass, JavaThread* current); public: static int min_invocations() { return Tier4MinInvocationThreshold; } static int c1_count() { return _c1_count; } @@ -352,8 +348,8 @@ class CompilationPolicy : AllStatic { // This supports the -Xcomp option. static void compile_if_required(const methodHandle& m, TRAPS); - static void replay_training_at_init(InstanceKlass* klass, TRAPS); - static void replay_training_at_init_loop(TRAPS); + static void replay_training_at_init(InstanceKlass* klass, JavaThread* current); + static void replay_training_at_init_loop(JavaThread* current); // m is allowed to be compiled static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 70e8f2437c1..4797eed0a31 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -83,7 +83,7 @@ static void verify_archived_entry(TrainingData* td, const TrainingData::Key* k) } void TrainingData::verify() { - if (TrainingData::have_data()) { + if (TrainingData::have_data() && !TrainingData::assembling_data()) { archived_training_data_dictionary()->iterate([&](TrainingData* td) { if (td->is_KlassTrainingData()) { KlassTrainingData* ktd = td->as_KlassTrainingData(); @@ -98,9 +98,21 @@ void TrainingData::verify() { Key k(mtd->holder()); verify_archived_entry(td, &k); } - mtd->verify(); - } else if (td->is_CompileTrainingData()) { - td->as_CompileTrainingData()->verify(); + mtd->verify(/*verify_dep_counter*/true); + } + }); + } + if (TrainingData::need_data()) { + TrainingDataLocker l; + training_data_set()->iterate([&](TrainingData* td) { + if (td->is_KlassTrainingData()) { + KlassTrainingData* ktd = td->as_KlassTrainingData(); + ktd->verify(); + } else if (td->is_MethodTrainingData()) { + MethodTrainingData* mtd = td->as_MethodTrainingData(); + // During the training run init deps tracking is not setup yet, + // don't verify it. + mtd->verify(/*verify_dep_counter*/false); } }); } @@ -229,7 +241,7 @@ CompileTrainingData* CompileTrainingData::make(CompileTask* task) { } -void CompileTrainingData::dec_init_deps_left(KlassTrainingData* ktd) { +void CompileTrainingData::dec_init_deps_left_release(KlassTrainingData* ktd) { LogStreamHandle(Trace, training) log; if (log.is_enabled()) { log.print("CTD "); print_on(&log); log.cr(); @@ -450,7 +462,7 @@ void KlassTrainingData::notice_fully_initialized() { TrainingDataLocker l; // Not a real lock if we don't collect the data, // that's why we need the atomic decrement below. for (int i = 0; i < comp_dep_count(); i++) { - comp_dep(i)->dec_init_deps_left(this); + comp_dep(i)->dec_init_deps_left_release(this); } holder()->set_has_init_deps_processed(); } @@ -476,10 +488,10 @@ void TrainingData::init_dumptime_table(TRAPS) { _dumptime_training_data_dictionary->append(td); } }); + } - if (AOTVerifyTrainingData) { - training_data_set()->verify(); - } + if (AOTVerifyTrainingData) { + TrainingData::verify(); } } @@ -592,22 +604,13 @@ void KlassTrainingData::verify() { } } -void MethodTrainingData::verify() { - iterate_compiles([](CompileTrainingData* ctd) { - ctd->verify(); - - int init_deps_left1 = ctd->init_deps_left(); - int init_deps_left2 = ctd->compute_init_deps_left(); - - if (init_deps_left1 != init_deps_left2) { - ctd->print_on(tty); tty->cr(); - } - guarantee(init_deps_left1 == init_deps_left2, "mismatch: %d %d %d", - init_deps_left1, init_deps_left2, ctd->init_deps_left()); +void MethodTrainingData::verify(bool verify_dep_counter) { + iterate_compiles([&](CompileTrainingData* ctd) { + ctd->verify(verify_dep_counter); }); } -void CompileTrainingData::verify() { +void CompileTrainingData::verify(bool verify_dep_counter) { for (int i = 0; i < init_dep_count(); i++) { KlassTrainingData* ktd = init_dep(i); if (ktd->has_holder() && ktd->holder()->defined_by_other_loaders()) { @@ -624,6 +627,18 @@ void CompileTrainingData::verify() { } guarantee(ktd->_comp_deps.contains(this), ""); } + + if (verify_dep_counter) { + int init_deps_left1 = init_deps_left_acquire(); + int init_deps_left2 = compute_init_deps_left(); + + bool invariant = (init_deps_left1 >= init_deps_left2); + if (!invariant) { + print_on(tty); + tty->cr(); + } + guarantee(invariant, "init deps invariant violation: %d >= %d", init_deps_left1, init_deps_left2); + } } void CompileTrainingData::cleanup(Visitor& visitor) { diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index c47d0a0f66e..b909be12324 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -673,9 +673,9 @@ public: } _init_deps.clear(); } - void dec_init_deps_left(KlassTrainingData* ktd); - int init_deps_left() const { - return Atomic::load(&_init_deps_left); + void dec_init_deps_left_release(KlassTrainingData* ktd); + int init_deps_left_acquire() const { + return Atomic::load_acquire(&_init_deps_left); } uint compute_init_deps_left(bool count_initialized = false); @@ -707,7 +707,7 @@ public: return (int)align_metadata_size(align_up(sizeof(CompileTrainingData), BytesPerWord)/BytesPerWord); } - void verify(); + void verify(bool verify_dep_counter); static CompileTrainingData* allocate(MethodTrainingData* mtd, int level, int compile_id) { return TrainingData::allocate(mtd, level, compile_id); @@ -828,7 +828,7 @@ class MethodTrainingData : public TrainingData { return "{ method training data }"; }; - void verify(); + void verify(bool verify_dep_counter); static MethodTrainingData* allocate(Method* m, KlassTrainingData* ktd) { return TrainingData::allocate(m, ktd); diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 73292a7b6d9..56e6ea30c0a 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -195,10 +195,7 @@ jint init_globals2() { } #endif - // Initialize TrainingData only we're recording/replaying - if (TrainingData::have_data() || TrainingData::need_data()) { - TrainingData::initialize(); - } + TrainingData::initialize(); if (!universe_post_init()) { return JNI_ERR; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index b3b46e5a9ab..351fd1ebb89 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -34,6 +34,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "compiler/compilationMemoryStatistic.hpp" +#include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compilerOracle.hpp" #include "gc/shared/collectedHeap.hpp" @@ -503,6 +504,12 @@ void before_exit(JavaThread* thread, bool halt) { // Note: we don't wait until it actually dies. os::terminate_signal_thread(); + #if INCLUDE_CDS + if (AOTVerifyTrainingData) { + TrainingData::verify(); + } + #endif + print_statistics(); { MutexLocker ml(BeforeExit_lock); From b50c11f9077f071cf5639de7e82ec261e0338532 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 2 Sep 2025 23:04:52 +0000 Subject: [PATCH 333/471] 8366195: Remove unnecessary quotes around -Ta ml64 assembler argument Reviewed-by: erikj --- make/autoconf/flags.m4 | 4 ++++ make/autoconf/spec.gmk.template | 1 + make/common/native/CompileFile.gmk | 8 +------- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index d50538108a4..c810d15ebbc 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -320,12 +320,16 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL], [ if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then CC_OUT_OPTION=-Fo + if test "x$OPENJDK_TARGET_CPU" != xaarch64; then + AS_NON_ASM_EXTENSION_OPTION=-Ta + fi else # The option used to specify the target .o,.a or .so file. # When compiling, how to specify the to be created object file. CC_OUT_OPTION='-o$(SPACE)' fi AC_SUBST(CC_OUT_OPTION) + AC_SUBST(AS_NON_ASM_EXTENSION_OPTION) # Generate make dependency files if test "x$TOOLCHAIN_TYPE" = xgcc; then diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index c96b730c6fa..e3345940101 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -492,6 +492,7 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@ HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@ CC_OUT_OPTION := @CC_OUT_OPTION@ +AS_NON_ASM_EXTENSION_OPTION := @AS_NON_ASM_EXTENSION_OPTION@ # Flags used for overriding the default opt setting for a C/C++ source file. C_O_FLAG_HIGHEST_JVM := @C_O_FLAG_HIGHEST_JVM@ diff --git a/make/common/native/CompileFile.gmk b/make/common/native/CompileFile.gmk index 39b5f34a4c5..a8d46949788 100644 --- a/make/common/native/CompileFile.gmk +++ b/make/common/native/CompileFile.gmk @@ -155,12 +155,6 @@ define CreateCompiledNativeFileBody endif $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h - else ifeq ($(TOOLCHAIN_TYPE), microsoft) - ifeq ($(OPENJDK_TARGET_CPU), aarch64) - $1_NON_ASM_EXTENSION_FLAG := - else - $1_NON_ASM_EXTENSION_FLAG := "-Ta" - endif endif else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) # Compile as a C++ or Objective-C++ file @@ -242,7 +236,7 @@ define CreateCompiledNativeFileBody # For assembler calls just create empty dependency lists $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ $$($1_COMPILER) $$($1_FLAGS) \ - $(CC_OUT_OPTION)$$($1_OBJ) $$($1_NON_ASM_EXTENSION_FLAG) $$($1_SRC_FILE))) \ + $(CC_OUT_OPTION)$$($1_OBJ) $(AS_NON_ASM_EXTENSION_OPTION) $$($1_SRC_FILE))) \ | $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \ $(ECHO) > $$($1_DEPS_FILE) ; \ $(ECHO) > $$($1_DEPS_TARGETS_FILE) From 5052a7eee57e9d145950a0ab1ca71edc02bfe0be Mon Sep 17 00:00:00 2001 From: Rui Li Date: Tue, 2 Sep 2025 23:49:23 +0000 Subject: [PATCH 334/471] 8246037: Shenandoah: update man pages to mention -XX:+UseShenandoahGC Reviewed-by: ysr, wkemper, cslucas --- .../gc/shenandoah/shenandoah_globals.hpp | 6 ++- src/java.base/share/man/java.md | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index c51f4f16489..026f352701d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -141,10 +141,12 @@ "GC heuristics to use. This fine-tunes the GC mode selected, " \ "by choosing when to start the GC, how much to process on each " \ "cycle, and what other features to automatically enable. " \ - "Possible values are:" \ + "When -XX:ShenandoahGCMode is generational, the only supported " \ + "option is the default, adaptive. Possible values are:" \ " adaptive - adapt to maintain the given amount of free heap " \ "at all times, even during the GC cycle;" \ - " static - trigger GC when free heap falls below the threshold;" \ + " static - trigger GC when free heap falls below a specified " \ + "threshold;" \ " aggressive - run GC continuously, try to evacuate everything;" \ " compact - run GC more frequently and with deeper targets to " \ "free up more memory.") \ diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 9a750f8cf1f..1a6a944594f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2882,6 +2882,46 @@ Java HotSpot VM. expensive operations. Using a lower value will cause heap memory to be uncommitted earlier, at the risk of soon having to commit it again. +`-XX:+UseShenandoahGC` +: Enables the use of the Shenandoah garbage collector. This is a low pause + time, concurrent garbage collector. Its pause times are not proportional to + the size of the heap. Shenandoah garbage collector can work with compressed + pointers. See `-XX:UseCompressedOops` for further information about + compressed pointers. + +`-XX:ShenandoahGCMode=`*mode* +: Sets the GC mode for Shenandoah GC to use. By default, this option is set + to `satb`. Among other things, this defines which barriers are in use. + Possible mode values include the following: + + `satb` + : Snapshot-at-the-beginning concurrent GC (three pass mark-evac-update). + It is a single generation GC. + + `generational` + : It is also a snapshot-at-the-beginning and concurrent GC, but it is + generational. Please see [JEP 404](https://openjdk.org/jeps/404) and + [JEP 521](https://openjdk.org/jeps/521) for its advantages and risks. + +`-XX:ShenandoahGCHeuristics=`*heuristics* +: Sets the heuristics for Shenandoah GC to use. By default, this option is + set to `adaptive`. This fine-tunes the GC mode selected, by choosing when + to start the GC, how much to process on each cycle, and what other features + to automatically enable. When `-XX:ShenandoahGCMode` is `generational`, the + only supported option is the default, `adaptive`. + + Possible heuristics are the following: + + `adaptive` + : To maintain the given amount of free heap at all times, even during + the GC cycle. + + `static` + : Trigger GC when free heap falls below a specified threshold. + + `compact` + : Run GC more frequently and with deeper targets to free up more memory. + ## Deprecated Java Options These `java` options are deprecated and might be removed in a future JDK From e268563a10b67bdcb3c030743ed3e2b3b7dfd0f7 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 3 Sep 2025 00:57:52 +0000 Subject: [PATCH 335/471] 8366476: Test gc/z/TestSmallHeap.java fails OOM with many NUMA nodes Reviewed-by: jsikstro, aboldtch --- test/hotspot/jtreg/gc/z/TestSmallHeap.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/z/TestSmallHeap.java b/test/hotspot/jtreg/gc/z/TestSmallHeap.java index c3c0dddd8e8..9a65227a10b 100644 --- a/test/hotspot/jtreg/gc/z/TestSmallHeap.java +++ b/test/hotspot/jtreg/gc/z/TestSmallHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -54,6 +54,8 @@ public class TestSmallHeap { public static void main(String[] args) throws Exception { for (var maxCapacity: args) { ProcessTools.executeTestJava( + // Disable NUMA to avoid potential OOM after JDK-8359683 + "-XX:-UseNUMA", "-XX:+UseZGC", "-Xlog:gc,gc+init,gc+reloc,gc+heap", "-Xmx" + maxCapacity, From 8c4090c2cfa00f9c3550669a0726a785b30ac1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Sep 2025 06:38:27 +0000 Subject: [PATCH 336/471] 8329077: C2 SuperWord: Add MoveD2L, MoveL2D, MoveF2I, MoveI2F Reviewed-by: epeter, qamai --- src/hotspot/share/opto/superword.cpp | 2 + src/hotspot/share/opto/vectornode.cpp | 4 ++ .../TestCompatibleUseDefTypeSize.java | 24 ++++++----- .../vm/compiler/TypeVectorOperations.java | 43 +++++++++++++++++++ 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 7b47992e77e..2b3928781b8 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1648,6 +1648,8 @@ bool SuperWord::implemented(const Node_List* pack, const uint size) const { retValue = ReductionNode::implemented(opc, size, arith_type->basic_type()); } else if (VectorNode::is_convert_opcode(opc)) { retValue = VectorCastNode::implemented(opc, size, velt_basic_type(p0->in(1)), velt_basic_type(p0)); + } else if (VectorNode::is_reinterpret_opcode(opc)) { + retValue = Matcher::match_rule_supported_auto_vectorization(Op_VectorReinterpret, size, velt_basic_type(p0)); } else if (VectorNode::is_minmax_opcode(opc) && is_subword_type(velt_basic_type(p0))) { // Java API for Math.min/max operations supports only int, long, float // and double types. Thus, avoid generating vector min/max nodes for diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index c126c91da1b..2153a12c402 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -992,6 +992,10 @@ bool VectorNode::is_vector_bitwise_not_pattern(Node* n) { bool VectorNode::is_reinterpret_opcode(int opc) { switch (opc) { + case Op_MoveF2I: + case Op_MoveD2L: + case Op_MoveL2D: + case Op_MoveI2F: case Op_ReinterpretHF2S: case Op_ReinterpretS2HF: return true; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java index f5445f3106b..e6c373c4c87 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java @@ -395,7 +395,7 @@ public class TestCompatibleUseDefTypeSize { // In theory, one would expect this to be a simple 4byte -> 4byte conversion. // But there is a CmpF and CMove here because we check for isNaN. Plus a MoveF2I. // - // Would be nice to vectorize: Missing support for CmpF, CMove and MoveF2I. + // Would be nice to vectorize: Missing support for CmpF and CMove. static Object[] test5(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { a[i] = Float.floatToIntBits(b[i]); @@ -404,10 +404,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveF2I static Object[] test6(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { a[i] = Float.floatToRawIntBits(b[i]); @@ -416,10 +417,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveI2F static Object[] test7(int[] a, float[] b) { for (int i = 0; i < a.length; i++) { b[i] = Float.intBitsToFloat(a[i]); @@ -431,7 +433,7 @@ public class TestCompatibleUseDefTypeSize { @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for Needs CmpD, CMove and MoveD2L + // Missing support to vectorize CmpD and CMove static Object[] test8(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { a[i] = Double.doubleToLongBits(b[i]); @@ -440,10 +442,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveD2L static Object[] test9(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { a[i] = Double.doubleToRawLongBits(b[i]); @@ -452,10 +455,11 @@ public class TestCompatibleUseDefTypeSize { } @Test - @IR(counts = {IRNode.STORE_VECTOR, "= 0"}, + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, applyIfPlatform = {"64-bit", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}) - // Missing support for MoveL2D static Object[] test10(long[] a, double[] b) { for (int i = 0; i < a.length; i++) { b[i] = Double.longBitsToDouble(a[i]); diff --git a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java index c39107fdd00..fcdbb9356e0 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java +++ b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025 IBM Corporation. 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 @@ -262,6 +263,20 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertD2LBits() { + for (int i = 0; i < COUNT; i++) { + resL[i] = Double.doubleToLongBits(doubles[i]); + } + } + + @Benchmark + public void convertD2LBitsRaw() { + for (int i = 0; i < COUNT; i++) { + resL[i] = Double.doubleToRawLongBits(doubles[i]); + } + } + @Benchmark public void convertF2I() { for (int i = 0; i < COUNT; i++) { @@ -269,6 +284,20 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertF2IBits() { + for (int i = 0; i < COUNT; i++) { + resI[i] = Float.floatToIntBits(floats[i]); + } + } + + @Benchmark + public void convertF2IBitsRaw() { + for (int i = 0; i < COUNT; i++) { + resI[i] = (int) Float.floatToRawIntBits(floats[i]); + } + } + @Benchmark public void convertF2B() { for (int i = 0; i < COUNT; i++) { @@ -304,6 +333,13 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertIBits2F() { + for (int i = 0; i < COUNT; i++) { + resF[i] = Float.intBitsToFloat(ints[i]); + } + } + @Benchmark public void convertI2D() { for (int i = 0; i < COUNT; i++) { @@ -325,6 +361,13 @@ public abstract class TypeVectorOperations { } } + @Benchmark + public void convertLBits2D() { + for (int i = 0; i < COUNT; i++) { + resD[i] = Double.longBitsToDouble(longs[i]); + } + } + @Benchmark public void convertL2B() { for (int i = 0; i < COUNT; i++) { From 7c70e7341438ce8a420021005a0f03fe917e5a26 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 3 Sep 2025 06:45:02 +0000 Subject: [PATCH 337/471] 8366660: Sort share/nmt includes Reviewed-by: ayang, shade --- src/hotspot/share/nmt/arrayWithFreeList.hpp | 1 + src/hotspot/share/nmt/mallocLimit.cpp | 4 ++-- src/hotspot/share/nmt/mallocTracker.cpp | 2 +- src/hotspot/share/nmt/mallocTracker.inline.hpp | 3 ++- src/hotspot/share/nmt/memMapPrinter.cpp | 4 ++-- src/hotspot/share/nmt/memReporter.cpp | 7 +++---- src/hotspot/share/nmt/memTracker.hpp | 2 +- src/hotspot/share/nmt/memoryFileTracker.cpp | 2 +- src/hotspot/share/nmt/memoryFileTracker.hpp | 2 +- src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp | 1 + src/hotspot/share/nmt/regionsTree.inline.hpp | 1 + src/hotspot/share/nmt/virtualMemoryTracker.cpp | 3 +-- src/hotspot/share/nmt/virtualMemoryTracker.hpp | 2 +- src/hotspot/share/nmt/vmatree.hpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 15 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/nmt/arrayWithFreeList.hpp b/src/hotspot/share/nmt/arrayWithFreeList.hpp index 2c1812dcc52..03a44f8c20b 100644 --- a/src/hotspot/share/nmt/arrayWithFreeList.hpp +++ b/src/hotspot/share/nmt/arrayWithFreeList.hpp @@ -26,6 +26,7 @@ #define SHARE_NMT_ARRAYWITHFREELIST_HPP #include "utilities/growableArray.hpp" + #include // A flat array of elements E, backed by C-heap, growing on-demand. It allows for diff --git a/src/hotspot/share/nmt/mallocLimit.cpp b/src/hotspot/share/nmt/mallocLimit.cpp index 2bce2e459e0..1751cb59ae7 100644 --- a/src/hotspot/share/nmt/mallocLimit.cpp +++ b/src/hotspot/share/nmt/mallocLimit.cpp @@ -26,11 +26,11 @@ #include "nmt/mallocLimit.hpp" #include "nmt/memTag.hpp" #include "nmt/nmtCommon.hpp" -#include "runtime/java.hpp" #include "runtime/globals.hpp" +#include "runtime/java.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/parseInteger.hpp" #include "utilities/ostream.hpp" +#include "utilities/parseInteger.hpp" MallocLimitSet MallocLimitHandler::_limits; bool MallocLimitHandler::_have_limit = false; diff --git a/src/hotspot/share/nmt/mallocTracker.cpp b/src/hotspot/share/nmt/mallocTracker.cpp index d919f3ce873..ab3cb322107 100644 --- a/src/hotspot/share/nmt/mallocTracker.cpp +++ b/src/hotspot/share/nmt/mallocTracker.cpp @@ -40,10 +40,10 @@ #include "runtime/os.hpp" #include "runtime/safefetch.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/vmError.hpp" -#include "utilities/globalDefinitions.hpp" MallocMemorySnapshot MallocMemorySummary::_snapshot; diff --git a/src/hotspot/share/nmt/mallocTracker.inline.hpp b/src/hotspot/share/nmt/mallocTracker.inline.hpp index 51a7f28cf99..abf0a499a9d 100644 --- a/src/hotspot/share/nmt/mallocTracker.inline.hpp +++ b/src/hotspot/share/nmt/mallocTracker.inline.hpp @@ -26,8 +26,9 @@ #ifndef SHARE_NMT_MALLOCTRACKER_INLINE_HPP #define SHARE_NMT_MALLOCTRACKER_INLINE_HPP -#include "nmt/mallocLimit.hpp" #include "nmt/mallocTracker.hpp" + +#include "nmt/mallocLimit.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index 41d977e9639..6086b1a6fd1 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -28,11 +28,11 @@ #include "gc/shared/collectedHeap.hpp" #include "logging/logAsyncWriter.hpp" #include "memory/allocation.hpp" -#include "memory/universe.hpp" #include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "nmt/memMapPrinter.hpp" #include "nmt/memTag.hpp" #include "nmt/memTagBitmap.hpp" -#include "nmt/memMapPrinter.hpp" #include "nmt/memTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/nonJavaThread.hpp" diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index a7c564eff53..65d4d76942b 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -26,11 +26,10 @@ #include "memory/metaspace.hpp" #include "memory/metaspaceUtils.hpp" #include "nmt/mallocTracker.hpp" -#include "nmt/memTag.hpp" -#include "nmt/memReporter.hpp" -#include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" -#include "nmt/regionsTree.hpp" +#include "nmt/memReporter.hpp" +#include "nmt/memTag.hpp" +#include "nmt/memTracker.hpp" #include "nmt/regionsTree.inline.hpp" #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 124c6163d76..b6a9ed261de 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -28,8 +28,8 @@ #include "memory/reservedSpace.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/memBaseline.hpp" -#include "nmt/nmtCommon.hpp" #include "nmt/memoryFileTracker.hpp" +#include "nmt/nmtCommon.hpp" #include "nmt/threadStackTracker.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index 55f1cb64626..2f3f4f1973a 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -23,8 +23,8 @@ */ #include "memory/allocation.hpp" -#include "nmt/memTracker.hpp" #include "nmt/memoryFileTracker.hpp" +#include "nmt/memTracker.hpp" #include "nmt/nmtCommon.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "nmt/vmatree.hpp" diff --git a/src/hotspot/share/nmt/memoryFileTracker.hpp b/src/hotspot/share/nmt/memoryFileTracker.hpp index 1b23dacab81..1e8bd40ed50 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.hpp +++ b/src/hotspot/share/nmt/memoryFileTracker.hpp @@ -28,8 +28,8 @@ #include "memory/allocation.hpp" #include "nmt/nmtCommon.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" -#include "nmt/vmatree.hpp" #include "nmt/virtualMemoryTracker.hpp" +#include "nmt/vmatree.hpp" #include "runtime/os.inline.hpp" #include "utilities/deferredStatic.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 85e044c1a45..6f194cfa5a1 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -28,6 +28,7 @@ #include "nmt/arrayWithFreeList.hpp" #include "utilities/growableArray.hpp" #include "utilities/nativeCallStack.hpp" + #include // Virtual memory regions that are tracked by NMT also have their NativeCallStack (NCS) tracked. diff --git a/src/hotspot/share/nmt/regionsTree.inline.hpp b/src/hotspot/share/nmt/regionsTree.inline.hpp index 665f4a93c88..98cfa0e7f2c 100644 --- a/src/hotspot/share/nmt/regionsTree.inline.hpp +++ b/src/hotspot/share/nmt/regionsTree.inline.hpp @@ -25,6 +25,7 @@ #define SHARE_NMT_REGIONSTREE_INLINE_HPP #include "nmt/regionsTree.hpp" + #include "nmt/virtualMemoryTracker.hpp" template diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 8a97253860c..bdb31d5c992 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -24,9 +24,8 @@ #include "logging/log.hpp" #include "nmt/memTracker.hpp" -#include "nmt/virtualMemoryTracker.hpp" -#include "nmt/regionsTree.hpp" #include "nmt/regionsTree.inline.hpp" +#include "nmt/virtualMemoryTracker.hpp" #include "runtime/os.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index 3c6c1efd6a2..121fcbbda4b 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -26,8 +26,8 @@ #define SHARE_NMT_VIRTUALMEMORYTRACKER_HPP #include "nmt/allocationSite.hpp" -#include "nmt/vmatree.hpp" #include "nmt/regionsTree.hpp" +#include "nmt/vmatree.hpp" #include "runtime/atomic.hpp" #include "utilities/nativeCallStack.hpp" #include "utilities/ostream.hpp" diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index d2acabdae07..01f0e107a56 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -26,12 +26,12 @@ #ifndef SHARE_NMT_VMATREE_HPP #define SHARE_NMT_VMATREE_HPP -#include "nmt/memTag.hpp" #include "nmt/memTag.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "utilities/rbTree.inline.hpp" + #include // A VMATree stores a sequence of points on the natural number line. diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index be35f8fa2b2..695b300f3fd 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -57,6 +57,7 @@ public class TestIncludesAreSorted { "share/logging", "share/memory", "share/metaprogramming", + "share/nmt", "share/oops", "share/opto", "share/precompiled", From 6dda2f6fad5cae95057fbdfa672e3b51aff61af7 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Sep 2025 07:52:28 +0000 Subject: [PATCH 338/471] 8366543: Clean up include headers in numberSeq Reviewed-by: tschatzl --- src/hotspot/share/utilities/numberSeq.cpp | 1 - src/hotspot/share/utilities/numberSeq.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/numberSeq.cpp b/src/hotspot/share/utilities/numberSeq.cpp index 276c5cb01ff..536f6563866 100644 --- a/src/hotspot/share/utilities/numberSeq.cpp +++ b/src/hotspot/share/utilities/numberSeq.cpp @@ -22,7 +22,6 @@ * */ -#include "memory/allocation.inline.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/numberSeq.hpp" diff --git a/src/hotspot/share/utilities/numberSeq.hpp b/src/hotspot/share/utilities/numberSeq.hpp index b57fdf45576..fff4b416745 100644 --- a/src/hotspot/share/utilities/numberSeq.hpp +++ b/src/hotspot/share/utilities/numberSeq.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_NUMBERSEQ_HPP #include "memory/allocation.hpp" +#include "utilities/ostream.hpp" /** ** This file contains a few classes that represent number sequence, From 3b2f3e53d7f27653c3d4608b141aed6a84829aa8 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Wed, 3 Sep 2025 12:36:36 +0000 Subject: [PATCH 339/471] 8366803: Bump timeout on sun/tools/jhsdb/BasicLauncherTest.java Reviewed-by: stefank --- test/jdk/sun/tools/jhsdb/BasicLauncherTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java index d2ca78f044a..75f2af6db5a 100644 --- a/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java +++ b/test/jdk/sun/tools/jhsdb/BasicLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @library /test/lib * @requires vm.hasSA * @build jdk.test.lib.apps.* - * @run main BasicLauncherTest + * @run main/timeout=480 BasicLauncherTest */ import java.io.BufferedReader; From 2a5f149bb8e26277778465fff670591c929842de Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Sep 2025 12:41:24 +0000 Subject: [PATCH 340/471] 8363966: GHA: Switch cross-compiling sysroots to Debian trixie Reviewed-by: ayang, fyang, erikj --- .github/workflows/build-cross-compile.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index 351d087ef7d..b3c63f488a0 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -64,33 +64,33 @@ jobs: gnu-arch: aarch64 debian-arch: arm64 debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: arm gnu-arch: arm debian-arch: armhf debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false gnu-abi: eabihf - target-cpu: s390x gnu-arch: s390x debian-arch: s390x debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: ppc64le gnu-arch: powerpc64le debian-arch: ppc64el debian-repository: https://httpredir.debian.org/debian/ - debian-version: bookworm + debian-version: trixie tolerate-sysroot-errors: false - target-cpu: riscv64 gnu-arch: riscv64 debian-arch: riscv64 debian-repository: https://httpredir.debian.org/debian/ - debian-version: sid - tolerate-sysroot-errors: true + debian-version: trixie + tolerate-sysroot-errors: false steps: - name: 'Checkout the JDK source' From 3abaa83610efb5c8e9b86c6f895d6b58d21e1fa2 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 3 Sep 2025 13:51:17 +0000 Subject: [PATCH 341/471] 8366298: FDLeakTest sometimes takes minutes to complete on Linux Reviewed-by: lkorinth, rriggs, stuefe --- .../ProcessBuilder/FDLeakTest/FDLeakTest.java | 6 +-- .../ProcessBuilder/FDLeakTest/libFDLeaker.c | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java index 02f3583f0b3..146c2be563f 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java @@ -27,7 +27,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=posix_spawn -agentlib:FDLeaker FDLeakTest */ /** @@ -35,7 +35,7 @@ * @summary Check that we don't leak FDs * @requires os.family != "windows" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest */ /** @@ -43,7 +43,7 @@ * @summary Check that we don't leak FDs * @requires os.family == "linux" * @library /test/lib - * @run main/othervm/native/timeout=480 -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest + * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest */ import jdk.test.lib.process.ProcessTools; diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c index b3fa296cae2..afec94f65c7 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/libFDLeaker.c @@ -21,16 +21,55 @@ * questions. */ +#include #include +#include +#include +#include #include "jvmti.h" +static jint limit_num_fds(); + JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + // Lower the number of possible open files to make the test go faster + jint ret = limit_num_fds(); + if (ret != 0) { + fprintf(stderr, "Failed to limit number of fds: %s", strerror(errno)); + return ret; + } + const char* filename = "./testfile_FDLeaker.txt"; FILE* f = fopen(filename, "w"); if (f == NULL) { + fprintf(stderr, "Failed to open file: %s", strerror(errno)); return JNI_ERR; } + printf("Opened and leaked %s (%d)", filename, fileno(f)); return JNI_OK; } + +static jint limit_num_fds() { + struct rlimit rl; + + // Fetch the current limit + int ret = getrlimit(RLIMIT_NOFILE, &rl); + if (ret != 0) { + return JNI_ERR; + } + + // Use a lower value unless it is already low + rlim_t limit = 100; + if (limit < rl.rlim_cur) { + rl.rlim_cur = limit; + } + + // Lower the value + int ret2 = setrlimit(RLIMIT_NOFILE, &rl); + if (ret2 != 0) { + return JNI_ERR; + } + + return JNI_OK; +} From d5935af228d7129d75d6987767de50b019ec30c7 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 3 Sep 2025 14:40:23 +0000 Subject: [PATCH 342/471] 8366768: Problemlist jdk/jshell/ToolSimpleTest.java Reviewed-by: jlahoda --- test/langtools/ProblemList.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 1d8df78266a..e1124f4784a 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -52,6 +52,8 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all +jdk/jshell/ToolSimpleTest.java 8366582 windows-x64 +jdk/jshell/ToolLocalSimpleTest.java 8366582 windows-x64 ########################################################################### # From a40afdd08f366afcefb1ac9d5fb184c8e803707e Mon Sep 17 00:00:00 2001 From: Vanitha B P Date: Wed, 3 Sep 2025 15:31:15 +0000 Subject: [PATCH 343/471] 8366537: Test "java/util/TimeZone/DefaultTimeZoneTest.java" is not updating the zone ID as expected Reviewed-by: naoto, jlu --- .../util/TimeZone/DefaultTimeZoneTest.java | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java index 4dd644d58b5..b386d39d499 100644 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -38,6 +38,11 @@ import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.BoxLayout; +import javax.swing.Box; +import java.awt.Dimension; +import java.awt.Component; import java.awt.BorderLayout; import java.awt.Window; import java.lang.reflect.InvocationTargetException; @@ -98,17 +103,36 @@ public class DefaultTimeZoneTest { private static Window createTest() { var contents = new JFrame("DefaultTimeZoneTest"); - var label = new JLabel(SDF.format(new Date())); - var panel = new JPanel(); - var button = new JButton("Update Time Zone"); - panel.add(button); contents.setSize(350, 250); - contents.add(label, BorderLayout.NORTH); - contents.add(panel, BorderLayout.CENTER); + // Panel with vertical layout + var panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); + // Time zone ID label + var timeZoneID = new JLabel("Time zone ID: " + SDF.getTimeZone().getID(), SwingConstants.CENTER); + timeZoneID.setAlignmentX(Component.CENTER_ALIGNMENT); + // Time label + var label = new JLabel(SDF.format(new Date()), SwingConstants.CENTER); + label.setAlignmentX(Component.CENTER_ALIGNMENT); + // Update button + var button = new JButton("Update Time Zone"); + button.setAlignmentX(Component.CENTER_ALIGNMENT); + // Add components with spacing + panel.add(Box.createRigidArea(new Dimension(0, 10))); + panel.add(timeZoneID); + panel.add(Box.createRigidArea(new Dimension(0, 5))); + panel.add(label); + panel.add(Box.createRigidArea(new Dimension(0, 10))); + panel.add(button); + contents.add(panel); + // Update default time zone on button click button.addActionListener(e -> { + // Clear JVM cached timezone and force reload from OS + TimeZone.setDefault(null); + System.setProperty("user.timezone", ""); TimeZone tz = TimeZone.getDefault(); SDF.setTimeZone(tz); + timeZoneID.setText("Time zone ID: " + tz.getID()); label.setText(SDF.format(new Date())); contents.repaint(); }); From e3b36e3babb860d9d24a610160f47d42cfaafaa3 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Sep 2025 18:00:13 +0000 Subject: [PATCH 344/471] 8366401: JCK test api/java_text/DecimalFormatSymbols/serial/InputTests.html fails after JDK-8363972 Reviewed-by: naoto --- .../java/text/DecimalFormatSymbols.java | 3 +- .../DecimalFormat/DFSSerializationTest.java | 264 ++++++++++++++++++ 2 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index ccb6c02535c..c255b93bd98 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -1015,7 +1015,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { currencyInitialized = true; } - if (loadNumberData(locale) instanceof Object[] d && + // `locale` was once nullable, need to check before loading locale data + if (locale != null && loadNumberData(locale) instanceof Object[] d && d[0] instanceof String[] numberElements && numberElements.length >= 14) { lenientMinusSigns = numberElements[13]; diff --git a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java new file mode 100644 index 00000000000..9e875e851c8 --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8366401 + * @summary Check serialization of DecimalFormatSymbols. That is, ensure the + * behavior for each stream version is correct during de-serialization. + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED DFSSerializationTest + */ + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.text.DecimalFormatSymbols; +import java.util.Currency; +import java.util.Locale; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class DFSSerializationTest { + + @Nested + class VersionTests { + + // Ensure correct monetarySeparator and exponential field defaults + // Reads monetary from decimal, and sets exponential to 'E' + @Test + public void version0Test() { + var crafted = new DFSBuilder() + .setVer(0) + .set("monetarySeparator", '~') + .set("exponential", 'Z') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Check exponential is set to proper default 'E', not 'Z' + assertEquals('E', readField(dfs, "exponential")); + // Ensure that mSep is based on dSep, and is not '~' + assertNotEquals('~', dfs.getMonetaryDecimalSeparator()); + assertEquals(dfs.getDecimalSeparator(), dfs.getMonetaryDecimalSeparator()); + } + + // Version 1 did not have a locale field, and it defaulted to Locale.ROOT. + // Note that other versions did allow a locale field, which was nullable. + // E.g. see nullableLocaleTest which does not set locale when it is `null` + @Test + public void version1Test() { + var crafted = new DFSBuilder() + .setVer(1) + .set("locale", null) + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(Locale.ROOT, dfs.getLocale()); + } + + // Version 2 did not have an exponential separator, and created it via exponent + // char field. + @Test + public void version2Test() { + var crafted = new DFSBuilder() + .setVer(2) + .set("exponentialSeparator", null) + .set("exponential", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("~", dfs.getExponentSeparator()); + } + + // Version 3 didn't have perMillText, percentText, and minusSignText. + // These were created from the corresponding char equivalents. + @Test + public void version3Test() { + var crafted = new DFSBuilder() + .setVer(3) + .set("perMillText", null) + .set("percentText", null) + .set("minusSignText", null) + .set("perMill", '~') + .set("percent", '~') + .set("minusSign", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Need to check these String fields using reflection, since they + // are not exposed via the public API + assertEquals("~", readField(dfs, "perMillText")); + assertEquals("~", readField(dfs, "percentText")); + assertEquals("~", readField(dfs, "minusSignText")); + } + + // Version 4 did not have monetaryGroupingSeparator. It should be based + // off of groupingSeparator. + @Test + public void version4Test() { + var crafted = new DFSBuilder() + .setVer(4) + .set("monetaryGroupingSeparator", 'Z') + .set("groupingSeparator", '~') + .build(); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(dfs.getGroupingSeparator(), dfs.getMonetaryGroupingSeparator()); + } + } + + // Up-to-date DFS stream versions do not expect a null locale since the + // standard DecimalFormatSymbols API forbids it. However, this was not always + // the case and previous stream versions can contain a null locale. Thus, + // ensure that a null locale does not cause number data loading to fail. + @Test + public void nullableLocaleTest() { + var bytes = ser(new DFSBuilder() + .set("locale", null) + .set("minusSignText", "zFoo") + .set("minusSign", 'z') // Set so that char/String forms agree + .build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertNull(dfs.getLocale()); + // LMS should be based off of minusSignText when locale is null + assertEquals("zFoo", readField(dfs, "lenientMinusSigns")); + } + + // readObject fails when the {@code char} and {@code String} representations + // of percent, per mille, and/or minus sign disagree. + @Test + public void disagreeingTextTest() { + var expected = "'char' and 'String' representations of either percent, " + + "per mille, and/or minus sign disagree."; + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("minusSignText", "Z") + .set("minusSign", 'X') + .build()))).getMessage()); + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("perMillText", "Z") + .set("perMill", 'X') + .build()))).getMessage()); + assertEquals(expected, assertThrows(InvalidObjectException.class, () -> + deSer(ser(new DFSBuilder() + .set("percentText", "Z") + .set("percent", 'X') + .build()))).getMessage()); + } + + // Ensure the serial version is updated to the current after de-serialization. + @Test + public void updatedVersionTest() { + var bytes = ser(new DFSBuilder().setVer(-25).build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(5, readField(dfs, "serialVersionOnStream")); + } + + // Should set currency from 4217 code when it is valid. + @Test + public void validIntlCurrencyTest() { + var bytes = ser(new DFSBuilder().set("intlCurrencySymbol", "JPY").build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(Currency.getInstance("JPY"), dfs.getCurrency()); + } + + // Should not set currency when 4217 code is invalid, it remains null. + @Test + public void invalidIntlCurrencyTest() { + var bytes = ser(new DFSBuilder() + .set("intlCurrencySymbol", ">.,") + .set("locale", Locale.JAPAN) + .build()); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + // Can not init off invalid 4217 code, remains null + assertNull(dfs.getCurrency()); + } + +// Utilities ---- + + // Utility to serialize + private static byte[] ser(Object obj) { + return assertDoesNotThrow(() -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); + } + }, "Unexpected error during serialization"); + } + + // Utility to deserialize + private static DecimalFormatSymbols deSer(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { + return (DecimalFormatSymbols) ois.readObject(); + } + } + + // Utility to read a private field + private static Object readField(DecimalFormatSymbols dfs, String name) { + return assertDoesNotThrow(() -> { + var field = DecimalFormatSymbols.class.getDeclaredField(name); + field.setAccessible(true); + return field.get(dfs); + }, "Unexpected error during field reading"); + } + + // Utility class to build instances of DFS via reflection + private static class DFSBuilder { + + private final DecimalFormatSymbols dfs; + + private DFSBuilder() { + dfs = new DecimalFormatSymbols(); + } + + private DFSBuilder setVer(Object value) { + return set("serialVersionOnStream", value); + } + + private DFSBuilder set(String field, Object value) { + return assertDoesNotThrow(() -> { + Field f = dfs.getClass().getDeclaredField(field); + f.setAccessible(true); + f.set(dfs, value); + return this; + }, "Unexpected error during reflection setting"); + } + + private DecimalFormatSymbols build() { + return dfs; + } + } +} From 8d236615b7db2bd5a2a59002b79e59cf4e6a308a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Sep 2025 18:47:58 +0000 Subject: [PATCH 345/471] 8366155: Serial: Obsolete PretenureSizeThreshold Reviewed-by: tschatzl --- .../share/gc/serial/defNewGeneration.cpp | 1 - .../share/gc/serial/defNewGeneration.hpp | 20 ------- src/hotspot/share/gc/serial/serialHeap.cpp | 52 ++++--------------- src/hotspot/share/gc/serial/serialHeap.hpp | 5 -- .../share/gc/serial/tenuredGeneration.hpp | 9 ---- src/hotspot/share/gc/shared/gc_globals.hpp | 5 -- src/hotspot/share/runtime/arguments.cpp | 2 + 7 files changed, 11 insertions(+), 83 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index a3d45a98354..3eab4a2e5fe 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -267,7 +267,6 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, update_counters(); _old_gen = nullptr; _tenuring_threshold = MaxTenuringThreshold; - _pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize; _ref_processor = nullptr; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index c5e1c2b152e..7f4077873b2 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -55,8 +55,6 @@ class DefNewGeneration: public Generation { uint _tenuring_threshold; // Tenuring threshold for next collection. AgeTable _age_table; - // Size of object to pretenure in words; command line provides bytes - size_t _pretenure_size_threshold_words; // ("Weak") Reference processing support SpanSubjectToDiscoveryClosure _span_based_discoverer; @@ -185,24 +183,6 @@ class DefNewGeneration: public Generation { HeapWord* block_start(const void* p) const; - // Allocation support - bool should_allocate(size_t word_size, bool is_tlab) { - assert(UseTLAB || !is_tlab, "Should not allocate tlab"); - assert(word_size != 0, "precondition"); - - size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize); - - const bool overflows = word_size >= overflow_limit; - const bool check_too_big = _pretenure_size_threshold_words > 0; - const bool not_too_big = word_size < _pretenure_size_threshold_words; - const bool size_ok = is_tlab || !check_too_big || not_too_big; - - bool result = !overflows && - size_ok; - - return result; - } - // Allocate requested size or return null; single-threaded and lock-free versions. HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 72f8ad85a4e..6bb1183aa56 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -283,16 +283,12 @@ size_t SerialHeap::max_capacity() const { } HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { - HeapWord* result = nullptr; - if (_old_gen->should_allocate(size, is_tlab)) { + HeapWord* result = _young_gen->allocate(size); + + if (result == nullptr) { result = _old_gen->expand_and_allocate(size); } - if (result == nullptr) { - if (_young_gen->should_allocate(size, is_tlab)) { - // Young-gen is not expanded. - result = _young_gen->allocate(size); - } - } + assert(result == nullptr || is_in_reserved(result), "result not in heap"); return result; } @@ -301,11 +297,9 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { HeapWord* result = nullptr; for (uint try_count = 1; /* break */; try_count++) { - if (_young_gen->should_allocate(size, is_tlab)) { - result = _young_gen->par_allocate(size); - if (result != nullptr) { - break; - } + result = _young_gen->par_allocate(size); + if (result != nullptr) { + break; } // Try old-gen allocation for non-TLAB. if (!is_tlab) { @@ -342,25 +336,6 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { return result; } -HeapWord* SerialHeap::attempt_allocation(size_t size, - bool is_tlab, - bool first_only) { - HeapWord* res = nullptr; - - if (_young_gen->should_allocate(size, is_tlab)) { - res = _young_gen->allocate(size); - if (res != nullptr || first_only) { - return res; - } - } - - if (_old_gen->should_allocate(size, is_tlab)) { - res = _old_gen->allocate(size); - } - - return res; -} - HeapWord* SerialHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { return mem_allocate_work(size, @@ -459,15 +434,10 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { HeapWord* result = nullptr; // If young-gen can handle this allocation, attempt young-gc firstly. - bool should_run_young_gc = _young_gen->should_allocate(size, is_tlab); + bool should_run_young_gc = is_tlab || size <= _young_gen->eden()->capacity(); collect_at_safepoint(!should_run_young_gc); - result = attempt_allocation(size, is_tlab, false /*first_only*/); - if (result != nullptr) { - return result; - } - - // OK, collection failed, try expansion. + // Just finished a GC, try to satisfy this allocation, using expansion if needed. result = expand_heap_and_allocate(size, is_tlab); if (result != nullptr) { return result; @@ -484,10 +454,6 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { do_full_collection(clear_all_soft_refs); } - result = attempt_allocation(size, is_tlab, false /* first_only */); - if (result != nullptr) { - return result; - } // The previous full-gc can shrink the heap, so re-expand it. result = expand_heap_and_allocate(size, is_tlab); if (result != nullptr) { diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index b89edb33307..f0194f1a4a2 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -102,11 +102,6 @@ private: // old-gen. bool _is_heap_almost_full; - // Helper functions for allocation - HeapWord* attempt_allocation(size_t size, - bool is_tlab, - bool first_only); - void do_full_collection(bool clear_all_soft_refs) override; // Does the "cause" of GC indicate that diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 1225005aff4..038038f6808 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -135,15 +135,6 @@ public: void gc_prologue(); void gc_epilogue(); - bool should_allocate(size_t word_size, bool is_tlab) { - bool result = false; - size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize); - if (!is_tlab) { - result = (word_size > 0) && (word_size < overflow_limit); - } - return result; - } - // Performance Counter support void update_counters(); diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 7f46f449085..240068f10c0 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -484,11 +484,6 @@ "OS specific low limit for heap base address") \ constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \ \ - product(size_t, PretenureSizeThreshold, 0, \ - "Maximum size in bytes of objects allocated in DefNew " \ - "generation; zero means no maximum") \ - range(0, max_uintx) \ - \ product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ range(1, max_uintx-2) \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 063090b93c9..0d4adc7f587 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -567,6 +567,8 @@ static SpecialFlag const special_jvm_flags[] = { { "UseAdaptiveSizePolicyWithSystemGC", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, { "UsePSAdaptiveSurvivorSizePolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + { "PretenureSizeThreshold", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif From 431f46724658b703e995e518cb7a2149c50d6a9d Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 3 Sep 2025 19:21:38 +0000 Subject: [PATCH 346/471] 8361635: Missing List length validation in the Class-File API Reviewed-by: asotona --- .../java/lang/classfile/Annotation.java | 8 + .../lang/classfile/AnnotationElement.java | 2 + .../java/lang/classfile/AnnotationValue.java | 7 +- .../java/lang/classfile/ClassBuilder.java | 12 +- .../java/lang/classfile/CodeBuilder.java | 4 +- .../java/lang/classfile/Interfaces.java | 12 +- .../java/lang/classfile/TypeAnnotation.java | 9 +- .../CharacterRangeTableAttribute.java | 2 + .../attribute/ExceptionsAttribute.java | 8 + .../attribute/InnerClassesAttribute.java | 4 + .../attribute/LineNumberTableAttribute.java | 2 + .../LocalVariableTableAttribute.java | 2 + .../LocalVariableTypeTableAttribute.java | 2 + .../attribute/MethodParametersAttribute.java | 4 + .../classfile/attribute/ModuleAttribute.java | 23 +- .../classfile/attribute/ModuleExportInfo.java | 28 +- .../attribute/ModuleHashesAttribute.java | 8 + .../classfile/attribute/ModuleOpenInfo.java | 24 +- .../attribute/ModulePackagesAttribute.java | 8 + .../attribute/ModuleProvideInfo.java | 10 +- .../attribute/NestMembersAttribute.java | 12 +- .../PermittedSubclassesAttribute.java | 12 +- .../classfile/attribute/RecordAttribute.java | 4 + .../attribute/RecordComponentInfo.java | 8 + .../RuntimeInvisibleAnnotationsAttribute.java | 4 + ...nvisibleParameterAnnotationsAttribute.java | 4 + ...timeInvisibleTypeAnnotationsAttribute.java | 4 + .../RuntimeVisibleAnnotationsAttribute.java | 4 + ...eVisibleParameterAnnotationsAttribute.java | 4 + ...untimeVisibleTypeAnnotationsAttribute.java | 4 + .../attribute/StackMapFrameInfo.java | 2 + .../attribute/StackMapTableAttribute.java | 2 + .../constantpool/ConstantPoolBuilder.java | 4 + .../classfile/constantpool/Utf8Entry.java | 3 +- .../java/lang/classfile/package-info.java | 2 +- .../classfile/impl/AnnotationImpl.java | 6 +- .../classfile/impl/AttributeHolder.java | 3 +- .../impl/BootstrapMethodEntryImpl.java | 8 +- .../classfile/impl/BufWriterImpl.java | 4 +- .../classfile/impl/DirectCodeBuilder.java | 11 +- .../classfile/impl/InterfacesImpl.java | 4 +- .../classfile/impl/SplitConstantPool.java | 10 +- .../classfile/impl/StackMapDecoder.java | 6 +- .../classfile/impl/TargetInfoImpl.java | 2 +- .../classfile/impl/UnboundAttribute.java | 74 ++-- .../jdk/internal/classfile/impl/Util.java | 29 ++ test/jdk/jdk/classfile/LimitsTest.java | 220 ++++++++++- .../jdk/jdk/classfile/ListValidationTest.java | 348 ++++++++++++++++++ 48 files changed, 866 insertions(+), 111 deletions(-) create mode 100644 test/jdk/jdk/classfile/ListValidationTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 5c4ee630b08..5a9aeaccfc4 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java @@ -95,6 +95,8 @@ public sealed interface Annotation * @param annotationClass the constant pool entry holding the descriptor string * of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(Utf8Entry annotationClass, List elements) { @@ -106,6 +108,8 @@ public sealed interface Annotation * @param annotationClass the constant pool entry holding the descriptor string * of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(Utf8Entry annotationClass, AnnotationElement... elements) { @@ -116,6 +120,8 @@ public sealed interface Annotation * {@return an annotation} * @param annotationClass the descriptor of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(ClassDesc annotationClass, List elements) { @@ -126,6 +132,8 @@ public sealed interface Annotation * {@return an annotation} * @param annotationClass the descriptor of the annotation interface * @param elements the element-value pairs of the annotation + * @throws IllegalArgumentException if the number of pairs exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static Annotation of(ClassDesc annotationClass, AnnotationElement... elements) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 23f830f1512..aed9a358535 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java @@ -209,6 +209,8 @@ public sealed interface AnnotationElement * @param name the name of the key * @param values the associated values * @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray + * @throws IllegalArgumentException if the number of associated values + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static AnnotationElement ofArray(String name, AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index ae31fdf3967..623cb5a771f 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -673,6 +673,8 @@ public sealed interface AnnotationValue { * on array values derived from Java source code. * * @param values the array elements + * @throws IllegalArgumentException if the length of array exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static OfArray ofArray(List values) { return new AnnotationImpl.OfArrayImpl(values); @@ -686,6 +688,8 @@ public sealed interface AnnotationValue { * on array values derived from Java source code. * * @param values the array elements + * @throws IllegalArgumentException if the length of array exceeds the limit + * of {@link java.lang.classfile##u2 u2} */ static OfArray ofArray(AnnotationValue... values) { return ofArray(List.of(values)); @@ -699,7 +703,8 @@ public sealed interface AnnotationValue { * @param value the annotation value * @throws IllegalArgumentException when the {@code value} parameter is not * a primitive, a wrapper of primitive, a String, a ClassDesc, - * an enum constant, or an array of one of these. + * an enum constant, or an array of one of these; or any array has + * length over the limit of {@link java.lang.classfile##u2 u2} */ static AnnotationValue of(Object value) { if (value instanceof String s) { diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 86cdb298d9e..7fd10b9dab1 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -131,6 +131,8 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder + * @throws IllegalArgumentException if the number of interfaces exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaces(List interfaces) { @@ -142,6 +144,8 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder + * @throws IllegalArgumentException if the number of interfaces exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaces(ClassEntry... interfaces) { @@ -153,7 +157,9 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder - * @throws IllegalArgumentException if any element of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaceSymbols(List interfaces) { @@ -165,7 +171,9 @@ public sealed interface ClassBuilder * * @param interfaces the interfaces * @return this builder - * @throws IllegalArgumentException if any element of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} * @see Interfaces */ default ClassBuilder withInterfaceSymbols(ClassDesc... interfaces) { diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 656e84adf58..b4d3e427e91 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -2402,8 +2402,8 @@ public sealed interface CodeBuilder * variable by a constant. *

            * This may also generate {@link Opcode#IINC_W wide iinc} instructions if - * {@code slot} exceeds {@code 255} or {@code val} exceeds the range of - * {@link TypeKind#BYTE byte}. + * {@code slot} exceeds the limit of {@link java.lang.classfile##u1 u1} or + * {@code val} exceeds the range of {@link TypeKind#BYTE byte}. * * @param slot the local variable slot * @param val the increment value diff --git a/src/java.base/share/classes/java/lang/classfile/Interfaces.java b/src/java.base/share/classes/java/lang/classfile/Interfaces.java index bd89c494f24..d4fac8e310a 100644 --- a/src/java.base/share/classes/java/lang/classfile/Interfaces.java +++ b/src/java.base/share/classes/java/lang/classfile/Interfaces.java @@ -54,6 +54,8 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces + * @throws IllegalArgumentException if the number of interfaces + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static Interfaces of(List interfaces) { return new InterfacesImpl(interfaces); @@ -62,6 +64,8 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces + * @throws IllegalArgumentException if the number of interfaces + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static Interfaces of(ClassEntry... interfaces) { return of(List.of(interfaces)); @@ -70,7 +74,9 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces - * @throws IllegalArgumentException if any of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static Interfaces ofSymbols(List interfaces) { return of(Util.entryList(interfaces)); @@ -79,7 +85,9 @@ public sealed interface Interfaces /** * {@return an {@linkplain Interfaces} element} * @param interfaces the interfaces - * @throws IllegalArgumentException if any of {@code interfaces} is primitive + * @throws IllegalArgumentException if any of {@code interfaces} is primitive, + * or if the number of interfaces exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static Interfaces ofSymbols(ClassDesc... interfaces) { return ofSymbols(Arrays.asList(interfaces)); diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 09dc3b59098..23c735257ae 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -182,6 +182,8 @@ public sealed interface TypeAnnotation * @param targetInfo which type in a declaration or expression is annotated * @param targetPath which part of the type is annotated * @param annotation the annotation + * @throws IllegalArgumentException if the size of {@code targetPath} + * exceeds the limit of {@link java.lang.classfile##u1 u1} */ static TypeAnnotation of(TargetInfo targetInfo, List targetPath, Annotation annotation) { @@ -486,6 +488,8 @@ public sealed interface TypeAnnotation * including a variable declared as a resource in a try-with-resources statement} * @param targetType {@link TargetType#LOCAL_VARIABLE} or {@link TargetType#RESOURCE_VARIABLE} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofVariable(TargetType targetType, List table) { return new TargetInfoImpl.LocalVarTargetImpl(targetType, table); @@ -494,6 +498,8 @@ public sealed interface TypeAnnotation /** * {@return a target for annotations on the type in a local variable declaration} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofLocalVariable(List table) { return ofVariable(TargetType.LOCAL_VARIABLE, table); @@ -503,6 +509,8 @@ public sealed interface TypeAnnotation * {@return a target for annotations on the type in a local variable declared * as a resource in a try-with-resources statement} * @param table the list of local variable targets + * @throws IllegalArgumentException if the size of the list of targets + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static LocalVarTarget ofResourceVariable(List table) { return ofVariable(TargetType.RESOURCE_VARIABLE, table); @@ -802,7 +810,6 @@ public sealed interface TypeAnnotation */ Label startLabel(); - /** * The given local variable has a value at indices into the code array in the interval * [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java index 49168ed99f8..45af5c20c0c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeTableAttribute.java @@ -88,6 +88,8 @@ public sealed interface CharacterRangeTableAttribute * {@link CodeBuilder#characterRange CodeBuilder::characterRange} instead. * * @param ranges the descriptions of the character ranges + * @throws IllegalArgumentException if the number of ranges exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static CharacterRangeTableAttribute of(List ranges) { return new UnboundAttribute.UnboundCharacterRangeTableAttribute(ranges); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java index acfd8bcca94..260cbe223e2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java @@ -77,6 +77,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute of(List exceptions) { return new UnboundAttribute.UnboundExceptionsAttribute(exceptions); @@ -85,6 +87,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute of(ClassEntry... exceptions) { return of(List.of(exceptions)); @@ -93,6 +97,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute ofSymbols(List exceptions) { return of(Util.entryList(exceptions)); @@ -101,6 +107,8 @@ public sealed interface ExceptionsAttribute /** * {@return an {@code Exceptions} attribute} * @param exceptions the exceptions that may be thrown from this method + * @throws IllegalArgumentException if the number of exceptions exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ExceptionsAttribute ofSymbols(ClassDesc... exceptions) { return ofSymbols(Arrays.asList(exceptions)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java index b50b38d0a00..a9e8e67805d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java @@ -65,6 +65,8 @@ public sealed interface InnerClassesAttribute /** * {@return an {@code InnerClasses} attribute} * @param innerClasses descriptions of the nested classes + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static InnerClassesAttribute of(List innerClasses) { return new UnboundAttribute.UnboundInnerClassesAttribute(innerClasses); @@ -73,6 +75,8 @@ public sealed interface InnerClassesAttribute /** * {@return an {@code InnerClasses} attribute} * @param innerClasses descriptions of the nested classes + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static InnerClassesAttribute of(InnerClassInfo... innerClasses) { return new UnboundAttribute.UnboundInnerClassesAttribute(List.of(innerClasses)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java index bb08beacaa2..0bcac754677 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java @@ -79,6 +79,8 @@ public sealed interface LineNumberTableAttribute * order instead. * * @param lines the line number descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LineNumberTableAttribute of(List lines) { return new UnboundAttribute.UnboundLineNumberTableAttribute(lines); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java index 6c1795e17bf..ad01a5c13ac 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java @@ -83,6 +83,8 @@ public sealed interface LocalVariableTableAttribute * {@link CodeBuilder#localVariable CodeBuilder::localVariable} instead. * * @param locals the local variable descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LocalVariableTableAttribute of(List locals) { return new UnboundAttribute.UnboundLocalVariableTableAttribute(locals); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java index b4bc80cdca1..180d30c321e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -79,6 +79,8 @@ public sealed interface LocalVariableTypeTableAttribute /** * {@return a {@code LocalVariableTypeTable} attribute} * @param locals the local variable descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static LocalVariableTypeTableAttribute of(List locals) { return new UnboundAttribute.UnboundLocalVariableTypeTableAttribute(locals); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java index 8cf6d7b6319..c86a0700204 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java @@ -68,6 +68,8 @@ public sealed interface MethodParametersAttribute /** * {@return a {@code MethodParameters} attribute} * @param parameters the method parameter descriptions + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1} */ static MethodParametersAttribute of(List parameters) { return new UnboundAttribute.UnboundMethodParametersAttribute(parameters); @@ -76,6 +78,8 @@ public sealed interface MethodParametersAttribute /** * {@return a {@code MethodParameters} attribute} * @param parameters the method parameter descriptions + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1} */ static MethodParametersAttribute of(MethodParameterInfo... parameters) { return of(List.of(parameters)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 678c0f29714..874a3eae4f2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -171,7 +171,8 @@ public sealed interface ModuleAttribute * @param uses the consumed services * @param provides the provided services * @throws IllegalArgumentException if {@code moduleFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or any of the collections has a size + * over the limit of {@link java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleEntry moduleName, int moduleFlags, Utf8Entry moduleVersion, @@ -188,6 +189,9 @@ public sealed interface ModuleAttribute * * @param moduleName the module name * @param attrHandler a handler that receives a {@link ModuleAttributeBuilder} + * @throws IllegalArgumentException if the information from the handler exceeds + * the {@code class} file format limit, such as a list with size + * over the limit of {@link java.lang.classfile##u2 u2} */ static ModuleAttribute of(ModuleDesc moduleName, Consumer attrHandler) { @@ -296,6 +300,8 @@ public sealed interface ModuleAttribute * @param exportsFlagsMask the export flags * @param exportsToModules the modules to export to, or empty for an unqualified export * @return this builder + * @throws IllegalArgumentException if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ ModuleAttributeBuilder exports(PackageDesc pkge, int exportsFlagsMask, ModuleDesc... exportsToModules); @@ -307,7 +313,9 @@ public sealed interface ModuleAttribute * @param exportsToModules the modules to export to, or empty for an unqualified export * @return this builder * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location or the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ default ModuleAttributeBuilder exports(PackageDesc pkge, Collection exportsFlags, ModuleDesc... exportsToModules) { return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules); @@ -333,6 +341,8 @@ public sealed interface ModuleAttribute * @param opensFlagsMask the open package flags * @param opensToModules the modules to open to, or empty for an unqualified open * @return this builder + * @throws IllegalArgumentException if the number of modules exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ ModuleAttributeBuilder opens(PackageDesc pkge, int opensFlagsMask, ModuleDesc... opensToModules); @@ -349,7 +359,9 @@ public sealed interface ModuleAttribute * @param opensToModules the modules to open to, or empty for an unqualified open * @return this builder * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection opensFlags, ModuleDesc... opensToModules) { return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules); @@ -391,7 +403,10 @@ public sealed interface ModuleAttribute * @param service the service class provided * @param implClasses the implementation classes * @return this builder - * @throws IllegalArgumentException if {@code service} or any of the {@code implClasses} represents a primitive type + * @throws IllegalArgumentException if {@code service} or any of the + * {@code implClasses} represents a primitive type, or the + * number of implementations exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index af04c83d260..09751817316 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -104,7 +104,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, List exportsTo) { @@ -119,7 +120,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, List exportsTo) { @@ -134,7 +137,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, int exportFlags, @@ -150,7 +154,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, @@ -166,7 +172,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, List exportsTo) { @@ -183,7 +190,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, List exportsTo) { @@ -198,7 +207,8 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if {@code exportFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, int exportFlags, @@ -214,7 +224,9 @@ public sealed interface ModuleExportInfo * @param exportsTo the modules to which this package is exported, or empty * if this is an unqualified export * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_EXPORTS} location + * {@link AccessFlag.Location#MODULE_EXPORTS} location, or if the + * number of modules exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java index 11c016aa9e1..30951753529 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleHashesAttribute.java @@ -96,6 +96,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(String algorithm, List hashes) { @@ -106,6 +108,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(String algorithm, ModuleHashInfo... hashes) { @@ -116,6 +120,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(Utf8Entry algorithm, List hashes) { @@ -126,6 +132,8 @@ public sealed interface ModuleHashesAttribute * {@return a {@code ModuleHashes} attribute} * @param algorithm the hashing algorithm * @param hashes the hash descriptions + * @throws IllegalArgumentException if the number of descriptions exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleHashesAttribute of(Utf8Entry algorithm, ModuleHashInfo... hashes) { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index 40a9b929776..3bccabcc907 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -110,7 +110,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, List opensTo) { @@ -125,7 +126,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, List opensTo) { @@ -140,7 +142,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, @@ -156,7 +159,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, @@ -171,7 +175,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, List opensTo) { @@ -187,7 +192,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the modules to which this package is opened, if it is a * qualified open, or empty * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, List opensTo) { @@ -201,7 +207,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if {@code opensFlags} is not {@link - * java.lang.classfile##u2 u2} + * java.lang.classfile##u2 u2} or if the number of modules exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, @@ -216,7 +223,8 @@ public sealed interface ModuleOpenInfo * @param opensTo the packages to which this package is opened, or empty if * this is an unqualified open * @throws IllegalArgumentException if any flag cannot be applied to the - * {@link AccessFlag.Location#MODULE_OPENS} location + * {@link AccessFlag.Location#MODULE_OPENS} location, or the number + * of modules exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java index 24a9218c9fd..147e3ec9d1f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java @@ -74,6 +74,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute of(List packages) { return new UnboundAttribute.UnboundModulePackagesAttribute(packages); @@ -82,6 +84,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute of(PackageEntry... packages) { return of(List.of(packages)); @@ -90,6 +94,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute ofNames(List packages) { var p = new PackageEntry[packages.size()]; @@ -102,6 +108,8 @@ public sealed interface ModulePackagesAttribute /** * {@return a {@code ModulePackages} attribute} * @param packages the packages + * @throws IllegalArgumentException if the number of packages exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static ModulePackagesAttribute ofNames(PackageDesc... packages) { // List view, since ref to packages is temporary diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java index 76dc88c50f7..c3707597b53 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleProvideInfo.java @@ -64,6 +64,8 @@ public sealed interface ModuleProvideInfo * {@return a service provision description} * @param provides the service class interface * @param providesWith the service class implementations, must not be empty + * @throws IllegalArgumentException if the number of implementations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassEntry provides, List providesWith) { @@ -74,6 +76,8 @@ public sealed interface ModuleProvideInfo * {@return a service provision description} * @param provides the service class interface * @param providesWith the service class implementations, must not be empty + * @throws IllegalArgumentException if the number of implementations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassEntry provides, ClassEntry... providesWith) { @@ -85,7 +89,8 @@ public sealed interface ModuleProvideInfo * @param provides the service class interface * @param providesWith the service class implementations, must not be empty * @throws IllegalArgumentException if {@code provides} or any of {@code - * providesWith} represents a primitive type + * providesWith} represents a primitive type, or the number of + * implementations exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassDesc provides, List providesWith) { @@ -97,7 +102,8 @@ public sealed interface ModuleProvideInfo * @param provides the service class interface * @param providesWith the service class implementations, must not be empty * @throws IllegalArgumentException if {@code provides} or any of {@code - * providesWith} represents a primitive type + * providesWith} represents a primitive type, or the number of + * implementations exceeds the limit of {@link java.lang.classfile##u2 u2} */ static ModuleProvideInfo of(ClassDesc provides, ClassDesc... providesWith) { diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java index baab955221c..244b7e67bcd 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java @@ -72,6 +72,8 @@ public sealed interface NestMembersAttribute extends Attribute nestMembers) { return new UnboundAttribute.UnboundNestMembersAttribute(nestMembers); @@ -81,6 +83,8 @@ public sealed interface NestMembersAttribute extends Attribute nestMembers) { return of(Util.entryList(nestMembers)); @@ -100,7 +106,9 @@ public sealed interface NestMembersAttribute extends Attribute permittedSubclasses) { return new UnboundAttribute.UnboundPermittedSubclassesAttribute(permittedSubclasses); @@ -86,6 +88,8 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces + * @throws IllegalArgumentException if the number of permitted subclasses + * or subinterfaces exceeds the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute of(ClassEntry... permittedSubclasses) { return of(List.of(permittedSubclasses)); @@ -95,7 +99,9 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces - * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive + * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive, + * or if the number of permitted subclasses or subinterfaces exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute ofSymbols(List permittedSubclasses) { return of(Util.entryList(permittedSubclasses)); @@ -105,7 +111,9 @@ public sealed interface PermittedSubclassesAttribute * {@return a {@code PermittedSubclasses} attribute} * * @param permittedSubclasses the permitted subclasses or subinterfaces - * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive + * @throws IllegalArgumentException if any of {@code permittedSubclasses} is primitive, + * or if the number of permitted subclasses or subinterfaces exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static PermittedSubclassesAttribute ofSymbols(ClassDesc... permittedSubclasses) { // List version does defensive copy diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java index 8f55b3a1cf9..f01765991d2 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java @@ -68,6 +68,8 @@ public sealed interface RecordAttribute extends Attribute, Clas * {@return a {@code Record} attribute} * * @param components the record components + * @throws IllegalArgumentException if the number of record components + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static RecordAttribute of(List components) { return new UnboundAttribute.UnboundRecordAttribute(components); @@ -77,6 +79,8 @@ public sealed interface RecordAttribute extends Attribute, Clas * {@return a {@code Record} attribute} * * @param components the record components + * @throws IllegalArgumentException if the number of record components + * exceeds the limit of {@link java.lang.classfile##u2 u2} */ static RecordAttribute of(RecordComponentInfo... components) { return of(List.of(components)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java index f3c74f066cf..23fb229ffd0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordComponentInfo.java @@ -90,6 +90,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component field descriptor string * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(Utf8Entry name, Utf8Entry descriptor, @@ -103,6 +105,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component field descriptor sting * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(Utf8Entry name, Utf8Entry descriptor, @@ -116,6 +120,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component symbolic field descriptor * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(String name, ClassDesc descriptor, @@ -131,6 +137,8 @@ public sealed interface RecordComponentInfo * @param name the component name * @param descriptor the component symbolic field descriptor * @param attributes the component attributes + * @throws IllegalArgumentException if the number of attributes exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RecordComponentInfo of(String name, ClassDesc descriptor, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index da453ad4f5e..8a1e14280d3 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -73,6 +73,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute * {@return a {@code RuntimeInvisibleAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeInvisibleAnnotationsAttribute(annotations); @@ -82,6 +84,8 @@ public sealed interface RuntimeInvisibleAnnotationsAttribute * {@return a {@code RuntimeInvisibleAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds + * the limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleAnnotationsAttribute of(Annotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index 2051cd5dcdf..a721b9c1f9f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -86,6 +86,10 @@ public sealed interface RuntimeInvisibleParameterAnnotationsAttribute * some synthetic or implicit parameters. * * @param parameterAnnotations a list of run-time invisible annotations for each parameter + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1}, or the number of + * annotations on any parameter exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static RuntimeInvisibleParameterAnnotationsAttribute of(List> parameterAnnotations) { return new UnboundAttribute.UnboundRuntimeInvisibleParameterAnnotationsAttribute(parameterAnnotations); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index 3ff1a643a82..15c90527c6a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -79,6 +79,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute * {@return a {@code RuntimeInvisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleTypeAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeInvisibleTypeAnnotationsAttribute(annotations); @@ -88,6 +90,8 @@ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute * {@return a {@code RuntimeInvisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeInvisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index ceabe2131af..db9cb96f4e0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -72,6 +72,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute /** * {@return a {@code RuntimeVisibleAnnotations} attribute} * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeVisibleAnnotationsAttribute(annotations); @@ -80,6 +82,8 @@ public sealed interface RuntimeVisibleAnnotationsAttribute /** * {@return a {@code RuntimeVisibleAnnotations} attribute} * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleAnnotationsAttribute of(Annotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 2cf462d246c..4585efe5c65 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -88,6 +88,10 @@ public sealed interface RuntimeVisibleParameterAnnotationsAttribute * some synthetic or implicit parameters. * * @param parameterAnnotations a list of run-time visible annotations for each parameter + * @throws IllegalArgumentException if the number of parameters exceeds the + * limit of {@link java.lang.classfile##u1 u1}, or the number of + * annotations on any parameter exceeds the limit of {@link + * java.lang.classfile##u2 u2} */ static RuntimeVisibleParameterAnnotationsAttribute of(List> parameterAnnotations) { return new UnboundAttribute.UnboundRuntimeVisibleParameterAnnotationsAttribute(parameterAnnotations); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index ad4595ffb6b..0476dc60b82 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -79,6 +79,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute * {@return a {@code RuntimeVisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleTypeAnnotationsAttribute of(List annotations) { return new UnboundAttribute.UnboundRuntimeVisibleTypeAnnotationsAttribute(annotations); @@ -88,6 +90,8 @@ public sealed interface RuntimeVisibleTypeAnnotationsAttribute * {@return a {@code RuntimeVisibleTypeAnnotations} attribute} * * @param annotations the annotations + * @throws IllegalArgumentException if the number of annotations exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ static RuntimeVisibleTypeAnnotationsAttribute of(TypeAnnotation... annotations) { return of(List.of(annotations)); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 71d5ccc79a4..06e9e6d585e 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -83,6 +83,8 @@ public sealed interface StackMapFrameInfo * @param target the location of the frame * @param locals the complete list of frame locals * @param stack the complete frame stack + * @throws IllegalArgumentException if the number of types in {@code locals} + * or {@code stack} exceeds the limit of {@link java.lang.classfile##u2 u2} */ public static StackMapFrameInfo of(Label target, List locals, diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java index e9b3acbff5b..f30e8cb01a7 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java @@ -75,6 +75,8 @@ public sealed interface StackMapTableAttribute * {@return a stack map table attribute} * * @param entries the stack map frames + * @throws IllegalArgumentException if the number of frames exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ public static StackMapTableAttribute of(List entries) { return new UnboundAttribute.UnboundStackMapTableAttribute(entries); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index 7d3f3c546a7..d10ff70120c 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -571,6 +571,8 @@ public sealed interface ConstantPoolBuilder * * @param methodReference the bootstrap method * @param arguments the arguments + * @throws IllegalArgumentException if the number of arguments exceeds the + * limit of {@link java.lang.classfile##u2 u2} */ default BootstrapMethodEntry bsmEntry(DirectMethodHandleDesc methodReference, List arguments) { @@ -586,6 +588,8 @@ public sealed interface ConstantPoolBuilder * * @param methodReference the {@code MethodHandleEntry} * @param arguments the list of {@code LoadableConstantEntry} + * @throws IllegalArgumentException if the number of arguments exceeds the + * limit of {@link java.lang.classfile##u2 u2} * @see BootstrapMethodEntry#bootstrapMethod() * BootstrapMethodEntry::bootstrapMethod * @see BootstrapMethodEntry#arguments() BootstrapMethodEntry::arguments diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java index 81a4e973d3f..1c87ff87a4d 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/Utf8Entry.java @@ -54,7 +54,8 @@ import jdk.internal.classfile.impl.AbstractPoolEntry; * Unlike most constant pool entries, a UTF-8 entry is of flexible length: it is * represented as an array structure, with an {@code u2} for the data length in * bytes, followed by that number of bytes of Modified UTF-8 data. It can - * represent at most 65535 bytes of data due to the physical restrictions. + * represent at most 65535 bytes of data due to the physical restrictions of + * {@link java.lang.classfile##u2 u2}. * * @jvms 4.4.7 The {@code CONSTANT_Utf8_info} Structure * @see DataInput##modified-utf-8 Modified UTF-8 diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index 5d905aace65..da9ad7fbf0d 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -255,7 +255,7 @@ * or method of any Class-File API class or interface will cause a {@link * NullPointerException} to be thrown. Additionally, * invoking a method with an array or collection containing a {@code null} element - * will cause a {@code NullPointerException}, unless otherwise specified.

            + * will cause a {@code NullPointerException}, unless otherwise specified. * *

            Symbolic information

            * To describe symbolic information for classes and types, the API uses the diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index b75cf100a1b..6543b4e5079 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -40,7 +40,7 @@ public record AnnotationImpl(Utf8Entry className, List elemen implements Annotation { public AnnotationImpl { requireNonNull(className); - elements = List.copyOf(elements); + elements = Util.sanitizeU2List(elements); } @Override @@ -189,7 +189,7 @@ public record AnnotationImpl(Utf8Entry className, List elemen public record OfArrayImpl(List values) implements AnnotationValue.OfArray { public OfArrayImpl { - values = List.copyOf(values); + values = Util.sanitizeU2List(values); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java index fffb963eab3..d5437bc3a2c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -66,6 +66,7 @@ public class AttributeHolder { public void writeTo(BufWriterImpl buf) { int attributesCount = this.attributesCount; + Util.checkU2(attributesCount, "attributes count"); buf.writeU2(attributesCount); for (int i = 0; i < attributesCount; i++) { Util.writeAttribute(buf, attributes[i]); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java index ed36b5ce172..9919d8a1697 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -41,13 +41,13 @@ public final class BootstrapMethodEntryImpl implements BootstrapMethodEntry { private final List arguments; BootstrapMethodEntryImpl(ConstantPool constantPool, int bsmIndex, int hash, - MethodHandleEntryImpl handle, - List arguments) { + MethodHandleEntryImpl handle, + List arguments) { this.index = bsmIndex; this.hash = hash; this.constantPool = constantPool; this.handle = handle; - this.arguments = List.copyOf(arguments); + this.arguments = Util.sanitizeU2List(arguments); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 40c5b1172b5..dda9accd8b9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -276,9 +276,7 @@ public final class BufWriterImpl implements BufWriter { int strlen = str.length(); int countNonZeroAscii = JLA.countNonZeroAscii(str); int utflen = utfLen(str, countNonZeroAscii); - if (utflen > 65535) { - throw new IllegalArgumentException("string too long"); - } + Util.checkU2(utflen, "utf8 length"); reserveSpace(utflen + 3); int offset = this.offset; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 0ed4a3a9418..5bdbb571b68 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -185,14 +185,14 @@ public final class DirectCodeBuilder private void writeExceptionHandlers(BufWriterImpl buf) { int pos = buf.size(); int handlersSize = handlers.size(); + Util.checkU2(handlersSize, "exception handlers"); buf.writeU2(handlersSize); if (handlersSize > 0) { - writeExceptionHandlers(buf, pos); + writeExceptionHandlers(buf, pos, handlersSize); } } - private void writeExceptionHandlers(BufWriterImpl buf, int pos) { - int handlersSize = handlers.size(); + private void writeExceptionHandlers(BufWriterImpl buf, int pos, int handlersSize) { for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { int startPc = labelToBci(h.tryStart()); int endPc = labelToBci(h.tryEnd()); @@ -227,6 +227,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int crSize = characterRangesCount; + Util.checkU2(crSize, "character range count"); b.writeU2(crSize); for (int i = 0; i < characterRangesCount; i++) { CharacterRange cr = characterRanges[i]; @@ -262,6 +263,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvSize = localVariablesCount; + Util.checkU2(lvSize, "local variable count"); b.writeU2(lvSize); for (int i = 0; i < localVariablesCount; i++) { LocalVariable l = localVariables[i]; @@ -291,6 +293,7 @@ public final class DirectCodeBuilder public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvtSize = localVariableTypesCount; + Util.checkU2(lvtSize, "local variable type count"); b.writeU2(lvtSize); for (int i = 0; i < localVariableTypesCount; i++) { LocalVariableType l = localVariableTypes[i]; @@ -441,7 +444,7 @@ public final class DirectCodeBuilder b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE)); push(); b.writeInt(buf.size() + 2); - b.writeU2(buf.size() / 4); + b.writeU2(Util.checkU2(buf.size() / 4, "line number count")); b.writeBytes(buf); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java index d27b5e20ab4..79c84e4e66f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -35,7 +35,7 @@ public final class InterfacesImpl private final List interfaces; public InterfacesImpl(List interfaces) { - this.interfaces = List.copyOf(interfaces); + this.interfaces = Util.sanitizeU2List(interfaces); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index d9ca3ff61bc..a82a9577225 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -129,6 +129,7 @@ public final class SplitConstantPool implements ConstantPoolBuilder { if (bsmSize == 0) return false; int pos = buf.size(); + Util.checkU2(bsmSize, "num bootstrap methods"); if (parent != null && parentBsmSize != 0) { parent.writeBootstrapMethods(buf); for (int i = parentBsmSize; i < bsmSize; i++) @@ -160,15 +161,14 @@ public final class SplitConstantPool implements ConstantPoolBuilder { void writeTo(BufWriterImpl buf) { int writeFrom = 1; - if (size() >= 65536) { - throw new IllegalArgumentException(String.format("Constant pool is too large %d", size())); - } - buf.writeU2(size()); + int mySize = size(); + Util.checkU2(mySize, "constant pool count"); + buf.writeU2(mySize); if (parent != null && buf.constantPool().canWriteDirect(this)) { parent.writeConstantPoolEntries(buf); writeFrom = parent.size(); } - for (int i = writeFrom; i < size(); ) { + for (int i = writeFrom; i < mySize; ) { var info = (AbstractPoolEntry) entryByIndex(i); info.writeTo(buf); i += info.width(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index f8e58ed2242..c5ce2204c09 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -303,8 +303,8 @@ public class StackMapDecoder { implements StackMapFrameInfo { public StackMapFrameImpl { requireNonNull(target); - locals = List.copyOf(locals); - stack = List.copyOf(stack); + locals = Util.sanitizeU2List(locals); + stack = Util.sanitizeU2List(stack); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index a0afb5efae1..62f0e2eab16 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -108,7 +108,7 @@ public final class TargetInfoImpl { public LocalVarTargetImpl(TargetType targetType, List table) { this.targetType = checkValid(targetType, TARGET_LOCAL_VARIABLE, TARGET_RESOURCE_VARIABLE); - this.table = List.copyOf(table); + this.table = Util.sanitizeU2List(table); } @Override public int size() { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 347b0c12657..94ba782d808 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -174,7 +174,7 @@ public abstract sealed class UnboundAttribute> public UnboundExceptionsAttribute(List exceptions) { super(Attributes.exceptions()); - this.exceptions = List.copyOf(exceptions); + this.exceptions = Util.sanitizeU2List(exceptions); } @Override @@ -244,7 +244,7 @@ public abstract sealed class UnboundAttribute> public UnboundStackMapTableAttribute(List entries) { super(Attributes.stackMapTable()); - this.entries = List.copyOf(entries); + this.entries = Util.sanitizeU2List(entries); } @Override @@ -268,7 +268,7 @@ public abstract sealed class UnboundAttribute> public UnboundInnerClassesAttribute(List innerClasses) { super(Attributes.innerClasses()); - this.innerClasses = List.copyOf(innerClasses); + this.innerClasses = Util.sanitizeU2List(innerClasses); } @Override @@ -292,7 +292,7 @@ public abstract sealed class UnboundAttribute> public UnboundRecordAttribute(List components) { super(Attributes.record()); - this.components = List.copyOf(components); + this.components = Util.sanitizeU2List(components); } @Override @@ -347,7 +347,7 @@ public abstract sealed class UnboundAttribute> public UnboundMethodParametersAttribute(List parameters) { super(Attributes.methodParameters()); - this.parameters = List.copyOf(parameters); + this.parameters = Util.sanitizeU1List(parameters); } @Override @@ -421,7 +421,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleHashesAttribute(Utf8Entry algorithm, List hashes) { super(Attributes.moduleHashes()); this.algorithm = requireNonNull(algorithm); - this.hashes = List.copyOf(hashes); + this.hashes = Util.sanitizeU2List(hashes); } @Override @@ -446,16 +446,16 @@ public abstract sealed class UnboundAttribute> private static final Utf8Entry NAME = TemporaryConstantPool.INSTANCE.utf8Entry(Attributes.NAME_MODULE_PACKAGES); - private final Collection packages; + private final List packages; public UnboundModulePackagesAttribute(Collection packages) { super(Attributes.modulePackages()); - this.packages = List.copyOf(packages); + this.packages = Util.sanitizeU2List(packages); } @Override public List packages() { - return List.copyOf(packages); + return packages; } @Override @@ -498,7 +498,7 @@ public abstract sealed class UnboundAttribute> public UnboundPermittedSubclassesAttribute(List permittedSubclasses) { super(Attributes.permittedSubclasses()); - this.permittedSubclasses = List.copyOf(permittedSubclasses); + this.permittedSubclasses = Util.sanitizeU2List(permittedSubclasses); } @Override @@ -522,7 +522,7 @@ public abstract sealed class UnboundAttribute> public UnboundNestMembersAttribute(List memberEntries) { super(Attributes.nestMembers()); - this.memberEntries = List.copyOf(memberEntries); + this.memberEntries = Util.sanitizeU2List(memberEntries); } @Override @@ -642,7 +642,7 @@ public abstract sealed class UnboundAttribute> public UnboundCharacterRangeTableAttribute(List ranges) { super(Attributes.characterRangeTable()); - this.ranges = List.copyOf(ranges); + this.ranges = Util.sanitizeU2List(ranges); } @Override @@ -666,7 +666,7 @@ public abstract sealed class UnboundAttribute> public UnboundLineNumberTableAttribute(List lines) { super(Attributes.lineNumberTable()); - this.lines = List.copyOf(lines); + this.lines = Util.sanitizeU2List(lines); } @Override @@ -690,7 +690,7 @@ public abstract sealed class UnboundAttribute> public UnboundLocalVariableTableAttribute(List locals) { super(Attributes.localVariableTable()); - this.locals = List.copyOf(locals); + this.locals = Util.sanitizeU2List(locals); } @Override @@ -714,7 +714,7 @@ public abstract sealed class UnboundAttribute> public UnboundLocalVariableTypeTableAttribute(List locals) { super(Attributes.localVariableTypeTable()); - this.locals = List.copyOf(locals); + this.locals = Util.sanitizeU2List(locals); } @Override @@ -738,7 +738,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleAnnotationsAttribute(List elements) { super(Attributes.runtimeVisibleAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -762,7 +762,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleAnnotationsAttribute(List elements) { super(Attributes.runtimeInvisibleAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -786,13 +786,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeVisibleParameterAnnotations()); - // deep copy - var array = elements.toArray().clone(); - for (int i = 0; i < array.length; i++) { - array[i] = List.copyOf((List) array[i]); - } - - this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + this.elements = Util.sanitizeParameterAnnotations(elements); } @Override @@ -816,13 +810,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeInvisibleParameterAnnotations()); - // deep copy - var array = elements.toArray().clone(); - for (int i = 0; i < array.length; i++) { - array[i] = List.copyOf((List) array[i]); - } - - this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + this.elements = Util.sanitizeParameterAnnotations(elements); } @Override @@ -846,7 +834,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeVisibleTypeAnnotationsAttribute(List elements) { super(Attributes.runtimeVisibleTypeAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -870,7 +858,7 @@ public abstract sealed class UnboundAttribute> public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List elements) { super(Attributes.runtimeInvisibleTypeAnnotations()); - this.elements = List.copyOf(elements); + this.elements = Util.sanitizeU2List(elements); } @Override @@ -955,7 +943,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleExportInfo { requireNonNull(exportedPackage); Util.checkFlags(exportsFlagsMask); - exportsTo = List.copyOf(exportsTo); + exportsTo = Util.sanitizeU2List(exportsTo); } } @@ -973,7 +961,7 @@ public abstract sealed class UnboundAttribute> public UnboundModuleOpenInfo { requireNonNull(openedPackage); Util.checkFlags(opensFlagsMask); - opensTo = List.copyOf(opensTo); + opensTo = Util.sanitizeU2List(opensTo); } } @@ -982,7 +970,7 @@ public abstract sealed class UnboundAttribute> implements ModuleProvideInfo { public UnboundModuleProvideInfo { requireNonNull(provides); - providesWith = List.copyOf(providesWith); + providesWith = Util.sanitizeU2List(providesWith); } } @@ -1003,7 +991,7 @@ public abstract sealed class UnboundAttribute> public UnboundRecordComponentInfo { requireNonNull(name); requireNonNull(descriptor); - attributes = List.copyOf(attributes); + attributes = Util.sanitizeU2List(attributes); } } @@ -1013,7 +1001,7 @@ public abstract sealed class UnboundAttribute> public UnboundTypeAnnotation { requireNonNull(targetInfo); - targetPath = List.copyOf(targetPath); + targetPath = Util.sanitizeU1List(targetPath); requireNonNull(annotation); } } @@ -1047,11 +1035,11 @@ public abstract sealed class UnboundAttribute> this.moduleName = requireNonNull(moduleName); this.moduleFlags = Util.checkFlags(moduleFlags); this.moduleVersion = moduleVersion; - this.requires = List.copyOf(requires); - this.exports = List.copyOf(exports); - this.opens = List.copyOf(opens); - this.uses = List.copyOf(uses); - this.provides = List.copyOf(provides); + this.requires = Util.sanitizeU2List(requires); + this.exports = Util.sanitizeU2List(exports); + this.opens = Util.sanitizeU2List(opens); + this.uses = Util.sanitizeU2List(uses); + this.provides = Util.sanitizeU2List(provides); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 0eea2bffd22..7e6384dd1a4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -146,6 +146,33 @@ public final class Util { : ClassDesc.ofInternalName(classInternalNameOrArrayDesc); } + /// Sanitizes an input list to make it immutable, and verify its size can + /// be represented with U1, throwing IAE otherwise. + public static List sanitizeU1List(List input) { + var copy = List.copyOf(input); + checkU1(copy.size(), "list size"); + return copy; + } + + /// Sanitizes an input list to make it immutable, and verify its size can + /// be represented with U2, throwing IAE otherwise. + public static List sanitizeU2List(Collection input) { + var copy = List.copyOf(input); + checkU2(copy.size(), "list size"); + return copy; + } + + /// Sanitizes an input nested list of parameter annotations. + public static List> sanitizeParameterAnnotations(List> input) { + var array = input.toArray().clone(); + checkU1(array.length, "parameter count"); + for (int i = 0; i < array.length; i++) { + array[i] = sanitizeU2List((List) array[i]); + } + + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); + } + public static List mappedList(List list, Function mapper) { return new AbstractList<>() { @Override @@ -259,6 +286,7 @@ public final class Util { @ForceInline public static void writeAttributes(BufWriterImpl buf, List> list) { int size = list.size(); + Util.checkU2(size, "attributes count"); buf.writeU2(size); for (int i = 0; i < size; i++) { writeAttribute(buf, list.get(i)); @@ -267,6 +295,7 @@ public final class Util { @ForceInline static void writeList(BufWriterImpl buf, Writable[] array, int size) { + Util.checkU2(size, "member count"); buf.writeU2(size); for (int i = 0; i < size; i++) { array[i].writeTo(buf); diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index 6f3dc04c665..0b347c835db 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -23,17 +23,22 @@ /* * @test - * @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833 + * @bug 8320360 8330684 8331320 8331655 8331940 8332486 8335820 8336833 8361635 * @summary Testing ClassFile limits. * @run junit LimitsTest */ + +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.AttributedElement; import java.lang.classfile.Attributes; -import java.lang.classfile.constantpool.PoolEntry; -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassReader; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.Label; import java.lang.classfile.Opcode; +import java.lang.classfile.Signature; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.attribute.LineNumberTableAttribute; @@ -41,8 +46,16 @@ import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.ConstantPoolException; import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectCodeBuilder; @@ -51,6 +64,8 @@ import jdk.internal.classfile.impl.LabelContext; import jdk.internal.classfile.impl.UnboundAttribute; import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.*; import static org.junit.jupiter.api.Assertions.*; class LimitsTest { @@ -73,6 +88,114 @@ class LimitsTest { })); } + @Test + void testBsmOverLimit() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + var cp = clb.constantPool(); + var mhe = cp.methodHandleEntry(BSM_GET_STATIC_FINAL); + var digits = new IntegerEntry[10]; + for (int i = 0; i < 10; i++) { + digits[i] = cp.intEntry(i); + } + int lastIndex = -1; + for (int i = 0; i < 66000; i++) { + lastIndex = cp.bsmEntry(mhe, List.of( + digits[i / 10000 % 10], + digits[i / 1000 % 10], + digits[i / 100 % 10], + digits[i / 10 % 10], + digits[i / 1 % 10])).bsmIndex(); + } + assertEquals(65999, lastIndex); + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyFields() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.withField("f", CD_int, 0); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyMethods() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.withMethodBody("m", MTD_void, 0, CodeBuilder::return_); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + static final class MyAttribute extends CustomAttribute { + static final MyAttribute INSTANCE = new MyAttribute(); + + private enum Mapper implements AttributeMapper { + INSTANCE; + + @Override + public MyAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + throw new UnsupportedOperationException(); + } + + @Override + public void writeAttribute(BufWriter buf, MyAttribute attr) { + buf.writeIndex(buf.constantPool().utf8Entry("MyAttribute")); + buf.writeInt(0); + } + + @Override + public boolean allowMultiple() { + return true; + } + + @Override + public AttributeStability stability() { + return AttributeStability.STATELESS; + } + + + } + + private MyAttribute() { + super(Mapper.INSTANCE); + } + } + + @Test + void testTooManyClassAttributes() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + for (int i = 1; i < 66000; i++) { + clb.with(MyAttribute.INSTANCE); + } + reached.set(true); + })); + assertTrue(reached.get()); + } + + @Test + void testTooManyFieldAttributes() { + AtomicBoolean reached = new AtomicBoolean(); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withField("f", CD_int, fb -> { + for (int i = 1; i < 66000; i++) { + fb.with(MyAttribute.INSTANCE); + } + reached.set(true); + }))); + assertTrue(reached.get()); + } + @Test void testCodeOverLimit() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(ClassDesc.of("BigClass"), cb -> cb.withMethodBody( @@ -99,6 +222,91 @@ class LimitsTest { assertThrows(IllegalArgumentException.class, () -> lc.getLabel(10)); } + private static void testPseudoOverflow(BiConsumer handler) { + ClassFile cf = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS); + AtomicBoolean reached = new AtomicBoolean(false); + assertDoesNotThrow(() -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + cob.nop(); + var label = cob.newLabel(); + for (int i = 0; i < 65535; i++) { + handler.accept(cob, label); + } + cob.labelBinding(label); + cob.return_(); + reached.set(true); + }))); + assertTrue(reached.get()); + + reached.set(false); + assertThrows(IllegalArgumentException.class, () -> cf.build(CD_Void, cb -> cb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + cob.nop(); + var label = cob.newLabel(); + for (int i = 0; i < 65536; i++) { + handler.accept(cob, label); + } + cob.labelBinding(label); + cob.return_(); + reached.set(true); + }))); + assertTrue(reached.get()); + } + + @Test + void testExceptionCatchOverflow() { + testPseudoOverflow((cob, label) -> cob.exceptionCatch(cob.startLabel(), label, label, CD_Throwable)); + } + + @Test + void testLocalVariableOverflow() { + testPseudoOverflow((cob, label) -> cob.localVariable(0, "fake", CD_int, cob.startLabel(), label)); + } + + @Test + void testLocalVariableTypeOverflow() { + testPseudoOverflow((cob, label) -> cob.localVariableType(0, "fake", Signature.of(CD_int), cob.startLabel(), label)); + } + + @Test + void testCharacterRangeOverflow() { + testPseudoOverflow((cob, label) -> cob.characterRange(cob.startLabel(), label, 0, 0, 0)); + } + + // LineNumber deduplicates so cannot really overflow + + @Test + void testHugeLookupswitch() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + var l = cob.newLabel(); + // 10000 * 8 > 65535 + var cases = new ArrayList(10000); + for (int i = 0; i < 10000; i++) { + cases.add(SwitchCase.of(i, l)); + } + cob.lookupswitch(l, cases); + cob.labelBinding(l); + cob.return_(); + }))); + } + + @Test + void testHugeTableswitch() { + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> clb.withMethodBody("test", MTD_void, ACC_STATIC, cob -> { + var l = cob.newLabel(); + // 20000 * 4 > 65535 + cob.tableswitch(-10000, 10000, l, List.of()); + cob.labelBinding(l); + cob.return_(); + }))); + } + + @Test + void testHugeUtf8Entry() { + var longString = String.valueOf((char) 0x800).repeat(22000); + assertThrows(IllegalArgumentException.class, () -> ClassFile.of().build(CD_Void, clb -> { + clb.constantPool().utf8Entry(longString); + })); + } + @Test void testSupportedClassVersion() { var cf = ClassFile.of(); diff --git a/test/jdk/jdk/classfile/ListValidationTest.java b/test/jdk/jdk/classfile/ListValidationTest.java new file mode 100644 index 00000000000..831bff3a7b4 --- /dev/null +++ b/test/jdk/jdk/classfile/ListValidationTest.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8361635 + * @summary Testing list size validation in class file format. + * @run junit ListValidationTest + */ + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Interfaces; +import java.lang.classfile.Label; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.*; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; +import java.util.List; +import java.util.Optional; + +import jdk.internal.classfile.impl.TemporaryConstantPool; +import jdk.internal.classfile.impl.UnboundAttribute; +import org.junit.jupiter.api.Test; + +import static java.lang.constant.ConstantDescs.*; +import static java.util.Collections.nCopies; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ListValidationTest { + @Test + void testAnnotationElements() { + var e = AnnotationElement.ofInt("dummy", 0); + assertDoesNotThrow(() -> Annotation.of(CD_String, nCopies(65535, e))); + assertThrows(IllegalArgumentException.class, () -> Annotation.of(CD_String, nCopies(66000, e))); + } + + @Test + void testAnnotationArrayValue() { + var v = AnnotationValue.ofInt(0); + assertDoesNotThrow(() -> AnnotationValue.ofArray(nCopies(65535, v))); + assertThrows(IllegalArgumentException.class, () -> AnnotationValue.ofArray(nCopies(66000, v))); + } + + @Test + void testTypeAnnotationPath() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(255, TypeAnnotation.TypePathComponent.INNER_TYPE), anno)); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), nCopies(256, TypeAnnotation.TypePathComponent.INNER_TYPE), anno)); + } + + @Test + void testBsmArgs() { + var cpb = ConstantPoolBuilder.of(); + assertDoesNotThrow(() -> cpb.bsmEntry(BSM_INVOKE, nCopies(65535, 0))); + assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0))); + } + + @Test + void testInterfaces() { + var cpb = ConstantPoolBuilder.of(); + assertDoesNotThrow(() -> Interfaces.ofSymbols(nCopies(65535, CD_Number))); + assertThrows(IllegalArgumentException.class, () -> cpb.bsmEntry(BSM_INVOKE, nCopies(66000, 0))); + } + + @Test + void testStackMapFrame() { + Label label = dummyLabel(); + assertDoesNotThrow(() -> StackMapFrameInfo.of(label, + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label, + nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + assertThrows(IllegalArgumentException.class, () -> StackMapFrameInfo.of(label, + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(66000, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE))); + } + + @Test + void testTypeAnnotationLocalVarTarget() { + Label label = dummyLabel(); + assertDoesNotThrow(() -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(65535, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0)))); + assertThrows(IllegalArgumentException.class, () -> TypeAnnotation.TargetInfo.ofLocalVariable(nCopies(66000, TypeAnnotation.LocalVarTargetInfo.of(label, label, 0)))); + } + + @Test + void testExceptionsAttribute() { + assertDoesNotThrow(() -> ExceptionsAttribute.ofSymbols(nCopies(65535, CD_Throwable))); + assertThrows(IllegalArgumentException.class, () -> ExceptionsAttribute.ofSymbols(nCopies(66000, CD_Throwable))); + } + + @Test + void testStackMapTableAttribute() { + var frame = StackMapFrameInfo.of(dummyLabel(), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.INTEGER), + nCopies(65535, StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE)); + assertDoesNotThrow(() -> StackMapTableAttribute.of(nCopies(65535, frame))); + assertThrows(IllegalArgumentException.class, () -> StackMapTableAttribute.of(nCopies(66000, frame))); + } + + @Test + void testInnerClassesAttribute() { + var entry = InnerClassInfo.of(CD_Void, Optional.empty(), Optional.empty(), 0); + assertDoesNotThrow(() -> InnerClassesAttribute.of(nCopies(65535, entry))); + assertThrows(IllegalArgumentException.class, () -> InnerClassesAttribute.of(nCopies(66000, entry))); + } + + @Test + void testRecordAttribute() { + var component = RecordComponentInfo.of("hello", CD_int, List.of()); + assertDoesNotThrow(() -> RecordAttribute.of(nCopies(65535, component))); + assertThrows(IllegalArgumentException.class, () -> RecordAttribute.of(nCopies(66000, component))); + } + + @Test + void testMethodParametersAttribute() { + var component = MethodParameterInfo.of(Optional.empty(), 0); + assertDoesNotThrow(() -> MethodParametersAttribute.of(nCopies(255, component))); + assertThrows(IllegalArgumentException.class, () -> MethodParametersAttribute.of(nCopies(300, component))); + } + + @Test + void testModuleHashesAttribute() { + var hash = ModuleHashInfo.of(ModuleDesc.of("java.base"), new byte[0]); + assertDoesNotThrow(() -> ModuleHashesAttribute.of("dummy", nCopies(65535, hash))); + assertThrows(IllegalArgumentException.class, () -> ModuleHashesAttribute.of("dummy", nCopies(66000, hash))); + } + + @Test + void testModulePackagesAttribute() { + var pkgDesc = PackageDesc.of("java.io"); + assertDoesNotThrow(() -> ModulePackagesAttribute.ofNames(nCopies(65535, pkgDesc))); + assertThrows(IllegalArgumentException.class, () -> ModulePackagesAttribute.ofNames(nCopies(66000, pkgDesc))); + } + + @Test + void testPermittedSubclassesAttribute() { + assertDoesNotThrow(() -> PermittedSubclassesAttribute.ofSymbols(nCopies(65535, CD_Collection))); + assertThrows(IllegalArgumentException.class, () -> PermittedSubclassesAttribute.ofSymbols(nCopies(66000, CD_Collection))); + } + + @Test + void testNestMembersAttribute() { + assertDoesNotThrow(() -> NestMembersAttribute.ofSymbols(nCopies(65535, CD_Collection))); + assertThrows(IllegalArgumentException.class, () -> NestMembersAttribute.ofSymbols(nCopies(66000, CD_Collection))); + } + + @Test + void testCharacterRangeTableAttribute() { + var range = CharacterRangeInfo.of(0, 0, 0, 0, 0); + assertDoesNotThrow(() -> CharacterRangeTableAttribute.of(nCopies(65535, range))); + assertThrows(IllegalArgumentException.class, () -> CharacterRangeTableAttribute.of(nCopies(66000, range))); + } + + @Test + void testLineNumberTableAttribute() { + var lineNumber = LineNumberInfo.of(0, 0); + assertDoesNotThrow(() -> LineNumberTableAttribute.of(nCopies(65535, lineNumber))); + assertThrows(IllegalArgumentException.class, () -> LineNumberTableAttribute.of(nCopies(66000, lineNumber))); + } + + @Test + void testLocalVariableTableAttribute() { + var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy"); + var localVariable = new UnboundAttribute.UnboundLocalVariableInfo(0, 0, utf8, utf8, 0); + assertDoesNotThrow(() -> LocalVariableTableAttribute.of(nCopies(65535, localVariable))); + assertThrows(IllegalArgumentException.class, () -> LocalVariableTableAttribute.of(nCopies(66000, localVariable))); + } + + @Test + void testLocalVariableTypeTableAttribute() { + var utf8 = TemporaryConstantPool.INSTANCE.utf8Entry("dummy"); + var localVariableType = new UnboundAttribute.UnboundLocalVariableTypeInfo(0, 0, utf8, utf8, 0); + assertDoesNotThrow(() -> LocalVariableTypeTableAttribute.of(nCopies(65535, localVariableType))); + assertThrows(IllegalArgumentException.class, () -> LocalVariableTypeTableAttribute.of(nCopies(66000, localVariableType))); + } + + @Test + void testRuntimeVisibleAnnotationsAttribute() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeVisibleAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeInvisibleAnnotationsAttribute() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeVisibleParameterAnnotationsAttributeTopLevel() { + assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(255, List.of()))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(nCopies(256, List.of()))); + } + + @Test + void testRuntimeInvisibleParameterAnnotationsAttributeTopLevel() { + assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(255, List.of()))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(nCopies(256, List.of()))); + } + + @Test + void testRuntimeVisibleParameterAnnotationsAttributeNested() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno)))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno)))); + } + + @Test + void testRuntimeInvisibleParameterAnnotationsAttributeNested() { + var anno = Annotation.of(CD_String); + assertDoesNotThrow(() -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65535, anno)))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(nCopies(65536, anno)))); + } + + @Test + void testRuntimeVisibleTypeAnnotationsAttribute() { + var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String)); + assertDoesNotThrow(() -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeVisibleTypeAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testRuntimeInvisibleTypeAnnotationsAttribute() { + var anno = TypeAnnotation.of(TypeAnnotation.TargetInfo.ofMethodReturn(), List.of(), Annotation.of(CD_String)); + assertDoesNotThrow(() -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(65535, anno))); + assertThrows(IllegalArgumentException.class, () -> RuntimeInvisibleTypeAnnotationsAttribute.of(nCopies(66000, anno))); + } + + @Test + void testModuleExportEntry() { + var pkg = PackageDesc.of("dummy.test"); + var mod = ModuleDesc.of("the.other"); + assertDoesNotThrow(() -> ModuleExportInfo.of(pkg, 0, nCopies(65535, mod))); + assertThrows(IllegalArgumentException.class, () -> ModuleExportInfo.of(pkg, 0, nCopies(66000, mod))); + } + + @Test + void testModuleOpenEntry() { + var pkg = PackageDesc.of("dummy.test"); + var mod = ModuleDesc.of("the.other"); + assertDoesNotThrow(() -> ModuleOpenInfo.of(pkg, 0, nCopies(65535, mod))); + assertThrows(IllegalArgumentException.class, () -> ModuleOpenInfo.of(pkg, 0, nCopies(66000, mod))); + } + + @Test + void testModuleProvideEntry() { + assertDoesNotThrow(() -> ModuleProvideInfo.of(CD_Object, nCopies(65535, CD_String))); + assertThrows(IllegalArgumentException.class, () -> ModuleProvideInfo.of(CD_Object, nCopies(66000, CD_String))); + } + + @Test + void testRecordComponentAttributes() { + var attr = SyntheticAttribute.of(); + assertDoesNotThrow(() -> RecordComponentInfo.of("dummy", CD_int, nCopies(65535, attr))); + assertThrows(IllegalArgumentException.class, () -> RecordComponentInfo.of("dummy", CD_int, nCopies(66000, attr))); + } + + @Test + void testModuleAttribute() { + var md = ModuleDesc.of("java.base"); + var pkg = PackageDesc.of("java.lang"); + var require = ModuleRequireInfo.of(md, 0, null); + var export = ModuleExportInfo.of(pkg, 0, List.of()); + var provide = ModuleProvideInfo.of(CD_Object, List.of()); + var open = ModuleOpenInfo.of(pkg, 0, List.of()); + var classEntry = TemporaryConstantPool.INSTANCE.classEntry(CD_String); + var moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(md); + assertDoesNotThrow(() -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(66000, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(66000, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(66000, open), + nCopies(65535, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(66000, classEntry), + nCopies(65535, provide) + )); + assertThrows(IllegalArgumentException.class, () -> ModuleAttribute.of(moduleEntry, 0, null, + nCopies(65535, require), + nCopies(65535, export), + nCopies(65535, open), + nCopies(65535, classEntry), + nCopies(66000, provide) + )); + } + + private static Label dummyLabel() { + Label[] capture = new Label[1]; + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + capture[0] = cob.startLabel(); + cob.return_(); + })); + return capture[0]; + } +} From becc35f28792a48fac488841d0bc43226d7c96a7 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Sep 2025 21:58:26 +0000 Subject: [PATCH 347/471] 8366400: JCK test api/java_text/DecimalFormat/Parse.html fails after JDK-8363972 Reviewed-by: naoto --- .../classes/java/text/DecimalFormat.java | 7 +- .../Format/NumberFormat/PositionTest.java | 68 ++++++++++++++++--- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index aa881aecc8a..7ace5e136fe 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -3517,13 +3517,14 @@ public class DecimalFormat extends NumberFormat { var alen = affix.length(); var tlen = text.length(); + // Verify position can fit length wise before checking char by char + if (position + alen > tlen || position < 0) { + return false; + } if (alen == 0) { // always match with an empty affix, as affix is optional return true; } - if (position >= tlen) { - return false; - } if (parseStrict) { return text.regionMatches(position, affix, 0, alen); } diff --git a/test/jdk/java/text/Format/NumberFormat/PositionTest.java b/test/jdk/java/text/Format/NumberFormat/PositionTest.java index d916e0ab1ed..5b3a01f5ef1 100644 --- a/test/jdk/java/text/Format/NumberFormat/PositionTest.java +++ b/test/jdk/java/text/Format/NumberFormat/PositionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -21,12 +21,6 @@ * questions. */ -/** - * @test - * @bug 4109023 4153060 4153061 - * @summary test ParsePosition and FieldPosition - * @run junit PositionTest - */ /* (C) Copyright Taligent, Inc. 1996 - All Rights Reserved (C) Copyright IBM Corp. 1996 - All Rights Reserved @@ -39,15 +33,71 @@ attribution to Taligent may not be removed. Taligent is a registered trademark of Taligent, Inc. */ -import java.text.*; -import java.io.*; +/* + * @test + * @bug 4109023 4153060 4153061 8366400 + * @summary test ParsePosition and FieldPosition + * @run junit PositionTest + */ import org.junit.jupiter.api.Test; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; public class PositionTest { + // Parsing text which contains un-parseable data, but the index + // begins at the valid portion. Ensure PP is properly updated. + @Test + public void modifiedPositionTest() { + var df = new DecimalFormat("YY#"); + df.setStrict(false); // Lenient by default, set for test explicitness + var pp = new ParsePosition(9); + assertEquals(123L, assertDoesNotThrow(() -> df.parse("FOOBARBAZYY123", pp))); + assertEquals(-1, pp.getErrorIndex()); + assertEquals(14, pp.getIndex()); + } + + // Clearly invalid index value that could not work under any scenarios + // Specifically, ensuring no SIOOBE during affix matching + @Test + public void invalidPositionParseTest() { + var df = new DecimalFormat(); + df.setStrict(false); // Lenient by default, set for test explicitness + assertNull(assertDoesNotThrow(() -> df.parse("1", new ParsePosition(-1)))); + assertNull(assertDoesNotThrow(() -> df.parse("1", new ParsePosition(Integer.MAX_VALUE)))); + } + + // When prefix matching, position + affix length is greater than parsed String length + // Ensure we do not index out of bounds of the length of the parsed String + @Test + public void prefixMatchingTest() { + var df = new DecimalFormat("ZZZ#;YYY#"); + df.setStrict(false); // Lenient by default, set for test explicitness + // 0 + 3 > 2 = (pos + prefix > text) + assertNull(assertDoesNotThrow(() -> df.parse("Z1", new ParsePosition(0)))); + assertNull(assertDoesNotThrow(() -> df.parse("Y1", new ParsePosition(0)))); + } + + // When suffix matching, position + affix length is greater than parsed String length + // Ensure we do not index out of bounds of the length of the parsed String + @Test + public void suffixMatchingTest() { + var df = new DecimalFormat("#ZZ;#YY"); + df.setStrict(false); // Lenient by default, set for test explicitness + // Matches prefix properly first. Then 3 + 2 > 4 = (pos + suffix > text) + assertNull(assertDoesNotThrow(() -> df.parse("123Z", new ParsePosition(0)))); + assertNull(assertDoesNotThrow(() -> df.parse("123Y", new ParsePosition(0)))); + } + @Test public void TestParsePosition() { ParsePosition pp1 = new ParsePosition(0); From 02dd21196ed27289a6fad92c4881af484ce9c258 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:28:25 +0000 Subject: [PATCH 348/471] 8366692: Several gc/shenandoah tests timed out Reviewed-by: shade, wkemper --- test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java | 4 ++-- test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java | 4 ++-- .../jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java b/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java index 18f0e104ce0..fa6f3ab9b04 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestAllocObjects.java @@ -54,12 +54,12 @@ * @summary Acceptance tests: collector can withstand allocation * @requires vm.gc.Shenandoah * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=240 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify * TestAllocObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=480 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify * TestAllocObjects diff --git a/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java b/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java index 37359b038b3..c3b09f5ab4c 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestSieveObjects.java @@ -63,7 +63,7 @@ * -XX:+ShenandoahOOMDuringEvacALot * TestSieveObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=240 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahAllocFailureALot * TestSieveObjects @@ -103,7 +103,7 @@ * -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify * TestSieveObjects * - * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/timeout=480 -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive -XX:ShenandoahGCMode=generational * -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify * TestSieveObjects diff --git a/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java b/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java index 6f211edf343..d2a6269dddd 100644 --- a/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java +++ b/test/hotspot/jtreg/gc/shenandoah/jni/TestJNIGlobalRefs.java @@ -27,7 +27,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * -XX:+ShenandoahVerify * TestJNIGlobalRefs @@ -37,7 +37,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive * TestJNIGlobalRefs */ @@ -46,7 +46,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * -XX:+ShenandoahVerify * TestJNIGlobalRefs @@ -56,7 +56,7 @@ * @summary Test JNI Global Refs with Shenandoah * @requires vm.gc.Shenandoah * - * @run main/othervm/native -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + * @run main/othervm/native/timeout=240 -Xmx1g -Xlog:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational * TestJNIGlobalRefs */ From ed62bda2e0c51a67baae1fc28e41c9cd878db5f4 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:29:34 +0000 Subject: [PATCH 349/471] 8366694: Test JdbStopInNotificationThreadTest.java timed out after 60 second Reviewed-by: cjplummer, ayang, lmesnik --- test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java index 98a0d9d98ce..761c84d2c4c 100644 --- a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java +++ b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -113,9 +113,11 @@ public class JdbStopInNotificationThreadTest extends JdbTest { private static final String DEBUGGEE_CLASS = JdbStopInNotificationThreadTestTarg.class.getName(); private static final String PATTERN1_TEMPLATE = "^Breakpoint hit: \"thread=Notification Thread\", " + "JdbStopInNotificationThreadTestTarg\\$1\\.handleNotification\\(\\), line=%LINE_NUMBER.*\\R%LINE_NUMBER\\s+System\\.out\\.println\\(\"Memory usage low!!!\"\\);.*"; + private static final String[] DEBUGGEE_OPTIONS = {"-Xmx64M"}; private JdbStopInNotificationThreadTest() { - super(DEBUGGEE_CLASS); + super(new LaunchOptions(DEBUGGEE_CLASS) + .addDebuggeeOptions(DEBUGGEE_OPTIONS)); } public static void main(String argv[]) { From 11743b1ed3d681ce17c2342616c4040c4b539b31 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 01:37:42 +0000 Subject: [PATCH 350/471] 8366695: Test sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java timed out Reviewed-by: lmesnik, kevinw --- .../jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index 2dc2b2b4587..88f1ed22e35 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -70,7 +70,7 @@ import sun.jvmstat.monitor.event.VmStatusChangeEvent; * @modules java.management * jdk.internal.jvmstat/sun.jvmstat.monitor * jdk.internal.jvmstat/sun.jvmstat.monitor.event - * @run main/othervm MonitorVmStartTerminate + * @run main/othervm/timeout=240 MonitorVmStartTerminate */ public final class MonitorVmStartTerminate { From f4d73d2a3dbeccfd04d49c0cfd690086edd0544f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 02:31:12 +0000 Subject: [PATCH 351/471] 8366584: Add an InstanceKlass::super() method that returns InstanceKlass* Reviewed-by: dholmes, coleenp --- src/hotspot/share/cds/aotArtifactFinder.cpp | 4 +-- src/hotspot/share/cds/aotClassLinker.cpp | 4 +-- .../share/cds/aotLinkedClassBulkLoader.cpp | 4 +-- src/hotspot/share/cds/classListParser.cpp | 4 +-- src/hotspot/share/cds/classListWriter.cpp | 4 +-- src/hotspot/share/cds/dynamicArchive.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 2 +- src/hotspot/share/cds/metaspaceShared.cpp | 4 +-- src/hotspot/share/ci/ciReplay.cpp | 4 +-- .../share/classfile/classFileParser.cpp | 14 ++++---- .../share/classfile/defaultMethods.cpp | 6 ++-- .../share/classfile/fieldLayoutBuilder.cpp | 4 +-- .../share/classfile/systemDictionary.cpp | 4 +-- .../classfile/systemDictionaryShared.cpp | 6 ++-- src/hotspot/share/classfile/vmClasses.cpp | 2 +- .../jfrEventClassTransformer.cpp | 2 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 3 +- src/hotspot/share/oops/fieldStreams.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 32 +++++++++---------- src/hotspot/share/oops/instanceKlass.hpp | 8 ++++- src/hotspot/share/oops/klass.hpp | 4 ++- src/hotspot/share/oops/klassVtable.cpp | 19 ++++++----- src/hotspot/share/prims/jvmtiTagMap.cpp | 14 ++++---- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 2 +- src/hotspot/share/services/heapDumper.cpp | 14 ++++---- 28 files changed, 90 insertions(+), 84 deletions(-) diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index a42d8882099..84bc2797c58 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -201,7 +201,7 @@ void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) { if (created) { _pending_aot_inited_classes->push(ik); - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr) { add_aot_inited_class(s); } @@ -236,7 +236,7 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { append_to_all_cached_classes(ik); // All super types must be added. - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr) { add_cached_instance_class(s); } diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index 47c7f6e3bf8..adb18aa3aef 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -93,7 +93,7 @@ void AOTClassLinker::add_vm_class(InstanceKlass* ik) { bool v = try_add_candidate(ik); assert(v, "must succeed for VM class"); } - InstanceKlass* super = ik->java_super(); + InstanceKlass* super = ik->super(); if (super != nullptr) { add_vm_class(super); } @@ -151,7 +151,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) { } } - InstanceKlass* s = ik->java_super(); + InstanceKlass* s = ik->super(); if (s != nullptr && !try_add_candidate(s)) { return false; } diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 39236975782..99d7c26b293 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -294,7 +294,7 @@ void AOTLinkedClassBulkLoader::load_hidden_class(ClassLoaderData* loader_data, I HeapShared::is_lambda_proxy_klass(ik) || HeapShared::is_string_concat_klass(ik), "sanity"); DEBUG_ONLY({ - assert(ik->java_super()->is_loaded(), "must be"); + assert(ik->super()->is_loaded(), "must be"); for (int i = 0; i < ik->local_interfaces()->length(); i++) { assert(ik->local_interfaces()->at(i)->is_loaded(), "must be"); } @@ -434,4 +434,4 @@ void AOTLinkedClassBulkLoader::replay_training_at_init_for_preloaded_classes(TRA replay_training_at_init(table->platform(), CHECK); replay_training_at_init(table->app(), CHECK); } -} \ No newline at end of file +} diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 9ee7afcbc3e..75737b1432e 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -561,10 +561,10 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS const char* source_path = ClassLoader::uri_to_path(_source); InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); - if (k->java_super() != specified_super) { + if (k->super() != specified_super) { error("The specified super class %s (id %d) does not match actual super class %s", specified_super->external_name(), _super, - k->java_super()->external_name()); + k->super()->external_name()); } if (k->local_interfaces()->length() != _interfaces->length()) { print_specified_interfaces(); diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 727cc03c216..4d48a07d736 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -139,7 +139,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre } { - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); if (super != nullptr && !has_id(super)) { return; } @@ -165,7 +165,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre ResourceMark rm; stream->print("%s id: %d", k->name()->as_C_string(), get_id(k)); if (!is_builtin_loader) { - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); assert(super != nullptr, "must be"); stream->print(" super: %d", get_id(super)); diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 397f9146afb..35a50297536 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -276,7 +276,7 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { remark_pointers_for_instance_klass(ik, false); // Make sure all supertypes have been sorted - sort_methods(ik->java_super()); + sort_methods(ik->super()); Array* interfaces = ik->local_interfaces(); int len = interfaces->length(); for (int i = 0; i < len; i++) { diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index ea9368c9277..89b3eca1257 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -183,7 +183,7 @@ static void reset_states(oop obj, TRAPS) { JavaCalls::call_special(&result, h_obj, klass, method_name, method_sig, CHECK); } - klass = klass->java_super(); + klass = klass->super(); } } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 4d8f2b50017..73c8710c62e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -191,8 +191,8 @@ class DumpClassListCLDClosure : public CLDClosure { if (_dumped_classes.maybe_grow()) { log_info(aot, hashtables)("Expanded _dumped_classes table to %d", _dumped_classes.table_size()); } - if (ik->java_super()) { - dump(ik->java_super()); + if (ik->super()) { + dump(ik->super()); } Array* interfaces = ik->local_interfaces(); int len = interfaces->length(); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 72ec2866c6e..6266c024260 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1572,7 +1572,7 @@ oop ciReplay::obj_field(oop obj, Symbol* name) { do { if (!ik->has_nonstatic_fields()) { - ik = ik->java_super(); + ik = ik->super(); continue; } @@ -1591,7 +1591,7 @@ oop ciReplay::obj_field(oop obj, Symbol* name) { } } - ik = ik->java_super(); + ik = ik->super(); } while (ik != nullptr); return nullptr; } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 01e35161efd..6c019f7c612 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3957,7 +3957,7 @@ void OopMapBlocksBuilder::print_value_on(outputStream* st) const { void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { assert(ik != nullptr, "invariant"); - const InstanceKlass* const super = ik->java_super(); + const InstanceKlass* const super = ik->super(); // Check if this klass has an empty finalize method (i.e. one with return bytecode only), // in which case we don't have to register objects as finalizable @@ -4092,7 +4092,7 @@ static Array* compute_transitive_interfaces(const InstanceKlass* void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, TRAPS) { assert(this_klass != nullptr, "invariant"); - const InstanceKlass* const super = this_klass->java_super(); + const InstanceKlass* const super = this_klass->super(); if (super != nullptr) { if (super->is_final()) { @@ -4210,7 +4210,7 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) const Symbol* const name = m->name(); const Symbol* const signature = m->signature(); - const InstanceKlass* k = this_klass->java_super(); + const InstanceKlass* k = this_klass->super(); const Method* super_m = nullptr; while (k != nullptr) { // skip supers that don't have final methods. @@ -4242,11 +4242,11 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) } // continue to look from super_m's holder's super. - k = super_m->method_holder()->java_super(); + k = super_m->method_holder()->super(); continue; } - k = k->java_super(); + k = k->super(); } } } @@ -5292,10 +5292,10 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ResourceMark rm; // print out the superclass. const char * from = ik->external_name(); - if (ik->java_super() != nullptr) { + if (ik->super() != nullptr) { log_debug(class, resolve)("%s %s (super)", from, - ik->java_super()->external_name()); + ik->super()->external_name()); } // print out each of the interface classes referred to by this class. const Array* const local_interfaces = ik->local_interfaces(); diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 80de93261f4..e5cb5d8f354 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -123,7 +123,7 @@ class HierarchyVisitor : StackObj { InstanceKlass* interface_at(int index) { return _class->local_interfaces()->at(index); } - InstanceKlass* next_super() { return _class->java_super(); } + InstanceKlass* next_super() { return _class->super(); } InstanceKlass* next_interface() { return interface_at(interface_index()); } @@ -636,7 +636,7 @@ static void find_empty_vtable_slots(GrowableArray* slots, // Also any overpasses in our superclasses, that we haven't implemented. // (can't use the vtable because it is not guaranteed to be initialized yet) - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); while (super != nullptr) { for (int i = 0; i < super->methods()->length(); ++i) { Method* m = super->methods()->at(i); @@ -668,7 +668,7 @@ static void find_empty_vtable_slots(GrowableArray* slots, } } } - super = super->java_super(); + super = super->super(); } LogTarget(Debug, defaultmethods) lt; diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index d06f5dd96d1..a87e12edc96 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -316,7 +316,7 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_instance block->set_offset(fs.offset()); all_fields->append(block); } - ik = ik->java_super() == nullptr ? nullptr : ik->java_super(); + ik = ik->super() == nullptr ? nullptr : ik->super(); } assert(last_offset == -1 || last_offset > 0, "Sanity"); if (last_offset > 0 && @@ -474,7 +474,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas break; } } - ik = ik->java_super(); + ik = ik->super(); } break; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index ae7432c9fce..9bc94f15100 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -431,7 +431,7 @@ InstanceKlass* SystemDictionary::resolve_with_circularity_detection(Symbol* clas // (a) RedefineClasses -- the class is already loaded // (b) Rarely, the class might have been loaded by a parallel thread // We can do a quick check against the already assigned superclass's name and loader. - InstanceKlass* superk = klassk->java_super(); + InstanceKlass* superk = klassk->super(); if (superk != nullptr && superk->name() == next_name && superk->class_loader() == class_loader()) { @@ -1049,7 +1049,7 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle // load from the shared archive. if (ik->super() != nullptr) { - bool check_super = check_shared_class_super_type(ik, ik->java_super(), + bool check_super = check_shared_class_super_type(ik, ik->super(), class_loader, true, CHECK_false); if (!check_super) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 1be7a6db662..904e8cca89d 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -238,7 +238,7 @@ bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { if (k->name()->equals("jdk/internal/event/Event")) { return true; } - k = k->java_super(); + k = k->super(); } return false; } @@ -329,7 +329,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return true; } - InstanceKlass* super = k->java_super(); + InstanceKlass* super = k->super(); if (super != nullptr && check_for_exclusion(super, nullptr)) { ResourceMark rm; aot_log_warning(aot)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); @@ -571,7 +571,7 @@ bool SystemDictionaryShared::has_been_redefined(InstanceKlass* k) { if (k->has_been_redefined()) { return true; } - if (k->java_super() != nullptr && has_been_redefined(k->java_super())) { + if (k->super() != nullptr && has_been_redefined(k->super())) { return true; } Array* interfaces = k->local_interfaces(); diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 9b9222268a6..f51c17eb038 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -225,7 +225,7 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load } // add super and interfaces first - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); if (super != nullptr && super->class_loader_data() == nullptr) { assert(super->is_instance_klass(), "Super should be instance klass"); resolve_shared_class(super, loader_data, domain, CHECK); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index 81e8a82c78d..d5ef3502fa2 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -214,7 +214,7 @@ static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_t if (has_annotation(ik, annotation_type, default_value, value)) { return true; } - InstanceKlass* const super = ik->java_super(); + InstanceKlass* const super = ik->super(); return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, default_value, value) : false; } diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index c9d79a23c2f..d431d98e383 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -76,7 +76,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { } jfs.next(); } - ik = ik->java_super(); + ik = ik->super(); } *modifiers = 0; return nullptr; diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 867ccc6106d..4d7e6c9369c 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -364,6 +364,7 @@ void KlassHierarchy::print_class_hierarchy(outputStream* st, bool print_interfac } else { // We are only printing the hierarchy of a specific class. if (strcmp(classname, cie->klass()->external_name()) == 0) { + assert(cie->klass()->is_instance_klass(), "elements array contains only instance klasses"); KlassHierarchy::set_do_print_for_class_hierarchy(cie, &cit, print_subclasses); } } @@ -402,7 +403,7 @@ void KlassHierarchy::print_class_hierarchy(outputStream* st, bool print_interfac void KlassHierarchy::set_do_print_for_class_hierarchy(KlassInfoEntry* cie, KlassInfoTable* cit, bool print_subclasses) { // Set do_print for all superclasses of this class. - Klass* super = ((InstanceKlass*)cie->klass())->java_super(); + InstanceKlass* super = InstanceKlass::cast(cie->klass())->super(); while (super != nullptr) { KlassInfoEntry* super_cie = cit->lookup(super); super_cie->set_do_print(true); diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index 23ec156473b..08b04409a97 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -212,7 +212,7 @@ class HierarchicalFieldStream : public StackObj { InstanceKlass* result = _next_klass; do { if (!result->is_interface() && result->super() != nullptr) { - result = result->java_super(); + result = result->super(); } else if (_interface_index > 0) { result = _interfaces->at(--_interface_index); } else { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index a7641b9a546..964006b3b9c 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -677,7 +677,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); - deallocate_interfaces(loader_data, java_super(), local_interfaces(), transitive_interfaces()); + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); @@ -748,7 +748,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { bool InstanceKlass::is_record() const { return _record_components != nullptr && is_final() && - java_super() == vmClasses::Record_klass(); + super() == vmClasses::Record_klass(); } bool InstanceKlass::is_sealed() const { @@ -763,9 +763,9 @@ bool InstanceKlass::is_sealed() const { // sealing conditions: it merely checks for a super of Enum. // This is sufficient for recognizing well-formed enums. bool InstanceKlass::is_enum_subclass() const { - InstanceKlass* s = java_super(); + InstanceKlass* s = super(); return (s == vmClasses::Enum_klass() || - (s != nullptr && s->java_super() == vmClasses::Enum_klass())); + (s != nullptr && s->super() == vmClasses::Enum_klass())); } bool InstanceKlass::should_be_initialized() const { @@ -829,7 +829,7 @@ void InstanceKlass::initialize(TRAPS) { void InstanceKlass::assert_no_clinit_will_run_for_aot_initialized_class() const { assert(has_aot_initialized_mirror(), "must be"); - InstanceKlass* s = java_super(); + InstanceKlass* s = super(); if (s != nullptr) { DEBUG_ONLY(ResourceMark rm); assert(s->is_initialized(), "super class %s of aot-inited class %s must have been initialized", @@ -942,7 +942,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { JavaThread* jt = THREAD; // link super class before linking this class - InstanceKlass* super_klass = java_super(); + InstanceKlass* super_klass = super(); if (super_klass != nullptr) { if (super_klass->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -1465,7 +1465,7 @@ void InstanceKlass::add_implementor(InstanceKlass* ik) { // Filter out subclasses whose supers already implement me. // (Note: CHA must walk subclasses of direct implementors // in order to locate indirect implementors.) - InstanceKlass* super_ik = ik->java_super(); + InstanceKlass* super_ik = ik->super(); if (super_ik != nullptr && super_ik->implements_interface(this)) // We only need to check one immediate superclass, since the // implements_interface query looks at transitive_interfaces. @@ -1831,7 +1831,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { InstanceKlass* supr = java_super(); + { InstanceKlass* supr = super(); if (supr != nullptr) return supr->find_field(name, sig, fd); } // 4) otherwise field lookup fails @@ -1851,7 +1851,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel if (intf != nullptr) return intf; } // 3) apply field lookup recursively if superclass exists - { InstanceKlass* supr = java_super(); + { InstanceKlass* supr = super(); if (supr != nullptr) return supr->find_field(name, sig, is_static, fd); } // 4) otherwise field lookup fails @@ -1876,7 +1876,7 @@ bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDesc if (klass->find_local_field_from_offset(offset, is_static, fd)) { return true; } - klass = klass->java_super(); + klass = klass->super(); } return false; } @@ -1919,7 +1919,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAP } void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = java_super(); + InstanceKlass* super = this->super(); if (super != nullptr) { super->do_nonstatic_fields(cl); } @@ -1936,7 +1936,7 @@ static int compare_fields_by_offset(FieldInfo* a, FieldInfo* b) { } void InstanceKlass::print_nonstatic_fields(FieldClosure* cl) { - InstanceKlass* super = java_super(); + InstanceKlass* super = this->super(); if (super != nullptr) { super->print_nonstatic_fields(cl); } @@ -2241,7 +2241,7 @@ Method* InstanceKlass::uncached_lookup_method(const Symbol* name, if (method != nullptr) { return method; } - klass = klass->java_super(); + klass = klass->super(); overpass_local_mode = OverpassLookupMode::skip; // Always ignore overpass methods in superclasses } return nullptr; @@ -2256,7 +2256,7 @@ bool InstanceKlass::has_redefined_this_or_super() const { if (klass->has_been_redefined()) { return true; } - klass = klass->java_super(); + klass = klass->super(); } return false; } @@ -2853,7 +2853,7 @@ bool InstanceKlass::can_be_verified_at_dumptime() const { if (major_version() < 50 /*JAVA_6_VERSION*/) { return false; } - if (java_super() != nullptr && !java_super()->can_be_verified_at_dumptime()) { + if (super() != nullptr && !super()->can_be_verified_at_dumptime()) { return false; } Array* interfaces = local_interfaces(); @@ -3985,7 +3985,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, // Class hierarchy info debug_stream.print(" klass: " PTR_FORMAT " super: " PTR_FORMAT, - p2i(this), p2i(java_super())); + p2i(this), p2i(super())); // Interfaces if (local_interfaces() != nullptr && local_interfaces()->length() > 0) { diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index a158494736b..3338b5cd446 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -918,8 +918,14 @@ public: return static_cast(k); } + // This hides Klass::super(). The _super of an InstanceKlass is + // always an InstanceKlass (or nullptr) + InstanceKlass* super() const { + return (Klass::super() == nullptr) ? nullptr : InstanceKlass::cast(Klass::super()); + } + virtual InstanceKlass* java_super() const { - return (super() == nullptr) ? nullptr : cast(super()); + return InstanceKlass::super(); } // Sizing (in words) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 1257f4cbcf8..91bd60b0e3e 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -217,7 +217,9 @@ protected: // super() cannot be InstanceKlass* -- Java arrays are covariant, and _super is used // to implement that. NB: the _super of "[Ljava/lang/Integer;" is "[Ljava/lang/Number;" - // If this is not what your code expects, you're probably looking for Klass::java_super(). + // If this is not what your code expects, you're probably looking for: + // - Klass::java_super() - if you have a Klass* + // - InstanceKlass::super() - if you have an InstanceKlass* ik, ik->super() returns InstanceKlass*. Klass* super() const { return _super; } void set_super(Klass* k) { _super = k; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index bb47496b406..55242b2a2d1 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -346,7 +346,7 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper break; } // if no override found yet, continue to search up - superk = superk->java_super(); + superk = superk->super(); } return superk; @@ -683,14 +683,14 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // a new entry Symbol* name = target_method->name(); Symbol* signature = target_method->signature(); - const InstanceKlass* k = super; + const InstanceKlass* ik = super; Method* super_method = nullptr; InstanceKlass *holder = nullptr; Method* recheck_method = nullptr; bool found_pkg_prvt_method = false; - while (k != nullptr) { + while (ik != nullptr) { // lookup through the hierarchy for a method with matching name and sign. - super_method = InstanceKlass::cast(k)->lookup_method(name, signature); + super_method = ik->lookup_method(name, signature); if (super_method == nullptr) { break; // we still have to search for a matching miranda method } @@ -722,7 +722,7 @@ bool klassVtable::needs_new_vtable_entry(Method* target_method, // Start with lookup result and continue to search up, for versions supporting transitive override if (major_version >= VTABLE_TRANSITIVE_OVERRIDE_VERSION) { - k = superk->java_super(); // haven't found an override match yet; continue to look + ik = superk->super(); // haven't found an override match yet; continue to look } else { break; } @@ -774,7 +774,7 @@ bool klassVtable::is_miranda_entry_at(int i) { if (holder->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(holder) , "this class should implement the interface"); - if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->java_super(), klass()->is_interface())) { + if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super(), klass()->is_interface())) { return true; } } @@ -865,7 +865,7 @@ bool klassVtable::is_miranda(Method* m, Array* class_methods, // Overpasses may or may not exist for supers for pass 1, // they should have been created for pass 2 and later. - for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->java_super()) { + for (const InstanceKlass* cursuper = super; cursuper != nullptr; cursuper = cursuper->super()) { Method* found_mth = cursuper->find_local_method(name, signature, Klass::OverpassLookupMode::find, Klass::StaticLookupMode::skip, @@ -959,7 +959,7 @@ void klassVtable::get_mirandas(GrowableArray* new_mirandas, int klassVtable::fill_in_mirandas(Thread* current, int initialized) { ResourceMark rm(current); GrowableArray mirandas(20); - get_mirandas(&mirandas, nullptr, ik()->java_super(), ik()->methods(), + get_mirandas(&mirandas, nullptr, ik()->super(), ik()->methods(), ik()->default_methods(), ik()->local_interfaces(), klass()->is_interface()); for (int i = 0; i < mirandas.length(); i++) { @@ -1571,8 +1571,7 @@ void klassVtable::verify(outputStream* st, bool forced) { // verify consistency with superKlass vtable Klass* super = _klass->super(); if (super != nullptr) { - InstanceKlass* sk = InstanceKlass::cast(super); - klassVtable vt = sk->vtable(); + klassVtable vt = super->vtable(); for (int i = 0; i < vt.length(); i++) { verify_against(st, &vt, i); } diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 0375756e219..4febb4f3125 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -451,7 +451,7 @@ ClassFieldMap* ClassFieldMap::create_map_of_static_fields(Klass* k) { // Static fields of interfaces and superclasses are reported as references from the interfaces/superclasses. // Need to calculate start index of this class fields: number of fields in all interfaces and superclasses. int index = interfaces_field_count(ik); - for (InstanceKlass* super_klass = ik->java_super(); super_klass != nullptr; super_klass = super_klass->java_super()) { + for (InstanceKlass* super_klass = ik->super(); super_klass != nullptr; super_klass = super_klass->super()) { FilteredJavaFieldStream super_fld(super_klass); index += super_fld.field_count(); } @@ -478,12 +478,12 @@ ClassFieldMap* ClassFieldMap::create_map_of_instance_fields(oop obj) { // fields of the superclasses are reported first, so need to know total field number to calculate field indices int total_field_number = interfaces_field_count(ik); - for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->java_super()) { + for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->super()) { FilteredJavaFieldStream fld(klass); total_field_number += fld.field_count(); } - for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->java_super()) { + for (InstanceKlass* klass = ik; klass != nullptr; klass = klass->super()) { FilteredJavaFieldStream fld(klass); int start_index = total_field_number - fld.field_count(); for (int index = 0; !fld.done(); fld.next(), index++) { @@ -2597,10 +2597,10 @@ inline bool VM_HeapWalkOperation::iterate_over_class(oop java_class) { oop mirror = klass->java_mirror(); // super (only if something more interesting than java.lang.Object) - InstanceKlass* java_super = ik->java_super(); - if (java_super != nullptr && java_super != vmClasses::Object_klass()) { - oop super = java_super->java_mirror(); - if (!CallbackInvoker::report_superclass_reference(mirror, super)) { + InstanceKlass* super_klass = ik->super(); + if (super_klass != nullptr && super_klass != vmClasses::Object_klass()) { + oop super_oop = super_klass->java_mirror(); + if (!CallbackInvoker::report_superclass_reference(mirror, super_oop)) { return false; } } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 521ac5454ea..da9a4e9cd9a 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1474,7 +1474,7 @@ public: // Gets the fields of `klass` that are eliminated by escape analysis and need to be reassigned static GrowableArray* get_reassigned_fields(InstanceKlass* klass, GrowableArray* fields, bool is_jvmci) { - InstanceKlass* super = klass->java_super(); + InstanceKlass* super = klass->super(); if (super != nullptr) { get_reassigned_fields(super, fields, is_jvmci); } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 5ea2a4e4385..89d742e0ea8 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1140,7 +1140,7 @@ void JavaThread::install_async_exception(AsyncExceptionHandshakeClosure* aehc) { ResourceMark rm; if (log_is_enabled(Info, exceptions)) { log_info(exceptions)("Pending Async. exception installed of type: %s", - InstanceKlass::cast(exception->klass())->external_name()); + exception->klass()->external_name()); } // for AbortVMOnException flag Exceptions::debug_check_abort(exception->klass()->external_name()); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index f2a7587d364..0f61770a639 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -459,7 +459,7 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) { char klass_name[256]; char tmp_sig_name[16]; const char* sig_name = "UNKNOWN"; - InstanceKlass::cast(PENDING_EXCEPTION->klass())-> + PENDING_EXCEPTION->klass()-> name()->as_klass_external_name(klass_name, 256); if (os::exception_name(sig, tmp_sig_name, 16) != nullptr) sig_name = tmp_sig_name; diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 59460dbf89b..cf62972ca16 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -765,7 +765,7 @@ class DumperSupport : AllStatic { // creates HPROF_GC_INSTANCE_DUMP record for the given object static void dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache); // creates HPROF_GC_CLASS_DUMP record for the given instance class - static void dump_instance_class(AbstractDumpWriter* writer, Klass* k); + static void dump_instance_class(AbstractDumpWriter* writer, InstanceKlass* ik); // creates HPROF_GC_CLASS_DUMP record for a given array class static void dump_array_class(AbstractDumpWriter* writer, Klass* k); @@ -1204,9 +1204,7 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClass } // creates HPROF_GC_CLASS_DUMP record for the given instance class -void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { - InstanceKlass* ik = InstanceKlass::cast(k); - +void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, InstanceKlass* ik) { // We can safepoint and do a heap dump at a point where we have a Klass, // but no java mirror class has been setup for it. So we need to check // that the class is at least loaded, to avoid crash from a null mirror. @@ -1227,11 +1225,11 @@ void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) { writer->write_u4(STACK_TRACE_ID); // super class ID - InstanceKlass* java_super = ik->java_super(); - if (java_super == nullptr) { + InstanceKlass* super = ik->super(); + if (super == nullptr) { writer->write_objectID(oop(nullptr)); } else { - writer->write_classID(java_super); + writer->write_classID(super); } writer->write_objectID(ik->class_loader()); @@ -1505,7 +1503,7 @@ class ClassDumper : public KlassClosure { void do_klass(Klass* k) { if (k->is_instance_klass()) { - DumperSupport::dump_instance_class(writer(), k); + DumperSupport::dump_instance_class(writer(), InstanceKlass::cast(k)); } else { DumperSupport::dump_array_class(writer(), k); } From 4d1dfabcb4e94601995b07b7ecea4249ae375a04 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Thu, 4 Sep 2025 04:35:51 +0000 Subject: [PATCH 352/471] 8366038: Thread::SpinRelease should use Atomic::release_store Reviewed-by: dholmes, ayang --- src/hotspot/share/runtime/thread.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index ed1c8c2508f..9c12da15180 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -602,7 +602,6 @@ void Thread::SpinAcquire(volatile int * adr) { void Thread::SpinRelease(volatile int * adr) { assert(*adr != 0, "invariant"); - OrderAccess::fence(); // guarantee at least release consistency. // Roach-motel semantics. // It's safe if subsequent LDs and STs float "up" into the critical section, // but prior LDs and STs within the critical section can't be allowed @@ -610,8 +609,7 @@ void Thread::SpinRelease(volatile int * adr) { // Loads and stores in the critical section - which appear in program // order before the store that releases the lock - must also appear // before the store that releases the lock in memory visibility order. - // Conceptually we need a #loadstore|#storestore "release" MEMBAR before - // the ST of 0 into the lock-word which releases the lock, so fence - // more than covers this on all platforms. - *adr = 0; + // So we need a #loadstore|#storestore "release" memory barrier before + // the ST of 0 into the lock-word which releases the lock. + Atomic::release_store(adr, 0); } From 90a2db1ecbc3ea25a8e9f15b34a3d8f3941b60d0 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 04:47:48 +0000 Subject: [PATCH 353/471] 8366474: Rename MetaspaceObj::is_shared() to MetaspaceObj::in_aot_cache() Reviewed-by: liach, kvn --- src/hotspot/os/posix/vmError_posix.cpp | 2 +- src/hotspot/os/windows/vmError_windows.cpp | 2 +- src/hotspot/share/cds/aotArtifactFinder.cpp | 2 +- src/hotspot/share/cds/aotClassLinker.cpp | 2 +- .../share/cds/aotConstantPoolResolver.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 8 +-- src/hotspot/share/cds/archiveUtils.hpp | 6 +- src/hotspot/share/cds/archiveUtils.inline.hpp | 2 +- src/hotspot/share/cds/cdsProtectionDomain.cpp | 4 +- src/hotspot/share/cds/classListWriter.cpp | 2 +- src/hotspot/share/cds/cppVtables.cpp | 2 +- src/hotspot/share/cds/dumpTimeClassInfo.cpp | 4 +- src/hotspot/share/cds/dynamicArchive.cpp | 16 ++--- src/hotspot/share/cds/filemap.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 4 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../share/cds/lambdaProxyClassDictionary.cpp | 14 ++-- src/hotspot/share/cds/metaspaceShared.cpp | 32 +++++----- src/hotspot/share/cds/metaspaceShared.hpp | 15 +++-- src/hotspot/share/cds/runTimeClassInfo.cpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 2 +- .../share/classfile/classLoaderData.cpp | 4 +- src/hotspot/share/classfile/javaClasses.cpp | 4 +- src/hotspot/share/classfile/klassFactory.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 6 +- .../classfile/systemDictionaryShared.cpp | 16 ++--- .../classfile/systemDictionaryShared.hpp | 4 +- src/hotspot/share/classfile/verifier.cpp | 2 +- src/hotspot/share/classfile/vmClasses.cpp | 6 +- .../share/compiler/compilationPolicy.cpp | 2 +- .../share/interpreter/interpreterRuntime.cpp | 2 +- src/hotspot/share/interpreter/rewriter.cpp | 6 +- src/hotspot/share/memory/allocation.cpp | 4 +- src/hotspot/share/memory/allocation.hpp | 38 +++++------ src/hotspot/share/memory/metadataFactory.hpp | 6 +- src/hotspot/share/memory/metaspace.cpp | 4 +- src/hotspot/share/memory/metaspace.hpp | 6 +- .../printCLDMetaspaceInfoClosure.cpp | 2 +- .../printMetaspaceInfoKlassClosure.cpp | 4 +- src/hotspot/share/oops/arrayKlass.cpp | 4 +- src/hotspot/share/oops/constantPool.cpp | 14 ++-- src/hotspot/share/oops/constantPool.hpp | 8 +-- src/hotspot/share/oops/cpCache.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 64 +++++++++---------- .../share/oops/instanceMirrorKlass.inline.hpp | 4 +- src/hotspot/share/oops/klass.cpp | 4 +- src/hotspot/share/oops/klass.hpp | 14 ++-- src/hotspot/share/oops/klassVtable.cpp | 10 +-- src/hotspot/share/oops/method.cpp | 8 +-- src/hotspot/share/oops/trainingData.cpp | 2 +- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 4 +- .../sun/jvm/hotspot/memory/MetaspaceObj.java | 14 ++-- 55 files changed, 204 insertions(+), 201 deletions(-) diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp index 9d6cd175c66..4bfd8efabe8 100644 --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -117,7 +117,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { if (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) { const void* const fault_addr = si->si_addr; if (fault_addr != nullptr) { - if (MetaspaceShared::is_in_shared_metaspace(fault_addr)) { + if (MetaspaceShared::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os/windows/vmError_windows.cpp b/src/hotspot/os/windows/vmError_windows.cpp index 1613f52136f..fbd91309822 100644 --- a/src/hotspot/os/windows/vmError_windows.cpp +++ b/src/hotspot/os/windows/vmError_windows.cpp @@ -51,7 +51,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { er->NumberParameters >= 2) { const void* const fault_addr = (const void*) er->ExceptionInformation[1]; if (fault_addr != nullptr) { - if (MetaspaceShared::is_in_shared_metaspace(fault_addr)) { + if (MetaspaceShared::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 84bc2797c58..5f346e832a8 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -224,7 +224,7 @@ void AOTArtifactFinder::append_to_all_cached_classes(Klass* k) { } void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { - if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->in_aot_cache()) { // This class is already included in the base archive. No need to cache // it again in the dynamic archive. return; diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index adb18aa3aef..1f9a03de83f 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -212,7 +212,7 @@ Array* AOTClassLinker::write_classes(oop class_loader, bool is_j continue; } - if (ik->is_shared() && CDSConfig::is_dumping_dynamic_archive()) { + if (ik->in_aot_cache() && CDSConfig::is_dumping_dynamic_archive()) { if (CDSConfig::is_using_aot_linked_classes()) { // This class was recorded as AOT-linked for the base archive, // so there's no need to do so again for the dynamic archive. diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.cpp b/src/hotspot/share/cds/aotConstantPoolResolver.cpp index 0eb7ddfbbf6..6cc3a81c2ae 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.cpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.cpp @@ -85,7 +85,7 @@ bool AOTConstantPoolResolver::is_class_resolution_deterministic(InstanceKlass* c if (resolved_class->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(resolved_class); - if (!ik->is_shared() && SystemDictionaryShared::is_excluded_class(ik)) { + if (!ik->in_aot_cache() && SystemDictionaryShared::is_excluded_class(ik)) { return false; } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 7ffbf0151d2..00aca188f96 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -365,8 +365,8 @@ address ArchiveBuilder::reserve_buffer() { if (CDSConfig::is_dumping_static_archive()) { my_archive_requested_bottom = _requested_static_archive_bottom; } else { - _mapped_static_archive_bottom = (address)MetaspaceObj::shared_metaspace_base(); - _mapped_static_archive_top = (address)MetaspaceObj::shared_metaspace_top(); + _mapped_static_archive_bottom = (address)MetaspaceObj::aot_metaspace_base(); + _mapped_static_archive_top = (address)MetaspaceObj::aot_metaspace_top(); assert(_mapped_static_archive_top >= _mapped_static_archive_bottom, "must be"); size_t static_archive_size = _mapped_static_archive_top - _mapped_static_archive_bottom; @@ -540,7 +540,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { return SystemDictionaryShared::is_excluded_class(ik); } else if (klass->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_shared_static(bottom)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache_static_region(bottom)) { // The bottom class is in the static archive so it's clearly not excluded. return false; } else if (bottom->is_instance_klass()) { @@ -553,7 +553,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { address obj = ref->obj(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(obj)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(obj)) { // Don't dump existing shared metadata again. return point_to_it; } else if (ref->msotype() == MetaspaceObj::MethodDataType || diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 8fce6e31bb1..be423881008 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -275,7 +275,7 @@ public: } // The following functions translate between a u4 offset and an address in the - // the range of the mapped CDS archive (e.g., Metaspace::is_in_shared_metaspace()). + // the range of the mapped CDS archive (e.g., Metaspace::in_aot_cache()). // Since the first 16 bytes in this range are dummy data (see ArchiveBuilder::reserve_buffer()), // we know that offset 0 never represents a valid object. As a result, an offset of 0 // is used to encode a nullptr. @@ -287,7 +287,7 @@ public: template T static offset_to_archived_address(u4 offset) { assert(offset != 0, "sanity"); T p = (T)(SharedBaseAddress + offset); - assert(Metaspace::is_in_shared_metaspace(p), "must be"); + assert(Metaspace::in_aot_cache(p), "must be"); return p; } @@ -303,7 +303,7 @@ public: template static u4 archived_address_to_offset(T p) { uintx pn = (uintx)p; uintx base = (uintx)SharedBaseAddress; - assert(Metaspace::is_in_shared_metaspace(p), "must be"); + assert(Metaspace::in_aot_cache(p), "must be"); assert(pn > base, "sanity"); // No valid object is stored at 0 offset from SharedBaseAddress uintx offset = pn - base; assert(offset <= MAX_SHARED_DELTA, "range check"); diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 12c9a0bc705..70b91fb8900 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -80,7 +80,7 @@ Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { for (int i = 0; i < tmp_array->length(); i++) { T ptr = tmp_array->at(i); if (ptr != nullptr && !builder->is_in_buffer_space(ptr)) { - if (is_dynamic_dump && MetaspaceShared::is_in_shared_metaspace(ptr)) { + if (is_dynamic_dump && MetaspaceShared::in_aot_cache(ptr)) { // We have a pointer that lives in the dynamic archive but points into // the static archive. } else { diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index e907998fa85..c95fd8b64df 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -117,8 +117,8 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { PackageEntry* pkg_entry = ik->package(); - if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) { - assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be"); + if (CDSConfig::is_using_full_module_graph() && ik->in_aot_cache() && pkg_entry != nullptr) { + assert(MetaspaceShared::in_aot_cache(pkg_entry), "must be"); assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); return pkg_entry; } diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 4d48a07d736..882bb84036f 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -110,7 +110,7 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre bool is_builtin_loader = SystemDictionaryShared::is_builtin_loader(loader_data); if (!is_builtin_loader) { // class may be loaded from shared archive - if (!k->is_shared()) { + if (!k->in_aot_cache()) { if (cfs == nullptr || cfs->source() == nullptr) { // CDS static dump only handles unregistered class with known source. return; diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 319e4f6e95f..261f5332526 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -321,7 +321,7 @@ void CppVtables::zero_archived_vtables() { } bool CppVtables::is_valid_shared_method(const Method* m) { - assert(MetaspaceShared::is_in_shared_metaspace(m), "must be"); + assert(MetaspaceShared::in_aot_cache(m), "must be"); return vtable_of(m) == _index[Method_Kind]->cloned_vtable() || vtable_of(m) == _archived_cpp_vtptrs[Method_Kind]; } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 6a06344fb0d..8af762dba4d 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -142,7 +142,7 @@ bool DumpTimeClassInfo::is_builtin() { } DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { - assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->in_aot_cache(), "Do not call with shared classes"); bool created; DumpTimeClassInfo* p = put_if_absent(k, &created); assert(created, "must not exist in table"); @@ -151,7 +151,7 @@ DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { } DumpTimeClassInfo* DumpTimeSharedClassTable::get_info(InstanceKlass* k) { - assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->in_aot_cache(), "Do not call with shared classes"); DumpTimeClassInfo* p = get(k); assert(p != nullptr, "we must not see any non-shared InstanceKlass* that's " "not stored with SystemDictionaryShared::init_dumptime_info"); diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 35a50297536..8499dced126 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -187,10 +187,10 @@ public: for (int i = T_BOOLEAN; i <= T_LONG; i++) { assert(is_java_primitive((BasicType)i), "sanity"); Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc - assert(MetaspaceShared::is_shared_static((void*)k), + assert(MetaspaceShared::in_aot_cache_static_region((void*)k), "one-dimensional primitive array should be in static archive"); ArrayKlass* ak = ArrayKlass::cast(k); - while (ak != nullptr && ak->is_shared()) { + while (ak != nullptr && ak->in_aot_cache()) { Klass* next_k = ak->array_klass_or_null(); if (next_k != nullptr) { ak = ArrayKlass::cast(next_k); @@ -253,7 +253,7 @@ void DynamicArchiveBuilder::sort_methods() { // klasses were created. Re-sort all the tables. See Method::sort_methods(). void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { assert(ik != nullptr, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); - if (MetaspaceShared::is_in_shared_metaspace(ik)) { + if (MetaspaceShared::in_aot_cache(ik)) { // We have reached a supertype that's already in the base archive return; } @@ -287,13 +287,13 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { if (ik->methods() != nullptr) { for (int m = 0; m < ik->methods()->length(); m++) { Symbol* name = ik->methods()->at(m)->name(); - assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); + assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } if (ik->default_methods() != nullptr) { for (int m = 0; m < ik->default_methods()->length(); m++) { Symbol* name = ik->default_methods()->at(m)->name(); - assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); + assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } #endif @@ -367,14 +367,14 @@ void DynamicArchiveBuilder::gather_array_klasses() { if (klasses()->at(i)->is_objArray_klass()) { ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i)); Klass* elem = oak->element_klass(); - if (MetaspaceShared::is_shared_static(elem)) { + if (MetaspaceShared::in_aot_cache_static_region(elem)) { // Only capture the array klass whose element_klass is in the static archive. // During run time, setup (see DynamicArchive::setup_array_klasses()) is needed // so that the element_klass can find its array klasses from the dynamic archive. DynamicArchive::append_array_klass(oak); } else { // The element_klass and its array klasses are in the same archive. - assert(!MetaspaceShared::is_shared_static(oak), + assert(!MetaspaceShared::in_aot_cache_static_region(oak), "we should not gather klasses that are already in the static archive"); } } @@ -435,7 +435,7 @@ void DynamicArchive::setup_array_klasses() { assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive"); Klass* elm = oak->element_klass(); - assert(MetaspaceShared::is_shared_static((void*)elm), "must be"); + assert(MetaspaceShared::in_aot_cache_static_region((void*)elm), "must be"); if (elm->is_instance_klass()) { assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be"); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index a2b9e83ee68..78f02161477 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1144,7 +1144,7 @@ MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* FileMapRegion* r = region_at(idx); DEBUG_ONLY(if (last_region != nullptr) { // Ensure that the OS won't be able to allocate new memory spaces between any mapped - // regions, or else it would mess up the simple comparison in MetaspaceObj::is_shared(). + // regions, or else it would mess up the simple comparison in MetaspaceObj::in_aot_cache(). assert(r->mapped_base() == last_region->mapped_end(), "must have no gaps"); } last_region = r;) diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 89b3eca1257..cfa2944d974 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1220,7 +1220,7 @@ const ArchivedKlassSubGraphInfoRecord* HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAPS) { assert(!CDSConfig::is_dumping_heap(), "Should not be called when dumping heap"); - if (!k->is_shared()) { + if (!k->in_aot_cache()) { return nullptr; } unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(k); @@ -1274,7 +1274,7 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP if (klasses != nullptr) { for (int i = 0; i < klasses->length(); i++) { Klass* klass = klasses->at(i); - if (!klass->is_shared()) { + if (!klass->in_aot_cache()) { return nullptr; } resolve_or_init(klass, do_init, CHECK_NULL); diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index ab91e76e923..4241619385e 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -179,7 +179,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { TempNewSymbol class_name_sym = SymbolTable::new_symbol(class_name); Klass* klass = SystemDictionary::resolve_or_null(class_name_sym, THREAD); assert(klass != nullptr, "must already be loaded"); - if (!klass->is_shared() && klass->shared_classpath_index() < 0) { + if (!klass->in_aot_cache() && klass->shared_classpath_index() < 0) { // Fake it, so that it will be included into the archive. klass->set_shared_classpath_index(0); // Set the "generated" bit, so it won't interfere with JVMTI. @@ -223,7 +223,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, assert(!HAS_PENDING_EXCEPTION, "Invariant"); result->set_is_generated_shared_class(); - if (!klass->is_shared()) { + if (!klass->in_aot_cache()) { log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string()); SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump } diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index a812af18ba7..c8281ef497c 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -247,12 +247,12 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(InstanceKlass assert(method_type != nullptr, "sanity"); assert(instantiated_method_type != nullptr, "sanity"); - if (!caller_ik->is_shared() || - !invoked_name->is_shared() || - !invoked_type->is_shared() || - !method_type->is_shared() || - (member_method != nullptr && !member_method->is_shared()) || - !instantiated_method_type->is_shared()) { + if (!caller_ik->in_aot_cache() || + !invoked_name->in_aot_cache() || + !invoked_type->in_aot_cache() || + !method_type->in_aot_cache() || + (member_method != nullptr && !member_method->in_aot_cache()) || + !instantiated_method_type->in_aot_cache()) { // These can't be represented as u4 offset, but we wouldn't have archived a lambda proxy in this case anyway. return nullptr; } @@ -325,7 +325,7 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* shared_nest_host = get_shared_nest_host(lambda_ik); assert(shared_nest_host != nullptr, "unexpected nullptr _nest_host"); - assert(shared_nest_host->is_shared(), "nest host must be in CDS archive"); + assert(shared_nest_host->in_aot_cache(), "nest host must be in aot metaspace"); Klass* resolved_nest_host = SystemDictionary::resolve_or_fail(shared_nest_host->name(), class_loader, true, CHECK_NULL); if (resolved_nest_host != shared_nest_host) { diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 73c8710c62e..92773c5be90 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -108,7 +108,7 @@ ReservedSpace MetaspaceShared::_symbol_rs; VirtualSpace MetaspaceShared::_symbol_vs; bool MetaspaceShared::_archive_loading_failed = false; bool MetaspaceShared::_remapped_readwrite = false; -void* MetaspaceShared::_shared_metaspace_static_top = nullptr; +void* MetaspaceShared::_aot_metaspace_static_top = nullptr; intx MetaspaceShared::_relocation_delta; char* MetaspaceShared::_requested_base_address; Array* MetaspaceShared::_archived_method_handle_intrinsics = nullptr; @@ -1208,7 +1208,7 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { JavaThread* THREAD = current; // For exception macros. assert(CDSConfig::is_dumping_archive(), "sanity"); - if (ik->is_shared() && !CDSConfig::is_dumping_final_static_archive()) { + if (ik->in_aot_cache() && !CDSConfig::is_dumping_final_static_archive()) { assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); return false; } @@ -1252,23 +1252,23 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() { } } -void MetaspaceShared::set_shared_metaspace_range(void* base, void *static_top, void* top) { +void MetaspaceShared::set_aot_metaspace_range(void* base, void *static_top, void* top) { assert(base <= static_top && static_top <= top, "must be"); - _shared_metaspace_static_top = static_top; - MetaspaceObj::set_shared_metaspace_range(base, top); + _aot_metaspace_static_top = static_top; + MetaspaceObj::set_aot_metaspace_range(base, top); } -bool MetaspaceShared::is_shared_dynamic(void* p) { - if ((p < MetaspaceObj::shared_metaspace_top()) && - (p >= _shared_metaspace_static_top)) { +bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { + if ((p < MetaspaceObj::aot_metaspace_top()) && + (p >= _aot_metaspace_static_top)) { return true; } else { return false; } } -bool MetaspaceShared::is_shared_static(void* p) { - if (is_in_shared_metaspace(p) && !is_shared_dynamic(p)) { +bool MetaspaceShared::in_aot_cache_static_region(void* p) { + if (in_aot_cache(p) && !in_aot_cache_dynamic_region(p)) { return true; } else { return false; @@ -1368,7 +1368,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end(); // Register CDS memory region with LSan. LSAN_REGISTER_ROOT_REGION(cds_base, cds_end - cds_base); - set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end); + set_aot_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end); _relocation_delta = static_mapinfo->relocation_delta(); _requested_base_address = static_mapinfo->requested_base_address(); if (dynamic_mapped) { @@ -1376,7 +1376,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { AutoCreateSharedArchive = false; } } else { - set_shared_metaspace_range(nullptr, nullptr, nullptr); + set_aot_metaspace_range(nullptr, nullptr, nullptr); if (CDSConfig::is_dumping_dynamic_archive()) { aot_log_warning(aot)("-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); } @@ -1466,7 +1466,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File if (dynamic_mapinfo != nullptr) { // Ensure that the OS won't be able to allocate new memory spaces between the two - // archives, or else it would mess up the simple comparison in MetaspaceObj::is_shared(). + // archives, or else it would mess up the simple comparison in MetaspaceObj::in_aot_cache(). assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap"); } @@ -2075,9 +2075,9 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() { void MetaspaceShared::print_on(outputStream* st) { if (CDSConfig::is_using_archive()) { st->print("CDS archive(s) mapped at: "); - address base = (address)MetaspaceObj::shared_metaspace_base(); - address static_top = (address)_shared_metaspace_static_top; - address top = (address)MetaspaceObj::shared_metaspace_top(); + address base = (address)MetaspaceObj::aot_metaspace_base(); + address static_top = (address)_aot_metaspace_static_top; + address top = (address)MetaspaceObj::aot_metaspace_top(); st->print("[" PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "), ", p2i(base), p2i(static_top), p2i(top)); st->print("size %zu, ", top - base); st->print("SharedBaseAddress: " PTR_FORMAT ", ArchiveRelocationMode: %d.", SharedBaseAddress, ArchiveRelocationMode); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 130e7fe4484..7f0f1128f96 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -54,7 +54,7 @@ class MetaspaceShared : AllStatic { static VirtualSpace _symbol_vs; // used only during -Xshare:dump static bool _archive_loading_failed; static bool _remapped_readwrite; - static void* _shared_metaspace_static_top; + static void* _aot_metaspace_static_top; static intx _relocation_delta; static char* _requested_base_address; static bool _use_optimized_module_handling; @@ -101,14 +101,17 @@ public: // Return true if given address is in the shared metaspace regions (i.e., excluding the // mapped heap region.) - static bool is_in_shared_metaspace(const void* p) { - return MetaspaceObj::is_shared((const MetaspaceObj*)p); + static bool in_aot_cache(const void* p) { + return MetaspaceObj::in_aot_cache((const MetaspaceObj*)p); } - static void set_shared_metaspace_range(void* base, void *static_top, void* top) NOT_CDS_RETURN; + static void set_aot_metaspace_range(void* base, void *static_top, void* top) NOT_CDS_RETURN; - static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false); - static bool is_shared_static(void* p) NOT_CDS_RETURN_(false); + // inside the metaspace of the AOT cache, or the static CDS archive + static bool in_aot_cache_static_region(void* p) NOT_CDS_RETURN_(false); + + // inside the metaspace of the dynamic static CDS archive + static bool in_aot_cache_dynamic_region(void* p) NOT_CDS_RETURN_(false); static void unrecoverable_loading_error(const char* message = "unrecoverable error"); static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0); diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index 3d237e6759a..10d2fc35ea9 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -75,7 +75,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { } InstanceKlass* RunTimeClassInfo::klass() const { - if (MetaspaceShared::is_in_shared_metaspace(this)) { + if (MetaspaceShared::in_aot_cache(this)) { // is inside a mmaped CDS archive. return ArchiveUtils::offset_to_archived_address(_klass_offset); } else { diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index 058d5181881..bf41e05eee5 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -251,7 +251,7 @@ private: public: static RunTimeClassInfo* get_for(InstanceKlass* klass) { - assert(klass->is_shared(), "don't call for non-shared class"); + assert(klass->in_aot_cache(), "don't call for non-shared class"); return *info_pointer_addr(klass); } static void set_for(InstanceKlass* klass, RunTimeClassInfo* record) { diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index d6677faa91d..deb2035eef2 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -415,7 +415,7 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { if (!InstanceKlass::cast(k)->is_loaded()) { continue; } - } else if (k->is_shared() && k->is_objArray_klass()) { + } else if (k->in_aot_cache() && k->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(k)->bottom_klass(); if (bottom->is_instance_klass() && !InstanceKlass::cast(bottom)->is_loaded()) { // This could happen if is a shared class that has been restored @@ -868,7 +868,7 @@ void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) { // a safepoint which checks if handles point to this metadata field. void ClassLoaderData::add_to_deallocate_list(Metadata* m) { // Metadata in shared region isn't deleted. - if (!m->is_shared()) { + if (!m->in_aot_cache()) { MutexLocker ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); if (_deallocate_list == nullptr) { _deallocate_list = new (mtClass) GrowableArray(100, mtClass); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index bf678f94e0e..683fc22b27a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -939,7 +939,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already"); // If the offset was read from the shared archive, it was fixed up already - if (!k->is_shared()) { + if (!k->in_aot_cache()) { if (k->is_instance_klass()) { // During bootstrap, java.lang.Class wasn't loaded so static field // offsets were computed without the size added it. Go back and @@ -977,7 +977,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { } } - if (k->is_shared() && k->has_archived_mirror_index()) { + if (k->in_aot_cache() && k->has_archived_mirror_index()) { if (ArchiveHeapLoader::is_in_use()) { bool present = restore_archived_mirror(k, Handle(), Handle(), Handle(), CHECK); assert(present, "Missing archived mirror for %s", k->external_name()); diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 5dd2cd2385b..50d327d7e8c 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -51,7 +51,7 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( TRAPS) { #if INCLUDE_CDS && INCLUDE_JVMTI assert(ik != nullptr, "sanity"); - assert(ik->is_shared(), "expecting a shared class"); + assert(ik->in_aot_cache(), "expecting a shared class"); if (JvmtiExport::should_post_class_file_load_hook()) { ResourceMark rm(THREAD); // Post the CFLH diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 9bc94f15100..946fbc07f28 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1014,7 +1014,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name, bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, InstanceKlass* super_type, Handle class_loader, bool is_superclass, TRAPS) { - assert(super_type->is_shared(), "must be"); + assert(super_type->in_aot_cache(), "must be"); // Quick check if the super type has been already loaded. // + Don't do it for unregistered classes -- they can be unloaded so @@ -1077,7 +1077,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS) { assert(ik != nullptr, "sanity"); - assert(ik->is_shared(), "sanity"); + assert(ik->in_aot_cache(), "sanity"); assert(!ik->is_unshareable_info_restored(), "shared class can be restored only once"); assert(Atomic::add(&ik->_shared_class_load_count, 1) == 1, "shared class loaded more than once"); Symbol* class_name = ik->name(); @@ -1745,7 +1745,7 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name, klass2, loader_data2); #if INCLUDE_CDS if (CDSConfig::is_dumping_archive() && klass_being_linked != nullptr && - !klass_being_linked->is_shared()) { + !klass_being_linked->in_aot_cache()) { SystemDictionaryShared::record_linking_constraint(constraint_name, InstanceKlass::cast(klass_being_linked), class_loader1, class_loader2); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 904e8cca89d..7b52dfe46aa 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -205,7 +205,7 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { } bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(k)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(k)) { // We have reached a super type that's already in the base archive. Treat it // as "not excluded". return false; @@ -250,7 +250,7 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() - && k->is_shared()) { + && k->in_aot_cache()) { return false; // Do not exclude: unregistered classes are passed from preimage to final image. } @@ -483,7 +483,7 @@ InstanceKlass* SystemDictionaryShared::get_unregistered_class(Symbol* name) { void SystemDictionaryShared::copy_unregistered_class_size_and_crc32(InstanceKlass* klass) { precond(CDSConfig::is_dumping_final_static_archive()); - precond(klass->is_shared()); + precond(klass->in_aot_cache()); // A shared class must have a RunTimeClassInfo record const RunTimeClassInfo* record = find_record(&_static_archive._unregistered_dictionary, @@ -665,7 +665,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { } else { InstanceKlass* ik = InstanceKlass::cast(k); - if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->in_aot_cache()) { // ik is already part of the static archive, so it will never be considered as excluded. return false; } @@ -1018,7 +1018,7 @@ unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); unsigned int hash = primitive_hash(offset); DEBUG_ONLY({ - if (MetaspaceObj::is_shared((const MetaspaceObj*)ptr)) { + if (MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr)) { assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be"); } }); @@ -1106,7 +1106,7 @@ void SystemDictionaryShared::serialize_vm_classes(SerializeClosure* soc) { const RunTimeClassInfo* SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTimeSharedDictionary* dynamic_dict, Symbol* name) { - if (!CDSConfig::is_using_archive() || !name->is_shared()) { + if (!CDSConfig::is_using_archive() || !name->in_aot_cache()) { // The names of all shared classes must also be a shared Symbol. return nullptr; } @@ -1124,7 +1124,7 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim } } - if (!MetaspaceShared::is_shared_dynamic(name)) { + if (!MetaspaceShared::in_aot_cache_dynamic_region(name)) { // The names of all shared classes in the static dict must also be in the // static archive record = static_dict->lookup(name, hash, 0); @@ -1163,7 +1163,7 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) { const char* SystemDictionaryShared::loader_type_for_shared_class(Klass* k) { assert(k != nullptr, "Sanity"); - assert(k->is_shared(), "Must be"); + assert(k->in_aot_cache(), "Must be"); assert(k->is_instance_klass(), "Must be"); InstanceKlass* ik = InstanceKlass::cast(k); if (ik->defined_by_boot_loader()) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index e3c22ee11a0..30b38a5aa59 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -127,7 +127,7 @@ class SharedClassLoadingMark { assert(THREAD != nullptr, "Current thread is nullptr"); assert(_klass != nullptr, "InstanceKlass is nullptr"); if (HAS_PENDING_EXCEPTION) { - if (_klass->is_shared()) { + if (_klass->in_aot_cache()) { _klass->set_shared_loading_failed(); } } @@ -297,7 +297,7 @@ public: template static unsigned int hash_for_shared_dictionary_quick(T* ptr) { - assert(MetaspaceObj::is_shared((const MetaspaceObj*)ptr), "must be"); + assert(MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr), "must be"); assert(ptr > (T*)SharedBaseAddress, "must be"); uintx offset = uintx(ptr) - uintx(SharedBaseAddress); return primitive_hash(offset); diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 4c0a40b837d..f6f5aa70fbd 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -140,7 +140,7 @@ static bool is_eligible_for_verification(InstanceKlass* klass, bool should_verif // Shared classes shouldn't have stackmaps either. // However, bytecodes for shared old classes can be verified because // they have not been rewritten. - !(klass->is_shared() && klass->is_rewritten())); + !(klass->in_aot_cache() && klass->is_rewritten())); } void Verifier::trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class) { diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index f51c17eb038..23bc054755a 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -138,7 +138,7 @@ void vmClasses::resolve_all(TRAPS) { ArchiveHeapLoader::fixup_region(); // Initialize the constant pool for the Object_class - assert(Object_klass()->is_shared(), "must be"); + assert(Object_klass()->in_aot_cache(), "must be"); Object_klass()->constants()->restore_unshareable_info(CHECK); resolve_through(VM_CLASS_ID(Class_klass), scan, CHECK); } else @@ -204,7 +204,7 @@ void vmClasses::resolve_all(TRAPS) { "All well known classes must be resolved in JVMTI early phase")); for (auto id : EnumRange{}) { InstanceKlass* k = _klasses[as_int(id)]; - assert(k->is_shared(), "must not be replaced by JVMTI class file load hook"); + assert(k->in_aot_cache(), "must not be replaced by JVMTI class file load hook"); } } #endif @@ -219,7 +219,7 @@ void vmClasses::resolve_all(TRAPS) { void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* loader_data, Handle domain, TRAPS) { assert(!Universe::is_fully_initialized(), "We can make short cuts only during VM initialization"); - assert(klass->is_shared(), "Must be shared class"); + assert(klass->in_aot_cache(), "Must be shared class"); if (klass->class_loader_data() != nullptr) { return; } diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 80223a4e5cb..5db6cb1b0cc 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -165,7 +165,7 @@ void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, JavaT void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, JavaThread* current) { assert(klass->is_initialized(), ""); - if (TrainingData::have_data() && klass->is_shared()) { + if (TrainingData::have_data() && klass->in_aot_cache()) { _training_replay_queue.push(klass, TrainingReplayQueue_lock, current); } } diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 50115f842e2..ae103c8a339 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -925,7 +925,7 @@ void InterpreterRuntime::cds_resolve_invoke(Bytecodes::Code bytecode, int method ResourceMark rm; InstanceKlass* resolved_iklass = InstanceKlass::cast(link_info.resolved_klass()); log_info(aot, resolve)("Not resolved: class not linked: %s %s %s", - resolved_iklass->is_shared() ? "is_shared" : "", + resolved_iklass->in_aot_cache() ? "in_aot_cache" : "", resolved_iklass->init_state_name(), resolved_iklass->external_name()); } diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index d64954b50bd..41a96eebfad 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -124,7 +124,7 @@ void Rewriter::make_constant_pool_cache(TRAPS) { THREAD); #if INCLUDE_CDS if (!HAS_PENDING_EXCEPTION && CDSConfig::is_dumping_archive()) { - if (_pool->pool_holder()->is_shared()) { + if (_pool->pool_holder()->in_aot_cache()) { assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); // We are linking a shared class from the base archive. This // class won't be written into the dynamic archive, so there's no @@ -567,8 +567,8 @@ void Rewriter::rewrite_bytecodes(TRAPS) { void Rewriter::rewrite(InstanceKlass* klass, TRAPS) { #if INCLUDE_CDS - if (klass->is_shared()) { - assert(!klass->is_rewritten(), "rewritten shared classes cannot be rewritten again"); + if (klass->in_aot_cache()) { + assert(!klass->is_rewritten(), "rewritten classes in the AOT cache cannot be rewritten again"); } #endif // INCLUDE_CDS ResourceMark rm(THREAD); diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index a7c0045eac3..f158fefdba0 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -65,8 +65,8 @@ void FreeHeap(void* p) { os::free(p); } -void* MetaspaceObj::_shared_metaspace_base = nullptr; -void* MetaspaceObj::_shared_metaspace_top = nullptr; +void* MetaspaceObj::_aot_metaspace_base = nullptr; +void* MetaspaceObj::_aot_metaspace_top = nullptr; void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 9e500135d0b..35180fdba5e 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -261,43 +261,43 @@ class MetaspaceObj { // void deallocate_contents(ClassLoaderData* loader_data); friend class VMStructs; - // When CDS is enabled, all shared metaspace objects are mapped + // All metsapce objects in the AOT cache (CDS archive) are mapped // into a single contiguous memory block, so we can use these - // two pointers to quickly determine if something is in the - // shared metaspace. - // When CDS is not enabled, both pointers are set to null. - static void* _shared_metaspace_base; // (inclusive) low address - static void* _shared_metaspace_top; // (exclusive) high address + // two pointers to quickly determine if a MetaspaceObj is in the + // AOT cache. + // When AOT/CDS is not enabled, both pointers are set to null. + static void* _aot_metaspace_base; // (inclusive) low address + static void* _aot_metaspace_top; // (exclusive) high address public: // Returns true if the pointer points to a valid MetaspaceObj. A valid // MetaspaceObj is MetaWord-aligned and contained within either - // non-shared or shared metaspace. + // regular- or aot metaspace. static bool is_valid(const MetaspaceObj* p); #if INCLUDE_CDS - static bool is_shared(const MetaspaceObj* p) { - // If no shared metaspace regions are mapped, _shared_metaspace_{base,top} will + static bool in_aot_cache(const MetaspaceObj* p) { + // If no shared metaspace regions are mapped, _aot_metaspace_{base,top} will // both be null and all values of p will be rejected quickly. - return (((void*)p) < _shared_metaspace_top && - ((void*)p) >= _shared_metaspace_base); + return (((void*)p) < _aot_metaspace_top && + ((void*)p) >= _aot_metaspace_base); } - bool is_shared() const { return MetaspaceObj::is_shared(this); } + bool in_aot_cache() const { return MetaspaceObj::in_aot_cache(this); } #else - static bool is_shared(const MetaspaceObj* p) { return false; } - bool is_shared() const { return false; } + static bool in_aot_cache(const MetaspaceObj* p) { return false; } + bool in_aot_cache() const { return false; } #endif void print_address_on(outputStream* st) const; // nonvirtual address printing - static void set_shared_metaspace_range(void* base, void* top) { - _shared_metaspace_base = base; - _shared_metaspace_top = top; + static void set_aot_metaspace_range(void* base, void* top) { + _aot_metaspace_base = base; + _aot_metaspace_top = top; } - static void* shared_metaspace_base() { return _shared_metaspace_base; } - static void* shared_metaspace_top() { return _shared_metaspace_top; } + static void* aot_metaspace_base() { return _aot_metaspace_base; } + static void* aot_metaspace_top() { return _aot_metaspace_top; } #define METASPACE_OBJ_TYPES_DO(f) \ f(Class) \ diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp index f2542069f04..6cc4fd97b0a 100644 --- a/src/hotspot/share/memory/metadataFactory.hpp +++ b/src/hotspot/share/memory/metadataFactory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -59,7 +59,7 @@ class MetadataFactory : AllStatic { static void free_array(ClassLoaderData* loader_data, Array* data) { if (data != nullptr) { assert(loader_data != nullptr, "shouldn't pass null"); - assert(!data->is_shared(), "cannot deallocate array in shared spaces"); + assert(!data->in_aot_cache(), "cannot deallocate array in aot metaspace spaces"); int size = data->size(); loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size); } @@ -73,7 +73,7 @@ class MetadataFactory : AllStatic { int size = md->size(); // Call metadata's deallocate function which will deallocate fields and release_C_heap_structures assert(!md->on_stack(), "can't deallocate things on stack"); - assert(!md->is_shared(), "cannot deallocate if in shared spaces"); + assert(!md->in_aot_cache(), "cannot deallocate if in aot metaspace spaces"); md->deallocate_contents(loader_data); // Call the destructor. This is currently used for MethodData which has a member // that needs to be destructed to release resources. Most Metadata derived classes have noop diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 92b33443457..1983fbc870c 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1036,8 +1036,8 @@ void Metaspace::purge(bool classes_unloaded) { // Returns true if pointer points into one of the metaspace regions, or // into the class space. -bool Metaspace::is_in_shared_metaspace(const void* ptr) { - return MetaspaceShared::is_in_shared_metaspace(ptr); +bool Metaspace::in_aot_cache(const void* ptr) { + return MetaspaceShared::in_aot_cache(ptr); } // Returns true if pointer points into one of the non-class-space metaspace regions. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 293782c0d75..b2c3c29a812 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -130,7 +130,7 @@ public: // Returns true if the pointer points into class space, non-class metaspace, or the // metadata portion of the CDS archive. static bool contains(const void* ptr) { - return is_in_shared_metaspace(ptr) || // in cds + return in_aot_cache(ptr) || // in cds is_in_class_space(ptr) || // in class space is_in_nonclass_metaspace(ptr); // in one of the non-class regions? } @@ -142,7 +142,7 @@ public: } // Returns true if pointer points into the CDS klass region. - static bool is_in_shared_metaspace(const void* ptr); + static bool in_aot_cache(const void* ptr); // Returns true if pointer points into one of the non-class-space metaspace regions. static bool is_in_nonclass_metaspace(const void* ptr); diff --git a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp index d366038ceb1..2d1877a1ed1 100644 --- a/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp +++ b/src/hotspot/share/memory/metaspace/printCLDMetaspaceInfoClosure.cpp @@ -63,7 +63,7 @@ public: CountKlassClosure() : _num_classes(0), _num_classes_shared(0) {} void do_klass(Klass* k) { _num_classes++; - if (k->is_shared()) { + if (k->in_aot_cache()) { _num_classes_shared++; } } diff --git a/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp b/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp index d0d68203759..75fc02df38f 100644 --- a/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp +++ b/src/hotspot/share/memory/metaspace/printMetaspaceInfoKlassClosure.cpp @@ -39,8 +39,8 @@ void PrintMetaspaceInfoKlassClosure::do_klass(Klass* k) { _out->cr(); _out->print("%4zu: ", _cnt); - // Print a 's' for shared classes - _out->put(k->is_shared() ? 's': ' '); + // Print a 's' for classes in the aot metaspace (used to be called shared classes) + _out->put(k->in_aot_cache() ? 's': ' '); ResourceMark rm; _out->print(" %s", k->external_name()); diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 73e3a5e4c15..198ff1ef75e 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -259,9 +259,9 @@ void ArrayKlass::log_array_class_load(Klass* k) { LogStream ls(lt); ResourceMark rm; ls.print("%s", k->name()->as_klass_external_name()); - if (MetaspaceShared::is_shared_dynamic((void*)k)) { + if (MetaspaceShared::in_aot_cache_dynamic_region((void*)k)) { ls.print(" source: shared objects file (top)"); - } else if (MetaspaceShared::is_shared_static((void*)k)) { + } else if (MetaspaceShared::in_aot_cache_static_region((void*)k)) { ls.print(" source: shared objects file"); } ls.cr(); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 3223c56628e..735968f7a95 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -383,8 +383,8 @@ void ConstantPool::restore_unshareable_info(TRAPS) { return; } assert(is_constantPool(), "ensure C++ vtable is restored"); - assert(on_stack(), "should always be set for shared constant pools"); - assert(is_shared(), "should always be set for shared constant pools"); + assert(on_stack(), "should always be set for constant pools in AOT cache"); + assert(in_aot_cache(), "should always be set for constant pools in AOT cache"); if (is_for_method_handle_intrinsic()) { // See the same check in remove_unshareable_info() below. assert(cache() == nullptr, "must not have cpCache"); @@ -428,11 +428,11 @@ void ConstantPool::restore_unshareable_info(TRAPS) { } void ConstantPool::remove_unshareable_info() { - // Shared ConstantPools are in the RO region, so the _flags cannot be modified. + // ConstantPools in AOT cache are in the RO region, so the _flags cannot be modified. // The _on_stack flag is used to prevent ConstantPools from deallocation during - // class redefinition. Since shared ConstantPools cannot be deallocated anyway, + // class redefinition. Since such ConstantPools cannot be deallocated anyway, // we always set _on_stack to true to avoid having to change _flags during runtime. - _flags |= (_on_stack | _is_shared); + _flags |= (_on_stack | _in_aot_cache); if (is_for_method_handle_intrinsic()) { // This CP was created by Method::make_method_handle_intrinsic() and has nothing @@ -2258,13 +2258,13 @@ void ConstantPool::set_on_stack(const bool value) { if (value) { // Only record if it's not already set. if (!on_stack()) { - assert(!is_shared(), "should always be set for shared constant pools"); + assert(!in_aot_cache(), "should always be set for constant pools in AOT cache"); _flags |= _on_stack; MetadataOnStackMark::record(this); } } else { // Clearing is done single-threadedly. - if (!is_shared()) { + if (!in_aot_cache()) { _flags &= (u2)(~_on_stack); } } diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 8999acf4d3a..9cbeb1245be 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -145,7 +145,7 @@ class ConstantPool : public Metadata { enum { _has_preresolution = 1, // Flags _on_stack = 2, - _is_shared = 4, + _in_aot_cache = 4, _has_dynamic_constant = 8, _is_for_method_handle_intrinsic = 16 }; @@ -212,7 +212,7 @@ class ConstantPool : public Metadata { bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } void set_has_preresolution() { - assert(!is_shared(), "should never be called on shared ConstantPools"); + assert(!in_aot_cache(), "should never be called on ConstantPools in AOT cache"); _flags |= _has_preresolution; } @@ -248,8 +248,8 @@ class ConstantPool : public Metadata { bool is_maybe_on_stack() const; void set_on_stack(const bool value); - // Faster than MetaspaceObj::is_shared() - used by set_on_stack() - bool is_shared() const { return (_flags & _is_shared) != 0; } + // Shadows MetaspaceObj::in_aot_cache(). It's faster and is used by set_on_stack() + bool in_aot_cache() const { return (_flags & _in_aot_cache) != 0; } bool has_dynamic_constant() const { return (_flags & _has_dynamic_constant) != 0; } void set_has_dynamic_constant() { _flags |= _has_dynamic_constant; } diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index a56e3453970..8944f85af0d 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -584,7 +584,7 @@ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, Resolv #endif // INCLUDE_CDS void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) { - assert(!is_shared(), "shared caches are not deallocated"); + assert(!in_aot_cache(), "objects in aot metaspace are not deallocated"); data->remove_handle(_resolved_references); set_resolved_references(OopHandle()); MetadataFactory::free_array(data, _reference_map); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 964006b3b9c..568ccd72176 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -561,7 +561,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { if (methods != nullptr && methods != Universe::the_empty_method_array() && - !methods->is_shared()) { + !methods->in_aot_cache()) { for (int i = 0; i < methods->length(); i++) { Method* method = methods->at(i); if (method == nullptr) continue; // maybe null if error processing @@ -585,21 +585,21 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, // check that the interfaces don't come from super class Array* sti = (super_klass == nullptr) ? nullptr : super_klass->transitive_interfaces(); - if (ti != sti && ti != nullptr && !ti->is_shared()) { + if (ti != sti && ti != nullptr && !ti->in_aot_cache()) { MetadataFactory::free_array(loader_data, ti); } } // local interfaces can be empty if (local_interfaces != Universe::the_empty_instance_klass_array() && - local_interfaces != nullptr && !local_interfaces->is_shared()) { + local_interfaces != nullptr && !local_interfaces->in_aot_cache()) { MetadataFactory::free_array(loader_data, local_interfaces); } } void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data, Array* record_components) { - if (record_components != nullptr && !record_components->is_shared()) { + if (record_components != nullptr && !record_components->in_aot_cache()) { for (int i = 0; i < record_components->length(); i++) { RecordComponent* record_component = record_components->at(i); MetadataFactory::free_metadata(loader_data, record_component); @@ -643,7 +643,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { if (method_ordering() != nullptr && method_ordering() != Universe::the_empty_int_array() && - !method_ordering()->is_shared()) { + !method_ordering()->in_aot_cache()) { MetadataFactory::free_array(loader_data, method_ordering()); } set_method_ordering(nullptr); @@ -651,7 +651,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // default methods can be empty if (default_methods() != nullptr && default_methods() != Universe::the_empty_method_array() && - !default_methods()->is_shared()) { + !default_methods()->in_aot_cache()) { MetadataFactory::free_array(loader_data, default_methods()); } // Do NOT deallocate the default methods, they are owned by superinterfaces. @@ -659,7 +659,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // default methods vtable indices can be empty if (default_vtable_indices() != nullptr && - !default_vtable_indices()->is_shared()) { + !default_vtable_indices()->in_aot_cache()) { MetadataFactory::free_array(loader_data, default_vtable_indices()); } set_default_vtable_indices(nullptr); @@ -672,7 +672,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { secondary_supers() != Universe::the_empty_klass_array() && // see comments in compute_secondary_supers about the following cast (address)(secondary_supers()) != (address)(transitive_interfaces()) && - !secondary_supers()->is_shared()) { + !secondary_supers()->in_aot_cache()) { MetadataFactory::free_array(loader_data, secondary_supers()); } set_secondary_supers(nullptr, SECONDARY_SUPERS_BITMAP_EMPTY); @@ -681,17 +681,17 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); - if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->is_shared()) { + if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fieldinfo_stream()); } set_fieldinfo_stream(nullptr); - if (fieldinfo_search_table() != nullptr && !fieldinfo_search_table()->is_shared()) { + if (fieldinfo_search_table() != nullptr && !fieldinfo_search_table()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fieldinfo_search_table()); } set_fieldinfo_search_table(nullptr); - if (fields_status() != nullptr && !fields_status()->is_shared()) { + if (fields_status() != nullptr && !fields_status()->in_aot_cache()) { MetadataFactory::free_array(loader_data, fields_status()); } set_fields_status(nullptr); @@ -700,7 +700,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // delete it, yet. The new class's previous version will point to this. if (constants() != nullptr) { assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - if (!constants()->is_shared()) { + if (!constants()->in_aot_cache()) { MetadataFactory::free_metadata(loader_data, constants()); } // Delete any cached resolution errors for the constant pool @@ -711,27 +711,27 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { if (inner_classes() != nullptr && inner_classes() != Universe::the_empty_short_array() && - !inner_classes()->is_shared()) { + !inner_classes()->in_aot_cache()) { MetadataFactory::free_array(loader_data, inner_classes()); } set_inner_classes(nullptr); if (nest_members() != nullptr && nest_members() != Universe::the_empty_short_array() && - !nest_members()->is_shared()) { + !nest_members()->in_aot_cache()) { MetadataFactory::free_array(loader_data, nest_members()); } set_nest_members(nullptr); if (permitted_subclasses() != nullptr && permitted_subclasses() != Universe::the_empty_short_array() && - !permitted_subclasses()->is_shared()) { + !permitted_subclasses()->in_aot_cache()) { MetadataFactory::free_array(loader_data, permitted_subclasses()); } set_permitted_subclasses(nullptr); // We should deallocate the Annotations instance if it's not in shared spaces. - if (annotations() != nullptr && !annotations()->is_shared()) { + if (annotations() != nullptr && !annotations()->in_aot_cache()) { MetadataFactory::free_metadata(loader_data, annotations()); } set_annotations(nullptr); @@ -994,7 +994,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { if (!is_linked()) { if (!is_rewritten()) { - if (is_shared()) { + if (in_aot_cache()) { assert(!verified_at_dump_time(), "must be"); } { @@ -1013,7 +1013,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // also sets rewritten rewrite_class(CHECK_false); - } else if (is_shared()) { + } else if (in_aot_cache()) { SystemDictionaryShared::check_verification_constraints(this, CHECK_false); } @@ -1031,7 +1031,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { // 2) the class is loaded by built-in class loader but failed to add archived loader constraints or // 3) the class was not verified during dump time bool need_init_table = true; - if (is_shared() && verified_at_dump_time() && + if (in_aot_cache() && verified_at_dump_time() && SystemDictionaryShared::check_linking_constraints(THREAD, this)) { need_init_table = false; } @@ -1073,7 +1073,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { void InstanceKlass::rewrite_class(TRAPS) { assert(is_loaded(), "must be loaded"); if (is_rewritten()) { - assert(is_shared(), "rewriting an unshared class?"); + assert(in_aot_cache(), "rewriting an unshared class?"); return; } Rewriter::rewrite(this, CHECK); @@ -1685,7 +1685,7 @@ void InstanceKlass::call_class_initializer(TRAPS) { AOTClassInitializer::call_runtime_setup(THREAD, this); return; } else if (has_archived_enum_objs()) { - assert(is_shared(), "must be"); + assert(in_aot_cache(), "must be"); bool initialized = CDSEnumKlass::initialize_enum_klass(this, CHECK); if (initialized) { return; @@ -2330,7 +2330,7 @@ void PrintClassClosure::do_klass(Klass* k) { if (ik->is_rewritten()) buf[i++] = 'W'; if (ik->is_contended()) buf[i++] = 'C'; if (ik->has_been_redefined()) buf[i++] = 'R'; - if (ik->is_shared()) buf[i++] = 'S'; + if (ik->in_aot_cache()) buf[i++] = 'S'; } buf[i++] = '\0'; _st->print("%-7s ", buf); @@ -2763,7 +2763,7 @@ void InstanceKlass::init_shared_package_entry() { } } else if (CDSConfig::is_dumping_dynamic_archive() && CDSConfig::is_using_full_module_graph() && - MetaspaceShared::is_in_shared_metaspace(_package_entry)) { + MetaspaceShared::in_aot_cache(_package_entry)) { // _package_entry is an archived package in the base archive. Leave it as is. } else { _package_entry = nullptr; @@ -2845,7 +2845,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl // retrieved during dump time. // Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { - if (MetaspaceShared::is_in_shared_metaspace(this)) { + if (MetaspaceShared::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; @@ -3081,14 +3081,14 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_ // ensure java/ packages only loaded by boot or platform builtin loaders // not needed for shared class since CDS does not archive prohibited classes. - if (!is_shared()) { + if (!in_aot_cache()) { check_prohibited_package(name(), loader_data, CHECK); } - if (is_shared() && _package_entry != nullptr) { + if (in_aot_cache() && _package_entry != nullptr) { if (CDSConfig::is_using_full_module_graph() && _package_entry == pkg_entry) { // we can use the saved package - assert(MetaspaceShared::is_in_shared_metaspace(_package_entry), "must be"); + assert(MetaspaceShared::in_aot_cache(_package_entry), "must be"); return; } else { _package_entry = nullptr; @@ -3970,8 +3970,8 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, info_stream.print(" source: %s", class_loader->klass()->external_name()); } } else { - assert(this->is_shared(), "must be"); - if (MetaspaceShared::is_shared_dynamic((void*)this)) { + assert(this->in_aot_cache(), "must be"); + if (MetaspaceShared::in_aot_cache_dynamic_region((void*)this)) { info_stream.print(" source: shared objects file (top)"); } else { info_stream.print(" source: shared objects file"); @@ -4254,7 +4254,7 @@ void JNIid::verify(InstanceKlass* holder) { void InstanceKlass::set_init_state(ClassState state) { #ifdef ASSERT - bool good_state = is_shared() ? (_init_state <= state) + bool good_state = in_aot_cache() ? (_init_state <= state) : (_init_state < state); assert(good_state || state == allocated, "illegal state transition"); #endif @@ -4355,7 +4355,7 @@ void InstanceKlass::purge_previous_version_list() { assert(pvcp->pool_holder() != nullptr, "Constant pool with no holder"); guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); live_count++; - if (pvcp->is_shared()) { + if (pvcp->in_aot_cache()) { // Shared previous versions can never be removed so no cleaning is needed. log_trace(redefine, class, iklass, purge)("previous version " PTR_FORMAT " is shared", p2i(pv_node)); } else { @@ -4467,7 +4467,7 @@ void InstanceKlass::add_previous_version(InstanceKlass* scratch_class, assert(scratch_class->previous_versions() == nullptr, "shouldn't have a previous version"); scratch_class->link_previous_versions(previous_versions()); link_previous_versions(scratch_class); - if (cp_ref->is_shared()) { + if (cp_ref->in_aot_cache()) { log_trace(redefine, class, iklass, add) ("scratch class added; class is shared"); } else { // We only set clean_previous_versions flag for processing during class diff --git a/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp b/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp index eed87d2644b..4014c752e04 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -52,7 +52,7 @@ void InstanceMirrorKlass::do_metadata(oop obj, OopClosureType* closure) { if (klass != nullptr) { if (klass->class_loader_data() == nullptr) { // This is a mirror that belongs to a shared class that has not been loaded yet. - assert(klass->is_shared(), "Must be"); + assert(klass->in_aot_cache(), "Must be"); } else if (klass->is_instance_klass() && klass->class_loader_data()->has_class_mirror_holder()) { // A non-strong hidden class doesn't have its own class loader, // so when handling the java mirror for the class we need to make sure its class diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 17e2ccbc911..f4ae128aef7 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -805,7 +805,7 @@ void Klass::remove_unshareable_info() { // Null out class_loader_data because we don't share that yet. set_class_loader_data(nullptr); - set_is_shared(); + set_in_aot_cache(); if (CDSConfig::is_dumping_classic_static_archive()) { // "Classic" static archives are required to have deterministic contents. @@ -858,7 +858,7 @@ void Klass::remove_java_mirror() { void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { assert(is_klass(), "ensure C++ vtable is restored"); - assert(is_shared(), "must be set"); + assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, aot, unshareable)) { diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 91bd60b0e3e..d62f3f21ee2 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -174,9 +174,9 @@ private: #if INCLUDE_CDS // Various attributes for shared classes. Should be zero for a non-shared class. - u2 _shared_class_flags; + u2 _shared_class_flags; enum CDSSharedClassFlags { - _is_shared_class = 1 << 0, // shadows MetaspaceObj::is_shared + _in_aot_cache = 1 << 0, _archived_lambda_proxy_is_available = 1 << 1, _has_value_based_class_annotation = 1 << 2, _verified_at_dump_time = 1 << 3, @@ -378,13 +378,13 @@ protected: NOT_CDS(return false;) } - bool is_shared() const { // shadows MetaspaceObj::is_shared)() - CDS_ONLY(return (_shared_class_flags & _is_shared_class) != 0;) + bool in_aot_cache() const { // shadows MetaspaceObj::in_aot_cache)() + CDS_ONLY(return (_shared_class_flags & _in_aot_cache) != 0;) NOT_CDS(return false;) } - void set_is_shared() { - CDS_ONLY(_shared_class_flags |= _is_shared_class;) + void set_in_aot_cache() { + CDS_ONLY(_shared_class_flags |= _in_aot_cache;) } // Obtain the module or package for this class @@ -610,7 +610,7 @@ public: virtual void remove_java_mirror(); bool is_unshareable_info_restored() const { - assert(is_shared(), "use this for shared classes only"); + assert(in_aot_cache(), "use this for shared classes only"); if (has_archived_mirror_index()) { // _java_mirror is not a valid OopHandle but rather an encoded reference in the shared heap return false; diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index 55242b2a2d1..ce4e322930f 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -50,7 +50,7 @@ inline InstanceKlass* klassVtable::ik() const { } bool klassVtable::is_preinitialized_vtable() { - return _klass->is_shared() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); + return _klass->in_aot_cache() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); } @@ -163,7 +163,7 @@ void klassVtable::initialize_vtable(GrowableArray* supers) { // Note: Arrays can have intermediate array supers. Use java_super to skip them. InstanceKlass* super = _klass->java_super(); - bool is_shared = _klass->is_shared(); + bool in_aot_cache = _klass->in_aot_cache(); Thread* current = Thread::current(); if (!_klass->is_array_klass()) { @@ -178,7 +178,7 @@ void klassVtable::initialize_vtable(GrowableArray* supers) { #endif if (Universe::is_bootstrapping()) { - assert(!is_shared, "sanity"); + assert(!in_aot_cache, "sanity"); // just clear everything for (int i = 0; i < _length; i++) table()[i].clear(); return; @@ -1089,7 +1089,7 @@ void itableMethodEntry::initialize(InstanceKlass* klass, Method* m) { if (m == nullptr) return; #ifdef ASSERT - if (MetaspaceShared::is_in_shared_metaspace((void*)&_method) && + if (MetaspaceShared::in_aot_cache((void*)&_method) && !MetaspaceShared::remapped_readwrite() && m->method_holder()->verified_at_dump_time() && klass->verified_at_dump_time()) { @@ -1275,7 +1275,7 @@ int klassItable::assign_itable_indices_for_interface(InstanceKlass* klass) { // A shared method could have an initialized itable_index that // is < 0. assert(m->vtable_index() == Method::pending_itable_index || - m->is_shared(), + m->in_aot_cache(), "set by initialize_vtable"); m->set_itable_index(ime_num); // Progress to next itable entry diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 40c44e07e37..03330aee209 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -446,7 +446,7 @@ void Method::restore_unshareable_info(TRAPS) { #endif void Method::set_vtable_index(int index) { - if (is_shared() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_vtable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. @@ -457,7 +457,7 @@ void Method::set_vtable_index(int index) { } void Method::set_itable_index(int index) { - if (is_shared() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. The dumptime @@ -1251,7 +1251,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // If the code cache is full, we may reenter this function for the // leftover methods that weren't linked. if (adapter() != nullptr) { - if (adapter()->is_shared()) { + if (adapter()->in_aot_cache()) { assert(adapter()->is_linked(), "Adapter is shared but not linked"); } else { return; @@ -2175,7 +2175,7 @@ bool Method::is_valid_method(const Method* m) { return false; } else if (!os::is_readable_range(m, m + 1)) { return false; - } else if (m->is_shared()) { + } else if (m->in_aot_cache()) { return CppVtables::is_valid_shared_method(m); } else if (Metaspace::contains_non_shared(m)) { return has_method_vptr((const void*)m); diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 4797eed0a31..49153b3e931 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -705,7 +705,7 @@ void TrainingData::metaspace_pointers_do(MetaspaceClosure* iter) { } bool TrainingData::Key::can_compute_cds_hash(const Key* const& k) { - return k->meta() == nullptr || MetaspaceObj::is_shared(k->meta()); + return k->meta() == nullptr || MetaspaceObj::in_aot_cache(k->meta()); } uint TrainingData::Key::cds_hash(const Key* const& k) { diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 0d705c84f82..511f9efdfb9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3422,7 +3422,7 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); - if (!caller_ik->is_shared()) { + if (!caller_ik->in_aot_cache()) { // there won't be a shared lambda class if the caller_ik is not in the shared archive. return nullptr; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a22cb9d51ce..63920583e18 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2154,7 +2154,7 @@ WB_ENTRY(jboolean, WB_IsSharedInternedString(JNIEnv* env, jobject wb, jobject st WB_END WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) - return (jboolean)MetaspaceShared::is_in_shared_metaspace(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + return (jboolean)MetaspaceShared::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); WB_END WB_ENTRY(jboolean, WB_AreSharedStringsMapped(JNIEnv* env)) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index dc25fec9de7..4d3f1327d43 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2737,7 +2737,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth if (entry != nullptr) { assert(entry->is_linked(), "AdapterHandlerEntry must have been linked"); #ifdef ASSERT - if (!entry->is_shared() && VerifyAdapterSharing) { + if (!entry->in_aot_cache() && VerifyAdapterSharing) { verify_adapter_sharing(total_args_passed, sig_bt, entry); } #endif diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 3575ef70d19..1fba55cde99 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -347,8 +347,8 @@ /* Memory */ \ /**********/ \ \ - static_field(MetaspaceObj, _shared_metaspace_base, void*) \ - static_field(MetaspaceObj, _shared_metaspace_top, void*) \ + static_field(MetaspaceObj, _aot_metaspace_base, void*) \ + static_field(MetaspaceObj, _aot_metaspace_top, void*) \ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java index 6550ca32d65..aab0281ef82 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/MetaspaceObj.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -32,8 +32,8 @@ import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; public class MetaspaceObj { - private static Address sharedMetaspaceBaseAddr; - private static Address sharedMetaspaceTopAddr; + private static Address aotMetaspaceBaseAddr; + private static Address aotMetaspaceTopAddr; static { VM.registerVMInitializedObserver(new Observer() { @@ -45,13 +45,13 @@ public class MetaspaceObj { private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("MetaspaceObj"); - sharedMetaspaceBaseAddr = type.getAddressField("_shared_metaspace_base").getStaticFieldAddress(); - sharedMetaspaceTopAddr = type.getAddressField("_shared_metaspace_top").getStaticFieldAddress(); + aotMetaspaceBaseAddr = type.getAddressField("_aot_metaspace_base").getStaticFieldAddress(); + aotMetaspaceTopAddr = type.getAddressField("_aot_metaspace_top").getStaticFieldAddress(); } public static boolean isShared(Address addr) { - Address base = sharedMetaspaceBaseAddr.getAddressAt(0); - Address top = sharedMetaspaceTopAddr. getAddressAt(0); + Address base = aotMetaspaceBaseAddr.getAddressAt(0); + Address top = aotMetaspaceTopAddr. getAddressAt(0); return base.lessThanOrEqual(addr) && addr.lessThan(top); } From 62bc7b7c4247a62c23ea93cd960c3c0434925c49 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Sep 2025 05:42:18 +0000 Subject: [PATCH 354/471] 8300080: offset_of for GCC/Clang exhibits undefined behavior and is not always a compile-time constant Reviewed-by: stefank, jsjolen --- make/hotspot/lib/CompileJvm.gmk | 4 +++- .../share/utilities/globalDefinitions.hpp | 3 +++ .../share/utilities/globalDefinitions_gcc.hpp | 18 ------------------ .../utilities/globalDefinitions_visCPP.hpp | 2 -- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 6b5edc85b23..bf92c50576a 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -97,11 +97,13 @@ CFLAGS_VM_VERSION := \ DISABLED_WARNINGS_gcc := array-bounds comment delete-non-virtual-dtor \ empty-body format-zero-length implicit-fallthrough int-in-bool-context \ + invalid-offsetof \ maybe-uninitialized missing-field-initializers \ shift-negative-value unknown-pragmas unused-but-set-variable \ unused-local-typedefs unused-variable -DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor missing-braces \ +DISABLED_WARNINGS_clang := delete-non-abstract-non-virtual-dtor \ + invalid-offsetof missing-braces \ sometimes-uninitialized unknown-pragmas unused-but-set-variable \ unused-function unused-local-typedef unused-private-field unused-variable diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 1ef548d6510..64ccae539a3 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -85,6 +85,9 @@ class oopDesc; // they cannot be defined and potential callers will fail to compile. #define NONCOPYABLE(C) C(C const&) = delete; C& operator=(C const&) = delete /* next token must be ; */ +// offset_of was a workaround for UB with offsetof uses that are no longer an +// issue. This can be removed once all uses have been converted. +#define offset_of(klass, field) offsetof(klass, field) //---------------------------------------------------------------------------------------------------- // Printf-style formatters for fixed- and variable-width types as pointers and diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index 41b7868f8c7..f82f9b1386a 100644 --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -84,24 +84,6 @@ inline int g_isnan(double f) { return isnan(f); } inline int g_isfinite(jfloat f) { return isfinite(f); } inline int g_isfinite(jdouble f) { return isfinite(f); } - -// gcc warns about applying offsetof() to non-POD object or calculating -// offset directly when base address is null. The -Wno-invalid-offsetof -// option could be used to suppress this warning, but we instead just -// avoid the use of offsetof(). -// -// FIXME: This macro is complex and rather arcane. Perhaps we should -// use offsetof() instead, with the invalid-offsetof warning -// temporarily disabled. -#define offset_of(klass,field) \ -([]() { \ - alignas(16) char space[sizeof (klass)]; \ - klass* dummyObj = (klass*)space; \ - char* c = (char*)(void*)&dummyObj->field; \ - return (size_t)(c - space); \ -}()) - - #if defined(_LP64) && defined(__APPLE__) #define JLONG_FORMAT "%ld" #define JLONG_FORMAT_W(width) "%" #width "ld" diff --git a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp index 536b79165ae..b9d25096cd5 100644 --- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp @@ -85,8 +85,6 @@ inline int g_isnan(jdouble f) { return _isnan(f); } inline int g_isfinite(jfloat f) { return _finite(f); } inline int g_isfinite(jdouble f) { return _finite(f); } -#define offset_of(klass,field) offsetof(klass,field) - #define THREAD_LOCAL __declspec(thread) // Inlining support From a03302d41bb9971736d4d56381ca0cad1eb3e34b Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 4 Sep 2025 06:33:57 +0000 Subject: [PATCH 355/471] 8366434: THP not working properly with G1 after JDK-8345655 Co-authored-by: Stefan Karlsson Co-authored-by: Stefan Johansson Reviewed-by: stefank, shade --- src/hotspot/share/memory/memoryReserver.cpp | 5 +- src/hotspot/share/memory/memoryReserver.hpp | 1 + .../gc/TestTransparentHugePagesHeap.java | 152 ++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index a6c1be5b33c..11a0422f7b0 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -110,12 +110,13 @@ static char* reserve_memory_inner(char* requested_address, ReservedSpace MemoryReserver::reserve_memory(char* requested_address, size_t size, size_t alignment, + size_t page_size, bool exec, MemTag mem_tag) { char* base = reserve_memory_inner(requested_address, size, alignment, exec, mem_tag); if (base != nullptr) { - return ReservedSpace(base, size, alignment, os::vm_page_size(), exec, false /* special */); + return ReservedSpace(base, size, alignment, page_size, exec, false /* special */); } // Failed @@ -188,7 +189,7 @@ ReservedSpace MemoryReserver::reserve(char* requested_address, } // == Case 3 == - return reserve_memory(requested_address, size, alignment, executable, mem_tag); + return reserve_memory(requested_address, size, alignment, page_size, executable, mem_tag); } ReservedSpace MemoryReserver::reserve(char* requested_address, diff --git a/src/hotspot/share/memory/memoryReserver.hpp b/src/hotspot/share/memory/memoryReserver.hpp index f8f642cca95..fd052e5e283 100644 --- a/src/hotspot/share/memory/memoryReserver.hpp +++ b/src/hotspot/share/memory/memoryReserver.hpp @@ -34,6 +34,7 @@ class MemoryReserver : AllStatic { static ReservedSpace reserve_memory(char* requested_address, size_t size, size_t alignment, + size_t page_size, bool exec, MemTag mem_tag); diff --git a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java new file mode 100644 index 00000000000..25044d2c3e4 --- /dev/null +++ b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=G1 + * @summary Run tests with G1 + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.G1 + * @run driver TestTransparentHugePagesHeap G1 +*/ +/* + * @test id=Parallel + * @summary Run tests with Parallel + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.Parallel + * @run driver TestTransparentHugePagesHeap Parallel +*/ +/* + * @test id=Serial + * @summary Run tests with Serial + * @library /test/lib + * @build jdk.test.lib.Platform + * @requires os.family == "linux" + * @requires vm.gc.Serial + * @run driver TestTransparentHugePagesHeap Serial +*/ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Scanner; + +import jdk.test.lib.os.linux.HugePageConfiguration; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; + +import jtreg.SkippedException; + +// We verify that the heap can be backed by THP by looking at the +// THPeligible field for the heap section in /proc/self/smaps. This +// field indicates if a mapping can use THP. +// THP mode 'always': this field is 1 whenever huge pages can be used +// THP mode 'madvise': this field is 1 if the mapping has been madvised +// as MADV_HUGEPAGE. In the JVM that should happen when the flag +// -XX:+UseTransparentHugePages is specified. +// +// Note: we don't verify if the heap is backed by huge pages because we +// can't know if the underlying system have any available. +public class TestTransparentHugePagesHeap { + + public static void main(String args[]) throws Exception { + // To be able to detect large page use (esp. THP) somewhat reliably, we + // need at least kernel 3.8 to get the "VmFlags" tag in smaps. + // (Note: its still good we started the VM at least since this serves as a nice + // test for all manners of large page options). + if (Platform.getOsVersionMajor() < 3 || + (Platform.getOsVersionMajor() == 3 && Platform.getOsVersionMinor() < 8)) { + throw new SkippedException("Kernel older than 3.8 - skipping this test."); + } + + final HugePageConfiguration hugePageConfiguration = HugePageConfiguration.readFromOS(); + if (!hugePageConfiguration.supportsTHP()) { + throw new SkippedException("THP is turned off"); + } + + OutputAnalyzer oa = ProcessTools.executeTestJava("-XX:+Use" + args[0] + "GC", "-Xmx128m", "-Xms128m", "-Xlog:pagesize:thp-%p.log", "-XX:+UseTransparentHugePages", VerifyTHPEnabledForHeap.class.getName()); + oa.shouldHaveExitValue(0); + } + + class VerifyTHPEnabledForHeap { + + public static void main(String args[]) throws Exception { + String heapAddress = readHeapAddressInLog(); + Path smaps = makeSmapsCopy(); + + final Pattern heapSection = Pattern.compile("^" + heapAddress + ".*"); + final Pattern thpEligible = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); + + Scanner smapsFile = new Scanner(smaps); + while (smapsFile.hasNextLine()) { + Matcher heapMatcher = heapSection.matcher(smapsFile.nextLine()); + + if (heapMatcher.matches()) { + // Found the first heap section, verify that it is THP eligible + while (smapsFile.hasNextLine()) { + Matcher m = thpEligible.matcher(smapsFile.nextLine()); + if (m.matches()) { + if (Integer.parseInt(m.group(1)) == 1) { + // THPeligible is 1, heap can be backed by huge pages + return; + } + + throw new RuntimeException("First heap section at 0x" + heapAddress + " is not THPeligible"); + } + } + } + } + + // Failed to verify THP for heap + throw new RuntimeException("Could not find heap section in smaps file"); + } + + private static String readHeapAddressInLog() throws Exception { + final Pattern heapAddress = Pattern.compile(".* Heap: .*base=(0x[0-9A-Fa-f]*).*"); + + Scanner logFile = new Scanner(Paths.get("thp-" + ProcessHandle.current().pid() + ".log")); + while (logFile.hasNextLine()) { + Matcher m = heapAddress.matcher(logFile.nextLine()); + if (m.matches()) { + return Long.toHexString(Long.decode(m.group(1))); + } + } + throw new RuntimeException("Failed to parse heap address, failing test"); + } + + private static Path makeSmapsCopy() throws Exception { + Path src = Paths.get("/proc/self/smaps"); + Path dest = Paths.get("smaps-copy-" + ProcessHandle.current().pid() + ".txt"); + Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); + return dest; + } + } +} + From 2527e9e58d770c50e6d807bf1483c6bb07dd3de7 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 4 Sep 2025 06:53:35 +0000 Subject: [PATCH 356/471] 8366490: C2 SuperWord: wrong result because CastP2X is missing ctrl and floats over SafePoint creating stale oops Reviewed-by: thartmann, chagedorn, mhaessig --- src/hotspot/share/opto/vectorization.cpp | 19 ++- src/hotspot/share/opto/vectorization.hpp | 4 +- src/hotspot/share/opto/vtransform.cpp | 19 ++- src/hotspot/share/opto/vtransform.hpp | 4 +- .../superword/TestAliasingCastP2XCtrl.java | 118 ++++++++++++++++++ 5 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index cd5aba6c31d..8e0f0980ff7 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -934,7 +934,7 @@ BoolNode* make_a_plus_b_leq_c(Node* a, Node* b, Node* c, PhaseIdealLoop* phase) return bol; } -BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) const { +BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* ctrl) const { // Ensure iv_scale1 <= iv_scale2. const VPointer& vp1 = (this->iv_scale() <= other.iv_scale()) ? *this : other; const VPointer& vp2 = (this->iv_scale() <= other.iv_scale()) ? other :*this ; @@ -971,8 +971,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) Node* main_init = new ConvL2INode(main_initL); phase->register_new_node_with_ctrl_of(main_init, pre_init); - Node* p1_init = vp1.make_pointer_expression(main_init); - Node* p2_init = vp2.make_pointer_expression(main_init); + Node* p1_init = vp1.make_pointer_expression(main_init, ctrl); + Node* p2_init = vp2.make_pointer_expression(main_init, ctrl); Node* size1 = igvn.longcon(vp1.size()); Node* size2 = igvn.longcon(vp2.size()); @@ -1092,13 +1092,18 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other) return bol; } -Node* VPointer::make_pointer_expression(Node* iv_value) const { +// Creates the long pointer expression, evaluated with iv = iv_value. +// Since we are casting pointers to long with CastP2X, we must be careful +// that the values do not cross SafePoints, where the oop could be moved +// by GC, and the already cast value would not be updated, as it is not in +// the oop-map. For this, we must set a ctrl that is late enough, so that we +// cannot cross a SafePoint. +Node* VPointer::make_pointer_expression(Node* iv_value, Node* ctrl) const { assert(is_valid(), "must be valid"); PhaseIdealLoop* phase = _vloop.phase(); PhaseIterGVN& igvn = phase->igvn(); Node* iv = _vloop.iv(); - Node* ctrl = phase->get_ctrl(iv_value); auto maybe_add = [&] (Node* n1, Node* n2, BasicType bt) { if (n1 == nullptr) { return n2; } @@ -1120,7 +1125,9 @@ Node* VPointer::make_pointer_expression(Node* iv_value) const { Node* scaleL = igvn.longcon(s.scaleL().value()); Node* variable = (s.variable() == iv) ? iv_value : s.variable(); if (variable->bottom_type()->isa_ptr() != nullptr) { - variable = new CastP2XNode(nullptr, variable); + // Use a ctrl that is late enough, so that we do not + // evaluate the cast before a SafePoint. + variable = new CastP2XNode(ctrl, variable); phase->register_new_node(variable, ctrl); } node = new MulLNode(scaleL, variable); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index baca0d5b927..b39e46cbf35 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -1013,8 +1013,8 @@ public: } bool can_make_speculative_aliasing_check_with(const VPointer& other) const; - Node* make_pointer_expression(Node* iv_value) const; - BoolNode* make_speculative_aliasing_check_with(const VPointer& other) const; + Node* make_pointer_expression(Node* iv_value, Node* ctrl) const; + BoolNode* make_speculative_aliasing_check_with(const VPointer& other, Node* ctrl) const; NOT_PRODUCT( void print_on(outputStream* st, bool end_with_cr = true) const; ) diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 2882cc2c1a3..af4cb345e14 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -217,7 +217,7 @@ void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { TRACE_SPECULATIVE_ALIGNMENT_CHECK(cmp_alignment); TRACE_SPECULATIVE_ALIGNMENT_CHECK(bol_alignment); - add_speculative_check(bol_alignment); + add_speculative_check([&] (Node* ctrl) { return bol_alignment; }); } class VPointerWeakAliasingPair : public StackObj { @@ -389,8 +389,9 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { } #endif - BoolNode* bol = vp1_union.make_speculative_aliasing_check_with(vp2_union); - add_speculative_check(bol); + add_speculative_check([&] (Node* ctrl) { + return vp1_union.make_speculative_aliasing_check_with(vp2_union, ctrl); + }); group_start = group_end; } @@ -420,7 +421,13 @@ void VTransform::apply_speculative_aliasing_runtime_checks() { // Multiversioning takes more compile time and code cache, but it also // produces fast code for when the runtime check passes (vectorized) and // when it fails (scalar performance). -void VTransform::add_speculative_check(BoolNode* bol) { +// +// Callback: +// In some cases, we require the ctrl just before the check iff_speculate to +// generate the values required in the check. We pass this ctrl into the +// callback, which is expected to produce the check, i.e. a BoolNode. +template +void VTransform::add_speculative_check(Callback callback) { assert(_vloop.are_speculative_checks_possible(), "otherwise we cannot make speculative assumptions"); ParsePredicateSuccessProj* parse_predicate_proj = _vloop.auto_vectorization_parse_predicate_proj(); IfTrueNode* new_check_proj = nullptr; @@ -432,6 +439,10 @@ void VTransform::add_speculative_check(BoolNode* bol) { new_check_proj = phase()->create_new_if_for_multiversion(_vloop.multiversioning_fast_proj()); } Node* iff_speculate = new_check_proj->in(0); + + // Create the check, given the ctrl just before the iff. + BoolNode* bol = callback(iff_speculate->in(0)); + igvn().replace_input_of(iff_speculate, 1, bol); TRACE_SPECULATIVE_ALIGNMENT_CHECK(iff_speculate); } diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 17dd81634ed..60b0b5d4f9d 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -258,7 +258,9 @@ private: void apply_speculative_alignment_runtime_checks(); void apply_speculative_aliasing_runtime_checks(); void add_speculative_alignment_check(Node* node, juint alignment); - void add_speculative_check(BoolNode* bol); + + template + void add_speculative_check(Callback callback); void apply_vectorization() const; }; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java new file mode 100644 index 00000000000..f33a46f4b49 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCastP2XCtrl.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=all-flags + * @bug 8366490 + * @summary Test that we set the ctrl of CastP2X when generating + * the aliasing runtime check, preventing the CastP2X + * from floating over a SafePoint that could move the oop, + * and render the cast value stale. + * @requires vm.gc == "G1" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCastP2XCtrl::test + * -XX:CompileCommand=dontinline,*TestAliasingCastP2XCtrl::allocateArrays + * -XX:-TieredCompilation + * -Xbatch + * -XX:+UseG1GC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM + * compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +/* + * @test id=fewer-flags + * @bug 8366490 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCastP2XCtrl::test + * -XX:CompileCommand=dontinline,*TestAliasingCastP2XCtrl::allocateArrays + * -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM + * compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +/* + * @test id=vanilla + * @bug 8366490 + * @run main compiler.loopopts.superword.TestAliasingCastP2XCtrl + */ + +package compiler.loopopts.superword; + +public class TestAliasingCastP2XCtrl { + static final int N = 400; + static boolean flag = false; + + static void allocateArrays() { + for (int i = 0; 200_000 > i; ++i) { + int[] a = new int[N]; + } + // Makes GC more likely. + // Without it I could not reproduce it on slowdebug, + // but only with fastdebug. + if (flag) { System.gc(); } + flag = !flag; + } + + static int[] test() { + int a[] = new int[N]; + // We must make sure that no CastP2X happens before + // the call below, otherwise we may have an old oop. + allocateArrays(); + // The CastP2X for the aliasing runtime check should + // only be emitted after the call, to ensure we only + // deal with oops that are updated if there is a GC + // that could move our allocated array. + + // Not fully sure why we need the outer loop, but maybe + // it is needed so that a part of the check is hoisted, + // and the floats up, over the call if we do not set + // the ctrl. + for (int k = 0; k < 500; k++) { + for (int i = 1; i < 69; i++) { + // Aliasing references -> needs runtime check, + // should always fail. + a[i] = 14; + a[4] -= 14; + // The range computation for the constant access + // produces a shape: + // AddL(CastP2X(a), 0x20) + // And this shape only depends on a, so it could + // easily float above the call to allocateArrays + // if we do not set a ctrl that prevents that. + } + } + return a; + } + + public static void main(String[] args) { + int[] gold = test(); + for (int r = 0; r < 20; r++) { + int[] a = test(); + if (a[4] != gold[4]) { + throw new RuntimeException("wrong value " + gold[4] + " " + a[4]); + } + } + } +} From 49fd6a0cb4ddabaa865155bbfd4290077b7d13ea Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Thu, 4 Sep 2025 07:03:10 +0000 Subject: [PATCH 357/471] 8366558: Gtests leave /tmp/cgroups-test* files Reviewed-by: mbaesken, stuefe, lmesnik --- test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index c090aa28e9a..b33d6454477 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -341,7 +341,6 @@ TEST(cgroupTest, read_string_tests) { ok = controller->read_string(base_with_slash, result, 1024); EXPECT_FALSE(ok) << "Empty file should have failed"; EXPECT_STREQ("", result) << "Expected untouched result"; - delete_file(test_file); // File contents larger than 1K // We only read in the first 1K - 1 bytes @@ -358,6 +357,8 @@ TEST(cgroupTest, read_string_tests) { EXPECT_TRUE(1023 == strlen(result)) << "Expected only the first 1023 chars to be read in"; EXPECT_EQ(0, strncmp(too_large, result, 1023)); EXPECT_EQ(result[1023], '\0') << "The last character must be the null character"; + + delete_file(test_file); } TEST(cgroupTest, read_number_tuple_test) { @@ -393,6 +394,8 @@ TEST(cgroupTest, read_number_tuple_test) { ok = controller->read_numerical_tuple_value(base_with_slash, true /* use_first */, &result); EXPECT_FALSE(ok) << "Empty file should be an error"; EXPECT_EQ((jlong)-10, result) << "result value should be unchanged"; + + delete_file(test_file); } TEST(cgroupTest, read_numerical_key_beyond_max_path) { From 222ae365c89e7bcd2cd920f60aa34eebee2c83b6 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 4 Sep 2025 07:03:28 +0000 Subject: [PATCH 358/471] 8366688: G1: Rename G1HeapRegionRemSet::is_added_to_cset_group() to has_cset_group() Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CardSet.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp | 8 ++++---- src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp | 14 +++++++------- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 2 +- src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 5286a764996..f5b9bf2aebe 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -783,7 +783,7 @@ G1AddCardResult G1CardSet::add_card(uintptr_t card) { { uint region_idx = card_region >> config()->log2_card_regions_per_heap_region(); G1HeapRegion* r = G1CollectedHeap::heap()->region_at(region_idx); - assert(!r->rem_set()->is_added_to_cset_group() || + assert(!r->rem_set()->has_cset_group() || r->rem_set()->cset_group()->card_set() != this, "Should not be sharing a cardset"); } #endif diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 1e836e3efa2..2e10412cebf 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -115,7 +115,7 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); - assert(!hr->rem_set()->is_added_to_cset_group(), "Should have already uninstalled group remset"); + assert(!hr->rem_set()->has_cset_group(), "Should have already uninstalled group remset"); assert(!hr->in_collection_set(), "should not already be in the collection set"); _g1h->register_old_region_with_region_attr(hr); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index f37ede6940e..5e42bf71882 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -3054,7 +3054,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { const char* remset_type = r->rem_set()->get_short_state_str(); uint cset_group_id = 0; - if (r->rem_set()->is_added_to_cset_group()) { + if (r->rem_set()->has_cset_group()) { cset_group_id = r->rem_set()->cset_group_id(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 7852bb7e8e3..b05a60234e2 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -63,7 +63,7 @@ G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr) : _state(Untracked) { } G1HeapRegionRemSet::~G1HeapRegionRemSet() { - assert(!is_added_to_cset_group(), "Still assigned to a CSet group"); + assert(!has_cset_group(), "Still assigned to a CSet group"); } void G1HeapRegionRemSet::clear_fcc() { @@ -76,7 +76,7 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { } clear_fcc(); - if (is_added_to_cset_group()) { + if (has_cset_group()) { card_set()->clear(); assert(card_set()->occupied() == 0, "Should be clear."); } @@ -90,13 +90,13 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { void G1HeapRegionRemSet::reset_table_scanner() { _code_roots.reset_table_scanner(); - if (is_added_to_cset_group()) { + if (has_cset_group()) { card_set()->reset_table_scanner(); } } G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set_memory_stats(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index d2d502636fa..32008f7f20d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -57,12 +57,12 @@ class G1HeapRegionRemSet : public CHeapObj { void clear_fcc(); G1CardSet* card_set() { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set(); } const G1CardSet* card_set() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->card_set(); } @@ -71,7 +71,7 @@ public: ~G1HeapRegionRemSet(); bool cardset_is_empty() const { - return !is_added_to_cset_group() || card_set()->is_empty(); + return !has_cset_group() || card_set()->is_empty(); } void install_cset_group(G1CSetCandidateGroup* cset_group) { @@ -83,7 +83,7 @@ public: void uninstall_cset_group(); - bool is_added_to_cset_group() const { + bool has_cset_group() const { return _cset_group != nullptr; } @@ -96,7 +96,7 @@ public: } uint cset_group_id() const { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return cset_group()->group_id(); } @@ -118,7 +118,7 @@ public: inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl); size_t occupied() { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); return card_set()->occupied(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 428586e160a..ff927959289 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -125,7 +125,7 @@ uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { } void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { - assert(is_added_to_cset_group(), "pre-condition"); + assert(has_cset_group(), "pre-condition"); assert(_state != Untracked, "must be"); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index cf032bc5d17..49cc993dac2 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -228,7 +228,7 @@ public: // Accumulate card set details for regions that are assigned to single region // groups. G1HeapRegionRemSet::mem_size() includes the size of the code roots - if (hrrs->is_added_to_cset_group() && hrrs->cset_group()->length() == 1) { + if (hrrs->has_cset_group() && hrrs->cset_group()->length() == 1) { G1CardSet* card_set = hrrs->cset_group()->card_set(); rs_mem_sz = hrrs->mem_size() + card_set->mem_size(); diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp index a5c8882e057..7b8d92b8fe4 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp @@ -108,7 +108,7 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t occupied = 0; // per region cardset details only valid if group contains a single region. - if (r->rem_set()->is_added_to_cset_group() && + if (r->rem_set()->has_cset_group() && r->rem_set()->cset_group()->length() == 1 ) { G1CardSet *card_set = r->rem_set()->cset_group()->card_set(); remset_bytes += card_set->mem_size(); From 1495dd94e97fc023dede71f957ce3b166d20d5ac Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 4 Sep 2025 07:13:41 +0000 Subject: [PATCH 359/471] 8366778: Sort share/asm, share/gc, share/include includes Reviewed-by: shade, ayang, jsikstro --- src/hotspot/share/asm/assembler.cpp | 1 - src/hotspot/share/asm/codeBuffer.hpp | 2 +- src/hotspot/share/asm/codeBuffer.inline.hpp | 1 + src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 1 - .../share/gc/g1/g1FullGCResetMetadataTask.hpp | 1 + src/hotspot/share/gc/serial/serialHeap.cpp | 1 - src/hotspot/share/gc/shared/collectedHeap.cpp | 1 - .../share/gc/shared/referenceProcessor.cpp | 1 - .../share/gc/shenandoah/shenandoahAsserts.cpp | 2 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 1 - .../share/gc/shenandoah/shenandoahHeap.cpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 1 - .../share/gc/z/zUncoloredRoot.inline.hpp | 1 - src/hotspot/share/include/jvm_io.h | 2 +- .../jtreg/sources/TestIncludesAreSorted.java | 23 +------------------ 15 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index d415ddf004a..9e342d23afd 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -23,7 +23,6 @@ */ #include "asm/codeBuffer.hpp" -#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "gc/shared/collectedHeap.hpp" #include "memory/universe.hpp" diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 57b4aaacdce..35bbd2f657f 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -33,8 +33,8 @@ #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" #include "utilities/linkedlist.hpp" -#include "utilities/resizableHashTable.hpp" #include "utilities/macros.hpp" +#include "utilities/resizableHashTable.hpp" template static inline void put_native(address p, T x) { diff --git a/src/hotspot/share/asm/codeBuffer.inline.hpp b/src/hotspot/share/asm/codeBuffer.inline.hpp index 06ec9174b34..076749e8967 100644 --- a/src/hotspot/share/asm/codeBuffer.inline.hpp +++ b/src/hotspot/share/asm/codeBuffer.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_ASM_CODEBUFFER_INLINE_HPP #include "asm/codeBuffer.hpp" + #include "ci/ciEnv.hpp" #include "code/compiledIC.hpp" diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 76d4ba5ab19..693e915b98e 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -30,7 +30,6 @@ #include "gc/shared/gcArguments.hpp" #include "gc/shared/locationPrinter.inline.hpp" #include "logging/log.hpp" -#include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp index 5f046e35001..d2bc8e7d8e0 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp @@ -24,6 +24,7 @@ #ifndef SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP #define SHARE_GC_G1_G1FULLGCRESETMETADATATASK_HPP + #include "gc/g1/g1FullGCTask.hpp" #include "gc/g1/g1HeapRegion.hpp" diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 6bb1183aa56..f97cd4e3b70 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -67,7 +67,6 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index e82ec1439ea..71017817d14 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -27,7 +27,6 @@ #include "classfile/vmClasses.hpp" #include "gc/shared/allocTracer.hpp" #include "gc/shared/barrierSet.hpp" -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcHeapSummary.hpp" diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index e5d1bd4bec1..0153ee13287 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -24,7 +24,6 @@ #include "classfile/javaClasses.inline.hpp" #include "compiler/compilerDefinitions.inline.hpp" -#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/gcTimer.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index ca9624ec752..93c218e9e8b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -29,8 +29,8 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" -#include "oops/oop.inline.hpp" #include "memory/resourceArea.hpp" +#include "oops/oop.inline.hpp" #include "runtime/os.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 293391a86eb..69827d72f44 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -31,7 +31,6 @@ #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -#include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b90468501f6..b662aeb7eb7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -29,10 +29,10 @@ #include "classfile/systemDictionary.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/fullGCForwarding.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/gc_globals.hpp" #include "gc/shared/locationPrinter.inline.hpp" #include "gc/shared/memAllocator.hpp" #include "gc/shared/plab.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 5cccd395d38..3aa3f6cb0ca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -30,7 +30,6 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" -#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 0d9fccde87c..128d8f1bfef 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -27,7 +27,6 @@ #include "gc/z/zUncoloredRoot.hpp" #include "gc/z/zAddress.inline.hpp" -#include "gc/z/zBarrier.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "oops/oop.hpp" diff --git a/src/hotspot/share/include/jvm_io.h b/src/hotspot/share/include/jvm_io.h index e6265fe5192..5233798b5a8 100644 --- a/src/hotspot/share/include/jvm_io.h +++ b/src/hotspot/share/include/jvm_io.h @@ -28,8 +28,8 @@ #include -#include "jni.h" #include "jvm_md.h" +#include "jni.h" #ifdef __cplusplus extern "C" { diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 695b300f3fd..19aaeed69a2 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -43,28 +43,7 @@ public class TestIncludesAreSorted { * can be checked). */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { - "share/adlc", - "share/c1", - "share/cds", - "share/ci", - "share/classfile", - "share/code", - "share/compiler", - "share/interpreter", - "share/jfr", - "share/jvmci", - "share/libadt", - "share/logging", - "share/memory", - "share/metaprogramming", - "share/nmt", - "share/oops", - "share/opto", - "share/precompiled", - "share/prims", - "share/runtime", - "share/services", - "share/utilities" + "share" }; /** From 986ecff5f9b16f1b41ff15ad94774d65f3a4631d Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Sep 2025 07:14:59 +0000 Subject: [PATCH 360/471] 8366849: Problemlist jdk/jshell/ToolSimpleTest.java as generic-all Reviewed-by: liach, jlahoda --- test/langtools/ProblemList.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index e1124f4784a..59b5b240a29 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -52,8 +52,8 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all -jdk/jshell/ToolSimpleTest.java 8366582 windows-x64 -jdk/jshell/ToolLocalSimpleTest.java 8366582 windows-x64 +jdk/jshell/ToolSimpleTest.java 8366582 generic-all +jdk/jshell/ToolLocalSimpleTest.java 8366582 generic-all ########################################################################### # From ab9f70dd5acd73744e3d82e9884985904f280c26 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 4 Sep 2025 08:01:01 +0000 Subject: [PATCH 361/471] 8366420: AOTMapTest fails when default jsa is missing from JDK Reviewed-by: iklam, azeller --- .../hotspot/jtreg/runtime/cds/CDSMapTest.java | 1 - .../cds/appcds/aotCache/AOTMapTest.java | 27 +++++-------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java index c93b16c68b8..e38b68bdbcf 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java @@ -25,7 +25,6 @@ * @test * @bug 8308903 * @summary Test the contents of -Xlog:aot+map - * @requires vm.flagless * @requires vm.cds * @library /test/lib * @run driver CDSMapTest diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java index f544b5653b7..438bfb22c9b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTMapTest.java @@ -25,7 +25,6 @@ * @test id=aot * @bug 8362566 * @summary Test the contents of -Xlog:aot+map with AOT workflow - * @requires vm.flagless * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds * @build AOTMapTest @@ -37,7 +36,6 @@ * @test id=dynamic * @bug 8362566 * @summary Test the contents of -Xlog:aot+map with AOT workflow - * @requires vm.flagless * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds * @build jdk.test.whitebox.WhiteBox @@ -58,16 +56,11 @@ public class AOTMapTest { static final String mainClass = "AOTMapTestApp"; public static void main(String[] args) throws Exception { - doTest(args, false); - - if (Platform.is64bit()) { - // There's no oop/klass compression on 32-bit. - doTest(args, true); - } + doTest(args); } - public static void doTest(String[] args, boolean compressed) throws Exception { - Tester tester = new Tester(compressed); + public static void doTest(String[] args) throws Exception { + Tester tester = new Tester(); tester.run(args); validate(tester.dumpMapFile); @@ -80,16 +73,14 @@ public class AOTMapTest { } static class Tester extends CDSAppTester { - boolean compressed; String dumpMapFile; String runMapFile; - public Tester(boolean compressed) { + public Tester() { super(mainClass); - this.compressed = compressed; - dumpMapFile = "test" + (compressed ? "0" : "1") + ".dump.aotmap"; - runMapFile = "test" + (compressed ? "0" : "1") + ".run.aotmap"; + dumpMapFile = "test" + "0" + ".dump.aotmap"; + runMapFile = "test" + "0" + ".run.aotmap"; } @Override @@ -104,12 +95,6 @@ public class AOTMapTest { vmArgs.add("-Xmx128M"); vmArgs.add("-Xlog:aot=debug"); - if (Platform.is64bit()) { - // These options are available only on 64-bit. - String sign = (compressed) ? "+" : "-"; - vmArgs.add("-XX:" + sign + "UseCompressedOops"); - } - // filesize=0 ensures that a large map file not broken up in multiple files. String logMapPrefix = "-Xlog:aot+map=debug,aot+map+oops=trace:file="; String logMapSuffix = ":none:filesize=0"; From 53d4e928ef2851f3e16d1d200b5c3fb036e15e00 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 09:47:42 +0000 Subject: [PATCH 362/471] 8366238: Improve RBTree API with stricter comparator semantics and pluggable validation/printing hooks Reviewed-by: jsjolen, ayang --- src/hotspot/share/gc/z/zMappedCache.cpp | 14 +- src/hotspot/share/gc/z/zMappedCache.hpp | 4 +- src/hotspot/share/nmt/vmatree.hpp | 9 +- src/hotspot/share/opto/printinlining.hpp | 6 +- src/hotspot/share/utilities/rbTree.hpp | 111 +++++++----- src/hotspot/share/utilities/rbTree.inline.hpp | 55 +++--- test/hotspot/gtest/utilities/test_rbtree.cpp | 159 +++++++++++++++--- 7 files changed, 258 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/gc/z/zMappedCache.cpp b/src/hotspot/share/gc/z/zMappedCache.cpp index ad02d265e93..394c5649c14 100644 --- a/src/hotspot/share/gc/z/zMappedCache.cpp +++ b/src/hotspot/share/gc/z/zMappedCache.cpp @@ -118,20 +118,20 @@ static ZMappedCacheEntry* create_entry(const ZVirtualMemory& vmem) { return entry; } -bool ZMappedCache::EntryCompare::cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { +bool ZMappedCache::EntryCompare::less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b) { const ZVirtualMemory vmem_a = ZMappedCacheEntry::cast_to_entry(a)->vmem(); const ZVirtualMemory vmem_b = ZMappedCacheEntry::cast_to_entry(b)->vmem(); return vmem_a.end() < vmem_b.start(); } -int ZMappedCache::EntryCompare::cmp(zoffset key, const IntrusiveRBNode* node) { +RBTreeOrdering ZMappedCache::EntryCompare::cmp(zoffset key, const IntrusiveRBNode* node) { const ZVirtualMemory vmem = ZMappedCacheEntry::cast_to_entry(node)->vmem(); - if (key < vmem.start()) { return -1; } - if (key > vmem.end()) { return 1; } + if (key < vmem.start()) { return RBTreeOrdering::LT; } + if (key > vmem.end()) { return RBTreeOrdering::GT; } - return 0; // Containing + return RBTreeOrdering::EQ; // Containing } void ZMappedCache::Tree::verify() const { @@ -168,12 +168,12 @@ void ZMappedCache::Tree::insert(TreeNode* node, const TreeCursor& cursor) { // Insert in tree TreeImpl::insert_at_cursor(node, cursor); - if (_left_most == nullptr || EntryCompare::cmp(node, _left_most)) { + if (_left_most == nullptr || EntryCompare::less_than(node, _left_most)) { // Keep track of left most node _left_most = node; } - if (_right_most == nullptr || EntryCompare::cmp(_right_most, node)) { + if (_right_most == nullptr || EntryCompare::less_than(_right_most, node)) { // Keep track of right most node _right_most = node; } diff --git a/src/hotspot/share/gc/z/zMappedCache.hpp b/src/hotspot/share/gc/z/zMappedCache.hpp index 28f37de0de1..8688e047ae1 100644 --- a/src/hotspot/share/gc/z/zMappedCache.hpp +++ b/src/hotspot/share/gc/z/zMappedCache.hpp @@ -40,8 +40,8 @@ class ZMappedCache { private: struct EntryCompare { - static int cmp(zoffset a, const IntrusiveRBNode* b); - static bool cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b); + static RBTreeOrdering cmp(zoffset a, const IntrusiveRBNode* b); + static bool less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b); }; struct ZSizeClassListNode { diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 01f0e107a56..1b5729054e4 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -50,11 +50,10 @@ public: class PositionComparator { public: - static int cmp(position a, position b) { - if (a < b) return -1; - if (a == b) return 0; - if (a > b) return 1; - ShouldNotReachHere(); + static RBTreeOrdering cmp(position a, position b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; diff --git a/src/hotspot/share/opto/printinlining.hpp b/src/hotspot/share/opto/printinlining.hpp index 3bf09bc921f..e331593ec0e 100644 --- a/src/hotspot/share/opto/printinlining.hpp +++ b/src/hotspot/share/opto/printinlining.hpp @@ -67,8 +67,10 @@ private: }; struct Cmp { - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index cc52cec3fe0..4c358b53ff0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -35,17 +35,13 @@ // An intrusive red-black tree is constructed with two template parameters: // K is the key type used. // COMPARATOR must have a static function `cmp(K a, const IntrusiveRBNode* b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// Additional static functions used for extra validation can optionally be provided: -// `cmp(K a, K b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// `cmp(const IntrusiveRBNode* a, const IntrusiveRBNode* b)` which returns: -// - true if a < b -// - false otherwise +// - RBTreeOrdering::LT when a < b +// - RBTreeOrdering::EQ when a == b +// - RBTreeOrdering::GT when a > b +// A second static function `less_than(const IntrusiveRBNode* a, const IntrusiveRBNode* b)` +// used for extra validation can optionally be provided. This should return: +// - true if a < b +// - false otherwise // K needs to be of a type that is trivially destructible. // K needs to be stored by the user and is not stored inside the tree. // Nodes are address stable and will not change during its lifetime. @@ -54,10 +50,10 @@ // K is the key type stored in the tree nodes. // V is the value type stored in the tree nodes. // COMPARATOR must have a static function `cmp(K a, K b)` which returns: -// - an int < 0 when a < b -// - an int == 0 when a == b -// - an int > 0 when a > b -// A second static function `cmp(const RBNode* a, const RBNode* b)` +// - RBTreeOrdering::LT when a < b +// - RBTreeOrdering::EQ when a == b +// - RBTreeOrdering::GT when a > b +// A second static function `less_than(const RBNode* a, const RBNode* b)` // used for extra validation can optionally be provided. This should return: // - true if a < b // - false otherwise @@ -65,6 +61,8 @@ // The tree will call a value's destructor when its node is removed. // Nodes are address stable and will not change during its lifetime. +enum class RBTreeOrdering : int { LT, EQ, GT }; + template class AbstractRBTree; @@ -126,10 +124,11 @@ private: // Returns left child (now parent) IntrusiveRBNode* rotate_right(); - template + template void verify(size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, - size_t& tree_depth, bool expect_visited, NodeVerifier verifier) const; + size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, + const USER_VERIFIER& extra_verifier) const; }; @@ -203,32 +202,37 @@ private: struct has_cmp_type(CMP::cmp), void())> : std::true_type {}; template - static constexpr bool HasKeyComparator = has_cmp_type::value; + static constexpr bool HasKeyComparator = has_cmp_type::value; template - static constexpr bool HasNodeComparator = has_cmp_type::value; + static constexpr bool HasNodeComparator = has_cmp_type::value; + + template + struct has_less_than_type : std::false_type {}; + template + struct has_less_than_type(CMP::less), void())> : std::true_type {}; template - static constexpr bool HasNodeVerifier = has_cmp_type::value; + static constexpr bool HasNodeVerifier = has_less_than_type::value; template && !HasNodeComparator)> - int cmp(const K& a, const NodeType* b) const { + RBTreeOrdering cmp(const K& a, const NodeType* b) const { return COMPARATOR::cmp(a, b->key()); } template )> - int cmp(const K& a, const NodeType* b) const { + RBTreeOrdering cmp(const K& a, const NodeType* b) const { return COMPARATOR::cmp(a, b); } template )> - bool cmp(const NodeType* a, const NodeType* b) const { + bool less_than(const NodeType* a, const NodeType* b) const { return true; } template )> - bool cmp(const NodeType* a, const NodeType* b) const { - return COMPARATOR::cmp(a, b); + bool less_than(const NodeType* a, const NodeType* b) const { + return COMPARATOR::less_than(a, b); } // Cannot assert if no key comparator exist. @@ -237,7 +241,7 @@ private: template )> void assert_key_leq(K a, K b) const { - assert(COMPARATOR::cmp(a, b) <= 0, "key a must be less or equal to key b"); + assert(COMPARATOR::cmp(a, b) != RBTreeOrdering::GT, "key a must be less or equal to key b"); } // True if node is black (nil nodes count as black) @@ -256,10 +260,23 @@ private: // Assumption: node has at most one child. Two children is handled in `remove_at_cursor()` void remove_from_tree(IntrusiveRBNode* node); - template - void verify_self(NodeVerifier verifier) const; + struct empty_verifier { + bool operator()(const NodeType* n) const { + return true; + } + }; - void print_node_on(outputStream* st, int depth, const NodeType* n) const; + template + void verify_self(NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const; + + struct default_printer { + void operator()(outputStream* st, const NodeType* n, int depth) const { + n->print_on(st, depth); + } + }; + + template + void print_node_on(outputStream* st, int depth, const NodeType* n, const PRINTER& node_printer) const; public: NONCOPYABLE(AbstractRBTree); @@ -422,22 +439,30 @@ public: // Verifies that the tree is correct and holds rb-properties // If not using a key comparator (when using IntrusiveRBTree for example), // A second `cmp` must exist in COMPARATOR (see top of file). - template )> - void verify_self() const { - verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a, b);}); + // Accepts an optional callable `bool extra_verifier(const Node* n)`. + // This should return true if the node is valid. + // If provided, each node is also verified through this callable. + template )> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::less_than(a, b);}, extra_verifier); } - template && !HasNodeVerifier)> - void verify_self() const { - verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a->key(), b->key()) < 0; }); + template && !HasNodeVerifier)> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType* a, const NodeType* b){ return COMPARATOR::cmp(a->key(), b->key()) == RBTreeOrdering::LT; }, extra_verifier); } - template && !HasKeyComparator && !HasNodeVerifier)> - void verify_self() const { - verify_self([](const NodeType*, const NodeType*){ return true;}); + template && !HasKeyComparator && !HasNodeVerifier)> + void verify_self(const USER_VERIFIER& extra_verifier = USER_VERIFIER()) const { + verify_self([](const NodeType*, const NodeType*){ return true;}, extra_verifier); } - void print_on(outputStream* st) const; + // Accepts an optional printing callable `void node_printer(outputStream* st, const Node* n, int depth)`. + // If provided, each node is printed through this callable rather than the default `print_on`. + template + void print_on(outputStream* st, const PRINTER& node_printer = PRINTER()) const; }; @@ -451,6 +476,14 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} ~RBTree() { remove_all(); } + RBTree(const RBTree& other) : BaseType(), _allocator() { + assert(std::is_copy_constructible(), "Value type must be copy-constructible"); + other.visit_in_order([&](auto node) { + this->upsert(node->key(), node->val()); + return true; + }); + } + RBTree& operator=(const RBTree& other) = delete; typedef typename BaseType::Cursor Cursor; using BaseType::cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 365786f7fc1..16150e41be8 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -123,10 +123,11 @@ inline IntrusiveRBNode* IntrusiveRBNode::next() { return const_cast(static_cast(this)->next()); } -template +template inline void IntrusiveRBNode::verify( size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, - size_t& tree_depth, bool expect_visited, NodeVerifier verifier) const { + size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { + assert(extra_verifier(static_cast(this)), "user provided verifier failed"); assert(expect_visited != _visited, "node already visited"); DEBUG_ONLY(_visited = !_visited); @@ -143,7 +144,7 @@ inline void IntrusiveRBNode::verify( assert(is_black() || _left->is_black(), "2 red nodes in a row"); assert(_left->parent() == this, "pointer mismatch"); _left->verify(num_nodes, num_black_nodes_left, shortest_leaf_path_left, - longest_leaf_path_left, tree_depth_left, expect_visited, verifier); + longest_leaf_path_left, tree_depth_left, expect_visited, verifier, extra_verifier); } size_t num_black_nodes_right = 0; @@ -159,7 +160,7 @@ inline void IntrusiveRBNode::verify( assert(is_black() || _left->is_black(), "2 red nodes in a row"); assert(_right->parent() == this, "pointer mismatch"); _right->verify(num_nodes, num_black_nodes_right, shortest_leaf_path_right, - longest_leaf_path_right, tree_depth_right, expect_visited, verifier); + longest_leaf_path_right, tree_depth_right, expect_visited, verifier, extra_verifier); } shortest_leaf_path = MAX2(longest_leaf_path_left, longest_leaf_path_right); @@ -190,13 +191,13 @@ AbstractRBTree::cursor(const K& key, const NodeType* hi IntrusiveRBNode* const* insert_location = &_root; if (hint_node != nullptr) { - const int hint_cmp = cmp(key, hint_node); + const RBTreeOrdering hint_cmp = cmp(key, hint_node); while (hint_node->parent() != nullptr) { - const int parent_cmp = cmp(key, (NodeType*)hint_node->parent()); + const RBTreeOrdering parent_cmp = cmp(key, (NodeType*)hint_node->parent()); // Move up until the parent would put us on the other side of the key. // Meaning we are in the correct subtree. - if ((parent_cmp <= 0 && hint_cmp < 0) || - (parent_cmp >= 0 && hint_cmp > 0)) { + if ((parent_cmp != RBTreeOrdering::GT && hint_cmp == RBTreeOrdering::LT) || + (parent_cmp != RBTreeOrdering::LT && hint_cmp == RBTreeOrdering::GT)) { hint_node = (NodeType*)hint_node->parent(); } else { break; @@ -212,14 +213,14 @@ AbstractRBTree::cursor(const K& key, const NodeType* hi while (*insert_location != nullptr) { NodeType* curr = (NodeType*)*insert_location; - const int key_cmp_k = cmp(key, curr); + const RBTreeOrdering key_cmp_k = cmp(key, curr); - if (key_cmp_k == 0) { + if (key_cmp_k == RBTreeOrdering::EQ) { break; } parent = *insert_location; - if (key_cmp_k < 0) { + if (key_cmp_k == RBTreeOrdering::LT) { insert_location = &curr->_left; } else { insert_location = &curr->_right; @@ -551,19 +552,19 @@ inline void AbstractRBTree::replace_at_cursor(NodeType* new_node->_parent = old_node->_parent; if (new_node->is_left_child()) { - assert(cmp(static_cast(new_node), static_cast(new_node->parent())), "new node not < parent"); + assert(less_than(static_cast(new_node), static_cast(new_node->parent())), "new node not < parent"); } else if (new_node->is_right_child()) { - assert(cmp(static_cast(new_node->parent()), static_cast(new_node)), "new node not > parent"); + assert(less_than(static_cast(new_node->parent()), static_cast(new_node)), "new node not > parent"); } new_node->_left = old_node->_left; new_node->_right = old_node->_right; if (new_node->_left != nullptr) { - assert(cmp(static_cast(new_node->_left), static_cast(new_node)), "left child not < new node"); + assert(less_than(static_cast(new_node->_left), static_cast(new_node)), "left child not < new node"); new_node->_left->set_parent(new_node); } if (new_node->_right != nullptr) { - assert(cmp(static_cast(new_node), static_cast(new_node->_right)), "right child not > new node"); + assert(less_than(static_cast(new_node), static_cast(new_node->_right)), "right child not > new node"); new_node->_right->set_parent(new_node); } @@ -661,8 +662,8 @@ inline void AbstractRBTree::visit_range_in_order(const } template -template -inline void AbstractRBTree::verify_self(NodeVerifier verifier) const { +template +inline void AbstractRBTree::verify_self(NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { if (_root == nullptr) { assert(_num_nodes == 0, "rbtree has %zu nodes but no root", _num_nodes); return; @@ -679,7 +680,7 @@ inline void AbstractRBTree::verify_self(NodeVerifier ve bool expected_visited = DEBUG_ONLY(_expected_visited) NOT_DEBUG(false); _root->verify(num_nodes, black_depth, shortest_leaf_path, longest_leaf_path, - tree_depth, expected_visited, verifier); + tree_depth, expected_visited, verifier, extra_verifier); const unsigned int maximum_depth = log2i(size() + 1) * 2; @@ -731,21 +732,23 @@ inline void RBNode::print_on(outputStream* st, int depth) const { } template -void AbstractRBTree::print_node_on(outputStream* st, int depth, const NodeType* n) const { - n->print_on(st, depth); +template +void AbstractRBTree::print_node_on(outputStream* st, int depth, const NodeType* n, const PRINTER& node_printer) const { + node_printer(st, n, depth); depth++; - if (n->_right != nullptr) { - print_node_on(st, depth, (NodeType*)n->_right); - } if (n->_left != nullptr) { - print_node_on(st, depth, (NodeType*)n->_left); + print_node_on(st, depth, (NodeType*)n->_left, node_printer); + } + if (n->_right != nullptr) { + print_node_on(st, depth, (NodeType*)n->_right, node_printer); } } template -void AbstractRBTree::print_on(outputStream* st) const { +template +void AbstractRBTree::print_on(outputStream* st, const PRINTER& node_printer) const { if (_root != nullptr) { - print_node_on(st, 0, (NodeType*)_root); + print_node_on(st, 0, (NodeType*)_root, node_printer); } } diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index d8394de017e..609fb43e59e 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -36,26 +36,30 @@ public: using RBTreeIntNode = RBNode; struct Cmp { - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } - static bool cmp(const RBTreeIntNode* a, const RBTreeIntNode* b) { + static bool less_than(const RBTreeIntNode* a, const RBTreeIntNode* b) { return a->key() < b->key(); } }; struct CmpInverse { - static int cmp(int a, int b) { - return b - a; + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::GT; + if (a > b) return RBTreeOrdering::LT; + return RBTreeOrdering::EQ; } }; struct FCmp { - static int cmp(float a, float b) { - if (a < b) return -1; - if (a == b) return 0; - return 1; + static RBTreeOrdering cmp(float a, float b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; @@ -94,16 +98,15 @@ struct ArrayAllocator { }; struct IntrusiveCmp { - static int cmp(int a, const IntrusiveTreeNode* b) { - return a - IntrusiveHolder::cast_to_self(b)->key; - } - - static int cmp(int a, int b) { - return a - b; + static RBTreeOrdering cmp(int a, const IntrusiveTreeNode* b_node) { + int b = IntrusiveHolder::cast_to_self(b_node)->key; + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } // true if a < b - static bool cmp(const IntrusiveTreeNode* a, const IntrusiveTreeNode* b) { + static bool less_than(const IntrusiveTreeNode* a, const IntrusiveTreeNode* b) { return (IntrusiveHolder::cast_to_self(a)->key - IntrusiveHolder::cast_to_self(b)->key) < 0; } @@ -837,6 +840,50 @@ public: } } + static bool custom_validator(const IntrusiveRBNode* n) { + IntrusiveHolder* holder = IntrusiveHolder::cast_to_self(n); + assert(holder->key == holder->data, "must be"); + + return true; + } + + void test_custom_verify_intrusive() { + IntrusiveTreeInt intrusive_tree; + int num_nodes = 100; + + // Insert values + for (int n = 0; n < num_nodes; n++) { + IntrusiveCursor cursor = intrusive_tree.cursor(n); + EXPECT_NULL(cursor.node()); + + // Custom allocation here is just malloc + IntrusiveHolder* place = (IntrusiveHolder*)os::malloc(sizeof(IntrusiveHolder), mtTest); + new (place) IntrusiveHolder(n, n); + + intrusive_tree.insert_at_cursor(place->get_node(), cursor); + IntrusiveCursor cursor2 = intrusive_tree.cursor(n); + + EXPECT_NOT_NULL(cursor2.node()); + } + + intrusive_tree.verify_self(RBTreeTest::custom_validator); + + int node_count = 0; + intrusive_tree.verify_self([&](const IntrusiveRBNode* n) { + node_count++; + + IntrusiveHolder* holder = IntrusiveHolder::cast_to_self(n); + assert(holder->key >= 0, "must be"); + assert(holder->data >= 0, "must be"); + assert(holder->key < num_nodes, "must be"); + assert(holder->data < num_nodes, "must be"); + + return true; + }); + + EXPECT_EQ(node_count, num_nodes); + } + #ifdef ASSERT void test_nodes_visited_once() { constexpr size_t memory_size = 65536; @@ -945,10 +992,13 @@ TEST_VM_F(RBTreeTest, LeftMostRightMost) { } struct PtrCmp { - static int cmp(const void* a, const void* b) { + static RBTreeOrdering cmp(const void* a, const void* b) { const uintptr_t ai = p2u(a); const uintptr_t bi = p2u(b); - return ai == bi ? 0 : (ai > bi ? 1 : -1); + + if (ai < bi) return RBTreeOrdering::LT; + if (ai > bi) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; } }; @@ -982,7 +1032,11 @@ TEST_VM(RBTreeTestNonFixture, TestPrintPointerTree) { } struct IntCmp { - static int cmp(int a, int b) { return a == b ? 0 : (a > b ? 1 : -1); } + static RBTreeOrdering cmp(int a, int b) { + if (a < b) return RBTreeOrdering::LT; + if (a > b) return RBTreeOrdering::GT; + return RBTreeOrdering::EQ; + } }; TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { @@ -1005,10 +1059,42 @@ TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { ASSERT_NE(strstr(ss.base(), s3), N); } +TEST_VM(RBTreeTestNonFixture, TestPrintCustomPrinter) { + typedef RBTree > TreeType; + typedef RBNode NodeType; + + TreeType tree; + const int i1 = -13591; + const int i2 = 0; + const int i3 = 82924; + tree.upsert(i1, 1U); + tree.upsert(i2, 2U); + tree.upsert(i3, 3U); + + stringStream ss; + int print_count = 0; + tree.print_on(&ss, [&](outputStream* st, const NodeType* n, int depth) { + st->print_cr("[%d] (%d): %d", depth, n->val(), n->key()); + print_count++; + }); + +const char* const expected = + "[0] (2): 0\n" + "[1] (1): -13591\n" + "[1] (3): 82924\n"; + + ASSERT_EQ(print_count, 3); + ASSERT_STREQ(ss.base(), expected); +} + TEST_VM_F(RBTreeTest, IntrusiveTest) { this->test_intrusive(); } +TEST_VM_F(RBTreeTest, IntrusiveCustomVerifyTest) { + this->test_custom_verify_intrusive(); +} + TEST_VM_F(RBTreeTest, FillAndVerify) { this->test_fill_verify(); } @@ -1021,6 +1107,22 @@ TEST_VM_F(RBTreeTest, CursorReplace) { TEST_VM_F(RBTreeTest, NodesVisitedOnce) { this->test_nodes_visited_once(); } + +TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, CustomVerifyAssert, ".*failed on key = 7") { + typedef RBTreeCHeap TreeType; + typedef RBNode NodeType; + + TreeType tree; + for (int i = 0; i < 10; i++) { + tree.upsert(i, i); + } + + tree.verify_self([&](const NodeType* n) { + assert(n->key() != 7, "failed on key = %d", n->key()); + return true; + }); +} + #endif // ASSERT TEST_VM_F(RBTreeTest, InsertRemoveVerify) { @@ -1039,6 +1141,25 @@ TEST_VM_F(RBTreeTest, InsertRemoveVerify) { } } +TEST_VM_F(RBTreeTest, CustomVerify) { + constexpr int num_nodes = 1000; + RBTreeInt tree; + for (int i = 0; i < num_nodes; i++) { + tree.upsert(i, i); + } + + int node_count = 0; + tree.verify_self([&](const RBTreeIntNode* n) { + node_count++; + + assert(n->key() >= 0, "must be"); + assert(n->key() < num_nodes, "must be"); + return true; + }); + + EXPECT_EQ(node_count, num_nodes); +} + TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { { // Repeatedly verify a tree of moderate size RBTreeInt rbtree; From 8c50bed86709a45615743dd7953b8c6861f1da0c Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 10:48:57 +0000 Subject: [PATCH 363/471] 8366872: Wrong number of template arguments in test in test_rbtree.cpp Reviewed-by: ayang, syan --- test/hotspot/gtest/utilities/test_rbtree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index 609fb43e59e..ff234dd764a 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1060,7 +1060,7 @@ TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) { } TEST_VM(RBTreeTestNonFixture, TestPrintCustomPrinter) { - typedef RBTree > TreeType; + typedef RBTreeCHeap TreeType; typedef RBNode NodeType; TreeType tree; From 80873a09bf8392d98d20273e0688b17c62252242 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 4 Sep 2025 13:17:29 +0000 Subject: [PATCH 364/471] 8366836: Don't execute post-IncludeCustomExtension if file was not included Reviewed-by: erikj --- make/common/MakeIncludeEnd.gmk | 13 +++++++++---- make/common/MakeIncludeStart.gmk | 1 - 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/make/common/MakeIncludeEnd.gmk b/make/common/MakeIncludeEnd.gmk index 7023a861fa1..47be7c65c72 100644 --- a/make/common/MakeIncludeEnd.gmk +++ b/make/common/MakeIncludeEnd.gmk @@ -27,10 +27,15 @@ # MakeIncludeEnd.gmk should be included last of all in all include files ################################################################################ -# Hook to include the corresponding custom file, if present. -ifneq ($(NO_CUSTOM_EXTENSIONS), true) - CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE)) - $(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME))) +ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) + # This was the first time this file was included. Prevent future inclusion. + INCLUDE_GUARD_$(THIS_INCLUDE) := true + + # Hook to include the corresponding custom file, if present. + ifneq ($(NO_CUSTOM_EXTENSIONS), true) + CUSTOM_POST_NAME := $(subst .gmk,-post.gmk, $(THIS_INCLUDE)) + $(eval $(call IncludeCustomExtension, $(CUSTOM_POST_NAME))) + endif endif # Pop our helper name off the stack diff --git a/make/common/MakeIncludeStart.gmk b/make/common/MakeIncludeStart.gmk index 3904633f9f2..f1d690ddb41 100644 --- a/make/common/MakeIncludeStart.gmk +++ b/make/common/MakeIncludeStart.gmk @@ -70,7 +70,6 @@ INCLUDE_STACK := $(THIS_INCLUDE) $(INCLUDE_STACK) # Setup an automatic include guard ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) - INCLUDE_GUARD_$(THIS_INCLUDE) := true INCLUDE := true # Hook to include the corresponding custom file, if present. From e19035577724f40aca14ef7d5dad0906ce9e89ab Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 4 Sep 2025 13:19:12 +0000 Subject: [PATCH 365/471] 8365467: Issues with jrtfs implementation for exploded run-time images Reviewed-by: rriggs, sundar --- .../jdk/internal/jrtfs/ExplodedImage.java | 175 ++++++------- .../jdk/internal/jrtfs/SystemImage.java | 8 +- .../whitebox/ExplodedImageTestDriver.java | 30 +++ .../internal/jrtfs/whitebox/TEST.properties | 4 + .../jdk/internal/jrtfs/ExplodedImageTest.java | 232 ++++++++++++++++++ 5 files changed, 359 insertions(+), 90 deletions(-) create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties create mode 100644 test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java index 87a00da4393..4fe6612a8ed 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,17 +27,15 @@ package jdk.internal.jrtfs; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.DirectoryStream; -import java.nio.file.FileSystem; import java.nio.file.FileSystemException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; import jdk.internal.jimage.ImageReader.Node; @@ -56,16 +54,15 @@ class ExplodedImage extends SystemImage { private static final String MODULES = "/modules/"; private static final String PACKAGES = "/packages/"; - private static final int PACKAGES_LEN = PACKAGES.length(); - private final FileSystem defaultFS; + private final Path modulesDir; private final String separator; - private final Map nodes = Collections.synchronizedMap(new HashMap<>()); + private final Map nodes = new HashMap<>(); private final BasicFileAttributes modulesDirAttrs; ExplodedImage(Path modulesDir) throws IOException { - defaultFS = FileSystems.getDefault(); - String str = defaultFS.getSeparator(); + this.modulesDir = modulesDir; + String str = modulesDir.getFileSystem().getSeparator(); separator = str.equals("/") ? null : str; modulesDirAttrs = Files.readAttributes(modulesDir, BasicFileAttributes.class); initNodes(); @@ -79,21 +76,26 @@ class ExplodedImage extends SystemImage { private PathNode link; private List children; - PathNode(String name, Path path, BasicFileAttributes attrs) { // path + private PathNode(String name, Path path, BasicFileAttributes attrs) { // path super(name, attrs); this.path = path; } - PathNode(String name, Node link) { // link + private PathNode(String name, Node link) { // link super(name, link.getFileAttributes()); this.link = (PathNode)link; } - PathNode(String name, List children) { // dir + private PathNode(String name, List children) { // dir super(name, modulesDirAttrs); this.children = children; } + @Override + public boolean isResource() { + return link == null && !getFileAttributes().isDirectory(); + } + @Override public boolean isDirectory() { return children != null || @@ -112,7 +114,7 @@ class ExplodedImage extends SystemImage { return recursive && link.isLink() ? link.resolveLink(true) : link; } - byte[] getContent() throws IOException { + private byte[] getContent() throws IOException { if (!getFileAttributes().isRegularFile()) throw new FileSystemException(getName() + " is not file"); return Files.readAllBytes(path); @@ -126,7 +128,7 @@ class ExplodedImage extends SystemImage { List list = new ArrayList<>(); try (DirectoryStream stream = Files.newDirectoryStream(path)) { for (Path p : stream) { - p = explodedModulesDir.relativize(p); + p = modulesDir.relativize(p); String pName = MODULES + nativeSlashToFrontSlash(p.toString()); Node node = findNode(pName); if (node != null) { // findNode may choose to hide certain files! @@ -152,7 +154,7 @@ class ExplodedImage extends SystemImage { } @Override - public void close() throws IOException { + public synchronized void close() throws IOException { nodes.clear(); } @@ -161,72 +163,76 @@ class ExplodedImage extends SystemImage { return ((PathNode)node).getContent(); } - // find Node for the given Path @Override - public synchronized Node findNode(String str) { - Node node = findModulesNode(str); + public synchronized Node findNode(String name) { + PathNode node = nodes.get(name); if (node != null) { return node; } - // lazily created for paths like /packages///xyz - // For example /packages/java.lang/java.base/java/lang/ - if (str.startsWith(PACKAGES)) { - // pkgEndIdx marks end of part - int pkgEndIdx = str.indexOf('/', PACKAGES_LEN); - if (pkgEndIdx != -1) { - // modEndIdx marks end of part - int modEndIdx = str.indexOf('/', pkgEndIdx + 1); - if (modEndIdx != -1) { - // make sure we have such module link! - // ie., /packages// is valid - Node linkNode = nodes.get(str.substring(0, modEndIdx)); - if (linkNode == null || !linkNode.isLink()) { - return null; - } - // map to "/modules/zyz" path and return that node - // For example, "/modules/java.base/java/lang" for - // "/packages/java.lang/java.base/java/lang". - String mod = MODULES + str.substring(pkgEndIdx + 1); - return findModulesNode(mod); + // If null, this was not the name of "/modules/..." node, and since all + // "/packages/..." nodes were created and cached in advance, the name + // cannot reference a valid node. + Path path = underlyingModulesPath(name); + if (path == null) { + return null; + } + // This can still return null for hidden files. + return createModulesNode(name, path); + } + + /** + * Lazily creates and caches a {@code Node} for the given "/modules/..." name + * and corresponding path to a file or directory. + * + * @param name a resource or directory node name, of the form "/modules/...". + * @param path the path of a file for a resource or directory. + * @return the newly created and cached node, or {@code null} if the given + * path references a file which must be hidden in the node hierarchy. + */ + private Node createModulesNode(String name, Path path) { + assert !nodes.containsKey(name) : "Node must not already exist: " + name; + assert isNonEmptyModulesPath(name) : "Invalid modules name: " + name; + + try { + // We only know if we're creating a resource of directory when we + // look up file attributes, and we only do that once. Thus, we can + // only reject "marker files" here, rather than by inspecting the + // given name string, since it doesn't apply to directories. + BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); + if (attrs.isRegularFile()) { + Path f = path.getFileName(); + if (f.toString().startsWith("_the.")) { + return null; } + } else if (!attrs.isDirectory()) { + return null; } + PathNode node = new PathNode(name, path, attrs); + nodes.put(name, node); + return node; + } catch (IOException x) { + // Since the path reference a file, any errors should not be ignored. + throw new UncheckedIOException(x); + } + } + + /** + * Returns the expected file path for name in the "/modules/..." namespace, + * or {@code null} if the name is not in the "/modules/..." namespace or the + * path does not reference a file. + */ + private Path underlyingModulesPath(String name) { + if (isNonEmptyModulesPath(name)) { + Path path = modulesDir.resolve(frontSlashToNativeSlash(name.substring(MODULES.length()))); + return Files.exists(path) ? path : null; } return null; } - // find a Node for a path that starts like "/modules/..." - Node findModulesNode(String str) { - PathNode node = nodes.get(str); - if (node != null) { - return node; - } - // lazily created "/modules/xyz/abc/" Node - // This is mapped to default file system path "/xyz/abc" - Path p = underlyingPath(str); - if (p != null) { - try { - BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class); - if (attrs.isRegularFile()) { - Path f = p.getFileName(); - if (f.toString().startsWith("_the.")) - return null; - } - node = new PathNode(str, p, attrs); - nodes.put(str, node); - return node; - } catch (IOException x) { - // does not exists or unable to determine - } - } - return null; - } - - Path underlyingPath(String str) { - if (str.startsWith(MODULES)) { - str = frontSlashToNativeSlash(str.substring("/modules".length())); - return defaultFS.getPath(explodedModulesDir.toString(), str); - } - return null; + private static boolean isNonEmptyModulesPath(String name) { + // Don't just check the prefix, there must be something after it too + // (otherwise you end up with an empty string after trimming). + return name.startsWith(MODULES) && name.length() > MODULES.length(); } // convert "/" to platform path separator @@ -249,24 +255,21 @@ class ExplodedImage extends SystemImage { // same package prefix may exist in multiple modules. This Map // is filled by walking "jdk modules" directory recursively! Map> packageToModules = new HashMap<>(); - try (DirectoryStream stream = Files.newDirectoryStream(explodedModulesDir)) { + try (DirectoryStream stream = Files.newDirectoryStream(modulesDir)) { for (Path module : stream) { if (Files.isDirectory(module)) { String moduleName = module.getFileName().toString(); // make sure "/modules/" is created - findModulesNode(MODULES + moduleName); + Objects.requireNonNull(createModulesNode(MODULES + moduleName, module)); try (Stream contentsStream = Files.walk(module)) { contentsStream.filter(Files::isDirectory).forEach((p) -> { p = module.relativize(p); String pkgName = slashesToDots(p.toString()); // skip META-INF and empty strings if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) { - List moduleNames = packageToModules.get(pkgName); - if (moduleNames == null) { - moduleNames = new ArrayList<>(); - packageToModules.put(pkgName, moduleNames); - } - moduleNames.add(moduleName); + packageToModules + .computeIfAbsent(pkgName, k -> new ArrayList<>()) + .add(moduleName); } }); } @@ -275,8 +278,8 @@ class ExplodedImage extends SystemImage { } // create "/modules" directory // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules - PathNode modulesDir = new PathNode("/modules", new ArrayList<>(nodes.values())); - nodes.put(modulesDir.getName(), modulesDir); + PathNode modulesRootNode = new PathNode("/modules", new ArrayList<>(nodes.values())); + nodes.put(modulesRootNode.getName(), modulesRootNode); // create children under "/packages" List packagesChildren = new ArrayList<>(packageToModules.size()); @@ -285,7 +288,7 @@ class ExplodedImage extends SystemImage { List moduleNameList = entry.getValue(); List moduleLinkNodes = new ArrayList<>(moduleNameList.size()); for (String moduleName : moduleNameList) { - Node moduleNode = findModulesNode(MODULES + moduleName); + Node moduleNode = Objects.requireNonNull(nodes.get(MODULES + moduleName)); PathNode linkNode = new PathNode(PACKAGES + pkgName + "/" + moduleName, moduleNode); nodes.put(linkNode.getName(), linkNode); moduleLinkNodes.add(linkNode); @@ -295,13 +298,13 @@ class ExplodedImage extends SystemImage { packagesChildren.add(pkgDir); } // "/packages" dir - PathNode packagesDir = new PathNode("/packages", packagesChildren); - nodes.put(packagesDir.getName(), packagesDir); + PathNode packagesRootNode = new PathNode("/packages", packagesChildren); + nodes.put(packagesRootNode.getName(), packagesRootNode); // finally "/" dir! List rootChildren = new ArrayList<>(); - rootChildren.add(packagesDir); - rootChildren.add(modulesDir); + rootChildren.add(packagesRootNode); + rootChildren.add(modulesRootNode); PathNode root = new PathNode("/", rootChildren); nodes.put(root.getName(), root); } diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java index 6813c7e627f..b38e953a5f9 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java @@ -78,13 +78,13 @@ abstract class SystemImage { return new ExplodedImage(explodedModulesDir); } - static final String RUNTIME_HOME; + private static final String RUNTIME_HOME; // "modules" jimage file Path - static final Path moduleImageFile; + private static final Path moduleImageFile; // "modules" jimage exists or not? - static final boolean modulesImageExists; + private static final boolean modulesImageExists; // /modules directory Path - static final Path explodedModulesDir; + private static final Path explodedModulesDir; static { PrivilegedAction pa = SystemImage::findHome; diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java b/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java new file mode 100644 index 00000000000..884024454d4 --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/ExplodedImageTestDriver.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Whitebox tests for ExplodedImage to ensure compatibility with ImageReader. + * @modules java.base/jdk.internal.jrtfs java.base/jdk.internal.jimage + * @run junit/othervm java.base/jdk.internal.jrtfs.ExplodedImageTest + */ +public class ExplodedImageTestDriver {} \ No newline at end of file diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties b/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties new file mode 100644 index 00000000000..6e60bee4991 --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/TEST.properties @@ -0,0 +1,4 @@ +modules = \ + java.base/jdk.internal.jimage \ + java.base/jdk.internal.jrtfs +bootclasspath.dirs=. diff --git a/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java b/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java new file mode 100644 index 00000000000..c63e163467b --- /dev/null +++ b/test/jdk/jdk/internal/jrtfs/whitebox/java.base/jdk/internal/jrtfs/ExplodedImageTest.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jrtfs; + +import jdk.internal.jimage.ImageReader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests an {@link ExplodedImage} view of a class-file hierarchy. + * + *

            For simplicity and performance, only a subset of the JRT files are copied + * to disk for testing. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ExplodedImageTest { + + private Path modulesRoot; + private SystemImage explodedImage; + private String pathSeparator; + + @BeforeAll + public void createTestDirectory(@TempDir Path modulesRoot) throws IOException { + this.modulesRoot = modulesRoot; + this.pathSeparator = modulesRoot.getFileSystem().getSeparator(); + // Copy only a useful subset of files for testing. Use at least two + // modules with "overlapping" packages to test /package links better. + unpackModulesDirectoriesFromJrtFileSystem(modulesRoot, + "java.base/java/util", + "java.base/java/util/zip", + "java.logging/java/util/logging"); + this.explodedImage = new ExplodedImage(modulesRoot); + } + + /** Unpacks a list of "/modules/..." directories non-recursively into the specified root directory. */ + private static void unpackModulesDirectoriesFromJrtFileSystem(Path modulesRoot, String... dirNames) + throws IOException { + FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/")); + List srcDirs = Arrays.stream(dirNames).map(s -> "/modules/" + s).map(jrtfs::getPath).toList(); + for (Path srcDir : srcDirs) { + // Skip-1 to remove "modules" segment (not part of the file system path). + Path dstDir = StreamSupport.stream(srcDir.spliterator(), false) + .skip(1) + .reduce(modulesRoot, (path, segment) -> path.resolve(segment.toString())); + Files.createDirectories(dstDir); + try (DirectoryStream files = Files.newDirectoryStream(srcDir)) { + for (Path srcFile : files) { + Files.copy(srcFile, dstDir.resolve(srcFile.getFileName().toString())); + } + } + } + } + + @Test + public void topLevelNodes() throws IOException { + ImageReader.Node root = explodedImage.findNode("/"); + ImageReader.Node modules = explodedImage.findNode("/modules"); + ImageReader.Node packages = explodedImage.findNode("/packages"); + assertEquals( + Set.of(modules.getName(), packages.getName()), + root.getChildNames().collect(Collectors.toSet())); + } + + @ParameterizedTest + @ValueSource(strings = { + "/modules/java.base/java/util/List.class", + "/modules/java.base/java/util/zip/ZipEntry.class", + "/modules/java.logging/java/util/logging/Logger.class"}) + public void basicLookupResource(String expectedResourceName) throws IOException { + ImageReader.Node node = assertResourceNode(expectedResourceName); + + Path fsRelPath = getRelativePath(expectedResourceName); + assertArrayEquals( + Files.readAllBytes(modulesRoot.resolve(fsRelPath)), + explodedImage.getResource(node)); + } + + @ParameterizedTest + @ValueSource(strings = { + "/modules/java.base", + "/modules/java.logging", + "/modules/java.base/java", + "/modules/java.base/java/util", + "/modules/java.logging/java/util", + }) + public void basicLookupDirectory(String expectedDirectoryName) throws IOException { + ImageReader.Node node = assertDirectoryNode(expectedDirectoryName); + + Path fsRelPath = getRelativePath(expectedDirectoryName); + List fsChildBaseNames; + try (DirectoryStream paths = Files.newDirectoryStream(modulesRoot.resolve(fsRelPath))) { + fsChildBaseNames = StreamSupport.stream(paths.spliterator(), false) + .map(Path::getFileName) + .map(Path::toString) + .toList(); + } + List nodeChildBaseNames = node.getChildNames() + .map(s -> s.substring(node.getName().length() + 1)) + .toList(); + assertEquals(fsChildBaseNames, nodeChildBaseNames, "expected same child names"); + } + + @ParameterizedTest + @ValueSource(strings = { + "/packages/java/java.base", + "/packages/java/java.logging", + "/packages/java.util/java.base", + "/packages/java.util/java.logging", + "/packages/java.util.zip/java.base"}) + public void basicLookupPackageLinks(String expectedLinkName) throws IOException { + ImageReader.Node node = assertLinkNode(expectedLinkName); + ImageReader.Node resolved = node.resolveLink(); + assertSame(explodedImage.findNode(resolved.getName()), resolved); + String moduleName = expectedLinkName.substring(expectedLinkName.lastIndexOf('/') + 1); + assertEquals("/modules/" + moduleName, resolved.getName()); + } + + @ParameterizedTest + @ValueSource(strings = { + "/packages/java", + "/packages/java.util", + "/packages/java.util.zip"}) + public void packageDirectories(String expectedDirectoryName) throws IOException { + ImageReader.Node node = assertDirectoryNode(expectedDirectoryName); + assertTrue(node.getChildNames().findFirst().isPresent(), + "Package directories should not be empty: " + node); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + ".", + "/.", + "modules", + "packages", + "/modules/", + "/modules/xxxx", + "/modules/java.base/java/lang/Xxxx.class", + "/packages/", + "/packages/xxxx", + "/packages/java.xxxx", + "/packages/java.util.", + // Mismatched module. + "/packages/java.util.logging/java.base", + "/packages/java.util.zip/java.logging", + // Links are not resolved as they are fetched (old/broken behaviour). + "/packages/java.util/java.base/java/util/Vector.class", + }) + public void invalidNames(String invalidName) throws IOException { + assertNull(explodedImage.findNode(invalidName), "No node expected for: " + invalidName); + } + + private ImageReader.Node assertResourceNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isResource(), "expected a resource: " + node); + assertFalse(node.isDirectory(), "resources are not directories: " + node); + assertFalse(node.isLink(), "resources are not links: " + node); + return node; + } + + private ImageReader.Node assertDirectoryNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isDirectory(), "expected a directory: " + node); + assertFalse(node.isResource(), "directories are not resources: " + node); + assertFalse(node.isLink(), "directories are not links: " + node); + return node; + } + + private ImageReader.Node assertLinkNode(String name) throws IOException { + ImageReader.Node node = explodedImage.findNode(name); + assertNotNull(node); + assertEquals(name, node.getName(), "expected node name: " + name); + assertTrue(node.isLink(), "expected a link: " + node); + assertFalse(node.isResource(), "links are not resources: " + node); + assertFalse(node.isDirectory(), "links are not directories: " + node); + return node; + } + + private Path getRelativePath(String name) { + return Path.of(name.substring("/modules/".length()).replace("/", pathSeparator)); + } +} From 79a1a98cabb579a5de504144abacb386486fba7e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 16:19:35 +0000 Subject: [PATCH 366/471] 8366498: Simplify ClassFileParser::parse_super_class Reviewed-by: dholmes, coleenp --- .../share/classfile/classFileParser.cpp | 44 ++++++++----------- .../share/classfile/classFileParser.hpp | 8 ++-- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 6c019f7c612..617110203cd 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3803,39 +3803,30 @@ AnnotationArray* ClassFileParser::allocate_annotations(const u1* const anno, return annotations; } -const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp, - const int super_class_index, - const bool need_verify, - TRAPS) { +void ClassFileParser::check_super_class(ConstantPool* const cp, + const int super_class_index, + const bool need_verify, + TRAPS) { assert(cp != nullptr, "invariant"); - const InstanceKlass* super_klass = nullptr; if (super_class_index == 0) { guarantee_property(_class_name == vmSymbols::java_lang_Object(), "Invalid superclass index %u in class file %s", super_class_index, - CHECK_NULL); + CHECK); } else { guarantee_property(valid_klass_reference_at(super_class_index), "Invalid superclass index %u in class file %s", super_class_index, - CHECK_NULL); + CHECK); + // The class name should be legal because it is checked when parsing constant pool. // However, make sure it is not an array type. - bool is_array = false; - if (cp->tag_at(super_class_index).is_klass()) { - super_klass = InstanceKlass::cast(cp->resolved_klass_at(super_class_index)); - if (need_verify) - is_array = super_klass->is_array_klass(); - } else if (need_verify) { - is_array = (cp->klass_name_at(super_class_index)->char_at(0) == JVM_SIGNATURE_ARRAY); - } if (need_verify) { - guarantee_property(!is_array, - "Bad superclass name in class file %s", CHECK_NULL); + guarantee_property(cp->klass_name_at(super_class_index)->char_at(0) != JVM_SIGNATURE_ARRAY, + "Bad superclass name in class file %s", CHECK); } } - return super_klass; } OopMapBlocksBuilder::OopMapBlocksBuilder(unsigned int max_blocks) { @@ -5667,10 +5658,10 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, // SUPERKLASS _super_class_index = stream->get_u2_fast(); - _super_klass = parse_super_class(cp, - _super_class_index, - _need_verify, - CHECK); + check_super_class(cp, + _super_class_index, + _need_verify, + CHECK); // Interfaces _itfs_len = stream->get_u2_fast(); @@ -5773,12 +5764,14 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st assert(_loader_data != nullptr, "invariant"); if (_class_name == vmSymbols::java_lang_Object()) { + precond(_super_class_index == 0); + precond(_super_klass == nullptr); guarantee_property(_local_interfaces == Universe::the_empty_instance_klass_array(), "java.lang.Object cannot implement an interface in class file %s", CHECK); - } - // We check super class after class file is parsed and format is checked - if (_super_class_index > 0 && nullptr == _super_klass) { + } else { + // Set _super_klass after class file is parsed and format is checked + assert(_super_class_index > 0, "any class other than Object must have a super class"); Symbol* const super_class_name = cp->klass_name_at(_super_class_index); if (_access_flags.is_interface()) { // Before attempting to resolve the superclass, check for class format @@ -5789,6 +5782,7 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st } Handle loader(THREAD, _loader_data->class_loader()); if (loader.is_null() && super_class_name == vmSymbols::java_lang_Object()) { + // fast path to avoid lookup _super_klass = vmClasses::Object_klass(); } else { _super_klass = (const InstanceKlass*) diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 2f5a1aef39f..e46dd4580bf 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -242,10 +242,10 @@ class ClassFileParser { bool* has_nonstatic_concrete_methods, TRAPS); - const InstanceKlass* parse_super_class(ConstantPool* const cp, - const int super_class_index, - const bool need_verify, - TRAPS); + void check_super_class(ConstantPool* const cp, + const int super_class_index, + const bool need_verify, + TRAPS); // Field parsing void parse_field_attributes(const ClassFileStream* const cfs, From f90d520308d5fa72497dc59bee7258931c2a3d95 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 4 Sep 2025 16:23:46 +0000 Subject: [PATCH 367/471] 8366475: Rename MetaspaceShared class to AOTMetaspace Reviewed-by: kvn, asmehra --- src/hotspot/os/posix/vmError_posix.cpp | 4 +- src/hotspot/os/windows/vmError_windows.cpp | 4 +- .../bsd_aarch64/javaThread_bsd_aarch64.cpp | 2 +- src/hotspot/share/cds/aotCacheAccess.cpp | 4 +- src/hotspot/share/cds/aotClassLocation.cpp | 8 +- .../share/cds/aotLinkedClassBulkLoader.cpp | 2 +- src/hotspot/share/cds/aotMapLogger.cpp | 6 +- .../{metaspaceShared.cpp => aotMetaspace.cpp} | 166 +++++++++--------- .../{metaspaceShared.hpp => aotMetaspace.hpp} | 12 +- .../share/cds/aotReferenceObjSupport.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 38 ++-- src/hotspot/share/cds/archiveHeapLoader.cpp | 14 +- src/hotspot/share/cds/archiveUtils.cpp | 14 +- src/hotspot/share/cds/archiveUtils.inline.hpp | 4 +- src/hotspot/share/cds/cdsConfig.cpp | 2 +- src/hotspot/share/cds/cdsHeapVerifier.cpp | 2 +- src/hotspot/share/cds/cdsProtectionDomain.cpp | 2 +- src/hotspot/share/cds/classListParser.cpp | 6 +- src/hotspot/share/cds/cppVtables.cpp | 4 +- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 4 +- src/hotspot/share/cds/dynamicArchive.cpp | 22 +-- src/hotspot/share/cds/dynamicArchive.hpp | 2 +- src/hotspot/share/cds/filemap.cpp | 164 ++++++++--------- src/hotspot/share/cds/filemap.hpp | 4 +- src/hotspot/share/cds/finalImageRecipes.cpp | 4 +- src/hotspot/share/cds/heapShared.cpp | 10 +- src/hotspot/share/cds/heapShared.hpp | 4 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../share/cds/lambdaProxyClassDictionary.hpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.cpp | 2 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 2 +- src/hotspot/share/classfile/modules.cpp | 10 +- src/hotspot/share/classfile/stringTable.cpp | 2 +- src/hotspot/share/classfile/symbolTable.cpp | 4 +- .../share/classfile/systemDictionary.cpp | 2 +- .../classfile/systemDictionaryShared.cpp | 10 +- src/hotspot/share/code/aotCodeCache.cpp | 6 +- src/hotspot/share/include/cds.h | 4 +- .../share/interpreter/abstractInterpreter.cpp | 2 +- src/hotspot/share/interpreter/rewriter.cpp | 2 +- src/hotspot/share/memory/metaspace.cpp | 10 +- src/hotspot/share/memory/metaspace.hpp | 4 +- src/hotspot/share/memory/universe.cpp | 8 +- src/hotspot/share/memory/universe.hpp | 4 +- src/hotspot/share/oops/arrayKlass.cpp | 6 +- src/hotspot/share/oops/instanceKlass.cpp | 10 +- src/hotspot/share/oops/klassVtable.cpp | 8 +- src/hotspot/share/oops/method.cpp | 6 +- src/hotspot/share/oops/symbol.cpp | 1 - src/hotspot/share/oops/trainingData.cpp | 1 - src/hotspot/share/prims/jvm.cpp | 3 +- .../share/prims/jvmtiRedefineClasses.cpp | 4 +- src/hotspot/share/prims/whitebox.cpp | 10 +- src/hotspot/share/runtime/java.cpp | 3 +- src/hotspot/share/runtime/threads.cpp | 6 +- src/hotspot/share/utilities/vmError.cpp | 6 +- .../runtime/cds/SpaceUtilizationCheck.java | 4 +- .../cds/appcds/SharedArchiveConsistency.java | 2 +- .../lib/jdk/test/lib/cds/CDSArchiveUtils.java | 4 +- 60 files changed, 332 insertions(+), 332 deletions(-) rename src/hotspot/share/cds/{metaspaceShared.cpp => aotMetaspace.cpp} (93%) rename src/hotspot/share/cds/{metaspaceShared.hpp => aotMetaspace.hpp} (97%) diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp index 4bfd8efabe8..81eeea6c168 100644 --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -23,8 +23,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "os_posix.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" @@ -117,7 +117,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { if (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) { const void* const fault_addr = si->si_addr; if (fault_addr != nullptr) { - if (MetaspaceShared::in_aot_cache(fault_addr)) { + if (AOTMetaspace::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os/windows/vmError_windows.cpp b/src/hotspot/os/windows/vmError_windows.cpp index fbd91309822..22df4d82cbf 100644 --- a/src/hotspot/os/windows/vmError_windows.cpp +++ b/src/hotspot/os/windows/vmError_windows.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "runtime/arguments.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" @@ -51,7 +51,7 @@ void VMError::check_failing_cds_access(outputStream* st, const void* siginfo) { er->NumberParameters >= 2) { const void* const fault_addr = (const void*) er->ExceptionInformation[1]; if (fault_addr != nullptr) { - if (MetaspaceShared::in_aot_cache(fault_addr)) { + if (AOTMetaspace::in_aot_cache(fault_addr)) { st->print("Error accessing class data sharing archive. " "Mapped file inaccessible during execution, possible disk/network problem."); } diff --git a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp index fa40ef2b8f1..982605bbed4 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/javaThread_bsd_aarch64.cpp @@ -24,7 +24,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/cds/aotCacheAccess.cpp b/src/hotspot/share/cds/aotCacheAccess.cpp index b6c4a201da5..117979f41b5 100644 --- a/src/hotspot/share/cds/aotCacheAccess.cpp +++ b/src/hotspot/share/cds/aotCacheAccess.cpp @@ -23,11 +23,11 @@ */ #include "cds/aotCacheAccess.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/stringTable.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -45,7 +45,7 @@ size_t AOTCacheAccess::get_aot_code_region_size() { assert(CDSConfig::is_using_archive(), "must be"); FileMapInfo* mapinfo = FileMapInfo::current_info(); assert(mapinfo != nullptr, "must be"); - return mapinfo->region_at(MetaspaceShared::ac)->used_aligned(); + return mapinfo->region_at(AOTMetaspace::ac)->used_aligned(); } bool AOTCacheAccess::map_aot_code_region(ReservedSpace rs) { diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index f04c601ac86..f77aac3540c 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -24,11 +24,11 @@ #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" #include "cds/filemap.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/serializeClosure.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" @@ -246,7 +246,7 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa type = FileType::NOT_EXIST; } else { aot_log_error(aot)("Unable to open file %s.", path); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } ResourceMark rm(current); @@ -1028,10 +1028,10 @@ bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_l vm_exit_during_initialization("Unable to use create AOT cache.", nullptr); } else { aot_log_error(aot)("%s%s", mismatch_msg, hint_msg); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } } else { - MetaspaceShared::report_loading_error("%s%s", mismatch_msg, hint_msg); + AOTMetaspace::report_loading_error("%s%s", mismatch_msg, hint_msg); } } return success; diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 99d7c26b293..11848b88300 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -221,7 +221,7 @@ void AOTLinkedClassBulkLoader::load_classes_impl(AOTLinkedClassCategory class_ca log_error(aot)("Unable to resolve %s class from %s: %s", category_name, CDSConfig::type_of_archive_being_loaded(), ik->external_name()); log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); log_error(aot)("JVMTI class retransformation is not supported when archive was generated with -XX:+AOTClassLinking."); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } assert(actual->is_loaded(), "must be"); } diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index 712901a71ca..a15d7f670d4 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -218,8 +218,8 @@ void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* r } void AOTMapLogger::runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap* objs) { - FileMapRegion* rw = mapinfo->region_at(MetaspaceShared::rw); - FileMapRegion* ro = mapinfo->region_at(MetaspaceShared::ro); + FileMapRegion* rw = mapinfo->region_at(AOTMetaspace::rw); + FileMapRegion* ro = mapinfo->region_at(AOTMetaspace::ro); address rw_base = address(rw->mapped_base()); address rw_end = address(rw->mapped_end()); @@ -782,7 +782,7 @@ void AOTMapLogger::dumptime_log_heap_region(ArchiveHeapInfo* heap_info) { void AOTMapLogger::runtime_log_heap_region(FileMapInfo* mapinfo) { ResourceMark rm; - int heap_region_index = MetaspaceShared::hp; + int heap_region_index = AOTMetaspace::hp; FileMapRegion* r = mapinfo->region_at(heap_region_index); size_t alignment = ObjectAlignmentInBytes; diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/aotMetaspace.cpp similarity index 93% rename from src/hotspot/share/cds/metaspaceShared.cpp rename to src/hotspot/share/cds/aotMetaspace.cpp index 92773c5be90..c2d9d0193f5 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -30,6 +30,7 @@ #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" #include "cds/aotMapLogger.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -47,7 +48,6 @@ #include "cds/heapShared.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/javaClasses.inline.hpp" @@ -104,15 +104,15 @@ #include -ReservedSpace MetaspaceShared::_symbol_rs; -VirtualSpace MetaspaceShared::_symbol_vs; -bool MetaspaceShared::_archive_loading_failed = false; -bool MetaspaceShared::_remapped_readwrite = false; -void* MetaspaceShared::_aot_metaspace_static_top = nullptr; -intx MetaspaceShared::_relocation_delta; -char* MetaspaceShared::_requested_base_address; -Array* MetaspaceShared::_archived_method_handle_intrinsics = nullptr; -bool MetaspaceShared::_use_optimized_module_handling = true; +ReservedSpace AOTMetaspace::_symbol_rs; +VirtualSpace AOTMetaspace::_symbol_vs; +bool AOTMetaspace::_archive_loading_failed = false; +bool AOTMetaspace::_remapped_readwrite = false; +void* AOTMetaspace::_aot_metaspace_static_top = nullptr; +intx AOTMetaspace::_relocation_delta; +char* AOTMetaspace::_requested_base_address; +Array* AOTMetaspace::_archived_method_handle_intrinsics = nullptr; +bool AOTMetaspace::_use_optimized_module_handling = true; // The CDS archive is divided into the following regions: // rw - read-write metadata @@ -121,10 +121,10 @@ bool MetaspaceShared::_use_optimized_module_handling = true; // bm - bitmap for relocating the above 7 regions. // // The rw and ro regions are linearly allocated, in the order of rw->ro. -// These regions are aligned with MetaspaceShared::core_region_alignment(). +// These regions are aligned with AOTMetaspace::core_region_alignment(). // // These 2 regions are populated in the following steps: -// [0] All classes are loaded in MetaspaceShared::preload_classes(). All metadata are +// [0] All classes are loaded in AOTMetaspace::preload_classes(). All metadata are // temporarily allocated outside of the shared regions. // [1] We enter a safepoint and allocate a buffer for the rw/ro regions. // [2] C++ vtables are copied into the rw region. @@ -139,7 +139,7 @@ bool MetaspaceShared::_use_optimized_module_handling = true; static DumpRegion _symbol_region("symbols"); -char* MetaspaceShared::symbol_space_alloc(size_t num_bytes) { +char* AOTMetaspace::symbol_space_alloc(size_t num_bytes) { return _symbol_region.allocate(num_bytes); } @@ -152,11 +152,11 @@ char* MetaspaceShared::symbol_space_alloc(size_t num_bytes) { // Upon successful configuration, the compactible alignment then can be defined in: // os_linux_aarch64.cpp // os_bsd_x86.cpp -size_t MetaspaceShared::core_region_alignment() { +size_t AOTMetaspace::core_region_alignment() { return os::cds_core_region_alignment(); } -size_t MetaspaceShared::protection_zone_size() { +size_t AOTMetaspace::protection_zone_size() { return os::cds_core_region_alignment(); } @@ -217,7 +217,7 @@ public: } }; -void MetaspaceShared::dump_loaded_classes(const char* file_name, TRAPS) { +void AOTMetaspace::dump_loaded_classes(const char* file_name, TRAPS) { fileStream stream(file_name, "w"); if (stream.is_open()) { MutexLocker lock(ClassLoaderDataGraph_lock); @@ -245,7 +245,7 @@ static bool shared_base_too_high(char* specified_base, char* aligned_base, size_ static char* compute_shared_base(size_t cds_max) { char* specified_base = (char*)SharedBaseAddress; - size_t alignment = MetaspaceShared::core_region_alignment(); + size_t alignment = AOTMetaspace::core_region_alignment(); if (UseCompressedClassPointers && CompressedKlassPointers::needs_class_space()) { alignment = MAX2(alignment, Metaspace::reserve_alignment()); } @@ -291,7 +291,7 @@ static char* compute_shared_base(size_t cds_max) { return aligned_base; } -void MetaspaceShared::initialize_for_static_dump() { +void AOTMetaspace::initialize_for_static_dump() { assert(CDSConfig::is_dumping_static_archive(), "sanity"); aot_log_info(aot)("Core region alignment: %zu", core_region_alignment()); // The max allowed size for CDS archive. We use this to limit SharedBaseAddress @@ -318,13 +318,13 @@ void MetaspaceShared::initialize_for_static_dump() { mtClassShared); if (!_symbol_rs.is_reserved()) { aot_log_error(aot)("Unable to reserve memory for symbols: %zu bytes.", symbol_rs_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } _symbol_region.init(&_symbol_rs, &_symbol_vs); } // Called by universe_post_init() -void MetaspaceShared::post_initialize(TRAPS) { +void AOTMetaspace::post_initialize(TRAPS) { if (CDSConfig::is_using_archive()) { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); @@ -337,11 +337,11 @@ void MetaspaceShared::post_initialize(TRAPS) { // Close any open file descriptors. However, mmap'ed pages will remain in memory. static_mapinfo->close(); - static_mapinfo->unmap_region(MetaspaceShared::bm); + static_mapinfo->unmap_region(AOTMetaspace::bm); if (dynamic_mapinfo != nullptr) { dynamic_mapinfo->close(); - dynamic_mapinfo->unmap_region(MetaspaceShared::bm); + dynamic_mapinfo->unmap_region(AOTMetaspace::bm); } int size = AOTClassLocationConfig::runtime()->length(); @@ -358,7 +358,7 @@ static GrowableArrayCHeap* _extra_symbols = nullptr; // Methods managed by SystemDictionary::find_method_handle_intrinsic() to be added to the archive static GrowableArray* _pending_method_handle_intrinsics = nullptr; -void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) { +void AOTMetaspace::read_extra_data(JavaThread* current, const char* filename) { _extra_interned_strings = new GrowableArrayCHeap(10000); _extra_symbols = new GrowableArrayCHeap(1000); @@ -372,7 +372,7 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) if (utf8_length == 0x7fffffff) { // buf_len will overflown 32-bit value. aot_log_error(aot)("string length too large: %d", utf8_length); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } int buf_len = utf8_length+1; char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len); @@ -407,7 +407,7 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) } } -void MetaspaceShared::make_method_handle_intrinsics_shareable() { +void AOTMetaspace::make_method_handle_intrinsics_shareable() { for (int i = 0; i < _pending_method_handle_intrinsics->length(); i++) { Method* m = ArchiveBuilder::current()->get_buffered_addr(_pending_method_handle_intrinsics->at(i)); m->remove_unshareable_info(); @@ -416,7 +416,7 @@ void MetaspaceShared::make_method_handle_intrinsics_shareable() { } } -void MetaspaceShared::write_method_handle_intrinsics() { +void AOTMetaspace::write_method_handle_intrinsics() { int len = _pending_method_handle_intrinsics->length(); _archived_method_handle_intrinsics = ArchiveBuilder::new_ro_array(len); int word_size = _archived_method_handle_intrinsics->size(); @@ -452,23 +452,23 @@ void MetaspaceShared::write_method_handle_intrinsics() { // Some of the xxx::serialize() functions may have side effects and assume that // the archive is already mapped. For example, SymbolTable::serialize_shared_table_header() // unconditionally makes the set of archived symbols available. Therefore, we put most -// of these xxx::serialize() functions inside MetaspaceShared::serialize(), which +// of these xxx::serialize() functions inside AOTMetaspace::serialize(), which // is called AFTER we made the decision to map the archive. // // However, some of the "serialized" data are used to decide whether an archive should // be mapped or not (e.g., for checking if the -Djdk.module.main property is compatible // with the archive). The xxx::serialize() functions for these data must be put inside -// MetaspaceShared::early_serialize(). Such functions must not produce side effects that +// AOTMetaspace::early_serialize(). Such functions must not produce side effects that // assume we will always decides to map the archive. -void MetaspaceShared::early_serialize(SerializeClosure* soc) { +void AOTMetaspace::early_serialize(SerializeClosure* soc) { int tag = 0; soc->do_tag(--tag); CDS_JAVA_HEAP_ONLY(Modules::serialize_archived_module_info(soc);) soc->do_tag(666); } -void MetaspaceShared::serialize(SerializeClosure* soc) { +void AOTMetaspace::serialize(SerializeClosure* soc) { int tag = 0; soc->do_tag(--tag); @@ -541,7 +541,7 @@ static void rewrite_nofast_bytecode(const methodHandle& method) { // [1] Rewrite all bytecodes as needed, so that the ConstMethod* will not be modified // at run time by RewriteBytecodes/RewriteFrequentPairs // [2] Assign a fingerprint, so one doesn't need to be assigned at run-time. -void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) { +void AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) { for (int i = 0; i < ik->methods()->length(); i++) { methodHandle m(thread, ik->methods()->at(i)); if (ik->can_be_verified_at_dumptime() && ik->is_linked()) { @@ -617,7 +617,7 @@ char* VM_PopulateDumpSharedSpace::dump_early_read_only_tables() { DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); WriteClosure wc(ro_region); - MetaspaceShared::early_serialize(&wc); + AOTMetaspace::early_serialize(&wc); return start; } @@ -633,7 +633,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& TrainingData::dump_training_data(); - MetaspaceShared::write_method_handle_intrinsics(); + AOTMetaspace::write_method_handle_intrinsics(); // Write lambform lines into archive LambdaFormInvokers::dump_static_archive_invokers(); @@ -646,7 +646,7 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); WriteClosure wc(ro_region); - MetaspaceShared::serialize(&wc); + AOTMetaspace::serialize(&wc); return start; } @@ -684,7 +684,7 @@ void VM_PopulateDumpSharedSpace::doit() { log_info(aot)("Make classes shareable"); _builder.make_klasses_shareable(); - MetaspaceShared::make_method_handle_intrinsics_shareable(); + AOTMetaspace::make_method_handle_intrinsics_shareable(); dump_java_heap_objects(); dump_shared_symbol_table(_builder.symbols()); @@ -712,7 +712,7 @@ void VM_PopulateDumpSharedSpace::doit() { const char* static_archive = CDSConfig::output_archive_path(); assert(static_archive != nullptr, "sanity"); _map_info = new FileMapInfo(static_archive, true); - _map_info->populate_header(MetaspaceShared::core_region_alignment()); + _map_info->populate_header(AOTMetaspace::core_region_alignment()); _map_info->set_early_serialized_data(early_serialized_data); _map_info->set_serialized_data(serialized_data); _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); @@ -754,7 +754,7 @@ public: // Check if we can eagerly link this class at dump time, so we can avoid the // runtime linking overhead (especially verification) -bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { +bool AOTMetaspace::may_be_eagerly_linked(InstanceKlass* ik) { if (!ik->can_be_verified_at_dumptime()) { // For old classes, try to leave them in the unlinked state, so // we can still store them in the archive. They must be @@ -773,7 +773,7 @@ bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { return true; } -void MetaspaceShared::link_shared_classes(TRAPS) { +void AOTMetaspace::link_shared_classes(TRAPS) { AOTClassLinker::initialize(); AOTClassInitializer::init_test_class(CHECK); @@ -816,7 +816,7 @@ void MetaspaceShared::link_shared_classes(TRAPS) { // Preload classes from a list, populate the shared spaces and dump to a // file. -void MetaspaceShared::preload_and_dump(TRAPS) { +void AOTMetaspace::preload_and_dump(TRAPS) { CDSConfig::DumperThreadMark dumper_thread_mark(THREAD); ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -832,12 +832,12 @@ void MetaspaceShared::preload_and_dump(TRAPS) { if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { aot_log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " "%zuM", MaxHeapSize/M); - MetaspaceShared::writing_error(); + AOTMetaspace::writing_error(); } else { oop message = java_lang_Throwable::message(PENDING_EXCEPTION); aot_log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), message == nullptr ? "(null)" : java_lang_String::as_utf8_string(message)); - MetaspaceShared::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail", + AOTMetaspace::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail", CDSConfig::new_aot_flags_used() ? "" : ",cds")); } } @@ -864,7 +864,7 @@ void MetaspaceShared::preload_and_dump(TRAPS) { } #if INCLUDE_CDS_JAVA_HEAP && defined(_LP64) -void MetaspaceShared::adjust_heap_sizes_for_dumping() { +void AOTMetaspace::adjust_heap_sizes_for_dumping() { if (!CDSConfig::is_dumping_heap() || UseCompressedOops) { return; } @@ -887,13 +887,13 @@ void MetaspaceShared::adjust_heap_sizes_for_dumping() { } #endif // INCLUDE_CDS_JAVA_HEAP && _LP64 -void MetaspaceShared::get_default_classlist(char* default_classlist, const size_t buf_size) { +void AOTMetaspace::get_default_classlist(char* default_classlist, const size_t buf_size) { const char* filesep = os::file_separator(); jio_snprintf(default_classlist, buf_size, "%s%slib%sclasslist", Arguments::get_java_home(), filesep, filesep); } -void MetaspaceShared::preload_classes(TRAPS) { +void AOTMetaspace::preload_classes(TRAPS) { char default_classlist[JVM_MAXPATHLEN]; const char* classlist_path; @@ -928,7 +928,7 @@ void MetaspaceShared::preload_classes(TRAPS) { aot_log_info(aot)("Loading classes to share: done."); } -void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { +void AOTMetaspace::exercise_runtime_cds_code(TRAPS) { // Exercise the manifest processing code const char* dummy = "Manifest-Version: 1.0\n"; CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK); @@ -937,7 +937,7 @@ void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK); } -void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { +void AOTMetaspace::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { if (CDSConfig::is_dumping_classic_static_archive()) { // We are running with -Xshare:dump preload_classes(CHECK); @@ -1058,8 +1058,8 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS } } -bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) { - // relocate the data so that it can be mapped to MetaspaceShared::requested_base_address() +bool AOTMetaspace::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) { + // relocate the data so that it can be mapped to AOTMetaspace::requested_base_address() // without runtime relocation. builder->relocate_to_requested(); @@ -1177,7 +1177,7 @@ static int exec_jvm_with_java_tool_options(const char* java_launcher_path, TRAPS return result.get_jint(); } -void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) { +void AOTMetaspace::fork_and_dump_final_static_archive(TRAPS) { assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity"); ResourceMark rm; @@ -1203,7 +1203,7 @@ void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) { } // Returns true if the class's status has changed. -bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { +bool AOTMetaspace::try_link_class(JavaThread* current, InstanceKlass* ik) { ExceptionMark em(current); JavaThread* THREAD = current; // For exception macros. assert(CDSConfig::is_dumping_archive(), "sanity"); @@ -1252,13 +1252,13 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() { } } -void MetaspaceShared::set_aot_metaspace_range(void* base, void *static_top, void* top) { +void AOTMetaspace::set_aot_metaspace_range(void* base, void *static_top, void* top) { assert(base <= static_top && static_top <= top, "must be"); _aot_metaspace_static_top = static_top; MetaspaceObj::set_aot_metaspace_range(base, top); } -bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { +bool AOTMetaspace::in_aot_cache_dynamic_region(void* p) { if ((p < MetaspaceObj::aot_metaspace_top()) && (p >= _aot_metaspace_static_top)) { return true; @@ -1267,7 +1267,7 @@ bool MetaspaceShared::in_aot_cache_dynamic_region(void* p) { } } -bool MetaspaceShared::in_aot_cache_static_region(void* p) { +bool AOTMetaspace::in_aot_cache_static_region(void* p) { if (in_aot_cache(p) && !in_aot_cache_dynamic_region(p)) { return true; } else { @@ -1280,7 +1280,7 @@ bool MetaspaceShared::in_aot_cache_static_region(void* p) { // - There's an error that indicates that the archive(s) files were corrupt or otherwise damaged. // - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due // to version or classpath mismatch. -void MetaspaceShared::unrecoverable_loading_error(const char* message) { +void AOTMetaspace::unrecoverable_loading_error(const char* message) { report_loading_error("%s", message); if (CDSConfig::is_dumping_final_static_archive()) { @@ -1292,7 +1292,7 @@ void MetaspaceShared::unrecoverable_loading_error(const char* message) { } } -void MetaspaceShared::report_loading_error(const char* format, ...) { +void AOTMetaspace::report_loading_error(const char* format, ...) { // When using AOT cache, errors messages are always printed on the error channel. LogStream ls_aot(LogLevel::Error, LogTagSetMapping::tagset()); @@ -1325,21 +1325,21 @@ void MetaspaceShared::report_loading_error(const char* format, ...) { // This function is called when the JVM is unable to write the specified CDS archive due to an // unrecoverable error. -void MetaspaceShared::unrecoverable_writing_error(const char* message) { +void AOTMetaspace::unrecoverable_writing_error(const char* message) { writing_error(message); vm_direct_exit(1); } // This function is called when the JVM is unable to write the specified CDS archive due to a // an error. The error will be propagated -void MetaspaceShared::writing_error(const char* message) { +void AOTMetaspace::writing_error(const char* message) { aot_log_error(aot)("An error has occurred while writing the shared archive file."); if (message != nullptr) { aot_log_error(aot)("%s", message); } } -void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { +void AOTMetaspace::initialize_runtime_shared_and_meta_spaces() { assert(CDSConfig::is_using_archive(), "Must be called when UseSharedSpaces is enabled"); MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; @@ -1385,10 +1385,10 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { AutoCreateSharedArchive = false; CDSConfig::disable_dumping_dynamic_archive(); if (PrintSharedArchiveAndExit) { - MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive."); + AOTMetaspace::unrecoverable_loading_error("Unable to use shared archive."); } else { if (RequireSharedSpaces) { - MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + AOTMetaspace::unrecoverable_loading_error("Unable to map shared spaces"); } else { report_loading_error("Unable to map shared spaces"); } @@ -1406,11 +1406,11 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { delete dynamic_mapinfo; } if (RequireSharedSpaces && has_failed) { - MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + AOTMetaspace::unrecoverable_loading_error("Unable to map shared spaces"); } } -FileMapInfo* MetaspaceShared::open_static_archive() { +FileMapInfo* AOTMetaspace::open_static_archive() { const char* static_archive = CDSConfig::input_static_archive_path(); assert(static_archive != nullptr, "sanity"); FileMapInfo* mapinfo = new FileMapInfo(static_archive, true); @@ -1421,7 +1421,7 @@ FileMapInfo* MetaspaceShared::open_static_archive() { return mapinfo; } -FileMapInfo* MetaspaceShared::open_dynamic_archive() { +FileMapInfo* AOTMetaspace::open_dynamic_archive() { if (CDSConfig::is_dumping_dynamic_archive()) { return nullptr; } @@ -1434,7 +1434,7 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { if (!mapinfo->open_as_input()) { delete(mapinfo); if (RequireSharedSpaces) { - MetaspaceShared::unrecoverable_loading_error("Failed to initialize dynamic archive"); + AOTMetaspace::unrecoverable_loading_error("Failed to initialize dynamic archive"); } return nullptr; } @@ -1444,8 +1444,8 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { // use_requested_addr: // true = map at FileMapHeader::_requested_base_address // false = map at an alternative address picked by OS. -MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, - bool use_requested_addr) { +MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, + bool use_requested_addr) { if (use_requested_addr && static_mapinfo->requested_base_address() == nullptr) { aot_log_info(aot)("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address."); return MAP_ARCHIVE_MMAP_FAILURE; @@ -1517,7 +1517,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File aot_log_info(aot)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size()); - if (MetaspaceShared::use_windows_memory_mapping()) { + if (AOTMetaspace::use_windows_memory_mapping()) { // We have now reserved address space for the archives, and will map in // the archive files into this space. // @@ -1721,12 +1721,12 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File // covers both spaces. // If UseCompressedClassPointers=0, class_space_rs remains unreserved. // - On error: null is returned and the spaces remain unreserved. -char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo, - FileMapInfo* dynamic_mapinfo, - bool use_archive_base_addr, - ReservedSpace& total_space_rs, - ReservedSpace& archive_space_rs, - ReservedSpace& class_space_rs) { +char* AOTMetaspace::reserve_address_space_for_archives(FileMapInfo* static_mapinfo, + FileMapInfo* dynamic_mapinfo, + bool use_archive_base_addr, + ReservedSpace& total_space_rs, + ReservedSpace& archive_space_rs, + ReservedSpace& class_space_rs) { address const base_address = (address) (use_archive_base_addr ? static_mapinfo->requested_base_address() : nullptr); const size_t archive_space_alignment = core_region_alignment(); @@ -1879,9 +1879,9 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma } -void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs, - ReservedSpace& archive_space_rs, - ReservedSpace& class_space_rs) { +void AOTMetaspace::release_reserved_spaces(ReservedSpace& total_space_rs, + ReservedSpace& archive_space_rs, + ReservedSpace& class_space_rs) { if (total_space_rs.is_reserved()) { aot_log_debug(aot)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base())); MemoryReserver::release(total_space_rs); @@ -1900,10 +1900,10 @@ void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs, } } -static int archive_regions[] = { MetaspaceShared::rw, MetaspaceShared::ro }; +static int archive_regions[] = { AOTMetaspace::rw, AOTMetaspace::ro }; static int archive_regions_count = 2; -MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) { +MapArchiveResult AOTMetaspace::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) { assert(CDSConfig::is_using_archive(), "must be runtime"); if (mapinfo == nullptr) { return MAP_ARCHIVE_SUCCESS; // The dynamic archive has not been specified. No error has happened -- trivially succeeded. @@ -1946,11 +1946,11 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped return MAP_ARCHIVE_SUCCESS; } -void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) { +void AOTMetaspace::unmap_archive(FileMapInfo* mapinfo) { assert(CDSConfig::is_using_archive(), "must be runtime"); if (mapinfo != nullptr) { mapinfo->unmap_regions(archive_regions, archive_regions_count); - mapinfo->unmap_region(MetaspaceShared::bm); + mapinfo->unmap_region(AOTMetaspace::bm); mapinfo->set_is_mapped(false); } } @@ -1971,7 +1971,7 @@ class CountSharedSymbols : public SymbolClosure { // Read the miscellaneous data from the shared file, and // serialize it out to its various destinations. -void MetaspaceShared::initialize_shared_spaces() { +void AOTMetaspace::initialize_shared_spaces() { FileMapInfo *static_mapinfo = FileMapInfo::current_info(); FileMapInfo *dynamic_mapinfo = FileMapInfo::dynamic_info(); @@ -2052,7 +2052,7 @@ void MetaspaceShared::initialize_shared_spaces() { } // JVM/TI RedefineClasses() support: -bool MetaspaceShared::remap_shared_readonly_as_readwrite() { +bool AOTMetaspace::remap_shared_readonly_as_readwrite() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (CDSConfig::is_using_archive()) { @@ -2072,7 +2072,7 @@ bool MetaspaceShared::remap_shared_readonly_as_readwrite() { return true; } -void MetaspaceShared::print_on(outputStream* st) { +void AOTMetaspace::print_on(outputStream* st) { if (CDSConfig::is_using_archive()) { st->print("CDS archive(s) mapped at: "); address base = (address)MetaspaceObj::aot_metaspace_base(); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/aotMetaspace.hpp similarity index 97% rename from src/hotspot/share/cds/metaspaceShared.hpp rename to src/hotspot/share/cds/aotMetaspace.hpp index 7f0f1128f96..6c0ad37dbf7 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_CDS_METASPACESHARED_HPP -#define SHARE_CDS_METASPACESHARED_HPP +#ifndef SHARE_CDS_AOTMETASPACE_HPP +#define SHARE_CDS_AOTMETASPACE_HPP #include "memory/allocation.hpp" #include "memory/memRegion.hpp" @@ -49,7 +49,7 @@ enum MapArchiveResult { }; // Class Data Sharing Support -class MetaspaceShared : AllStatic { +class AOTMetaspace : AllStatic { static ReservedSpace _symbol_rs; // used only during -Xshare:dump static VirtualSpace _symbol_vs; // used only during -Xshare:dump static bool _archive_loading_failed; @@ -63,8 +63,8 @@ class MetaspaceShared : AllStatic { public: enum { // core archive spaces - rw = 0, // read-write shared space - ro = 1, // read-only shared space + rw = 0, // read-write + ro = 1, // read-only bm = 2, // relocation bitmaps (freed after file mapping is finished) hp = 3, // heap region ac = 4, // aot code @@ -202,4 +202,4 @@ private: static void unmap_archive(FileMapInfo* mapinfo); static void get_default_classlist(char* default_classlist, const size_t buf_size); }; -#endif // SHARE_CDS_METASPACESHARED_HPP +#endif // SHARE_CDS_AOTMETASPACE_HPP diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.cpp b/src/hotspot/share/cds/aotReferenceObjSupport.cpp index b43c766b8db..e1598035d15 100644 --- a/src/hotspot/share/cds/aotReferenceObjSupport.cpp +++ b/src/hotspot/share/cds/aotReferenceObjSupport.cpp @@ -209,7 +209,7 @@ bool AOTReferenceObjSupport::check_if_ref_obj(oop obj) { log_error(aot, heap)("%s", (referent == nullptr) ? "referent cannot be null" : "referent is not registered with CDS.keepAlive()"); HeapShared::debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (log_is_enabled(Info, aot, ref)) { diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 00aca188f96..7a6c91e503e 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -27,6 +27,7 @@ #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotLogging.hpp" #include "cds/aotMapLogger.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" @@ -35,7 +36,6 @@ #include "cds/dumpAllocStats.hpp" #include "cds/dynamicArchive.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataShared.hpp" @@ -330,12 +330,12 @@ address ArchiveBuilder::reserve_buffer() { // AOTCodeCache::max_aot_code_size() accounts for aot code region. size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M) + AOTCodeCache::max_aot_code_size(); ReservedSpace rs = MemoryReserver::reserve(buffer_size, - MetaspaceShared::core_region_alignment(), + AOTMetaspace::core_region_alignment(), os::vm_page_size(), mtNone); if (!rs.is_reserved()) { aot_log_error(aot)("Failed to reserve %zu bytes of output buffer.", buffer_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when @@ -357,7 +357,7 @@ address ArchiveBuilder::reserve_buffer() { ArchivePtrMarker::initialize(&_ptrmap, &_shared_vs); // The bottom of the static archive should be mapped at this address by default. - _requested_static_archive_bottom = (address)MetaspaceShared::requested_base_address(); + _requested_static_archive_bottom = (address)AOTMetaspace::requested_base_address(); // The bottom of the archive (that I am writing now) should be mapped at this address by default. address my_archive_requested_bottom; @@ -372,7 +372,7 @@ address ArchiveBuilder::reserve_buffer() { // At run time, we will mmap the dynamic archive at my_archive_requested_bottom _requested_static_archive_top = _requested_static_archive_bottom + static_archive_size; - my_archive_requested_bottom = align_up(_requested_static_archive_top, MetaspaceShared::core_region_alignment()); + my_archive_requested_bottom = align_up(_requested_static_archive_top, AOTMetaspace::core_region_alignment()); _requested_dynamic_archive_bottom = my_archive_requested_bottom; } @@ -387,13 +387,13 @@ address ArchiveBuilder::reserve_buffer() { aot_log_error(aot)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top)); aot_log_error(aot)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " "Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom)); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (CDSConfig::is_dumping_static_archive()) { // We don't want any valid object to be at the very bottom of the archive. // See ArchivePtrMarker::mark_pointer(). - _pz_region.allocate(MetaspaceShared::protection_zone_size()); + _pz_region.allocate(AOTMetaspace::protection_zone_size()); start_dump_region(&_rw_region); } @@ -540,7 +540,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { return SystemDictionaryShared::is_excluded_class(ik); } else if (klass->is_objArray_klass()) { Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache_static_region(bottom)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache_static_region(bottom)) { // The bottom class is in the static archive so it's clearly not excluded. return false; } else if (bottom->is_instance_klass()) { @@ -553,7 +553,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { address obj = ref->obj(); - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(obj)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(obj)) { // Don't dump existing shared metadata again. return point_to_it; } else if (ref->msotype() == MetaspaceObj::MethodDataType || @@ -956,7 +956,7 @@ void ArchiveBuilder::make_klasses_shareable() { } } - MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); + AOTMetaspace::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); ik->remove_unshareable_info(); } @@ -1188,12 +1188,12 @@ void ArchiveBuilder::print_stats() { void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info) { // Make sure NUM_CDS_REGIONS (exported in cds.h) agrees with - // MetaspaceShared::n_regions (internal to hotspot). - assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity"); + // AOTMetaspace::n_regions (internal to hotspot). + assert(NUM_CDS_REGIONS == AOTMetaspace::n_regions, "sanity"); - write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); - write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); - write_region(mapinfo, MetaspaceShared::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); + write_region(mapinfo, AOTMetaspace::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false); // Split pointer map into read-write and read-only bitmaps ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap); @@ -1208,7 +1208,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i print_region_stats(mapinfo, heap_info); - mapinfo->set_requested_base((char*)MetaspaceShared::requested_base_address()); + mapinfo->set_requested_base((char*)AOTMetaspace::requested_base_address()); mapinfo->set_header_crc(mapinfo->compute_header_crc()); // After this point, we should not write any data into mapinfo->header() since this // would corrupt its checksum we have calculated before. @@ -1239,8 +1239,8 @@ void ArchiveBuilder::count_relocated_pointer(bool tagged, bool nulled) { void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* heap_info) { // Print statistics of all the regions - const size_t bitmap_used = mapinfo->region_at(MetaspaceShared::bm)->used(); - const size_t bitmap_reserved = mapinfo->region_at(MetaspaceShared::bm)->used_aligned(); + const size_t bitmap_used = mapinfo->region_at(AOTMetaspace::bm)->used(); + const size_t bitmap_reserved = mapinfo->region_at(AOTMetaspace::bm)->used_aligned(); const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() + bitmap_reserved + _total_heap_region_size; @@ -1284,5 +1284,5 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes) _ro_region.print_out_of_space_msg(name, needed_bytes); log_error(aot)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 673c4baa6f6..6efc8f6fe1e 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -22,10 +22,10 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/systemDictionaryShared.hpp" #include "gc/shared/collectedHeap.hpp" @@ -261,7 +261,7 @@ class ArchiveHeapLoader::PatchLoadedRegionPointers: public BitMapClosure { bool ArchiveHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_region, MemRegion& archive_space) { size_t total_bytes = 0; - FileMapRegion* r = mapinfo->region_at(MetaspaceShared::hp); + FileMapRegion* r = mapinfo->region_at(AOTMetaspace::hp); r->assert_is_heap_region(); if (r->used() == 0) { return false; @@ -269,7 +269,7 @@ bool ArchiveHeapLoader::init_loaded_region(FileMapInfo* mapinfo, LoadedArchiveHe assert(is_aligned(r->used(), HeapWordSize), "must be"); total_bytes += r->used(); - loaded_region->_region_index = MetaspaceShared::hp; + loaded_region->_region_index = AOTMetaspace::hp; loaded_region->_region_size = r->used(); loaded_region->_dumptime_base = (uintptr_t)mapinfo->heap_region_dumptime_address(); @@ -447,20 +447,20 @@ class PatchNativePointers: public BitMapClosure { bool do_bit(size_t offset) { Metadata** p = _start + offset; - *p = (Metadata*)(address(*p) + MetaspaceShared::relocation_delta()); + *p = (Metadata*)(address(*p) + AOTMetaspace::relocation_delta()); return true; } }; void ArchiveHeapLoader::patch_native_pointers() { - if (MetaspaceShared::relocation_delta() == 0) { + if (AOTMetaspace::relocation_delta() == 0) { return; } - FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::hp); + FileMapRegion* r = FileMapInfo::current_info()->region_at(AOTMetaspace::hp); if (r->mapped_base() != nullptr && r->has_ptrmap()) { log_info(aot, heap)("Patching native pointers in heap region"); - BitMapView bm = FileMapInfo::current_info()->ptrmap_view(MetaspaceShared::hp); + BitMapView bm = FileMapInfo::current_info()->ptrmap_view(AOTMetaspace::hp); PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos()); bm.iterate(&patcher); } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 3c900cad035..82d4379f631 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveUtils.hpp" @@ -33,7 +34,6 @@ #include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" #include "interpreter/bootstrapInfo.hpp" @@ -117,7 +117,7 @@ void ArchivePtrMarker::mark_pointer(address* ptr_loc) { if (ptr_base() <= ptr_loc && ptr_loc < ptr_end()) { address value = *ptr_loc; // We don't want any pointer that points to very bottom of the archive, otherwise when - // MetaspaceShared::default_base_address()==0, we can't distinguish between a pointer + // AOTMetaspace::default_base_address()==0, we can't distinguish between a pointer // to nothing (null) vs a pointer to an objects that happens to be at the very bottom // of the archive. assert(value != (address)ptr_base(), "don't point to the bottom of the archive"); @@ -209,7 +209,7 @@ char* DumpRegion::expand_top_to(char* newtop) { // happens only if you allocate more than 2GB of shared objects and would require // millions of shared classes. aot_log_error(aot)("Out of memory in the CDS archive: Please reduce the number of shared classes."); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } @@ -236,11 +236,11 @@ void DumpRegion::commit_to(char* newtop) { if (!_vs->expand_by(commit, false)) { aot_log_error(aot)("Failed to expand shared space to %zu bytes", need_committed_size); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } const char* which; - if (_rs->base() == (char*)MetaspaceShared::symbol_rs_base()) { + if (_rs->base() == (char*)AOTMetaspace::symbol_rs_base()) { which = "symbol"; } else { which = "shared"; @@ -298,10 +298,10 @@ void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) { void DumpRegion::pack(DumpRegion* next) { if (!is_packed()) { - _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); + _end = (char*)align_up(_top, AOTMetaspace::core_region_alignment()); _is_packed = true; } - _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); + _end = (char*)align_up(_top, AOTMetaspace::core_region_alignment()); _is_packed = true; if (next != nullptr) { next->_rs = _rs; diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 70b91fb8900..6f635d01745 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -28,9 +28,9 @@ #include "cds/archiveUtils.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "oops/array.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/growableArray.hpp" @@ -80,7 +80,7 @@ Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { for (int i = 0; i < tmp_array->length(); i++) { T ptr = tmp_array->at(i); if (ptr != nullptr && !builder->is_in_buffer_space(ptr)) { - if (is_dynamic_dump && MetaspaceShared::in_aot_cache(ptr)) { + if (is_dynamic_dump && AOTMetaspace::in_aot_cache(ptr)) { // We have a pointer that lives in the dynamic archive but points into // the static archive. } else { diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 6922b66d7cd..90b802731f0 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -767,7 +767,7 @@ void CDSConfig::prepare_for_dumping() { #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." if (RecordDynamicDumpInfo) { aot_log_error(aot)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } else { assert(ArchiveClassesAtExit != nullptr, "sanity"); aot_log_warning(aot)("-XX:ArchiveClassesAtExit" __THEMSG); diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index 0da9e3f2c8d..a9f46c21ad3 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -157,7 +157,7 @@ CDSHeapVerifier::~CDSHeapVerifier() { "an object points to a static field that " "may hold a different value at runtime.", _archived_objs, _problems); log_error(aot, heap)("Please see cdsHeapVerifier.cpp and aotClassInitializer.cpp for details"); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index c95fd8b64df..ff15fdccabe 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -118,7 +118,7 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) { PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) { PackageEntry* pkg_entry = ik->package(); if (CDSConfig::is_using_full_module_graph() && ik->in_aot_cache() && pkg_entry != nullptr) { - assert(MetaspaceShared::in_aot_cache(pkg_entry), "must be"); + assert(AOTMetaspace::in_aot_cache(pkg_entry), "must be"); assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); return pkg_entry; } diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 75737b1432e..2405d0dc2ff 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -24,11 +24,11 @@ #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" #include "cds/classListParser.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/unregisteredClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.inline.hpp" @@ -185,7 +185,7 @@ void ClassListParser::parse_class_name_and_attributes(TRAPS) { // cpcache to be created. The linking is done as soon as classes // are loaded in order that the related data structures (klass and // cpCache) are located together. - MetaspaceShared::try_link_class(THREAD, ik); + AOTMetaspace::try_link_class(THREAD, ik); } } @@ -674,7 +674,7 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, true, CHECK); if (klass->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(klass); - MetaspaceShared::try_link_class(THREAD, ik); + AOTMetaspace::try_link_class(THREAD, ik); if (!ik->is_linked()) { // Verification of ik has failed return; diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 261f5332526..f2862454286 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -22,11 +22,11 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" #include "cds/cppVtables.hpp" -#include "cds/metaspaceShared.hpp" #include "logging/log.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -321,7 +321,7 @@ void CppVtables::zero_archived_vtables() { } bool CppVtables::is_valid_shared_method(const Method* m) { - assert(MetaspaceShared::in_aot_cache(m), "must be"); + assert(AOTMetaspace::in_aot_cache(m), "must be"); return vtable_of(m) == _index[Method_Kind]->cloned_vtable() || vtable_of(m) == _archived_cpp_vtptrs[Method_Kind]; } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 0feed8682da..0bc0f8bedda 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_CDS_DUMPTIMECLASSINFO_HPP #define SHARE_CDS_DUMPTIMECLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "memory/metaspaceClosure.hpp" #include "oops/instanceKlass.hpp" @@ -231,7 +231,7 @@ template inline unsigned DumpTimeSharedClassTable_hash(T* const& k) { if (CDSConfig::is_dumping_static_archive()) { // Deterministic archive contents - uintx delta = k->name() - MetaspaceShared::symbol_rs_base(); + uintx delta = k->name() - AOTMetaspace::symbol_rs_base(); return primitive_hash(delta); } else { // Deterministic archive is not possible because classes can be loaded diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 8499dced126..d628a4e991f 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassLinker.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.inline.hpp" @@ -34,7 +35,6 @@ #include "cds/dynamicArchive.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -187,7 +187,7 @@ public: for (int i = T_BOOLEAN; i <= T_LONG; i++) { assert(is_java_primitive((BasicType)i), "sanity"); Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc - assert(MetaspaceShared::in_aot_cache_static_region((void*)k), + assert(AOTMetaspace::in_aot_cache_static_region((void*)k), "one-dimensional primitive array should be in static archive"); ArrayKlass* ak = ArrayKlass::cast(k); while (ak != nullptr && ak->in_aot_cache()) { @@ -216,7 +216,7 @@ void DynamicArchiveBuilder::init_header() { _header = mapinfo->dynamic_header(); _header->set_base_header_crc(base_info->crc()); - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { _header->set_base_region_crc(i, base_info->region_crc(i)); } } @@ -253,7 +253,7 @@ void DynamicArchiveBuilder::sort_methods() { // klasses were created. Re-sort all the tables. See Method::sort_methods(). void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { assert(ik != nullptr, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); - if (MetaspaceShared::in_aot_cache(ik)) { + if (AOTMetaspace::in_aot_cache(ik)) { // We have reached a supertype that's already in the base archive return; } @@ -287,13 +287,13 @@ void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { if (ik->methods() != nullptr) { for (int m = 0; m < ik->methods()->length(); m++) { Symbol* name = ik->methods()->at(m)->name(); - assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); + assert(AOTMetaspace::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } if (ik->default_methods() != nullptr) { for (int m = 0; m < ik->default_methods()->length(); m++) { Symbol* name = ik->default_methods()->at(m)->name(); - assert(MetaspaceShared::in_aot_cache(name) || is_in_buffer_space(name), "must be"); + assert(AOTMetaspace::in_aot_cache(name) || is_in_buffer_space(name), "must be"); } } #endif @@ -367,14 +367,14 @@ void DynamicArchiveBuilder::gather_array_klasses() { if (klasses()->at(i)->is_objArray_klass()) { ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i)); Klass* elem = oak->element_klass(); - if (MetaspaceShared::in_aot_cache_static_region(elem)) { + if (AOTMetaspace::in_aot_cache_static_region(elem)) { // Only capture the array klass whose element_klass is in the static archive. // During run time, setup (see DynamicArchive::setup_array_klasses()) is needed // so that the element_klass can find its array klasses from the dynamic archive. DynamicArchive::append_array_klass(oak); } else { // The element_klass and its array klasses are in the same archive. - assert(!MetaspaceShared::in_aot_cache_static_region(oak), + assert(!AOTMetaspace::in_aot_cache_static_region(oak), "we should not gather klasses that are already in the static archive"); } } @@ -435,7 +435,7 @@ void DynamicArchive::setup_array_klasses() { assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive"); Klass* elm = oak->element_klass(); - assert(MetaspaceShared::in_aot_cache_static_region((void*)elm), "must be"); + assert(AOTMetaspace::in_aot_cache_static_region((void*)elm), "must be"); if (elm->is_instance_klass()) { assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be"); @@ -476,7 +476,7 @@ int DynamicArchive::num_array_klasses() { } void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAPS) { - MetaspaceShared::link_shared_classes(CHECK); + AOTMetaspace::link_shared_classes(CHECK); if (!jcmd_request && CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { LambdaFormInvokers::regenerate_holder_classes(CHECK); } @@ -532,7 +532,7 @@ bool DynamicArchive::validate(FileMapInfo* dynamic_info) { } // Check each space's crc - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { if (dynamic_header->base_region_crc(i) != base_info->region_crc(i)) { aot_log_warning(aot)("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); return false; diff --git a/src/hotspot/share/cds/dynamicArchive.hpp b/src/hotspot/share/cds/dynamicArchive.hpp index 8c23750734c..19086053d76 100644 --- a/src/hotspot/share/cds/dynamicArchive.hpp +++ b/src/hotspot/share/cds/dynamicArchive.hpp @@ -41,7 +41,7 @@ class DynamicArchiveHeader : public FileMapHeader { friend class CDSConstants; private: int _base_header_crc; - int _base_region_crc[MetaspaceShared::n_regions]; + int _base_region_crc[AOTMetaspace::n_regions]; public: int base_header_crc() const { return _base_header_crc; } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 78f02161477..409052eae6a 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -24,6 +24,7 @@ #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveHeapWriter.hpp" @@ -33,7 +34,6 @@ #include "cds/dynamicArchive.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" @@ -329,7 +329,7 @@ bool FileMapInfo::validate_class_location() { bool has_extra_module_paths = false; if (!config->validate(full_path(), header()->has_aot_linked_classes(), &has_extra_module_paths)) { if (PrintSharedArchiveAndExit) { - MetaspaceShared::set_archive_loading_failed(); + AOTMetaspace::set_archive_loading_failed(); return true; } else { return false; @@ -338,7 +338,7 @@ bool FileMapInfo::validate_class_location() { if (header()->has_full_module_graph() && has_extra_module_paths) { CDSConfig::stop_using_optimized_module_handling(); - MetaspaceShared::report_loading_error("optimized module handling: disabled because extra module path(s) are specified"); + AOTMetaspace::report_loading_error("optimized module handling: disabled because extra module path(s) are specified"); } if (CDSConfig::is_dumping_dynamic_archive()) { @@ -409,7 +409,7 @@ public: assert(_archive_name != nullptr, "Archive name is null"); _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { - MetaspaceShared::report_loading_error("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); + AOTMetaspace::report_loading_error("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); return false; } return initialize(_fd); @@ -694,7 +694,7 @@ bool FileMapInfo::init_from_file(int fd) { size_t len = os::lseek(fd, 0, SEEK_END); - for (int i = 0; i < MetaspaceShared::n_regions; i++) { + for (int i = 0; i < AOTMetaspace::n_regions; i++) { FileMapRegion* r = region_at(i); if (r->file_offset() > len || len - r->file_offset() < r->used()) { aot_log_warning(aot)("The %s has been truncated.", file_type); @@ -708,7 +708,7 @@ bool FileMapInfo::init_from_file(int fd) { void FileMapInfo::seek_to_position(size_t pos) { if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { aot_log_error(aot)("Unable to seek to position %zu", pos); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } } @@ -763,7 +763,7 @@ void FileMapInfo::open_as_output() { if (fd < 0) { aot_log_error(aot)("Unable to create %s %s: (%s).", CDSConfig::type_of_archive_being_written(), _full_path, os::strerror(errno)); - MetaspaceShared::writing_error(); + AOTMetaspace::writing_error(); return; } _fd = fd; @@ -773,7 +773,7 @@ void FileMapInfo::open_as_output() { // and their CRCs computed. size_t header_bytes = header()->header_size(); - header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment()); + header_bytes = align_up(header_bytes, AOTMetaspace::core_region_alignment()); _file_offset = header_bytes; seek_to_position(_file_offset); } @@ -788,13 +788,13 @@ void FileMapInfo::write_header() { } size_t FileMapRegion::used_aligned() const { - return align_up(used(), MetaspaceShared::core_region_alignment()); + return align_up(used(), AOTMetaspace::core_region_alignment()); } void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, bool read_only, bool allow_exec, int crc) { _is_heap_region = HeapShared::is_heap_region(region_index); - _is_bitmap_region = (region_index == MetaspaceShared::bm); + _is_bitmap_region = (region_index == AOTMetaspace::bm); _mapping_offset = mapping_offset; _used = size; _read_only = read_only; @@ -890,7 +890,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size, char* requested_base; size_t mapping_offset = 0; - if (region == MetaspaceShared::bm) { + if (region == AOTMetaspace::bm) { requested_base = nullptr; // always null for bm region } else if (size == 0) { // This is an unused region (e.g., a heap region when !INCLUDE_CDS_JAVA_HEAP) @@ -908,7 +908,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size, } #endif // INCLUDE_CDS_JAVA_HEAP } else { - char* requested_SharedBaseAddress = (char*)MetaspaceShared::requested_base_address(); + char* requested_SharedBaseAddress = (char*)AOTMetaspace::requested_base_address(); requested_base = ArchiveBuilder::current()->to_requested(base); assert(requested_base >= requested_SharedBaseAddress, "must be"); mapping_offset = requested_base - requested_SharedBaseAddress; @@ -984,14 +984,14 @@ char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_p char* buffer = NEW_C_HEAP_ARRAY(char, size_in_bytes, mtClassShared); size_t written = 0; - region_at(MetaspaceShared::rw)->init_ptrmap(0, rw_ptrmap->size()); + region_at(AOTMetaspace::rw)->init_ptrmap(0, rw_ptrmap->size()); written = write_bitmap(rw_ptrmap, buffer, written); - region_at(MetaspaceShared::ro)->init_ptrmap(written, ro_ptrmap->size()); + region_at(AOTMetaspace::ro)->init_ptrmap(written, ro_ptrmap->size()); written = write_bitmap(ro_ptrmap, buffer, written); if (heap_info->is_used()) { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); r->init_oopmap(written, heap_info->oopmap()->size()); written = write_bitmap(heap_info->oopmap(), buffer, written); @@ -1000,14 +1000,14 @@ char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_p written = write_bitmap(heap_info->ptrmap(), buffer, written); } - write_region(MetaspaceShared::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false); + write_region(AOTMetaspace::bm, (char*)buffer, size_in_bytes, /*read_only=*/true, /*allow_exec=*/false); return buffer; } size_t FileMapInfo::write_heap_region(ArchiveHeapInfo* heap_info) { char* buffer_start = heap_info->buffer_start(); size_t buffer_size = heap_info->buffer_byte_size(); - write_region(MetaspaceShared::hp, buffer_start, buffer_size, false, false); + write_region(AOTMetaspace::hp, buffer_start, buffer_size, false, false); header()->set_heap_root_segments(heap_info->heap_root_segments()); return buffer_size; } @@ -1022,11 +1022,11 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { remove(_full_path); if (CDSConfig::is_dumping_preimage_static_archive()) { - MetaspaceShared::writing_error("Unable to write to AOT configuration file."); + AOTMetaspace::writing_error("Unable to write to AOT configuration file."); } else if (CDSConfig::new_aot_flags_used()) { - MetaspaceShared::writing_error("Unable to write to AOT cache."); + AOTMetaspace::writing_error("Unable to write to AOT cache."); } else { - MetaspaceShared::writing_error("Unable to write to shared archive."); + AOTMetaspace::writing_error("Unable to write to shared archive."); } } _file_offset += nbytes; @@ -1034,7 +1034,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { bool FileMapInfo::is_file_position_aligned() const { return _file_offset == align_up(_file_offset, - MetaspaceShared::core_region_alignment()); + AOTMetaspace::core_region_alignment()); } // Align file position to an allocation unit boundary. @@ -1042,7 +1042,7 @@ bool FileMapInfo::is_file_position_aligned() const { void FileMapInfo::align_file_position() { assert(_file_open, "must be"); size_t new_file_offset = align_up(_file_offset, - MetaspaceShared::core_region_alignment()); + AOTMetaspace::core_region_alignment()); if (new_file_offset != _file_offset) { _file_offset = new_file_offset; // Seek one byte back from the target and write a byte to insure @@ -1068,7 +1068,7 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, size_t nbytes) { void FileMapInfo::close() { if (_file_open) { if (::close(_fd) < 0) { - MetaspaceShared::unrecoverable_loading_error("Unable to close the shared archive file."); + AOTMetaspace::unrecoverable_loading_error("Unable to close the shared archive file."); } _file_open = false; _fd = -1; @@ -1093,7 +1093,7 @@ static char* map_memory(int fd, const char* file_name, size_t file_offset, // JVM/TI RedefineClasses() support: // Remap the shared readonly space to shared readwrite, private. bool FileMapInfo::remap_shared_readonly_as_readwrite() { - int idx = MetaspaceShared::ro; + int idx = AOTMetaspace::ro; FileMapRegion* r = region_at(idx); if (!r->read_only()) { // the space is already readwrite so we are done @@ -1200,7 +1200,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba r->set_mapped_from_file(false); r->set_in_reserved_space(false); - if (MetaspaceShared::use_windows_memory_mapping()) { + if (AOTMetaspace::use_windows_memory_mapping()) { // Windows cannot remap read-only shared memory to read-write when required for // RedefineClasses, which is also used by JFR. Always map windows regions as RW. r->set_read_only(false); @@ -1212,13 +1212,13 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba r->set_read_only(false); // Need to patch the pointers } - if (MetaspaceShared::use_windows_memory_mapping() && rs.is_reserved()) { + if (AOTMetaspace::use_windows_memory_mapping() && rs.is_reserved()) { // This is the second time we try to map the archive(s). We have already created a ReservedSpace // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows // can't mmap into a ReservedSpace, so we just ::read() the data. We're going to patch all the // regions anyway, so there's no benefit for mmap anyway. if (!read_region(i, requested_addr, size, /* do_commit = */ true)) { - MetaspaceShared::report_loading_error("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, + AOTMetaspace::report_loading_error("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error. } else { @@ -1227,12 +1227,12 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba } else { // Note that this may either be a "fresh" mapping into unreserved address // space (Windows, first mapping attempt), or a mapping into pre-reserved - // space (Posix). See also comment in MetaspaceShared::map_archives(). + // space (Posix). See also comment in AOTMetaspace::map_archives(). char* base = map_memory(_fd, _full_path, r->file_offset(), requested_addr, size, r->read_only(), r->allow_exec(), mtClassShared); if (base != requested_addr) { - MetaspaceShared::report_loading_error("Unable to map %s shared space at " INTPTR_FORMAT, + AOTMetaspace::report_loading_error("Unable to map %s shared space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); _memory_mapping_failed = true; return MAP_ARCHIVE_MMAP_FAILURE; @@ -1258,7 +1258,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba // The return value is the location of the archive relocation bitmap. char* FileMapInfo::map_bitmap_region() { - FileMapRegion* r = region_at(MetaspaceShared::bm); + FileMapRegion* r = region_at(AOTMetaspace::bm); if (r->mapped_base() != nullptr) { return r->mapped_base(); } @@ -1267,7 +1267,7 @@ char* FileMapInfo::map_bitmap_region() { char* bitmap_base = map_memory(_fd, _full_path, r->file_offset(), requested_addr, r->used_aligned(), read_only, allow_exec, mtClassShared); if (bitmap_base == nullptr) { - MetaspaceShared::report_loading_error("failed to map relocation bitmap"); + AOTMetaspace::report_loading_error("failed to map relocation bitmap"); return nullptr; } @@ -1283,22 +1283,22 @@ char* FileMapInfo::map_bitmap_region() { r->set_mapped_base(bitmap_base); aot_log_info(aot)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", is_static() ? "static " : "dynamic", - MetaspaceShared::bm, p2i(r->mapped_base()), p2i(r->mapped_end()), - shared_region_name[MetaspaceShared::bm]); + AOTMetaspace::bm, p2i(r->mapped_base()), p2i(r->mapped_end()), + shared_region_name[AOTMetaspace::bm]); return bitmap_base; } bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { - FileMapRegion* r = region_at(MetaspaceShared::ac); + FileMapRegion* r = region_at(AOTMetaspace::ac); assert(r->used() > 0 && r->used_aligned() == rs.size(), "must be"); char* requested_base = rs.base(); assert(requested_base != nullptr, "should be inside code cache"); char* mapped_base; - if (MetaspaceShared::use_windows_memory_mapping()) { - if (!read_region(MetaspaceShared::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) { - MetaspaceShared::report_loading_error("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT, + if (AOTMetaspace::use_windows_memory_mapping()) { + if (!read_region(AOTMetaspace::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) { + AOTMetaspace::report_loading_error("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT, p2i(requested_base)); return false; } @@ -1311,15 +1311,15 @@ bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { requested_base, r->used_aligned(), read_only, allow_exec, mtClassShared); } if (mapped_base == nullptr) { - MetaspaceShared::report_loading_error("failed to map aot code region"); + AOTMetaspace::report_loading_error("failed to map aot code region"); return false; } else { assert(mapped_base == requested_base, "must be"); r->set_mapped_from_file(true); r->set_mapped_base(mapped_base); aot_log_info(aot)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", - MetaspaceShared::ac, p2i(r->mapped_base()), p2i(r->mapped_end()), - shared_region_name[MetaspaceShared::ac]); + AOTMetaspace::ac, p2i(r->mapped_base()), p2i(r->mapped_end()), + shared_region_name[AOTMetaspace::ac]); return true; } } @@ -1359,8 +1359,8 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { if (bitmap_base == nullptr) { return false; // OOM, or CRC check failure } else { - BitMapView rw_ptrmap = ptrmap_view(MetaspaceShared::rw); - BitMapView ro_ptrmap = ptrmap_view(MetaspaceShared::ro); + BitMapView rw_ptrmap = ptrmap_view(AOTMetaspace::rw); + BitMapView ro_ptrmap = ptrmap_view(AOTMetaspace::ro); FileMapRegion* rw_region = first_core_region(); FileMapRegion* ro_region = last_core_region(); @@ -1398,7 +1398,7 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { ro_ptrmap.iterate(&ro_patcher); } - // The MetaspaceShared::bm region will be unmapped in MetaspaceShared::initialize_shared_spaces(). + // The AOTMetaspace::bm region will be unmapped in AOTMetaspace::initialize_shared_spaces(). aot_log_debug(aot, reloc)("runtime archive relocation done"); return true; @@ -1421,11 +1421,11 @@ size_t FileMapInfo::read_bytes(void* buffer, size_t count) { size_t FileMapInfo::readonly_total() { size_t total = 0; if (current_info() != nullptr) { - FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::ro); + FileMapRegion* r = FileMapInfo::current_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } if (dynamic_info() != nullptr) { - FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(MetaspaceShared::ro); + FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } return total; @@ -1435,7 +1435,7 @@ size_t FileMapInfo::readonly_total() { MemRegion FileMapInfo::_mapped_heap_memregion; bool FileMapInfo::has_heap_region() { - return (region_at(MetaspaceShared::hp)->used() > 0); + return (region_at(AOTMetaspace::hp)->used() > 0); } // Returns the address range of the archived heap region computed using the @@ -1443,7 +1443,7 @@ bool FileMapInfo::has_heap_region() { // dump time due to encoding mode differences. The result is used in determining // if/how these regions should be relocated at run time. MemRegion FileMapInfo::get_heap_region_requested_range() { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); size_t size = r->used(); assert(size > 0, "must have non-empty heap region"); @@ -1465,9 +1465,9 @@ void FileMapInfo::map_or_load_heap_region() { success = ArchiveHeapLoader::load_heap_region(this); } else { if (!UseCompressedOops && !ArchiveHeapLoader::can_map()) { - MetaspaceShared::report_loading_error("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); + AOTMetaspace::report_loading_error("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); } else { - MetaspaceShared::report_loading_error("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); + AOTMetaspace::report_loading_error("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } } } @@ -1482,7 +1482,7 @@ void FileMapInfo::map_or_load_heap_region() { aot_log_error(aot)("%s has aot-linked classes but the archived " "heap objects cannot be loaded. Try increasing your heap size.", CDSConfig::type_of_archive_being_loaded()); - MetaspaceShared::unrecoverable_loading_error(); + AOTMetaspace::unrecoverable_loading_error(); } CDSConfig::stop_using_full_module_graph("archive heap loading failed"); } @@ -1575,7 +1575,7 @@ bool FileMapInfo::can_use_heap_region() { // The actual address of this region during dump time. address FileMapInfo::heap_region_dumptime_address() { - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); assert(CDSConfig::is_using_archive(), "runtime only"); assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be"); if (UseCompressedOops) { @@ -1589,7 +1589,7 @@ address FileMapInfo::heap_region_dumptime_address() { // patching any of the pointers that are embedded in this region. address FileMapInfo::heap_region_requested_address() { assert(CDSConfig::is_using_archive(), "runtime only"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); assert(is_aligned(r->mapping_offset(), sizeof(HeapWord)), "must be"); assert(ArchiveHeapLoader::can_use(), "GC must support mapping or loading"); if (UseCompressedOops) { @@ -1643,7 +1643,7 @@ bool FileMapInfo::map_heap_region() { bool FileMapInfo::map_heap_region_impl() { assert(UseG1GC, "the following code assumes G1"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); size_t size = r->used(); if (size == 0) { return false; // no archived java heap data @@ -1657,7 +1657,7 @@ bool FileMapInfo::map_heap_region_impl() { // allocate from java heap HeapWord* start = G1CollectedHeap::heap()->alloc_archive_region(word_size, (HeapWord*)requested_start); if (start == nullptr) { - MetaspaceShared::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); + AOTMetaspace::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); return false; } @@ -1668,11 +1668,11 @@ bool FileMapInfo::map_heap_region_impl() { char* addr = (char*)_mapped_heap_memregion.start(); char* base; - if (MetaspaceShared::use_windows_memory_mapping() || UseLargePages) { + if (AOTMetaspace::use_windows_memory_mapping() || UseLargePages) { // With UseLargePages, memory mapping may fail on some OSes if the size is not // large page aligned, so let's use read() instead. In this case, the memory region // is already commited by G1 so we don't need to commit it again. - if (!read_region(MetaspaceShared::hp, addr, + if (!read_region(AOTMetaspace::hp, addr, align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()), /* do_commit = */ !UseLargePages)) { dealloc_heap_region(); @@ -1687,7 +1687,7 @@ bool FileMapInfo::map_heap_region_impl() { r->allow_exec(), mtJavaHeap); if (base == nullptr || base != addr) { dealloc_heap_region(); - MetaspaceShared::report_loading_error("UseSharedSpaces: Unable to map at required address in java heap. " + AOTMetaspace::report_loading_error("UseSharedSpaces: Unable to map at required address in java heap. " INTPTR_FORMAT ", size = %zu bytes", p2i(addr), _mapped_heap_memregion.byte_size()); return false; @@ -1695,7 +1695,7 @@ bool FileMapInfo::map_heap_region_impl() { if (VerifySharedSpaces && !r->check_region_crc(base)) { dealloc_heap_region(); - MetaspaceShared::report_loading_error("UseSharedSpaces: mapped heap region is corrupt"); + AOTMetaspace::report_loading_error("UseSharedSpaces: mapped heap region is corrupt"); return false; } } @@ -1719,7 +1719,7 @@ bool FileMapInfo::map_heap_region_impl() { if (_heap_pointers_need_patching) { char* bitmap_base = map_bitmap_region(); if (bitmap_base == nullptr) { - MetaspaceShared::report_loading_error("CDS heap cannot be used because bitmap region cannot be mapped"); + AOTMetaspace::report_loading_error("CDS heap cannot be used because bitmap region cannot be mapped"); dealloc_heap_region(); _heap_pointers_need_patching = false; return false; @@ -1734,7 +1734,7 @@ bool FileMapInfo::map_heap_region_impl() { narrowOop FileMapInfo::encoded_heap_region_dumptime_address() { assert(CDSConfig::is_using_archive(), "runtime only"); assert(UseCompressedOops, "sanity"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); return CompressedOops::narrow_oop_cast(r->mapping_offset() >> narrow_oop_shift()); } @@ -1746,10 +1746,10 @@ void FileMapInfo::patch_heap_embedded_pointers() { char* bitmap_base = map_bitmap_region(); assert(bitmap_base != nullptr, "must have already been mapped"); - FileMapRegion* r = region_at(MetaspaceShared::hp); + FileMapRegion* r = region_at(AOTMetaspace::hp); ArchiveHeapLoader::patch_embedded_pointers( this, _mapped_heap_memregion, - (address)(region_at(MetaspaceShared::bm)->mapped_base()) + r->oopmap_offset(), + (address)(region_at(AOTMetaspace::bm)->mapped_base()) + r->oopmap_offset(), r->oopmap_size_in_bits()); } @@ -1805,7 +1805,7 @@ void FileMapInfo::unmap_region(int i) { void FileMapInfo::assert_mark(bool check) { if (!check) { - MetaspaceShared::unrecoverable_loading_error("Mark mismatch while restoring from shared file."); + AOTMetaspace::unrecoverable_loading_error("Mark mismatch while restoring from shared file."); } } @@ -1832,16 +1832,16 @@ bool FileMapInfo::open_as_input() { // are replaced at runtime by JVMTI ClassFileLoadHook. All of those classes are resolved // during the JVMTI "early" stage, so we can still use CDS if // JvmtiExport::has_early_class_hook_env() is false. - MetaspaceShared::report_loading_error("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); + AOTMetaspace::report_loading_error("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); return false; } if (!open_for_read() || !init_from_file(_fd) || !validate_header()) { if (_is_static) { - MetaspaceShared::report_loading_error("Loading static archive failed."); + AOTMetaspace::report_loading_error("Loading static archive failed."); return false; } else { - MetaspaceShared::report_loading_error("Loading dynamic archive failed."); + AOTMetaspace::report_loading_error("Loading dynamic archive failed."); if (AutoCreateSharedArchive) { CDSConfig::enable_dumping_dynamic_archive(_full_path); } @@ -1894,11 +1894,11 @@ bool FileMapInfo::validate_aot_class_linking() { // The 2 core spaces are RW->RO FileMapRegion* FileMapInfo::first_core_region() const { - return region_at(MetaspaceShared::rw); + return region_at(AOTMetaspace::rw); } FileMapRegion* FileMapInfo::last_core_region() const { - return region_at(MetaspaceShared::ro); + return region_at(AOTMetaspace::ro); } void FileMapInfo::print(outputStream* st) const { @@ -1925,13 +1925,13 @@ int FileMapHeader::compute_crc() { bool FileMapHeader::validate() { const char* file_type = CDSConfig::type_of_archive_being_loaded(); if (_obj_alignment != ObjectAlignmentInBytes) { - MetaspaceShared::report_loading_error("The %s's ObjectAlignmentInBytes of %d" + AOTMetaspace::report_loading_error("The %s's ObjectAlignmentInBytes of %d" " does not equal the current ObjectAlignmentInBytes of %d.", file_type, _obj_alignment, ObjectAlignmentInBytes); return false; } if (_compact_strings != CompactStrings) { - MetaspaceShared::report_loading_error("The %s's CompactStrings setting (%s)" + AOTMetaspace::report_loading_error("The %s's CompactStrings setting (%s)" " does not equal the current CompactStrings setting (%s).", file_type, _compact_strings ? "enabled" : "disabled", CompactStrings ? "enabled" : "disabled"); @@ -1949,46 +1949,46 @@ bool FileMapHeader::validate() { (compiler_type == CompilerType::compiler_none); if (!intepreter_is_used && jvmci_compiler_is_enabled != (archive_compiler_type == CompilerType::compiler_jvmci)) { - MetaspaceShared::report_loading_error("The %s's JIT compiler setting (%s)" + AOTMetaspace::report_loading_error("The %s's JIT compiler setting (%s)" " does not equal the current setting (%s).", file_type, compilertype2name(archive_compiler_type), compilertype2name(compiler_type)); return false; } if (TrainingData::have_data()) { if (_type_profile_level != TypeProfileLevel) { - MetaspaceShared::report_loading_error("The %s's TypeProfileLevel setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileLevel setting (%d)" " does not equal the current TypeProfileLevel setting (%d).", file_type, _type_profile_level, TypeProfileLevel); return false; } if (_type_profile_args_limit != TypeProfileArgsLimit) { - MetaspaceShared::report_loading_error("The %s's TypeProfileArgsLimit setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileArgsLimit setting (%d)" " does not equal the current TypeProfileArgsLimit setting (%d).", file_type, _type_profile_args_limit, TypeProfileArgsLimit); return false; } if (_type_profile_parms_limit != TypeProfileParmsLimit) { - MetaspaceShared::report_loading_error("The %s's TypeProfileParamsLimit setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileParamsLimit setting (%d)" " does not equal the current TypeProfileParamsLimit setting (%d).", file_type, _type_profile_args_limit, TypeProfileArgsLimit); return false; } if (_type_profile_width != TypeProfileWidth) { - MetaspaceShared::report_loading_error("The %s's TypeProfileWidth setting (%d)" + AOTMetaspace::report_loading_error("The %s's TypeProfileWidth setting (%d)" " does not equal the current TypeProfileWidth setting (%d).", file_type, (int)_type_profile_width, (int)TypeProfileWidth); return false; } if (_bci_profile_width != BciProfileWidth) { - MetaspaceShared::report_loading_error("The %s's BciProfileWidth setting (%d)" + AOTMetaspace::report_loading_error("The %s's BciProfileWidth setting (%d)" " does not equal the current BciProfileWidth setting (%d).", file_type, (int)_bci_profile_width, (int)BciProfileWidth); return false; } if (_type_profile_casts != TypeProfileCasts) { - MetaspaceShared::report_loading_error("The %s's TypeProfileCasts setting (%s)" + AOTMetaspace::report_loading_error("The %s's TypeProfileCasts setting (%s)" " does not equal the current TypeProfileCasts setting (%s).", file_type, _type_profile_casts ? "enabled" : "disabled", TypeProfileCasts ? "enabled" : "disabled"); @@ -1997,7 +1997,7 @@ bool FileMapHeader::validate() { } if (_profile_traps != ProfileTraps) { - MetaspaceShared::report_loading_error("The %s's ProfileTraps setting (%s)" + AOTMetaspace::report_loading_error("The %s's ProfileTraps setting (%s)" " does not equal the current ProfileTraps setting (%s).", file_type, _profile_traps ? "enabled" : "disabled", ProfileTraps ? "enabled" : "disabled"); @@ -2005,7 +2005,7 @@ bool FileMapHeader::validate() { return false; } if (_spec_trap_limit_extra_entries != SpecTrapLimitExtraEntries) { - MetaspaceShared::report_loading_error("The %s's SpecTrapLimitExtraEntries setting (%d)" + AOTMetaspace::report_loading_error("The %s's SpecTrapLimitExtraEntries setting (%d)" " does not equal the current SpecTrapLimitExtraEntries setting (%d).", file_type, _spec_trap_limit_extra_entries, SpecTrapLimitExtraEntries); return false; @@ -2018,7 +2018,7 @@ bool FileMapHeader::validate() { const char* prop = Arguments::get_property("java.system.class.loader"); if (prop != nullptr) { if (has_aot_linked_classes()) { - MetaspaceShared::report_loading_error("%s has aot-linked classes. It cannot be used when the " + AOTMetaspace::report_loading_error("%s has aot-linked classes. It cannot be used when the " "java.system.class.loader property is specified.", CDSConfig::type_of_archive_being_loaded()); return false; @@ -2032,7 +2032,7 @@ bool FileMapHeader::validate() { if (!_verify_local && BytecodeVerificationLocal) { // we cannot load boot classes, so there's no point of using the CDS archive - MetaspaceShared::report_loading_error("The %s's BytecodeVerificationLocal setting (%s)" + AOTMetaspace::report_loading_error("The %s's BytecodeVerificationLocal setting (%s)" " does not equal the current BytecodeVerificationLocal setting (%s).", file_type, _verify_local ? "enabled" : "disabled", BytecodeVerificationLocal ? "enabled" : "disabled"); @@ -2056,7 +2056,7 @@ bool FileMapHeader::validate() { // Note: _allow_archiving_with_java_agent is set in the shared archive during dump time // while AllowArchivingWithJavaAgent is set during the current run. if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) { - MetaspaceShared::report_loading_error("The setting of the AllowArchivingWithJavaAgent is different " + AOTMetaspace::report_loading_error("The setting of the AllowArchivingWithJavaAgent is different " "from the setting in the %s.", file_type); return false; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 02390874f39..b40e793a0fd 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_FILEMAP_HPP #define SHARE_CDS_FILEMAP_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" -#include "cds/metaspaceShared.hpp" #include "include/cds.h" #include "logging/logLevel.hpp" #include "memory/allocation.hpp" @@ -71,7 +71,7 @@ public: size_t mapping_offset() const { return _mapping_offset; } size_t mapping_end_offset() const { return _mapping_offset + used_aligned(); } size_t used() const { return _used; } - size_t used_aligned() const; // aligned up to MetaspaceShared::core_region_alignment() + size_t used_aligned() const; // aligned up to AOTMetaspace::core_region_alignment() char* mapped_base() const { return _mapped_base; } char* mapped_end() const { return mapped_base() + used_aligned(); } bool read_only() const { return _read_only != 0; } diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index 8fc01220a6f..2d237edfd2d 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -184,7 +184,7 @@ void FinalImageRecipes::load_all_classes(TRAPS) { log_error(aot)("Unable to resolve class from CDS archive: %s", ik->external_name()); log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); log_error(aot)("Please check if your VM command-line is the same as in the training run"); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } assert(ik->is_loaded(), "must be"); ik->link_class(CHECK); @@ -208,7 +208,7 @@ void FinalImageRecipes::apply_recipes(TRAPS) { log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); log_error(aot)("Please check if your VM command-line is the same as in the training run"); - MetaspaceShared::unrecoverable_writing_error("Unexpected exception, use -Xlog:aot,exceptions=trace for detail"); + AOTMetaspace::unrecoverable_writing_error("Unexpected exception, use -Xlog:aot,exceptions=trace for detail"); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index cfa2944d974..6b7cffdf321 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassInitializer.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" @@ -35,7 +36,6 @@ #include "cds/cdsEnumKlass.hpp" #include "cds/cdsHeapVerifier.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.inline.hpp" @@ -873,7 +873,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) { ResourceMark rm; log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s", ik->external_name(), lambda_msg, testcls_msg); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } bool KlassSubGraphInfo::is_non_early_klass(Klass* k) { @@ -1509,7 +1509,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap ResourceMark rm; log_error(aot, heap)("Cannot archive object " PTR_FORMAT " of class %s", p2i(orig_obj), orig_obj->klass()->external_name()); debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } if (log_is_enabled(Debug, aot, heap) && java_lang_Class::is_instance(orig_obj)) { @@ -1562,7 +1562,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // defined at the top of this file. log_error(aot, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level); debug_trace(); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } @@ -1592,7 +1592,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // We don't know how to handle an object that has been archived, but some of its reachable // objects cannot be archived. Bail out for now. We might need to fix this in the future if // we have a real use case. - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } } } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index c0e89809274..110cdef8796 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_HEAPSHARED_HPP #define SHARE_CDS_HEAPSHARED_HPP +#include "cds/aotMetaspace.hpp" #include "cds/dumpTimeClassInfo.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "gc/shared/gc_globals.hpp" @@ -432,7 +432,7 @@ private: static void init_scratch_objects_for_basic_type_mirrors(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void init_box_classes(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static bool is_heap_region(int idx) { - CDS_JAVA_HEAP_ONLY(return (idx == MetaspaceShared::hp);) + CDS_JAVA_HEAP_ONLY(return (idx == AOTMetaspace::hp);) NOT_CDS_JAVA_HEAP_RETURN_(false); } diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 4241619385e..966b3eab298 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -23,10 +23,10 @@ */ #include "cds/aotClassFilter.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/lambdaFormInvokers.inline.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoadInfo.hpp" @@ -219,7 +219,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, result->add_to_hierarchy(THREAD); // new class not linked yet. - MetaspaceShared::try_link_class(THREAD, result); + AOTMetaspace::try_link_class(THREAD, result); assert(!HAS_PENDING_EXCEPTION, "Invariant"); result->set_is_generated_shared_class(); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp index ff7acb15292..91e508bfdc5 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP #define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaClasses.hpp" #include "memory/metaspaceClosure.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index 10d2fc35ea9..d93ef5e9c1d 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -75,7 +75,7 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { } InstanceKlass* RunTimeClassInfo::klass() const { - if (MetaspaceShared::in_aot_cache(this)) { + if (AOTMetaspace::in_aot_cache(this)) { // is inside a mmaped CDS archive. return ArchiveUtils::offset_to_archived_address(_klass_offset); } else { diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index bf41e05eee5..29670f5ec51 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_CDS_RUNTIMECLASSINFO_HPP #define SHARE_CDS_RUNTIMECLASSINFO_HPP +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cds_globals.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "memory/metaspaceClosure.hpp" diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 683fc22b27a..8cc00d1feb9 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -22,12 +22,12 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 132c1c4ca49..062521e7495 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -23,9 +23,9 @@ */ #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -601,21 +601,21 @@ void Modules::ArchivedProperty::runtime_check() const { bool disable = false; if (runtime_value == nullptr) { if (_archived_value != nullptr) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); disable = true; } } else { if (_archived_value == nullptr) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); disable = true; } else if (strcmp(runtime_value, _archived_value) != 0) { - MetaspaceShared::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); + AOTMetaspace::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); disable = true; } } if (disable) { - MetaspaceShared::report_loading_error("Disabling optimized module handling"); + AOTMetaspace::report_loading_error("Disabling optimized module handling"); CDSConfig::stop_using_optimized_module_handling(); } } diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index cf5d98650ce..6f6409ee27a 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -993,7 +993,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern // but bail out for safety. log_error(aot)("Too many strings to be archived: %zu", items_count_acquire()); - MetaspaceShared::unrecoverable_writing_error(); + AOTMetaspace::unrecoverable_writing_error(); } objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK); diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index e6889e6248d..d0bcca87c14 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -146,7 +146,7 @@ public: "refcount %d", value.refcount()); #if INCLUDE_CDS if (CDSConfig::is_dumping_static_archive()) { - // We have allocated with MetaspaceShared::symbol_space_alloc(). No deallocation is needed. + // We have allocated with AOTMetaspace::symbol_space_alloc(). No deallocation is needed. // Unreferenced Symbols will not be copied into the archive. return; } @@ -185,7 +185,7 @@ private: // the archived symbol of "java/lang/Object" may sometimes be lower than "java/lang/String", and // sometimes be higher. This would cause non-deterministic contents in the archive. DEBUG_ONLY(static void* last = nullptr); - void* p = (void*)MetaspaceShared::symbol_space_alloc(alloc_size); + void* p = (void*)AOTMetaspace::symbol_space_alloc(alloc_size); assert(p > last, "must increase monotonically"); DEBUG_ONLY(last = p); return p; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 946fbc07f28..f4f7f694d6d 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -2001,7 +2001,7 @@ void SystemDictionary::restore_archived_method_handle_intrinsics() { } void SystemDictionary::restore_archived_method_handle_intrinsics_impl(TRAPS) { - Array* list = MetaspaceShared::archived_method_handle_intrinsics(); + Array* list = AOTMetaspace::archived_method_handle_intrinsics(); for (int i = 0; i < list->length(); i++) { methodHandle m(THREAD, list->at(i)); Method::restore_archived_method_handle_intrinsic(m, CHECK); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 7b52dfe46aa..df22db82165 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -26,6 +26,7 @@ #include "cds/aotClassFilter.hpp" #include "cds/aotClassLocation.hpp" #include "cds/aotLogging.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -38,7 +39,6 @@ #include "cds/heapShared.hpp" #include "cds/lambdaFormInvokers.inline.hpp" #include "cds/lambdaProxyClassDictionary.hpp" -#include "cds/metaspaceShared.hpp" #include "cds/runTimeClassInfo.hpp" #include "cds/unregisteredClasses.hpp" #include "classfile/classFileStream.hpp" @@ -205,7 +205,7 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { } bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::in_aot_cache(k)) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { // We have reached a super type that's already in the base archive. Treat it // as "not excluded". return false; @@ -300,7 +300,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (has_class_failed_verification(k)) { return warn_excluded(k, "Failed verification"); } else if (CDSConfig::is_dumping_aot_linked_classes()) { - // Most loaded classes should have been speculatively linked by MetaspaceShared::link_class_for_cds(). + // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). // However, we do not speculatively link old classes, as they are not recorded by // SystemDictionaryShared::record_linking_constraint(). As a result, such an unlinked // class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), @@ -691,7 +691,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { return check_for_exclusion(ik, p); } else { // No need to check for is_linked() as all eligible classes should have - // already been linked in MetaspaceShared::link_class_for_cds(). + // already been linked in AOTMetaspace::link_class_for_cds(). // Can't take the lock as we are in safepoint. DumpTimeClassInfo* p = _dumptime_table->get(ik); if (p->is_excluded()) { @@ -1124,7 +1124,7 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim } } - if (!MetaspaceShared::in_aot_cache_dynamic_region(name)) { + if (!AOTMetaspace::in_aot_cache_dynamic_region(name)) { // The names of all shared classes in the static dict must also be in the // static archive record = static_dict->lookup(name, hash, 0); diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 7e53f493c47..a24bae03137 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -25,10 +25,10 @@ #include "asm/macroAssembler.hpp" #include "cds/aotCacheAccess.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaAssertions.hpp" #include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" @@ -96,7 +96,7 @@ static void report_store_failure() { // where we set number of compiler threads for AOT assembly phase. // // 3. We determine presence of AOT code in AOT Cache in -// MetaspaceShared::open_static_archive() which is calles +// AOTMetaspace::open_static_archive() which is calles // after compilationPolicy_init() but before codeCache_init(). // // 4. AOTCodeCache::initialize() is called during universe_init() @@ -165,7 +165,7 @@ uint AOTCodeCache::max_aot_code_size() { return _max_aot_code_size; } -// It is called from MetaspaceShared::initialize_shared_spaces() +// It is called from AOTMetaspace::initialize_shared_spaces() // which is called from universe_init(). // At this point all AOT class linking seetings are finilized // and AOT cache is open so we can map AOT code region. diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index 685fba47349..a7bc896172c 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -35,7 +35,7 @@ // // Also, this is a C header file. Do not use C++ here. -#define NUM_CDS_REGIONS 5 // this must be the same as MetaspaceShared::n_regions +#define NUM_CDS_REGIONS 5 // this must be the same as AOTMetaspace::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 #define CDS_PREIMAGE_ARCHIVE_MAGIC 0xcafea07c @@ -72,7 +72,7 @@ typedef struct CDSFileMapRegion { size_t _ptrmap_size_in_bits; char* _mapped_base; // Actually mapped address used for mapping the core regions. At that address the // zero nklass protection zone is established; following that (at offset - // MetaspaceShared::protection_zone_size()) the lowest core region (rw for the + // AOTMetaspace::protection_zone_size()) the lowest core region (rw for the // static archive) is is mapped. bool _in_reserved_space; // Is this region in a ReservedSpace } CDSFileMapRegion; diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 05590add8ff..640e3ab3fff 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -23,7 +23,7 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "compiler/disassembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeStream.hpp" diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index 41a96eebfad..a9ee92cb570 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/vmClasses.hpp" #include "interpreter/bytecodes.hpp" #include "interpreter/bytecodeStream.hpp" diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 1983fbc870c..2a744c12c01 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -24,8 +24,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoaderData.hpp" #include "gc/shared/collectedHeap.hpp" #include "logging/log.hpp" @@ -721,7 +721,7 @@ void Metaspace::global_initialize() { metaspace::ChunkHeaderPool::initialize(); if (CDSConfig::is_dumping_static_archive()) { - MetaspaceShared::initialize_for_static_dump(); + AOTMetaspace::initialize_for_static_dump(); } // If UseCompressedClassPointers=1, we have two cases: @@ -740,7 +740,7 @@ void Metaspace::global_initialize() { if (!FLAG_IS_DEFAULT(CompressedClassSpaceBaseAddress)) { log_warning(metaspace)("CDS active - ignoring CompressedClassSpaceBaseAddress."); } - MetaspaceShared::initialize_runtime_shared_and_meta_spaces(); + AOTMetaspace::initialize_runtime_shared_and_meta_spaces(); // If any of the archived space fails to map, UseSharedSpaces // is reset to false. } @@ -853,7 +853,7 @@ void Metaspace::global_initialize() { LogTarget(Info, gc, metaspace) lt; if (lt.is_enabled()) { LogStream ls(lt); - CDS_ONLY(MetaspaceShared::print_on(&ls);) + CDS_ONLY(AOTMetaspace::print_on(&ls);) Metaspace::print_compressed_class_space(&ls); CompressedKlassPointers::print_mode(&ls); } @@ -1037,7 +1037,7 @@ void Metaspace::purge(bool classes_unloaded) { // Returns true if pointer points into one of the metaspace regions, or // into the class space. bool Metaspace::in_aot_cache(const void* ptr) { - return MetaspaceShared::in_aot_cache(ptr); + return AOTMetaspace::in_aot_cache(ptr); } // Returns true if pointer points into one of the non-class-space metaspace regions. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index b2c3c29a812..408dbf6d23f 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -31,7 +31,7 @@ #include "utilities/globalDefinitions.hpp" class ClassLoaderData; -class MetaspaceShared; +class AOTMetaspace; class MetaspaceTracer; class Mutex; class outputStream; @@ -43,7 +43,7 @@ class ReservedSpace; // (auxiliary stuff goes into MetaspaceUtils) class Metaspace : public AllStatic { - friend class MetaspaceShared; + friend class AOTMetaspace; public: enum MetadataType { diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 8afa17b0b3d..f34a771138d 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -22,11 +22,11 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderDataShared.hpp" @@ -878,7 +878,7 @@ jint universe_init() { ObjLayout::initialize(); #ifdef _LP64 - MetaspaceShared::adjust_heap_sizes_for_dumping(); + AOTMetaspace::adjust_heap_sizes_for_dumping(); #endif // _LP64 GCConfig::arguments()->initialize_heap_sizes(); @@ -904,7 +904,7 @@ jint universe_init() { if (CDSConfig::is_using_archive()) { // Read the data structures supporting the shared spaces (shared // system dictionary, symbol table, etc.) - MetaspaceShared::initialize_shared_spaces(); + AOTMetaspace::initialize_shared_spaces(); } #endif @@ -1161,7 +1161,7 @@ bool universe_post_init() { MemoryService::set_universe_heap(Universe::heap()); #if INCLUDE_CDS - MetaspaceShared::post_initialize(CHECK_false); + AOTMetaspace::post_initialize(CHECK_false); #endif return true; } diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index ee4c05e1e06..90874d2392d 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -54,7 +54,7 @@ class Universe: AllStatic { friend class VMStructs; friend class VM_PopulateDumpSharedSpace; friend class Metaspace; - friend class MetaspaceShared; + friend class AOTMetaspace; friend class vmClasses; friend jint universe_init(); diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 198ff1ef75e..32a86c7ab24 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/javaClasses.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/vmClasses.hpp" @@ -259,9 +259,9 @@ void ArrayKlass::log_array_class_load(Klass* k) { LogStream ls(lt); ResourceMark rm; ls.print("%s", k->name()->as_klass_external_name()); - if (MetaspaceShared::in_aot_cache_dynamic_region((void*)k)) { + if (AOTMetaspace::in_aot_cache_dynamic_region((void*)k)) { ls.print(" source: shared objects file (top)"); - } else if (MetaspaceShared::in_aot_cache_static_region((void*)k)) { + } else if (AOTMetaspace::in_aot_cache_static_region((void*)k)) { ls.print(" source: shared objects file"); } ls.cr(); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 568ccd72176..1afc59d8da1 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -23,12 +23,12 @@ */ #include "cds/aotClassInitializer.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" #include "cds/cdsEnumKlass.hpp" #include "cds/classListWriter.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileParser.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" @@ -2763,7 +2763,7 @@ void InstanceKlass::init_shared_package_entry() { } } else if (CDSConfig::is_dumping_dynamic_archive() && CDSConfig::is_using_full_module_graph() && - MetaspaceShared::in_aot_cache(_package_entry)) { + AOTMetaspace::in_aot_cache(_package_entry)) { // _package_entry is an archived package in the base archive. Leave it as is. } else { _package_entry = nullptr; @@ -2845,7 +2845,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl // retrieved during dump time. // Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { - if (MetaspaceShared::in_aot_cache(this)) { + if (AOTMetaspace::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; @@ -3088,7 +3088,7 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_ if (in_aot_cache() && _package_entry != nullptr) { if (CDSConfig::is_using_full_module_graph() && _package_entry == pkg_entry) { // we can use the saved package - assert(MetaspaceShared::in_aot_cache(_package_entry), "must be"); + assert(AOTMetaspace::in_aot_cache(_package_entry), "must be"); return; } else { _package_entry = nullptr; @@ -3971,7 +3971,7 @@ void InstanceKlass::print_class_load_helper(ClassLoaderData* loader_data, } } else { assert(this->in_aot_cache(), "must be"); - if (MetaspaceShared::in_aot_cache_dynamic_region((void*)this)) { + if (AOTMetaspace::in_aot_cache_dynamic_region((void*)this)) { info_stream.print(" source: shared objects file (top)"); } else { info_stream.print(" source: shared objects file"); diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index ce4e322930f..ead413dfa2c 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -22,7 +22,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" @@ -50,7 +50,7 @@ inline InstanceKlass* klassVtable::ik() const { } bool klassVtable::is_preinitialized_vtable() { - return _klass->in_aot_cache() && !MetaspaceShared::remapped_readwrite() && _klass->verified_at_dump_time(); + return _klass->in_aot_cache() && !AOTMetaspace::remapped_readwrite() && _klass->verified_at_dump_time(); } @@ -1089,8 +1089,8 @@ void itableMethodEntry::initialize(InstanceKlass* klass, Method* m) { if (m == nullptr) return; #ifdef ASSERT - if (MetaspaceShared::in_aot_cache((void*)&_method) && - !MetaspaceShared::remapped_readwrite() && + if (AOTMetaspace::in_aot_cache((void*)&_method) && + !AOTMetaspace::remapped_readwrite() && m->method_holder()->verified_at_dump_time() && klass->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 03330aee209..69203189bb7 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -22,9 +22,9 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" #include "cds/cppVtables.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/metadataOnStackMark.hpp" @@ -446,7 +446,7 @@ void Method::restore_unshareable_info(TRAPS) { #endif void Method::set_vtable_index(int index) { - if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !AOTMetaspace::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_vtable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. @@ -457,7 +457,7 @@ void Method::set_vtable_index(int index) { } void Method::set_itable_index(int index) { - if (in_aot_cache() && !MetaspaceShared::remapped_readwrite() && method_holder()->verified_at_dump_time()) { + if (in_aot_cache() && !AOTMetaspace::remapped_readwrite() && method_holder()->verified_at_dump_time()) { // At runtime initialize_itable is rerun as part of link_class_impl() // for a shared class loaded by the non-boot loader to obtain the loader // constraints based on the runtime classloaders' context. The dumptime diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index 0f2cd8e6e6b..3a24a78936b 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -23,7 +23,6 @@ */ #include "cds/archiveBuilder.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/vmSymbols.hpp" diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 49153b3e931..845dc20c0d0 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -23,7 +23,6 @@ */ #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "ci/ciEnv.hpp" #include "ci/ciMetadata.hpp" #include "classfile/classLoaderData.hpp" diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 511f9efdfb9..99c8a56c727 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassInitializer.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListParser.hpp" #include "cds/classListWriter.hpp" @@ -3503,7 +3504,7 @@ JVM_ENTRY(void, JVM_DumpClassListToFile(JNIEnv *env, jstring listFileName)) ResourceMark rm(THREAD); Handle file_handle(THREAD, JNIHandles::resolve_non_null(listFileName)); char* file_name = java_lang_String::as_utf8_string(file_handle()); - MetaspaceShared::dump_loaded_classes(file_name, THREAD); + AOTMetaspace::dump_loaded_classes(file_name, THREAD); #endif // INCLUDE_CDS JVM_END diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index dc2d621f694..d4ee34b881f 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -22,8 +22,8 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cdsConfig.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoadInfo.hpp" @@ -254,7 +254,7 @@ void VM_RedefineClasses::doit() { // shared readwrite, private just in case we need to redefine // a shared class. We do the remap during the doit() phase of // the safepoint to be safer. - if (!MetaspaceShared::remap_shared_readonly_as_readwrite()) { + if (!AOTMetaspace::remap_shared_readonly_as_readwrite()) { log_info(redefine, class, load)("failed to remap shared readonly space to readwrite, private"); _res = JVMTI_ERROR_INTERNAL; _timer_vm_op_doit.stop(); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 63920583e18..cbb135a82d9 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -23,11 +23,11 @@ */ #include "cds.h" +#include "cds/aotMetaspace.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConstants.hpp" #include "cds/filemap.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderStats.hpp" @@ -1884,9 +1884,9 @@ WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb)) WB_END // The function is only valid when CDS is available. -WB_ENTRY(jlong, WB_MetaspaceSharedRegionAlignment(JNIEnv* env, jobject wb)) +WB_ENTRY(jlong, WB_AOTMetaspaceRegionAlignment(JNIEnv* env, jobject wb)) #if INCLUDE_CDS - return (jlong)MetaspaceShared::core_region_alignment(); + return (jlong)AOTMetaspace::core_region_alignment(); #else ShouldNotReachHere(); return 0L; @@ -2154,7 +2154,7 @@ WB_ENTRY(jboolean, WB_IsSharedInternedString(JNIEnv* env, jobject wb, jobject st WB_END WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) - return (jboolean)MetaspaceShared::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + return (jboolean)AOTMetaspace::in_aot_cache(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); WB_END WB_ENTRY(jboolean, WB_AreSharedStringsMapped(JNIEnv* env)) @@ -2887,7 +2887,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace }, {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC }, {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC }, - {CC"metaspaceSharedRegionAlignment", CC"()J", (void*)&WB_MetaspaceSharedRegionAlignment }, + {CC"metaspaceSharedRegionAlignment", CC"()J", (void*)&WB_AOTMetaspaceRegionAlignment }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 351fd1ebb89..997dd1f802a 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" @@ -449,7 +450,7 @@ void before_exit(JavaThread* thread, bool halt) { ClassListWriter::write_resolved_constants(); if (CDSConfig::is_dumping_preimage_static_archive()) { - MetaspaceShared::preload_and_dump(thread); + AOTMetaspace::preload_and_dump(thread); } #endif diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 5ba3499efbe..3cf1058b6f7 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -25,10 +25,10 @@ */ #include "cds/aotLinkedClassBulkLoader.hpp" +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" -#include "cds/metaspaceShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" #include "classfile/javaThreadStatus.hpp" @@ -889,10 +889,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (CDSConfig::is_dumping_classic_static_archive()) { // Classic -Xshare:dump, aka "old workflow" - MetaspaceShared::preload_and_dump(CHECK_JNI_ERR); + AOTMetaspace::preload_and_dump(CHECK_JNI_ERR); } else if (CDSConfig::is_dumping_final_static_archive()) { tty->print_cr("Reading AOTConfiguration %s and writing AOTCache %s", AOTConfiguration, AOTCache); - MetaspaceShared::preload_and_dump(CHECK_JNI_ERR); + AOTMetaspace::preload_and_dump(CHECK_JNI_ERR); } if (log_is_enabled(Info, perf, class, link)) { diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 19c9773dfe5..a4d44a96878 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -24,7 +24,7 @@ * */ -#include "cds/metaspaceShared.hpp" +#include "cds/aotMetaspace.hpp" #include "code/codeCache.hpp" #include "compiler/compilationFailureInfo.hpp" #include "compiler/compilationMemoryStatistic.hpp" @@ -1199,7 +1199,7 @@ void VMError::report(outputStream* st, bool _verbose) { st->cr(); STEP_IF("printing compressed klass pointers mode", _verbose && UseCompressedClassPointers) - CDS_ONLY(MetaspaceShared::print_on(st);) + CDS_ONLY(AOTMetaspace::print_on(st);) Metaspace::print_compressed_class_space(st); CompressedKlassPointers::print_mode(st); st->cr(); @@ -1414,7 +1414,7 @@ void VMError::print_vm_info(outputStream* st) { // STEP("printing compressed class ptrs mode") if (UseCompressedClassPointers) { - CDS_ONLY(MetaspaceShared::print_on(st);) + CDS_ONLY(AOTMetaspace::print_on(st);) Metaspace::print_compressed_class_space(st); CompressedKlassPointers::print_mode(st); st->cr(); diff --git a/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java b/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java index 8184f272af7..e38273c0484 100644 --- a/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java +++ b/test/hotspot/jtreg/runtime/cds/SpaceUtilizationCheck.java @@ -59,7 +59,7 @@ public class SpaceUtilizationCheck { Pattern pattern = Pattern.compile("(..) space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)"); WhiteBox wb = WhiteBox.getWhiteBox(); long reserve_alignment = wb.metaspaceSharedRegionAlignment(); - System.out.println("MetaspaceShared::core_region_alignment() = " + reserve_alignment); + System.out.println("AOTMetaspace::core_region_alignment() = " + reserve_alignment); // Look for output like this. The pattern will only match the first 2 regions, which is what we need to check // @@ -90,7 +90,7 @@ public class SpaceUtilizationCheck { } if (unused > reserve_alignment) { // [1] Check for unused space - throw new RuntimeException("Unused space (" + unused + ") must be smaller than MetaspaceShared::core_region_alignment() (" + + throw new RuntimeException("Unused space (" + unused + ") must be smaller than AOTMetaspace::core_region_alignment() (" + reserve_alignment + ")"); } if (last_region >= 0 && address != last_region) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 2ed29454df7..f2d3575597f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -45,7 +45,7 @@ public class SharedArchiveConsistency { private static int genericHeaderMinVersion; // minimum supported CDS version private static int currentCDSArchiveVersion; // current CDS version in java process - // The following should be consistent with the enum in the C++ MetaspaceShared class + // The following should be consistent with the enum in the C++ AOTMetaspace class public static String[] shared_region_name = { "rw", // ReadWrite "ro", // ReadOnly diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index f616b22ef38..35cee750822 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -67,9 +67,9 @@ public class CDSArchiveUtils { private static int staticArchiveHeaderSize; // static archive file header size private static int dynamicArchiveHeaderSize; // dynamic archive file header size private static int cdsFileMapRegionSize; // size of CDSFileMapRegion - private static long alignment; // MetaspaceShared::core_region_alignment + private static long alignment; // AOTMetaspace::core_region_alignment - // The following should be consistent with the enum in the C++ MetaspaceShared class + // The following should be consistent with the enum in the C++ AOTMetaspace class private static String[] shared_region_name = { "rw", // ReadWrite "ro", // ReadOnly From 8520fd3f6a8d00d3ab0b01af6ce2307f74258fb6 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 4 Sep 2025 16:50:58 +0000 Subject: [PATCH 368/471] 8366365: [test] test/lib-test/jdk/test/whitebox/CPUInfoTest.java should be updated Reviewed-by: kvn, sviswanathan --- test/lib-test/jdk/test/whitebox/CPUInfoTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index 8f0ef108885..809953a1263 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -66,7 +66,8 @@ public class CPUInfoTest { "hv", "fsrm", "avx512_bitalg", "gfni", "f16c", "pku", "ospke", "cet_ibt", "cet_ss", "avx512_ifma", "serialize", "avx_ifma", - "apx_f", "avx10_1", "avx10_2" + "apx_f", "avx10_1", "avx10_2", "avx512_fp16", + "sha512", "hybrid" ); // @formatter:on // Checkstyle: resume From 1dc1d56f79e10c9b4c5c8b42a80a191f7b14c738 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 4 Sep 2025 16:57:36 +0000 Subject: [PATCH 369/471] 8363858: [perf] OptimizeFill may use wide set of intrinsics Reviewed-by: roland, sviswanathan --- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 1c9f8ed2e40..094ab370190 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1665,7 +1665,7 @@ void VM_Version::get_processor_features() { #ifdef COMPILER2 if (FLAG_IS_DEFAULT(OptimizeFill)) { - if (MaxVectorSize < 32 || !VM_Version::supports_avx512vlbw()) { + if (MaxVectorSize < 32 || (!EnableX86ECoreOpts && !VM_Version::supports_avx512vlbw())) { OptimizeFill = false; } } From 945aaf893219f9ead94fd8aae4994f7b520f64bf Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 4 Sep 2025 19:00:39 +0000 Subject: [PATCH 370/471] 8366897: RBTreeTest.IntrusiveCustomVerifyTest and RBTreeTest.CustomVerify tests fail on non-debug builds Reviewed-by: ayang --- src/hotspot/share/utilities/rbTree.inline.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 16150e41be8..f28923eb867 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -127,7 +127,8 @@ template inline void IntrusiveRBNode::verify( size_t& num_nodes, size_t& black_nodes_until_leaf, size_t& shortest_leaf_path, size_t& longest_leaf_path, size_t& tree_depth, bool expect_visited, NODE_VERIFIER verifier, const USER_VERIFIER& extra_verifier) const { - assert(extra_verifier(static_cast(this)), "user provided verifier failed"); + bool extra_verifier_result = extra_verifier(static_cast(this)); + assert(extra_verifier_result, "user provided verifier failed"); assert(expect_visited != _visited, "node already visited"); DEBUG_ONLY(_visited = !_visited); From 581070715ab1ef081032b78ceb3c2cfbdbcff611 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 4 Sep 2025 21:58:08 +0000 Subject: [PATCH 371/471] 8366102: Clarification Needed: Symbolic Link Handling in File API Specifications Reviewed-by: alanb --- src/java.base/share/classes/java/io/File.java | 187 +++++++++--------- 1 file changed, 99 insertions(+), 88 deletions(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index bb216366344..494dac7f51e 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -80,17 +80,22 @@ import jdk.internal.util.StaticProperty; * {@code user.dir}, and is typically the directory in which the Java * virtual machine was invoked. * - *

            Unless otherwise noted, {@linkplain java.nio.file##links symbolic links} - * are automatically redirected to the target of the link, whether they - * are provided by a pathname string or via a {@code File} object. + *

            Many operating systems and file systems have support for + * {@linkplain java.nio.file##links symbolic links}. + * A symbolic link is a special file that serves as a reference to another file. + * Unless otherwise specified, symbolic links are transparent to applications + * and operations on files that are symbolic links are automatically redirected + * to the target of the link. Methods that only operate on the abstract + * pathname do not access the file system and thus do not resolve symbolic + * links. * *

            The parent of an abstract pathname may be obtained by invoking * the {@link #getParent} method of this class and consists of the pathname's * prefix and each name in the pathname's name sequence except for the last. * Each directory's absolute pathname is an ancestor of any {@code File} * object with an absolute abstract pathname which begins with the directory's - * absolute pathname. For example, the directory denoted by the abstract - * pathname {@code "/usr"} is an ancestor of the directory denoted by the + * absolute pathname. For example, the directory located by the abstract + * pathname {@code "/usr"} is an ancestor of the directory located by the * pathname {@code "/usr/local/bin"}. * *

            The prefix concept is used to handle root directories on UNIX platforms, @@ -113,8 +118,8 @@ import jdk.internal.util.StaticProperty; * *

          * - *

          Instances of this class may or may not denote an actual file-system - * object such as a file or a directory. If it does denote such an object + *

          Instances of this class may or may not locate an actual file-system + * object such as a file or a directory. If it does locate such an object * then that object resides in a partition. A partition is an * operating system-specific portion of storage for a file system. A single * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may @@ -448,12 +453,12 @@ public class File /* -- Path-component accessors -- */ /** - * Returns the name of the file or directory denoted by this abstract + * Returns the name component of this abstract * pathname. This is just the last name in the pathname's name * sequence. If the pathname's name sequence is empty, then the empty * string is returned. * - * @return The name of the file or directory denoted by this abstract + * @return The name component of this abstract * pathname, or the empty string if this pathname's name sequence * is empty */ @@ -592,7 +597,7 @@ public class File * symbolic links, and converting drive letters to a standard case (on * Microsoft Windows platforms). * - *

          Every pathname that denotes an existing file or directory has a + *

          Every pathname that locates an existing file or directory has a * unique canonical form. Every pathname that denotes a nonexistent file * or directory also has a unique canonical form. The canonical form of * the pathname of a nonexistent file or directory may be different from @@ -601,7 +606,7 @@ public class File * file or directory may be different from the canonical form of the same * pathname after the file or directory is deleted. * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -623,7 +628,7 @@ public class File * Returns the canonical form of this abstract pathname. Equivalent to * new File(this.{@link #getCanonicalPath}). * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -656,7 +661,7 @@ public class File /** * Converts this abstract pathname into a {@code file:} URL. The * exact form of the URL is system-dependent. If it can be determined that - * the file denoted by this abstract pathname is a directory, then the + * the file located by this abstract pathname is a directory, then the * resulting URL will end with a slash. * * @return A URL object representing the equivalent file URL @@ -689,7 +694,7 @@ public class File * Constructs a {@code file:} URI that represents this abstract pathname. * *

          The exact form of the URI is system-dependent. If it can be - * determined that the file denoted by this abstract pathname is a + * determined that the file located by this abstract pathname is a * directory, then the resulting URI will end with a slash. * *

          For a given abstract pathname f, it is guaranteed that @@ -740,13 +745,13 @@ public class File /* -- Attribute accessors -- */ /** - * Tests whether the application can read the file denoted by this + * Tests whether the application can read the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to read * files that are marked as unreadable. Consequently, this method may return * {@code true} even though the file does not have read permissions. * - * @return {@code true} if and only if the file specified by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and can be read by the * application; {@code false} otherwise */ @@ -758,14 +763,14 @@ public class File } /** - * Tests whether the application can modify the file denoted by this + * Tests whether the application can modify the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to modify * files that are marked read-only. Consequently, this method may return * {@code true} even though the file is marked read-only. * * @return {@code true} if and only if the file system actually - * contains a file denoted by this abstract pathname and + * contains a file located by this abstract pathname and * the application is allowed to write to the file; * {@code false} otherwise. */ @@ -777,10 +782,10 @@ public class File } /** - * Tests whether the file or directory denoted by this abstract pathname + * Tests whether the file or directory located by this abstract pathname * exists. * - * @return {@code true} if and only if the file or directory denoted + * @return {@code true} if and only if the file or directory located * by this abstract pathname exists; {@code false} otherwise */ public boolean exists() { @@ -791,7 +796,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a + * Tests whether the file located by this abstract pathname is a * directory. * *

          Where it is required to distinguish an I/O exception from the case @@ -800,7 +805,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a directory; * {@code false} otherwise */ @@ -812,7 +817,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a normal + * Tests whether the file located by this abstract pathname is a normal * file. A file is normal if it is not a directory and, in * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. @@ -823,7 +828,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a normal file; * {@code false} otherwise */ @@ -835,7 +840,7 @@ public class File } /** - * Tests whether the file named by this abstract pathname is a hidden + * Tests whether the file located by this abstract pathname is a hidden * file. The exact definition of hidden is system-dependent. On * UNIX systems, a file is considered to be hidden if its name begins with * a period character ({@code '.'}). On Microsoft Windows systems, a file @@ -849,7 +854,7 @@ public class File * with a period character. On Windows systems, a symbolic link is * considered hidden if its target is so marked in the filesystem. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname is hidden according to the conventions of the * underlying platform * @@ -863,7 +868,7 @@ public class File } /** - * Returns the time that the file denoted by this abstract pathname was + * Returns the time that the file located by this abstract pathname was * last modified. * * @apiNote @@ -897,8 +902,8 @@ public class File } /** - * Returns the length of the file denoted by this abstract pathname. - * The return value is unspecified if this pathname denotes a directory. + * Returns the length of the file located by this abstract pathname. + * The return value is unspecified if this pathname locates a directory. * *

          Where it is required to distinguish an I/O exception from the case * that {@code 0L} is returned, or where several attributes of the same file @@ -906,10 +911,10 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return The length, in bytes, of the file denoted by this abstract + * @return The length, in bytes, of the file located by this abstract * pathname, or {@code 0L} if the file does not exist. Some * operating systems may return {@code 0L} for pathnames - * denoting system-dependent entities such as devices or pipes. + * locating system-dependent entities such as devices or pipes. */ public long length() { if (isInvalid()) { @@ -935,7 +940,7 @@ public class File * * @return {@code true} if the named file does not exist and was * successfully created; {@code false} if the named file - * already exists + * already exists, including if it is a symbolic link * * @throws IOException * If an I/O error occurred @@ -950,9 +955,9 @@ public class File } /** - * Deletes the file or directory denoted by this abstract pathname. If - * this pathname denotes a directory, then the directory must be empty in - * order to be deleted. If this pathname denotes a symbolic link, then the + * Deletes the file or directory located by this abstract pathname. If + * this pathname locates a directory, then the directory must be empty in + * order to be deleted. If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * *

          Note that the {@link java.nio.file.Files} class defines the {@link @@ -971,9 +976,9 @@ public class File } /** - * Requests that the file or directory denoted by this abstract + * Requests that the file or directory located by this abstract * pathname be deleted when the virtual machine terminates. - * If this pathname denotes a symbolic link, then the + * If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * Files (or directories) are deleted in the reverse order that * they are registered. Invoking this method to delete a file or @@ -1003,12 +1008,12 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. + * directory located by this abstract pathname. * - *

          If this abstract pathname does not denote a directory, then this + *

          If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of strings is * returned, one for each file or directory in the directory. Names - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each string is a file name rather than a * complete path. * @@ -1023,9 +1028,9 @@ public class File * may be more responsive when working with remote directories. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ public String[] list() { @@ -1034,13 +1039,13 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The strings are + * directory located by this abstract pathname. The strings are * ensured to represent normalized paths. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ private final String[] normalizedList() { @@ -1060,7 +1065,7 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname that satisfy the specified + * directory located by this abstract pathname that satisfy the specified * filter. The behavior of this method is the same as that of the * {@link #list()} method, except that the strings in the returned array * must satisfy the filter. If the given {@code filter} is {@code null} @@ -1068,16 +1073,16 @@ public class File * and only if the value {@code true} results when the {@link * FilenameFilter#accept FilenameFilter.accept(File, String)} method * of the filter is invoked on this abstract pathname and the name of a - * file or directory in the directory that it denotes. + * file or directory in the directory that it locates. * * @param filter * A filename filter * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname that were accepted + * directory located by this abstract pathname that were accepted * by the given {@code filter}. The array will be empty if the * directory is empty or if no names were accepted by the filter. - * Returns {@code null} if this abstract pathname does not denote + * Returns {@code null} if this abstract pathname does not locate * a directory, or if an I/O error occurs. * * @see java.nio.file.Files#newDirectoryStream(Path,String) @@ -1097,13 +1102,13 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files in the - * directory denoted by this abstract pathname. + * Returns an array of abstract pathnames locating the files in the + * directory located by this abstract pathname. * - *

          If this abstract pathname does not denote a directory, then this + *

          If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of {@code File} objects * is returned, one for each file or directory in the directory. Pathnames - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each resulting abstract pathname is * constructed from this abstract pathname using the {@link #File(File, * String) File(File, String)} constructor. Therefore if this @@ -1121,10 +1126,10 @@ public class File * directory. This may use less resources when working with very large * directories. * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1141,8 +1146,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1151,15 +1156,15 @@ public class File * the {@link FilenameFilter#accept * FilenameFilter.accept(File, String)} method of the filter is * invoked on this abstract pathname and the name of a file or directory in - * the directory that it denotes. + * the directory that it locates. * * @param filter * A filename filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1177,8 +1182,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1190,10 +1195,10 @@ public class File * @param filter * A file filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1255,8 +1260,8 @@ public class File } /** - * Renames the file denoted by this abstract pathname. If this pathname - * denotes a symbolic link, then the link itself, not its target, will be + * Renames the file located by this abstract pathname. If this pathname + * locates a symbolic link, then the link itself, not its target, will be * renamed. * *

          Many aspects of the behavior of this method are inherently @@ -1291,7 +1296,7 @@ public class File } /** - * Sets the last-modified time of the file or directory named by this + * Sets the last-modified time of the file or directory located by this * abstract pathname. * *

          All platforms support file-modification times to the nearest second, @@ -1320,7 +1325,7 @@ public class File } /** - * Marks the file or directory named by this abstract pathname so that + * Marks the file or directory located by this abstract pathname so that * only read operations are allowed. After invoking this method the file * or directory will not change until it is either deleted or marked * to allow write access. On some platforms it may be possible to start the @@ -1341,7 +1346,8 @@ public class File } /** - * Sets the owner's or everybody's write permission for this abstract + * Sets the owner's or everybody's write permission of the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1375,7 +1381,8 @@ public class File } /** - * A convenience method to set the owner's write permission for this abstract + * A convenience method to set the owner's write permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1402,7 +1409,8 @@ public class File } /** - * Sets the owner's or everybody's read permission for this abstract + * Sets the owner's or everybody's read permission for the file or directory + * located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1442,7 +1450,8 @@ public class File } /** - * A convenience method to set the owner's read permission for this abstract + * A convenience method to set the owner's read permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1475,7 +1484,8 @@ public class File } /** - * Sets the owner's or everybody's execute permission for this abstract + * Sets the owner's or everybody's execute permission for the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to execute files that are * not marked executable. @@ -1515,7 +1525,8 @@ public class File } /** - * A convenience method to set the owner's execute permission for this + * A convenience method to set the owner's execute permission for the file + * or directory located by this * abstract pathname. On some platforms it may be possible to start the Java * virtual machine with special privileges that allow it to execute files * that are not marked executable. @@ -1548,7 +1559,7 @@ public class File } /** - * Tests whether the application can execute the file denoted by this + * Tests whether the application can execute the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to execute * files that are not marked executable. Consequently, this method may return @@ -1794,7 +1805,7 @@ public class File * returns successfully then it is guaranteed that: * *

            - *
          1. The file denoted by the returned abstract pathname did not exist + *
          2. The file located by the returned abstract pathname did not exist * before this method was invoked, and *
          3. Neither this method nor any of its variants will return the same * abstract pathname again in the current invocation of the virtual @@ -1837,7 +1848,7 @@ public class File * to have any effect upon the temporary directory used by this method. * *

            If the {@code directory} argument is not {@code null} and its - * abstract pathname is valid and denotes an existing, writable directory, + * abstract pathname is valid and locates an existing, writable directory, * then the file will be created in that directory. Otherwise the file will * not be created and an {@code IOException} will be thrown. Under no * circumstances will a directory be created at the location specified by @@ -1854,7 +1865,7 @@ public class File * {@code null} if the default temporary-file * directory is to be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1911,7 +1922,7 @@ public class File * name; may be {@code null}, in which case the * suffix {@code ".tmp"} will be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1934,7 +1945,9 @@ public class File * Compares two abstract pathnames lexicographically. The ordering * defined by this method depends upon the underlying system. On UNIX * systems, alphabetic case is significant in comparing pathnames; on - * Microsoft Windows systems it is not. + * Microsoft Windows systems it is not. This method only compares the + * abstract pathnames; it does not access the file system and the file is + * not required to exist. * * @param pathname The abstract pathname to be compared to this abstract * pathname @@ -1958,11 +1971,9 @@ public class File * abstract pathname. Whether or not two abstract * pathnames are equal depends upon the underlying operating system. * On UNIX systems, alphabetic case is significant in comparing pathnames; - * on Microsoft Windows systems it is not. - * - * @apiNote This method only tests whether the abstract pathnames are equal; - * it does not access the file system and the file is not required - * to exist. + * on Microsoft Windows systems it is not. This method only tests whether + * the abstract pathnames are equal; it does not access the file system and + * the file is not required to exist. * * @param obj The object to be compared with this abstract pathname * From b7b64bb6c800b45e32ff37b1b92b5927a3b3fb56 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 4 Sep 2025 22:35:21 +0000 Subject: [PATCH 372/471] 8365937: post_method_exit might incorrectly set was_popped_by_exception and value in the middle of stack unwinding Reviewed-by: dholmes, pchilanomate --- src/hotspot/share/prims/jvmtiExport.cpp | 29 ++-- .../TestMethodExitWithPendingException.java | 58 ++++++++ .../libTestMethodExitWithPendingException.cpp | 126 ++++++++++++++++++ .../TestPoppedByException.java | 50 +++++++ .../libTestPoppedByException.cpp | 86 ++++++++++++ 5 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 26284b41ef0..8c10a371e5a 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1836,25 +1836,20 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur return; } - // return a flag when a method terminates by throwing an exception - // i.e. if an exception is thrown and it's not caught by the current method - bool exception_exit = state->is_exception_detected() && !state->is_exception_caught(); Handle result; jvalue value; value.j = 0L; if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { - // if the method hasn't been popped because of an exception then we populate - // the return_value parameter for the callback. At this point we only have - // the address of a "raw result" and we just call into the interpreter to - // convert this into a jvalue. - if (!exception_exit) { - oop oop_result; - BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); - if (is_reference_type(type)) { - result = Handle(thread, oop_result); - value.l = JNIHandles::make_local(thread, result()); - } + // At this point we only have the address of a "raw result" and + // we just call into the interpreter to convert this into a jvalue. + oop oop_result; + BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); + assert(type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, + "Stack shouldn't be empty"); + if (is_reference_type(type)) { + result = Handle(thread, oop_result); + value.l = JNIHandles::make_local(thread, result()); } } @@ -1862,12 +1857,10 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur // depth 0 as it is already late in the method exiting dance. state->set_top_frame_is_exiting(); - // Deferred transition to VM, so we can stash away the return oop before GC - // Note that this transition is not needed when throwing an exception, because - // there is no oop to retain. + // Deferred transition to VM, so we can stash away the return oop before GC. JavaThread* current = thread; // for JRT_BLOCK JRT_BLOCK - post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value); + post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); JRT_BLOCK_END // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava desctructor. Now it is safe to allow diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java new file mode 100644 index 00000000000..ebeb157d633 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/TestMethodExitWithPendingException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test verifies that MethodExit event is correctly posted + * if method is called while there is a pending exception on this thread. + * + * @bug 8365937 + * @run main/othervm/native -agentlib:TestMethodExitWithPendingException TestMethodExitWithPendingException + */ +public class TestMethodExitWithPendingException { + + private static native void enable(); + private static native void disableAndCheck(); + + static String exceptionExit() { + throw new RuntimeException("MyRuntimeException"); + } + + + // Called from ExceptionExit MethodExit callback via JNI. + // So MyRuntimeException is thrown already and hasn't been caught yet + // when this method is called. + static String upCall() { + return "MyNewString"; + } + + public static void main(String[] args) throws InterruptedException { + System.loadLibrary("TestMethodExitWithPendingException"); + try { + enable(); + exceptionExit(); + } catch (RuntimeException e){ + disableAndCheck(); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp new file mode 100644 index 00000000000..55a6cf059a6 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PendingException/libTestMethodExitWithPendingException.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +jvmtiEnv* jvmti_env; + +bool method_exit_posted = false; +// This method exit callback actually works only for 2 methods: +// 1) for ExceptionExit it verifies that method exit +// has been popped by exception and calls 'upCall' method using JNI. +// 2) for upCall method it verifies that event has correct +// return value and was not popped by exception. +// The event callback just exits for all other methods. +static void JNICALL +cbMethodExit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID method, + jboolean was_popped_by_exception, jvalue return_value) { + const char * mname = get_method_name(jvmti, jni, method); + if (strcmp("upCall", mname) == 0) { + if (was_popped_by_exception) { + fatal(jni, "The method's was_popped_by_exception value is incorrect."); + } + jstring upcall_result = (jstring) return_value.l; + const char *str = jni->GetStringUTFChars(upcall_result, nullptr); + if (str == nullptr) { + fatal(jni, "Failed to convert Java string to C string."); + } + if (strcmp("MyNewString", str) != 0) { + fatal(jni, "The upCall result value is incorrect."); + } + method_exit_posted = true; + } + if (strcmp("exceptionExit", mname) != 0) { + return; + } + if (!was_popped_by_exception) { + fatal(jni, "Should have was_popped_by_esxception = true."); + } + jclass main_class = jni->FindClass("TestMethodExitWithPendingException"); + if (main_class == nullptr) { + fatal(jni, "Can't find TestMethodExitWithPendingException class."); + return; + } + jmethodID upcall_method = jni->GetStaticMethodID(main_class, + "upCall", "()Ljava/lang/String;"); + if (upcall_method == nullptr) { + fatal(jni, "Can't find upCall method."); + } + // Call 'upCall' method while current thread has exception + // that has been thrown but hasn't been caught yet. + jstring upcall_result = (jstring) jni->CallStaticObjectMethod(main_class, upcall_method); + const char *str = jni->GetStringUTFChars(upcall_result, nullptr); + if (str == nullptr) { + fatal(jni, "Failed to convert Java string to C string."); + return; + } + if (strcmp("MyNewString", str) != 0) { + fatal(jni, "The upCall result value is incorrect."); + } + jni->ReleaseStringUTFChars(upcall_result, str); +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + jint res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_21); + if (res != JNI_OK) { + return JNI_ERR; + } + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof (capabilities)); + capabilities.can_generate_method_exit_events = true; + err = jvmti->AddCapabilities(&capabilities); + check_jvmti_error(err, "AddCapabilities"); + jvmtiEventCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof (callbacks)); + callbacks.MethodExit = &cbMethodExit; + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + jvmti_env = jvmti; + return JNI_OK; +} + + +extern "C" { + +JNIEXPORT void JNICALL +Java_TestMethodExitWithPendingException_enable(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thread); +} + + +JNIEXPORT void JNICALL +Java_TestMethodExitWithPendingException_disableAndCheck(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thread); + if (!method_exit_posted) { + fatal(jni, "Failed to post method exit event."); + } +} + +} // extern "C" diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java new file mode 100644 index 00000000000..2ea3e0fc27b --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/TestPoppedByException.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @run main/othervm/native -agentlib:TestPoppedByException TestPoppedByException + */ +public class TestPoppedByException { + + private static native void enable(); + private static native void disableAndCheck(); + + static String exceptionExit() { + throw new RuntimeException("MyRuntimeException"); + } + + static String exceptionExitOuter() { + return exceptionExit(); + } + + public static void main(String[] args) throws InterruptedException { + System.loadLibrary("TestPoppedByException"); + try { + enable(); + exceptionExitOuter(); + } catch (RuntimeException e){ + disableAndCheck(); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp new file mode 100644 index 00000000000..645057e24eb --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/MethodExit/PoppedByException/libTestPoppedByException.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +jvmtiEnv* jvmti_env; +bool method_exit_posted = false; +static void JNICALL +cbMethodExit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID method, + jboolean was_popped_by_exception, jvalue return_value) { + const char * mname = get_method_name(jvmti, jni, method); + if (strcmp("exceptionExitOuter", mname) == 0) { + if (!was_popped_by_exception) { + fatal(jni, "The method's was_popped_by_exception value is incorrect."); + } + if (return_value.l != nullptr) { + fatal(jni, "return_value should be nullptr."); + } + method_exit_posted = true; + } +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + jint res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_21); + if (res != JNI_OK) { + return JNI_ERR; + } + jvmtiError err = JVMTI_ERROR_NONE; + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof (capabilities)); + capabilities.can_generate_method_exit_events = true; + err = jvmti->AddCapabilities(&capabilities); + check_jvmti_error(err, "AddCapabilities"); + jvmtiEventCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof (callbacks)); + callbacks.MethodExit = &cbMethodExit; + err = jvmti->SetEventCallbacks(&callbacks, (int) sizeof (jvmtiEventCallbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + jvmti_env = jvmti; + return JNI_OK; +} + + +extern "C" { +JNIEXPORT void JNICALL +Java_TestPoppedByException_enable(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thread); +} + + +JNIEXPORT void JNICALL +Java_TestPoppedByException_disableAndCheck(JNIEnv *jni, jclass clazz) { + jthread thread = get_current_thread(jvmti_env, jni); + jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thread); + if (!method_exit_posted) { + fatal(jni, "Failed to post method exit event."); + } + printf("The expected method_exit posted.\n"); +} + +} From 40a602520ba1a4682213b74e6f2a6f5a6e35d839 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Fri, 5 Sep 2025 00:26:44 +0000 Subject: [PATCH 373/471] 8364735: [asan] heap-use-after-free error detected in defaultStream::writer during VM shutdown Reviewed-by: jsjolen, stuefe --- src/hotspot/share/utilities/ostream.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 532e540af9a..5e339a700cb 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -992,9 +992,13 @@ void ostream_exit() { if (tmp != &tty_preinit_stream && tmp != defaultStream::instance) { delete tmp; } - delete defaultStream::instance; - xtty = nullptr; + // Keep xtty usable as long as possible by ensuring we null it out before + // deleting anything. + defaultStream* ds = defaultStream::instance; defaultStream::instance = nullptr; + xtty = nullptr; + OrderAccess::fence(); // force visibility to concurrently executing threads + delete ds; } // ostream_abort() is called by os::abort() when VM is about to die. From 0d7f8f83c7a674f5da4b93d66a24f9ce5ba46011 Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Fri, 5 Sep 2025 06:13:44 +0000 Subject: [PATCH 374/471] 8366747: RISC-V: Improve VerifyMethodHandles for method handle linkers Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 55 +++++++++++++++++-- src/hotspot/cpu/riscv/methodHandles_riscv.hpp | 4 +- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index 39b6737631d..d770999df96 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm, void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {} +void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) { + BLOCK_COMMENT("verify_method {"); + __ verify_method_ptr(method); + if (VerifyMethodHandles) { + Label L_ok; + assert_different_registers(method, t0, t1); + const Register method_holder = t1; + __ load_method_holder(method_holder, method); + + switch (iid) { + case vmIntrinsicID::_invokeBasic: + // Require compiled LambdaForm class to be fully initialized. + __ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ mv(t1, InstanceKlass::fully_initialized); + __ beq(t0, t1, L_ok); + break; + case vmIntrinsicID::_linkToStatic: + __ clinit_barrier(method_holder, t0, &L_ok); + break; + + case vmIntrinsicID::_linkToVirtual: + case vmIntrinsicID::_linkToSpecial: + case vmIntrinsicID::_linkToInterface: + // Class initialization check is too strong here. Just ensure that class initialization has been initiated. + __ lbu(t0, Address(method_holder, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ mv(t1, InstanceKlass::being_initialized); + __ bge(t0, t1, L_ok); + + // init_state check failed, but it may be an abstract interface method + __ lhu(t0, Address(method, Method::access_flags_offset())); + __ test_bit(t1, t0, exact_log2(JVM_ACC_ABSTRACT)); + __ bnez(t1, L_ok); + break; + + default: + fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); + } + + // Method holder init state check failed for a concrete method. + __ stop("Method holder klass is not initialized"); + __ BIND(L_ok); + } + BLOCK_COMMENT("} verify_method"); +} #endif //ASSERT void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry) { + bool for_compiler_entry, vmIntrinsics::ID iid) { assert(method == xmethod, "interpreter calling convention"); Label L_no_such_method; __ beqz(xmethod, L_no_such_method); - __ verify_method_ptr(method); + verify_method(_masm, method, iid); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; @@ -158,7 +204,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, __ BIND(L); } - jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); + jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic); BLOCK_COMMENT("} jump_to_lambda_form"); } @@ -437,8 +483,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, // After figuring out which concrete method to call, jump into it. // Note that this works in the interpreter with no data motion. // But the compiled version will require that r2_recv be shifted out. - __ verify_method_ptr(xmethod); - jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry); + jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry, iid); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.hpp b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp index 6017b26c66d..ffc3b3ab676 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.hpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp @@ -39,6 +39,8 @@ public: Register obj, vmClassID klass_id, const char* error_message = "wrong klass") NOT_DEBUG_RETURN; + static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN; + static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle), "reference is a MH"); @@ -49,7 +51,7 @@ public: // Similar to InterpreterMacroAssembler::jump_from_interpreted. // Takes care of special dispatch from single stepping too. static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry); + bool for_compiler_entry, vmIntrinsics::ID iid); static void jump_to_lambda_form(MacroAssembler* _masm, Register recv, Register method_temp, From a2f8d3c4c25fdadf378313ef52185dceee98773d Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 5 Sep 2025 06:40:33 +0000 Subject: [PATCH 375/471] 8366765: [REDO] Rename JavaLangAccess::*NoRepl methods Reviewed-by: rriggs, liach, alanb --- .../share/classes/java/lang/String.java | 338 ++++++++++++------ .../share/classes/java/lang/System.java | 16 +- .../share/classes/java/nio/file/Files.java | 4 +- .../share/classes/java/util/zip/ZipCoder.java | 12 +- .../jdk/internal/access/JavaLangAccess.java | 25 +- .../jdk/internal/foreign/StringSupport.java | 6 +- .../unix/classes/sun/nio/fs/UnixPath.java | 2 +- .../{NoReplTest.java => OrThrowTest.java} | 20 +- 8 files changed, 273 insertions(+), 150 deletions(-) rename test/jdk/java/lang/String/{NoReplTest.java => OrThrowTest.java} (79%) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 15b8e98369e..24ead22e283 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -604,14 +604,14 @@ public final class String } byte[] utf16 = StringUTF16.newBytesFor(length); StringLatin1.inflate(latin1, 0, utf16, 0, dp); - dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp, true); + dp = decodeUTF8_UTF16(latin1, sp, length, utf16, dp); if (dp != length) { utf16 = Arrays.copyOf(utf16, dp << 1); } return new String(utf16, UTF16); } else { // !COMPACT_STRINGS byte[] dst = StringUTF16.newBytesFor(length); - int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } @@ -688,13 +688,25 @@ public final class String } } - /* - * Throws iae, instead of replacing, if malformed or unmappable. - * The byte array can be exclusively used to construct - * the string and is not modified or used for any other purpose. + /** + * {@return a new string by decoding from the given UTF-8 bytes array} + *

            + * WARNING: The caller of this method is assumed to have relinquished + * and transferred the ownership of the byte array. It can thus be + * exclusively used to construct the {@code String}. + * + * @param bytes byte array containing UTF-8 encoded characters + * @param offset the index of the first byte to decode + * @param length the number of bytes to decode + * @throws NullPointerException If {@code bytes} is null + * @throws StringIndexOutOfBoundsException If {@code offset} is negative, + * {@code length} is negative, or {@code offset} is greater than + * {@code bytes.length - length} + * @throws CharacterCodingException for malformed input or unmappable characters */ - private static String newStringUTF8NoRepl(byte[] bytes, int offset, int length) { - checkBoundsOffCount(offset, length, bytes.length); + private static String newStringUTF8OrThrow(byte[] bytes, int offset, int length) + throws CharacterCodingException { + checkBoundsOffCount(offset, length, bytes.length); // Implicit null check on `bytes` if (length == 0) { return ""; } @@ -745,10 +757,10 @@ public final class String StringLatin1.inflate(dst, 0, buf, 0, dp); dst = buf; } - dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, sl, dst, dp); } else { // !COMPACT_STRINGS dst = StringUTF16.newBytesFor(length); - dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); + dp = decodeUTF8_UTF16OrThrow(bytes, offset, offset + length, dst, 0); } if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); @@ -783,27 +795,16 @@ public final class String * @param cs charset the byte array encoded in * * @throws CharacterCodingException for malformed input or unmappable characters + * @throws NullPointerException If {@code src} or {@code cs} is null */ - static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { - try { - return newStringNoRepl1(src, cs); - } catch (IllegalArgumentException e) { - //newStringNoRepl1 throws IAE with MalformedInputException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof MalformedInputException mie) { - throw mie; - } - throw (CharacterCodingException)cause; - } - } - - private static String newStringNoRepl1(byte[] src, Charset cs) { - int len = src.length; + static String newStringOrThrow(byte[] src, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + int len = src.length; // Implicit null check on `src` if (len == 0) { return ""; } if (cs == UTF_8.INSTANCE) { - return newStringUTF8NoRepl(src, 0, src.length); + return newStringUTF8OrThrow(src, 0, src.length); } if (cs == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) @@ -816,7 +817,7 @@ public final class String return new String(src, LATIN1); return new String(StringLatin1.inflate(src, 0, src.length), UTF16); } else { - throwMalformed(src); + throw malformedASCII(src); } } @@ -831,13 +832,7 @@ public final class String } int en = scale(len, cd.maxCharsPerByte()); char[] ca = new char[en]; - int caLen; - try { - caLen = decodeWithDecoder(cd, ca, src, 0, src.length); - } catch (CharacterCodingException x) { - // throw via IAE - throw new IllegalArgumentException(x); - } + int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); byte coder = StringUTF16.coderFromArrayLen(val, caLen); @@ -874,7 +869,7 @@ public final class String private static byte[] encode(Charset cs, byte coder, byte[] val) { if (cs == UTF_8.INSTANCE) { - return encodeUTF8(coder, val, true); + return encodeUTF8(coder, val); } if (cs == ISO_8859_1.INSTANCE) { return encode8859_1(coder, val); @@ -882,13 +877,30 @@ public final class String if (cs == US_ASCII.INSTANCE) { return encodeASCII(coder, val); } - return encodeWithEncoder(cs, coder, val, true); + return encodeWithEncoder(cs, coder, val, null); } - private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with the encoder of {@code + * cs}} + * + * @param cs a charset to obtain the encoder from + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeWithEncoder( + Charset cs, byte coder, byte[] val, Class exClass) + throws E { CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); + boolean doReplace = exClass == null; // fastpath with ArrayEncoder implies `doReplace`. if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible @@ -930,7 +942,9 @@ public final class String cr.throwException(); } catch (CharacterCodingException x) { if (!doReplace) { - throw new IllegalArgumentException(x); + @SuppressWarnings("unchecked") + E cce = (E) x; + throw cce; } else { throw new Error(x); } @@ -938,60 +952,69 @@ public final class String return trimArray(ba, bb.position()); } - /* - * Throws iae, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} + * + * @param s the string to encode + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesUTF8NoRepl(String s) { - return encodeUTF8(s.coder(), s.value(), false); + static byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return encodeUTF8OrThrow(s.coder(), s.value()); // Implicit null check on `s` } private static boolean isASCII(byte[] src) { return !StringCoding.hasNegatives(src, 0, src.length); } - /* - * Throws CCE, instead of replacing, if unmappable. + /** + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} + *

            + * WARNING: This method returns the {@code byte[]} backing the provided + * {@code String}, if the input is ASCII. Hence, the returned byte array + * must not be modified. + * + * @param s the string to encode + * @param cs the charset + * @throws NullPointerException If {@code s} or {@code cs} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - static byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - try { - return getBytesNoRepl1(s, cs); - } catch (IllegalArgumentException e) { - //getBytesNoRepl1 throws IAE with UnmappableCharacterException or CCE as the cause - Throwable cause = e.getCause(); - if (cause instanceof UnmappableCharacterException) { - throw (UnmappableCharacterException)cause; - } - throw (CharacterCodingException)cause; - } - } - - private static byte[] getBytesNoRepl1(String s, Charset cs) { - byte[] val = s.value(); + static byte[] getBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + Objects.requireNonNull(cs); + byte[] val = s.value(); // Implicit null check on `s` byte coder = s.coder(); if (cs == UTF_8.INSTANCE) { if (coder == LATIN1 && isASCII(val)) { return val; } - return encodeUTF8(coder, val, false); + return encodeUTF8OrThrow(coder, val); } if (cs == ISO_8859_1.INSTANCE) { if (coder == LATIN1) { return val; } - return encode8859_1(coder, val, false); + return encode8859_1OrThrow(coder, val); } if (cs == US_ASCII.INSTANCE) { if (coder == LATIN1) { if (isASCII(val)) { return val; } else { - throwUnmappable(val); + throw unmappableASCII(val); } } } - return encodeWithEncoder(cs, coder, val, false); + return encodeWithEncoder(cs, coder, val, CharacterCodingException.class); } + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with US-ASCII} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + */ private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { int positives = StringCoding.countPositives(val, 0, val.length); @@ -1031,10 +1054,26 @@ public final class String } private static byte[] encode8859_1(byte coder, byte[] val) { - return encode8859_1(coder, val, true); + return encode8859_1(coder, val, null); } - private static byte[] encode8859_1(byte coder, byte[] val, boolean doReplace) { + private static byte[] encode8859_1OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encode8859_1(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with ISO-8859-1} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encode8859_1(byte coder, byte[] val, Class exClass) throws E { if (coder == LATIN1) { return val.clone(); } @@ -1048,8 +1087,8 @@ public final class String sp = sp + ret; dp = dp + ret; if (ret != len) { - if (!doReplace) { - throwUnmappable(sp); + if (exClass != null) { + throw String.unmappableCharacterException(sp); } char c = StringUTF16.getChar(val, sp++); if (Character.isHighSurrogate(c) && sp < sl && @@ -1143,7 +1182,26 @@ public final class String ((byte) 0x80 << 0)))); } - private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp, boolean doReplace) { + private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int dp) { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, null); + } + + private static int decodeUTF8_UTF16OrThrow( + byte[] src, int sp, int sl, byte[] dst, int dp) + throws MalformedInputException { + return decodeUTF8_UTF16(src, sp, sl, dst, dp, MalformedInputException.class); + } + + /** + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static int decodeUTF8_UTF16( + byte[] src, int sp, int sl, byte[] dst, int dp, Class exClass) + throws E { while (sp < sl) { int b1 = src[sp++]; if (b1 >= 0) { @@ -1152,8 +1210,8 @@ public final class String if (sp < sl) { int b2 = src[sp++]; if (isNotContinuation(b2)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); sp--; @@ -1162,8 +1220,8 @@ public final class String } continue; } - if (!doReplace) { - throwMalformed(sp, 1); // underflow() + if (exClass != null) { + throw String.malformedInputException(sp, 1); // underflow() } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1172,8 +1230,8 @@ public final class String int b2 = src[sp++]; int b3 = src[sp++]; if (isMalformed3(b1, b2, b3)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); sp -= 3; @@ -1181,8 +1239,8 @@ public final class String } else { char c = decode3(b1, b2, b3); if (Character.isSurrogate(c)) { - if (!doReplace) { - throwMalformed(sp - 3, 3); + if (exClass != null) { + throw String.malformedInputException(sp - 3, 3); } StringUTF16.putChar(dst, dp++, REPL); } else { @@ -1192,14 +1250,14 @@ public final class String continue; } if (sp < sl && isMalformed3_2(b1, src[sp])) { - if (!doReplace) { - throwMalformed(sp - 1, 2); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 2); } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp, 1); + if (exClass != null) { + throw String.malformedInputException(sp, 1); } StringUTF16.putChar(dst, dp++, REPL); break; @@ -1211,8 +1269,8 @@ public final class String int uc = decode4(b1, b2, b3, b4); if (isMalformed4(b2, b3, b4) || !Character.isSupplementaryCodePoint(uc)) { // shortest form check - if (!doReplace) { - throwMalformed(sp - 4, 4); + if (exClass != null) { + throw String.malformedInputException(sp - 4, 4); } StringUTF16.putChar(dst, dp++, REPL); sp -= 4; @@ -1225,14 +1283,14 @@ public final class String } b1 &= 0xff; if (b1 > 0xf4 || sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - if (!doReplace) { - throwMalformed(sp - 1, 1); // or 2 + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); // or 2 } StringUTF16.putChar(dst, dp++, REPL); continue; } - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } sp++; StringUTF16.putChar(dst, dp++, REPL); @@ -1241,8 +1299,8 @@ public final class String } break; } else { - if (!doReplace) { - throwMalformed(sp - 1, 1); + if (exClass != null) { + throw String.malformedInputException(sp - 1, 1); } StringUTF16.putChar(dst, dp++, REPL); } @@ -1284,29 +1342,76 @@ public final class String return 3; } - private static void throwMalformed(int off, int nb) { - String msg = "malformed input off : " + off + ", length : " + nb; - throw new IllegalArgumentException(msg, new MalformedInputException(nb)); + /** + * {@return a new {@link MalformedInputException} for the sub-range denoted + * by specified {@code offset} and {@code length}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E malformedInputException(int offset, int length) { + MalformedInputException mie = new MalformedInputException(length); + String msg = "malformed input offset : " + offset + ", length : " + length; + mie.initCause(new IllegalArgumentException(msg)); + return (E) mie; } - private static void throwMalformed(byte[] val) { + /** + * {@return a new {@link MalformedInputException} for the given malformed + * ASCII string} + */ + private static MalformedInputException malformedASCII(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - throwMalformed(dp, 1); + return malformedInputException(dp, 1); } - private static void throwUnmappable(int off) { - String msg = "malformed input off : " + off + ", length : 1"; - throw new IllegalArgumentException(msg, new UnmappableCharacterException(1)); + /** + * {@return a new {@link UnmappableCharacterException} at given {@code offset}} + * + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + @SuppressWarnings("unchecked") + private static E unmappableCharacterException(int offset) { + UnmappableCharacterException uce = new UnmappableCharacterException(1); + String msg = "malformed input offset : " + offset + ", length : 1"; + uce.initCause(new IllegalArgumentException(msg, uce)); + return (E) uce; } - private static void throwUnmappable(byte[] val) { + /** + * {@return a new {@link UnmappableCharacterException} for the given + * malformed ASCII string} + */ + private static UnmappableCharacterException unmappableASCII(byte[] val) { int dp = StringCoding.countPositives(val, 0, val.length); - throwUnmappable(dp); + return unmappableCharacterException(dp); } - private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { + private static byte[] encodeUTF8(byte coder, byte[] val) { + return encodeUTF8(coder, val, null); + } + + private static byte[] encodeUTF8OrThrow(byte coder, byte[] val) throws UnmappableCharacterException { + return encodeUTF8(coder, val, UnmappableCharacterException.class); + } + + /** + * {@return the byte array obtained by first decoding {@code val} with + * {@code coder}, and then encoding the result with UTF-8} + * + * @param coder a coder to decode {@code val} with + * @param val a string byte array encoded with {@code coder} + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8(byte coder, byte[] val, Class exClass) throws E { if (coder == UTF16) { - return encodeUTF8_UTF16(val, doReplace); + return encodeUTF8_UTF16(val, exClass); } int positives = StringCoding.countPositives(val, 0, val.length); @@ -1334,13 +1439,24 @@ public final class String return Arrays.copyOf(dst, dp); } - private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { + /** + * {@return the byte array obtained by first decoding {@code val} with + * UTF-16, and then encoding the result with UTF-8} + * + * @param val a string byte array encoded with UTF-16 + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting replaced. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception + */ + private static byte[] encodeUTF8_UTF16(byte[] val, Class exClass) throws E { int dp = 0; int sp = 0; int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; if (allocLen > (long)Integer.MAX_VALUE) { throw new OutOfMemoryError("Required length exceeds implementation limit"); } @@ -1369,10 +1485,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dst[dp++] = '?'; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dst[dp++] = (byte)(0xf0 | ((uc >> 18))); @@ -1396,10 +1512,14 @@ public final class String /** * {@return the exact size required to UTF_8 encode this UTF16 string} - * @param val UTF16 encoded byte array - * @param doReplace true to replace unmappable characters + * + * @param exClass The exception class where any non-null value indicates + * malformed or unmappable bytes will result in an exception + * to be thrown instead of getting discarded. + * @param The exception type parameter to enable callers to avoid + * having to declare the exception */ - private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { + private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { long dp = 0L; int sp = 0; int sl = val.length >> 1; @@ -1418,10 +1538,10 @@ public final class String uc = Character.toCodePoint(c, c2); } if (uc < 0) { - if (doReplace) { + if (exClass == null) { dp++; } else { - throwUnmappable(sp - 1); + throw String.unmappableCharacterException(sp - 1); } } else { dp += 4; diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index a40c27bbf47..bb1775fbc6b 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2124,6 +2124,7 @@ public final class System { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { return StringCoding.countNonZeroAscii(s); } @@ -2132,21 +2133,24 @@ public final class System { return String.newStringWithLatin1Bytes(bytes); } - public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { - return String.newStringNoRepl(bytes, cs); + public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException { + return String.newStringOrThrow(bytes, cs); } + public char uncheckedGetUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } + public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) { StringUTF16.putChar(bytes, index, ch); } - public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException { - return String.getBytesNoRepl(s, cs); + + public byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException { + return String.getBytesOrThrow(s, cs); } - public byte[] getBytesUTF8NoRepl(String s) { - return String.getBytesUTF8NoRepl(s); + public byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException { + return String.getBytesUTF8OrThrow(s); } public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) { diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index f8278fa2642..80c771f5306 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public final class Files { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.uncheckedNewStringNoRepl(ba, cs); + return JLA.uncheckedNewStringOrThrow(ba, cs); } /** @@ -3362,7 +3362,7 @@ public final class Files { Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesOrThrow(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 8b812eba202..b9906d348e3 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -256,7 +256,7 @@ class ZipCoder { try { // Copy subrange for exclusive use by the string being created byte[] bytes = Arrays.copyOfRange(ba, off, off + length); - return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8); + return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8); } catch (CharacterCodingException cce) { throw new IllegalArgumentException(cce); } @@ -264,7 +264,11 @@ class ZipCoder { @Override byte[] getBytes(String s) { - return JLA.getBytesUTF8NoRepl(s); + try { + return JLA.getBytesUTF8OrThrow(s); + } catch (CharacterCodingException cce) { + throw new IllegalArgumentException(cce); + } } @Override @@ -278,8 +282,6 @@ class ZipCoder { // Non-ASCII, fall back to decoding a String // We avoid using decoder() here since the UTF8ZipCoder is // shared and that decoder is not thread safe. - // We use the JLA.newStringUTF8NoRepl variant to throw - // exceptions eagerly when opening ZipFiles return hash(toString(a, off, len)); } int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0); @@ -296,7 +298,7 @@ class ZipCoder { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index aa5b6e438f5..e529e8ba350 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -45,7 +45,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; -import java.util.function.BiFunction; import java.util.stream.Stream; import jdk.internal.loader.NativeLibraries; @@ -332,7 +331,7 @@ public interface JavaLangAccess { /** * Constructs a new {@code String} by decoding the specified byte array - * using the specified {@linkplain java.nio.charset.Charset charset}. + * using the specified {@code Charset}. *

            * WARNING: The caller of this method shall relinquish and transfer the * ownership of the byte array to the callee, since the latter will not @@ -342,26 +341,24 @@ public interface JavaLangAccess { * @param cs the Charset * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes + * @throws NullPointerException If {@code bytes} or {@code cs} is null */ - String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * Encode the given string into a sequence of bytes using the specified - * {@linkplain java.nio.charset.Charset charset}. + * {@return the sequence of bytes obtained by encoding the given string in + * the specified {@code Charset}} *

            * WARNING: This method returns the {@code byte[]} backing the provided * {@code String}, if the input is ASCII. Hence, the returned byte array * must not be modified. - *

            - * This method throws {@code CharacterCodingException} instead of replacing - * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset - * @return the encoded bytes + * @throws NullPointerException If {@code s} or {@code cs} is null * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException; /** * Get the {@code char} at {@code index} in a {@code byte[]} in internal @@ -387,13 +384,13 @@ public interface JavaLangAccess { void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** - * Encode the given string into a sequence of bytes using utf8. + * {@return the sequence of bytes obtained by encoding the given string in UTF-8} * * @param s the string to encode - * @return the encoded bytes in utf8 - * @throws IllegalArgumentException for malformed surrogates + * @throws NullPointerException If {@code s} is null + * @throws CharacterCodingException For malformed input or unmappable characters */ - byte[] getBytesUTF8NoRepl(String s); + byte[] getBytesUTF8OrThrow(String s) throws CharacterCodingException; /** * Inflated copy from {@code byte[]} to {@code char[]}, as defined by diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index 2f842810aa7..bb6cb2d3915 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -73,7 +73,7 @@ public final class StringSupport { final byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); @@ -92,7 +92,7 @@ public final class StringSupport { byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); @@ -111,7 +111,7 @@ public final class StringSupport { byte[] bytes = new byte[len]; MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, len); try { - return JAVA_LANG_ACCESS.uncheckedNewStringNoRepl(bytes, charset); + return JAVA_LANG_ACCESS.uncheckedNewStringOrThrow(bytes, charset); } catch (CharacterCodingException _) { // use replacement characters for malformed input return new String(bytes, charset); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 5dfc73f57aa..5a77bb0b935 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -126,7 +126,7 @@ class UnixPath implements Path { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesOrThrow(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/test/jdk/java/lang/String/NoReplTest.java b/test/jdk/java/lang/String/OrThrowTest.java similarity index 79% rename from test/jdk/java/lang/String/NoReplTest.java rename to test/jdk/java/lang/String/OrThrowTest.java index 1817a1ffe73..340a190b4eb 100644 --- a/test/jdk/java/lang/String/NoReplTest.java +++ b/test/jdk/java/lang/String/OrThrowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -24,8 +24,8 @@ /* * @test * @bug 8286287 8288589 - * @summary Tests for *NoRepl() shared secret methods. - * @run testng NoReplTest + * @summary Tests for *OrThrow() shared secret methods. + * @run testng OrThrowTest * @modules jdk.charsets */ @@ -39,17 +39,17 @@ import static java.nio.charset.StandardCharsets.UTF_16; import org.testng.annotations.Test; @Test -public class NoReplTest { +public class OrThrowTest { private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); /** - * Verifies newStringNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.readString()` method. + * Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.readString()} method. */ @Test - public void newStringNoReplTest() throws IOException { + public void uncheckedNewStringOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try (var fos = Files.newOutputStream(f)) { fos.write(MALFORMED_UTF16); @@ -67,11 +67,11 @@ public class NoReplTest { } /** - * Verifies getBytesNoRepl() throws a CharacterCodingException. - * The method is invoked by `Files.writeString()` method. + * Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}. + * The method is invoked by {@code Files.writeString()} method. */ @Test - public void getBytesNoReplTest() throws IOException { + public void uncheckedGetBytesOrThrowTest() throws IOException { var f = Files.createTempFile(null, null); try { Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); From e6fa8aae6168ea5a8579cd0a38209ca71c32e704 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 5 Sep 2025 08:46:56 +0000 Subject: [PATCH 376/471] 8366845: C2 SuperWord: wrong VectorCast after VectorReinterpret with swapped src/dst type Reviewed-by: thartmann, galder, vlivanov --- src/hotspot/share/opto/vtransform.cpp | 2 +- .../superword/TestReinterpretAndCast.java | 225 ++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index af4cb345e14..2f77c1c2e37 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -813,7 +813,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyStat } else if (VectorNode::is_reinterpret_opcode(opc)) { assert(first->req() == 2 && req() == 2, "only one input expected"); const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new VectorReinterpretNode(in1, vt, in1->bottom_type()->is_vect()); + vn = new VectorReinterpretNode(in1, in1->bottom_type()->is_vect(), vt); } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { opc = Op_RShiftI; vn = VectorNode::make(opc, in1, in2, vlen, bt); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java new file mode 100644 index 00000000000..a72126ebad5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReinterpretAndCast.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8366845 + * @summary Test Reinterpret with Cast cases, where the order of the src/dst types of Reinterpret matters. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestReinterpretAndCast + */ + +package compiler.loopopts.superword; + +import jdk.incubator.vector.Float16; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.*; + +public class TestReinterpretAndCast { + static int SIZE = 1028 * 8; + + public static final Generator GEN_FLOAT = Generators.G.floats(); + public static final Generator GEN_DOUBLE = Generators.G.doubles(); + private static final Generator GEN_FLOAT16 = Generators.G.float16s(); + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + static long[] fillWithDoubles(long[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = Double.doubleToLongBits(GEN_DOUBLE.next()); + } + return a; + } + + static int[] fillWithFloats(int[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = Float.floatToIntBits(GEN_FLOAT.next()); + } + return a; + } + + static short[] fillWithFloat16s(short[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = GEN_FLOAT16.next(); + } + return a; + } + + static void verify(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + long aa = Double.doubleToLongBits(Double.longBitsToDouble(a[i])); + long bb = Double.doubleToLongBits(Double.longBitsToDouble(b[i])); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + static void verify(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + int aa = Float.floatToIntBits(Float.intBitsToFloat(a[i])); + int bb = Float.floatToIntBits(Float.intBitsToFloat(b[i])); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + static void verify(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + // Make sure we remove non-canonical NaN's. + int aa = Float.floatToIntBits(Float16.shortBitsToFloat16(a[i]).floatValue()); + int bb = Float.floatToIntBits(Float16.shortBitsToFloat16(b[i]).floatValue()); + if (aa != bb) { + throw new RuntimeException("Wrong value: " + aa + " vs " + bb + " - " + a[i] + " vs " + b[i]); + } + } + } + + // -------------- test1 + public static long[] test1_in = fillWithDoubles(new long[SIZE]); + public static int[] test1_gold = new int[SIZE]; + public static int[] test1_test = new int[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test1(test1_in, test1_gold); } + + @Setup + public static Object[] setup1() { + return new Object[] {test1_in, test1_test}; + } + + @Test + @Arguments(setup = "setup1") + @IR(counts = {IRNode.LOAD_VECTOR_L, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_double, max_long)", "> 0", + IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_double, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have both L2D and F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test1(long[] a, int[] b) { + for (int i = 0; i < SIZE; i++) { + long v0 = a[i]; + double v1 = Double.longBitsToDouble(v0); + // Reinterpret: long -> double + // Before fix: double -> long (no direct problem) + float v2 = (float)v1; + // Cast: double -> float + // Before fix: long -> float (wrong!) + int v3 = Float.floatToRawIntBits(v2); + b[i] = v3; + } + } + + @Check(test = "test1") + public static void check1() { + verify(test1_test, test1_gold); + } + + // -------------- test2 + public static int[] test2_in = fillWithFloats(new int[SIZE]); + public static short[] test2_gold = new short[SIZE]; + public static short[] test2_test = new short[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test2(test2_in, test2_gold); } + + @Setup + public static Object[] setup2() { + return new Object[] {test2_in, test2_test}; + } + + @Test + @Arguments(setup = "setup2") + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_int, max_float, max_short)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least I2F + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test2(int[] a, short[] b) { + for (int i = 0; i < SIZE; i++) { + int v0 = a[i]; + float v1 = Float.intBitsToFloat(v0); + // Reinterpret: int -> float + // Before fix: float -> int (no direct problem) + short v2 = Float.floatToFloat16(v1); + // Cast: float -> float16/short + // Before fix: int -> float16/short (wrong!) + b[i] = v2; + } + } + + @Check(test = "test2") + public static void check2() { + verify(test2_test, test2_gold); + } + + // -------------- test3 + public static short[] test3_in = fillWithFloat16s(new short[SIZE]); + public static long[] test3_gold = new long[SIZE]; + public static long[] test3_test = new long[SIZE]; + + // Esecute in interpreter, to compare to compiled results later. + static { test3(test3_in, test3_gold); } + + @Setup + public static Object[] setup3() { + return new Object[] {test3_in, test3_test}; + } + + @Test + @Arguments(setup = "setup3") + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_float, max_short, max_long)", "> 0", + IRNode.STORE_VECTOR, "> 0", + IRNode.VECTOR_REINTERPRET, "> 0"}, // We have at least F2I + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + public static void test3(short[] a, long[] b) { + for (int i = 0; i < SIZE; i++) { + short v0 = a[i]; + Float16 v1 = Float16.shortBitsToFloat16(v0); + float v2 = v1.floatValue(); + int v3 = Float.floatToRawIntBits(v2); + // Reinterpret: float -> int + // Before fix: int -> float + long v4 = v3; + // Cast: int -> long + // Before fix: float -> long (wrong!) + b[i] = v4; + } + } + + @Check(test = "test3") + public static void check3() { + verify(test3_test, test3_gold); + } +} From 0dad3f1ae8d0c35c4b7a8188ad7854d01c7cd6b4 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 5 Sep 2025 10:55:41 +0000 Subject: [PATCH 377/471] 8366893: java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java timed out on macos-aarch64 Reviewed-by: alanb, jpai --- .../Thread/virtual/stress/GetStackTraceALotWhenBlocking.java | 4 ++-- .../Thread/virtual/stress/GetStackTraceALotWhenPinned.java | 4 ++-- test/jdk/java/lang/Thread/virtual/stress/ParkALot.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java index fa4d16d9f82..733ee261b09 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java @@ -53,8 +53,8 @@ public class GetStackTraceALotWhenBlocking { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java index f68b595eed4..ef385e47e21 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -56,8 +56,8 @@ public class GetStackTraceALotWhenPinned { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; diff --git a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java index 29704fd8975..ceed243f009 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java +++ b/test/jdk/java/lang/Thread/virtual/stress/ParkALot.java @@ -49,8 +49,8 @@ public class ParkALot { public static void main(String[] args) throws Exception { int iterations; int value = Integer.parseInt(args[0]); - if (Platform.isOSX() && Platform.isX64()) { - // reduced iterations on macosx-x64 + if (Platform.isOSX()) { + // reduced iterations on macosx iterations = Math.max(value / 4, 1); } else { iterations = value; From 124fcf1d9abb6cafe34637ba357617c7c7be56c8 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 5 Sep 2025 13:31:23 +0000 Subject: [PATCH 378/471] 8233115: Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: erikj --- make/RunTests.gmk | 28 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++++++++++--------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 +++-- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 10f0a2f87ed..b44243dae76 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - )) + ) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 3cf2a4dd136..80d6b4538c8 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ + COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index d1bb0396943..97ef88932cb 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,6 +284,12 @@ else LogCmdlines = endif +# Check if the command line contains redirection, that is <, > or >>, +# and if so, return a value that is interpreted as true in a make $(if) +# construct. +is_redirect = \ + $(if $(filter < > >>, $1), true) + ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -291,21 +297,23 @@ endif # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # -# NOTE: If the command redirects stdout, the caller needs to wrap it in a -# subshell (by adding parentheses around it), otherwise the redirect to the -# subshell tee process will create a race condition where the target file may -# not be fully written when the make recipe is done. -# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: [$(strip $2)]) \ + $(call LogCmdlines, Executing: \ + [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN))]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && \ + $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN)) \ + > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index 1b4a5b76ea1..c60b49ae85f 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) + $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index e71c3cb961d..7a80bf47285 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,8 +47,9 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) - $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, \ + $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 33794d161467635eb32591fee189e5409cd2d114 Mon Sep 17 00:00:00 2001 From: Guoxiong Li Date: Fri, 5 Sep 2025 13:34:45 +0000 Subject: [PATCH 379/471] 8357188: Remove the field MemAllocator::Allocation::_overhead_limit_exceeded and the related code Reviewed-by: ayang, shade --- src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 3 +-- src/hotspot/share/gc/epsilon/epsilonHeap.hpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +-- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 3 +-- .../share/gc/parallel/parallelScavengeHeap.cpp | 13 ++++--------- .../share/gc/parallel/parallelScavengeHeap.hpp | 12 +++--------- src/hotspot/share/gc/serial/serialHeap.cpp | 3 +-- src/hotspot/share/gc/serial/serialHeap.hpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.hpp | 3 +-- src/hotspot/share/gc/shared/memAllocator.cpp | 11 +++-------- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 3 +-- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.hpp | 2 +- 14 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index 693e915b98e..c324aa9baff 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -260,8 +260,7 @@ HeapWord* EpsilonHeap::allocate_new_tlab(size_t min_size, return res; } -HeapWord* EpsilonHeap::mem_allocate(size_t size, bool *gc_overhead_limit_was_exceeded) { - *gc_overhead_limit_was_exceeded = false; +HeapWord* EpsilonHeap::mem_allocate(size_t size) { return allocate_work(size); } diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 24b43fe3541..f8aa9d7dbf1 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -85,7 +85,7 @@ public: // Allocation HeapWord* allocate_work(size_t size, bool verbose = true); - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; HeapWord* allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) override; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 618e9b055fe..de3fc0f5da5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -396,8 +396,7 @@ HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size, } HeapWord* -G1CollectedHeap::mem_allocate(size_t word_size, - bool* gc_overhead_limit_was_exceeded) { +G1CollectedHeap::mem_allocate(size_t word_size) { assert_heap_not_locked_and_not_at_safepoint(); if (is_humongous(word_size)) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 49bbcf888be..0bb16edaf78 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -442,8 +442,7 @@ private: size_t requested_size, size_t* actual_size) override; - HeapWord* mem_allocate(size_t word_size, - bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t word_size) override; // First-level mutator allocation attempt: try to allocate out of // the mutator alloc region without taking the Heap_lock. This diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 3b530895eb1..9b40475288d 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -266,19 +266,16 @@ bool ParallelScavengeHeap::requires_barriers(stackChunkOop p) const { // and the rest will not be executed. For that reason, this method loops // during failed allocation attempts. If the java heap becomes exhausted, // we rely on the size_policy object to force a bail out. -HeapWord* ParallelScavengeHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ParallelScavengeHeap::mem_allocate(size_t size) { assert(!SafepointSynchronize::is_at_safepoint(), "should not be at safepoint"); assert(Thread::current() != (Thread*)VMThread::vm_thread(), "should not be in vm thread"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); bool is_tlab = false; - return mem_allocate_work(size, is_tlab, gc_overhead_limit_was_exceeded); + return mem_allocate_work(size, is_tlab); } -HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, - bool is_tlab, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { for (uint loop_count = 0; /* empty */; ++loop_count) { // Try young-gen first. HeapWord* result = young_gen()->allocate(size); @@ -442,10 +439,8 @@ size_t ParallelScavengeHeap::unsafe_max_tlab_alloc(Thread* thr) const { } HeapWord* ParallelScavengeHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) { - bool dummy; HeapWord* result = mem_allocate_work(requested_size /* size */, - true /* is_tlab */, - &dummy); + true /* is_tlab */); if (result != nullptr) { *actual_size = requested_size; } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index b0e804edb70..bd701ae8be3 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -102,9 +102,7 @@ class ParallelScavengeHeap : public CollectedHeap { inline bool should_alloc_in_eden(size_t size) const; - HeapWord* mem_allocate_work(size_t size, - bool is_tlab, - bool* gc_overhead_limit_was_exceeded); + HeapWord* mem_allocate_work(size_t size, bool is_tlab); HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); @@ -192,12 +190,8 @@ public: MemRegion reserved_region() const { return _reserved; } HeapWord* base() const { return _reserved.start(); } - // Memory allocation. "gc_time_limit_was_exceeded" will - // be set to true if the adaptive size policy determine that - // an excessive amount of time is being spent doing collections - // and caused a null to be returned. If a null is not returned, - // "gc_time_limit_was_exceeded" has an undefined meaning. - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + // Memory allocation. + HeapWord* mem_allocate(size_t size) override; HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index f97cd4e3b70..662a6be695b 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -335,8 +335,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, bool is_tlab) { return result; } -HeapWord* SerialHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* SerialHeap::mem_allocate(size_t size) { return mem_allocate_work(size, false /* is_tlab */); } diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index f0194f1a4a2..72778981eee 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -133,7 +133,7 @@ public: size_t max_capacity() const override; - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; // Callback from VM_SerialCollectForAllocation operation. // This function does everything necessary/possible to satisfy an diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 33d2fad8bba..57bd9316731 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -162,8 +162,7 @@ class CollectedHeap : public CHeapObj { // The obj and array allocate methods are covers for these methods. // mem_allocate() should never be // called to allocate TLABs, only individual objects. - virtual HeapWord* mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) = 0; + virtual HeapWord* mem_allocate(size_t size) = 0; // Filler object utilities. static inline size_t filler_array_hdr_size(); diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index 741b0ffb020..265c01b3683 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -48,7 +48,6 @@ class MemAllocator::Allocation: StackObj { const MemAllocator& _allocator; JavaThread* _thread; oop* _obj_ptr; - bool _overhead_limit_exceeded; bool _allocated_outside_tlab; size_t _allocated_tlab_size; @@ -71,7 +70,6 @@ public: : _allocator(allocator), _thread(JavaThread::cast(allocator._thread)), // Do not use Allocation in non-JavaThreads. _obj_ptr(obj_ptr), - _overhead_limit_exceeded(false), _allocated_outside_tlab(false), _allocated_tlab_size(0) { @@ -119,7 +117,7 @@ bool MemAllocator::Allocation::check_out_of_memory() { return false; } - const char* message = _overhead_limit_exceeded ? "GC overhead limit exceeded" : "Java heap space"; + const char* message = "Java heap space"; if (!_thread->is_in_internal_oome_mark()) { // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support report_java_out_of_memory(message); @@ -133,10 +131,7 @@ bool MemAllocator::Allocation::check_out_of_memory() { message); } - oop exception = _overhead_limit_exceeded ? - Universe::out_of_memory_error_gc_overhead_limit() : - Universe::out_of_memory_error_java_heap(); - THROW_OOP_(exception, true); + THROW_OOP_(Universe::out_of_memory_error_java_heap(), true); } else { THROW_OOP_(Universe::out_of_memory_error_java_heap_without_backtrace(), true); } @@ -238,7 +233,7 @@ void MemAllocator::Allocation::notify_allocation() { HeapWord* MemAllocator::mem_allocate_outside_tlab(Allocation& allocation) const { allocation._allocated_outside_tlab = true; - HeapWord* mem = Universe::heap()->mem_allocate(_word_size, &allocation._overhead_limit_exceeded); + HeapWord* mem = Universe::heap()->mem_allocate(_word_size); if (mem == nullptr) { return mem; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b662aeb7eb7..927c9e15dc5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1094,8 +1094,7 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req return result; } -HeapWord* ShenandoahHeap::mem_allocate(size_t size, - bool* gc_overhead_limit_was_exceeded) { +HeapWord* ShenandoahHeap::mem_allocate(size_t size) { ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size); return allocate_memory(req); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index bec1235e941..eafd1b28b3a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -704,7 +704,7 @@ private: public: HeapWord* allocate_memory(ShenandoahAllocRequest& request); - HeapWord* mem_allocate(size_t size, bool* what) override; + HeapWord* mem_allocate(size_t size) override; MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) override; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 238b5b06683..ae60219139c 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -149,7 +149,7 @@ oop ZCollectedHeap::array_allocate(Klass* klass, size_t size, int length, bool d return allocator.allocate(); } -HeapWord* ZCollectedHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { +HeapWord* ZCollectedHeap::mem_allocate(size_t size) { const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(size)); return (HeapWord*)ZHeap::heap()->alloc_object(size_in_bytes); } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 3d466564b54..c124976c80f 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -76,7 +76,7 @@ public: bool requires_barriers(stackChunkOop obj) const override; oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) override; - HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override; + HeapWord* mem_allocate(size_t size) override; MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) override; From 1e90af08abb74df9ec4ab94b67deeae5c1c9fee1 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Fri, 5 Sep 2025 14:30:40 +0000 Subject: [PATCH 380/471] 8359383: Incorrect starting positions for implicitly typed variables Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 7 +- .../sun/tools/javac/parser/JavacParser.java | 27 +++--- .../com/sun/tools/javac/tree/JCTree.java | 27 ++++-- .../com/sun/tools/javac/tree/Pretty.java | 5 +- .../com/sun/tools/javac/tree/TreeCopier.java | 2 +- .../com/sun/tools/javac/tree/TreeInfo.java | 13 +-- .../com/sun/tools/javac/tree/TreeMaker.java | 5 +- .../javac/parser/DeclarationEndPositions.java | 93 +++++++++++++++---- .../tools/javac/patterns/PrettyTest.java | 10 +- test/langtools/tools/javac/tree/VarTree.java | 6 ++ .../tools/javac/tree/VarWarnPosition.java | 3 + .../tools/javac/tree/VarWarnPosition.out | 4 +- 12 files changed, 143 insertions(+), 59 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 45ece909ad7..9f32e7f6186 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1261,14 +1261,14 @@ public class Attr extends JCTree.Visitor { if (tree.init == null) { //cannot use 'var' without initializer log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit)); - tree.vartype = make.Erroneous(); + tree.vartype = make.at(tree.pos()).Erroneous(); } else { Fragment msg = canInferLocalVarType(tree); if (msg != null) { //cannot use 'var' with initializer which require an explicit target //(e.g. lambda, method reference, array initializer). log.error(tree, Errors.CantInferLocalVarType(tree.name, msg)); - tree.vartype = make.Erroneous(); + tree.vartype = make.at(tree.pos()).Erroneous(); } } } @@ -5707,6 +5707,9 @@ public class Attr extends JCTree.Visitor { private void setSyntheticVariableType(JCVariableDecl tree, Type type) { if (type.isErroneous()) { tree.vartype = make.at(tree.pos()).Erroneous(); + } else if (tree.declaredUsingVar()) { + Assert.check(tree.typePos != Position.NOPOS); + tree.vartype = make.at(tree.typePos).Type(type); } else { tree.vartype = make.at(tree.pos()).Type(type); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 4a990701315..fb8d3aaeecd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -990,10 +990,12 @@ public class JavacParser implements Parser { pattern = toP(F.at(token.pos).AnyPattern()); } else { + int varTypePos = Position.NOPOS; if (parsedType == null) { boolean var = token.kind == IDENTIFIER && token.name() == names.var; e = unannotatedType(allowVar, TYPE | NOLAMBDA); if (var) { + varTypePos = e.pos; e = null; } } else { @@ -1031,9 +1033,10 @@ public class JavacParser implements Parser { if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) { name = names.empty; } - JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null)); + JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null, + varTypePos != Position.NOPOS ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, + varTypePos)); if (e == null) { - var.startPos = pos; if (var.name == names.underscore && !allowVar) { log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed); } @@ -2175,7 +2178,8 @@ public class JavacParser implements Parser { if (param.vartype != null && restrictedTypeName(param.vartype, true) != null) { checkSourceLevel(param.pos, Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS); - param.startPos = TreeInfo.getStartPos(param.vartype); + param.declKind = JCVariableDecl.DeclKind.VAR; + param.typePos = TreeInfo.getStartPos(param.vartype); param.vartype = null; } } @@ -3815,7 +3819,7 @@ public class JavacParser implements Parser { syntaxError(token.pos, Errors.Expected(EQ)); } - int startPos = Position.NOPOS; + int varTypePos = Position.NOPOS; JCTree elemType = TreeInfo.innermostType(type, true); if (elemType.hasTag(IDENT)) { Name typeName = ((JCIdent) elemType).name; @@ -3827,19 +3831,17 @@ public class JavacParser implements Parser { reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName)); } else { declaredUsingVar = true; + varTypePos = elemType.pos; if (compound) //error - 'var' in compound local var decl reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName)); - startPos = TreeInfo.getStartPos(mods); - if (startPos == Position.NOPOS) - startPos = TreeInfo.getStartPos(type); //implicit type type = null; } } } - JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar)); - result.startPos = startPos; + JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, + declaredUsingVar ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, varTypePos)); return attach(result, dc); } @@ -3953,8 +3955,11 @@ public class JavacParser implements Parser { name = names.empty; } - return toP(F.at(pos).VarDef(mods, name, type, null, - type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var)); + boolean declaredUsingVar = type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var; + JCVariableDecl.DeclKind declKind = declaredUsingVar ? JCVariableDecl.DeclKind.VAR : + type != null ? JCVariableDecl.DeclKind.EXPLICIT : JCVariableDecl.DeclKind.IMPLICIT; + int typePos = type != null ? type.pos : pos; + return toP(F.at(pos).VarDef(mods, name, type, null, declKind, typePos)); } /** Resources = Resource { ";" Resources } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index debc10c9ff8..0436f68b9e3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1002,6 +1002,13 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { * A variable definition. */ public static class JCVariableDecl extends JCStatement implements VariableTree { + + public enum DeclKind { + EXPLICIT, // "SomeType name" + IMPLICIT, // "name" + VAR, // "var name" + } + /** variable modifiers */ public JCModifiers mods; /** variable name */ @@ -1014,17 +1021,17 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public JCExpression init; /** symbol */ public VarSymbol sym; - /** explicit start pos */ - public int startPos = Position.NOPOS; - /** declared using `var` */ - private boolean declaredUsingVar; + /** how the variable's type was declared */ + public DeclKind declKind; + /** a source code position to use for "vartype" when null (can happen if declKind != EXPLICIT) */ + public int typePos; protected JCVariableDecl(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, VarSymbol sym) { - this(mods, name, vartype, init, sym, false); + this(mods, name, vartype, init, sym, DeclKind.EXPLICIT, Position.NOPOS); } protected JCVariableDecl(JCModifiers mods, @@ -1032,19 +1039,21 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { JCExpression vartype, JCExpression init, VarSymbol sym, - boolean declaredUsingVar) { + DeclKind declKind, + int typePos) { this.mods = mods; this.name = name; this.vartype = vartype; this.init = init; this.sym = sym; - this.declaredUsingVar = declaredUsingVar; + this.declKind = declKind; + this.typePos = typePos; } protected JCVariableDecl(JCModifiers mods, JCExpression nameexpr, JCExpression vartype) { - this(mods, null, vartype, null, null, false); + this(mods, null, vartype, null, null, DeclKind.EXPLICIT, Position.NOPOS); this.nameexpr = nameexpr; if (nameexpr.hasTag(Tag.IDENT)) { this.name = ((JCIdent)nameexpr).name; @@ -1059,7 +1068,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } public boolean declaredUsingVar() { - return declaredUsingVar; + return declKind == DeclKind.VAR; } @Override diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index 919b2325ef6..d953663a6d7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -724,7 +724,10 @@ public class Pretty extends JCTree.Visitor { print("... "); print(tree.name); } else { - printExpr(tree.vartype); + if (tree.vartype == null && tree.declaredUsingVar()) + print("var"); + else + printExpr(tree.vartype); print(' '); if (tree.name.isEmpty()) { print('_'); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 9c3ed3bbcd2..9efc6a9d895 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -551,7 +551,7 @@ public class TreeCopier

            implements TreeVisitor { JCExpression vartype = copy(t.vartype, p); if (t.nameexpr == null) { JCExpression init = copy(t.init, p); - return M.at(t.pos).VarDef(mods, t.name, vartype, init); + return M.at(t.pos).VarDef(mods, t.name, vartype, init, t.declKind, t.typePos); } else { JCExpression nameexpr = copy(t.nameexpr, p); return M.at(t.pos).ReceiverVarDef(mods, nameexpr, vartype); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index ae946c5b6d6..a66dcaad851 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -610,17 +610,14 @@ public class TreeInfo { } case VARDEF: { JCVariableDecl node = (JCVariableDecl)tree; - if (node.startPos != Position.NOPOS) { - return node.startPos; - } else if (node.mods.pos != Position.NOPOS) { + if (node.mods.pos != Position.NOPOS) { return node.mods.pos; - } else if (node.vartype == null || node.vartype.pos == Position.NOPOS) { - //if there's no type (partially typed lambda parameter) - //simply return node position - return node.pos; - } else { + } else if (node.vartype != null) { return getStartPos(node.vartype); + } else if (node.typePos != Position.NOPOS) { + return node.typePos; } + break; } case BINDINGPATTERN: { JCBindingPattern node = (JCBindingPattern)tree; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 0d0852cb91b..0e71df99bdc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -237,8 +237,9 @@ public class TreeMaker implements JCTree.Factory { return tree; } - public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, boolean declaredUsingVar) { - JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declaredUsingVar); + public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, + JCVariableDecl.DeclKind declKind, int typePos) { + JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declKind, typePos); tree.pos = pos; return tree; } diff --git a/test/langtools/tools/javac/parser/DeclarationEndPositions.java b/test/langtools/tools/javac/parser/DeclarationEndPositions.java index 473d6bc2712..226b77769d1 100644 --- a/test/langtools/tools/javac/parser/DeclarationEndPositions.java +++ b/test/langtools/tools/javac/parser/DeclarationEndPositions.java @@ -49,7 +49,7 @@ import javax.tools.ToolProvider; public class DeclarationEndPositions { - public static void checkEndPosition(Class nodeType, String input, String marker) throws IOException { + public static void checkPositions(Class nodeType, String input, String markers) throws IOException { // Create source var source = new SimpleJavaFileObject(URI.create("file://T.java"), JavaFileObject.Kind.SOURCE) { @@ -71,11 +71,26 @@ public class DeclarationEndPositions { public Void scan(Tree node, Void aVoid) { if (nodeType.isInstance(node)) { JCTree tree = (JCTree)node; - int actual = TreeInfo.getEndPos(tree, unit.endPositions); - int expected = marker.indexOf('^') + 1; - if (actual != expected) { + + // Verify declaration start and end positions + int start = tree.getStartPosition(); + if (markers.charAt(start) != '<') { throw new AssertionError(String.format( - "wrong end pos %d != %d for \"%s\" @ %d", actual, expected, input, tree.pos)); + "wrong %s pos %d for \"%s\" in \"%s\"", "start", start, tree, input)); + } + int end = TreeInfo.getEndPos(tree, unit.endPositions); + if (markers.charAt(end - 1) != '>') { + throw new AssertionError(String.format( + "wrong %s pos %d for \"%s\" in \"%s\"", "end", end, tree, input)); + } + + // For variable declarations using "var", verify the "var" position + if (tree instanceof JCVariableDecl varDecl && varDecl.declaredUsingVar()) { + int vpos = varDecl.typePos; + if (!input.substring(vpos).startsWith("var")) { + throw new AssertionError(String.format( + "wrong %s pos %d for \"%s\" in \"%s\"", "var", vpos, tree, input)); + } } } return super.scan(node, aVoid); @@ -86,34 +101,74 @@ public class DeclarationEndPositions { public static void main(String... args) throws Exception { // JCModuleDecl - checkEndPosition(JCModuleDecl.class, + checkPositions(JCModuleDecl.class, "/* comment */ module fred { /* comment */ } /* comment */", - " ^ "); + " <---------------------------> "); // JCPackageDecl - checkEndPosition(JCPackageDecl.class, + checkPositions(JCPackageDecl.class, "/* comment */ package fred; /* comment */", - " ^ "); + " <-----------> "); // JCClassDecl - checkEndPosition(JCClassDecl.class, + checkPositions(JCClassDecl.class, "/* comment */ class Fred { /* comment */ } /* comment */", - " ^ "); + " <--------------------------> "); // JCMethodDecl - checkEndPosition(JCMethodDecl.class, + checkPositions(JCMethodDecl.class, "/* comment */ class Fred { void m() { /* comment */ } } /* comment */", - " ^ "); + " <------------------------> "); // JCVariableDecl - checkEndPosition(JCVariableDecl.class, + checkPositions(JCVariableDecl.class, "/* comment */ class Fred { int x; } /* comment */", - " ^ "); - checkEndPosition(JCVariableDecl.class, + " <----> "); + checkPositions(JCVariableDecl.class, "/* comment */ class Fred { int x = 123; } /* comment */", - " ^ "); - checkEndPosition(JCVariableDecl.class, + " <----------> "); + checkPositions(JCVariableDecl.class, "/* comment */ class A { try {} catch (Error err) {} } /* comment */", - " ^ "); + " <-------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class Fred { final int x = 123; } /* comment */", + " <----------------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class Fred { final int x = 123, y = 456; } /* comment */", + " <---------------->--------> "); + checkPositions(JCVariableDecl.class, + "/* comment */ class A { void m() { try {} catch (Error err) {} } } /* comment */", + " <-------> "); + + // JCVariableDecl with "var" declarations + checkPositions(JCVariableDecl.class, + "class A { void m() { var foo; } }", + " <------> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { var foo = 42; } }", + " <-----------> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { final var foo = 42; } }", + " <-----------------> "); + + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = foo -> { } } }", + " <-> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (foo) -> { } } }", + " <-> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (var foo) -> { } } }", + " <-----> "); + checkPositions(JCVariableDecl.class, + "class A { void m() { java.util.function.Consumer = (final var foo) -> { } } }", + " <-----------> "); + + checkPositions(JCVariableDecl.class, + "class A { record R(int x) { } void m() { switch (null) { case R(var x) -> {} default -> {} } } }", + " <---> <---> "); + checkPositions(JCVariableDecl.class, + "class A { record R(int x) { } void m() { switch (null) { case R(final var x) -> {} default -> {} } } }", + " <---> <---------> "); } } diff --git a/test/langtools/tools/javac/patterns/PrettyTest.java b/test/langtools/tools/javac/patterns/PrettyTest.java index 5425127e91b..5f9c74b760e 100644 --- a/test/langtools/tools/javac/patterns/PrettyTest.java +++ b/test/langtools/tools/javac/patterns/PrettyTest.java @@ -72,12 +72,12 @@ public class PrettyTest { boolean _ = true; b = o instanceof String s; b = o instanceof R(String s); - b = o instanceof R(/*missing*/ s); - b = o instanceof R2(R(/*missing*/ s), String t); - b = o instanceof R2(R(/*missing*/ s), /*missing*/ t); + b = o instanceof R(var s); + b = o instanceof R2(R(var s), String t); + b = o instanceof R2(R(var s), var t); b = o instanceof R(String _); - b = o instanceof R2(R(/*missing*/ _), /*missing*/ _); - b = o instanceof R2(R(_), /*missing*/ t); + b = o instanceof R2(R(var _), var _); + b = o instanceof R2(R(_), var t); } \n\ class R { diff --git a/test/langtools/tools/javac/tree/VarTree.java b/test/langtools/tools/javac/tree/VarTree.java index 5ce7ec07541..2c70d5eb317 100644 --- a/test/langtools/tools/javac/tree/VarTree.java +++ b/test/langtools/tools/javac/tree/VarTree.java @@ -67,6 +67,12 @@ public class VarTree { "java.lang.String testVar"); test.run("java.util.function.Consumer c = (|var testVar|) -> {};", "java.lang.String testVar"); + test.run("java.util.function.Consumer c = (|final var testVar|) -> {};", + "final java.lang.String testVar"); + test.run("record Rec(int x) { }; switch (null) { case Rec(|var testVar|) -> {} default -> {} };", + "int testVar"); + test.run("record Rec(int x) { }; switch (null) { case Rec(|final var testVar|) -> {} default -> {} };", + "final int testVar"); } void run(String code, String expected) throws IOException { diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.java b/test/langtools/tools/javac/tree/VarWarnPosition.java index 7dae84f3542..f1d5f4346d0 100644 --- a/test/langtools/tools/javac/tree/VarWarnPosition.java +++ b/test/langtools/tools/javac/tree/VarWarnPosition.java @@ -22,6 +22,9 @@ public class VarWarnPosition { // Test 3 Consumer c2 = (var d) -> { }; + + // Test 4 + Consumer c3 = (final var d) -> { }; } } diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.out b/test/langtools/tools/javac/tree/VarWarnPosition.out index 2200c8b4ae0..87a4ca3a1fd 100644 --- a/test/langtools/tools/javac/tree/VarWarnPosition.out +++ b/test/langtools/tools/javac/tree/VarWarnPosition.out @@ -3,4 +3,6 @@ VarWarnPosition.java:21:18: compiler.warn.has.been.deprecated: Depr, compiler.mi VarWarnPosition.java:21:28: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package VarWarnPosition.java:24:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package VarWarnPosition.java:24:30: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package -5 warnings +VarWarnPosition.java:27:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:27:36: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +7 warnings From ceacf6f7852514dc9877cfe284f9550c179d913a Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 5 Sep 2025 15:26:13 +0000 Subject: [PATCH 381/471] 8366890: C2: Split through phi printing with TraceLoopOpts misses line break Reviewed-by: rcastanedalo, mhaessig, epeter --- src/hotspot/share/opto/loopopts.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index a09eef0bb81..66404b44b86 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -230,8 +230,8 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { #ifndef PRODUCT if (TraceLoopOpts) { - tty->print("Split %d %s through %d Phi in %d %s", - n->_idx, n->Name(), phi->_idx, region->_idx, region->Name()); + tty->print_cr("Split %d %s through %d Phi in %d %s", + n->_idx, n->Name(), phi->_idx, region->_idx, region->Name()); } #endif // !PRODUCT From 9f4d5b2398cb925ec1a66f9f7676b76c99ff7b62 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 5 Sep 2025 15:55:19 +0000 Subject: [PATCH 382/471] 8365428: Unclear comments on java.lang.invoke Holder classes Reviewed-by: iklam, jvernee --- .../java/lang/invoke/BoundMethodHandle.java | 40 ++++---- .../lang/invoke/DelegatingMethodHandle.java | 8 +- .../java/lang/invoke/DirectMethodHandle.java | 8 +- .../lang/invoke/GenerateJLIClassesHelper.java | 95 ++++++++++++++++--- .../lang/invoke/InvokerBytecodeGenerator.java | 1 + .../classes/java/lang/invoke/Invokers.java | 8 +- .../classes/java/lang/invoke/LambdaForm.java | 17 +++- 7 files changed, 139 insertions(+), 38 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index e7cbed61522..f8f62394095 100644 --- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -38,13 +38,23 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newInternalError; import static java.lang.invoke.MethodHandleStatics.uncaughtException; -/** - * The flavor of method handle which emulates an invoke instruction - * on a predetermined argument. The JVM dispatches to the correct method - * when the handle is created, not when it is invoked. - * - * All bound arguments are encapsulated in dedicated species. - */ +/// The flavor of method handle which is constructed with unmodifiable bound values, +/// usable by lambda forms. For example, they can carry a configuration object +/// for its lambda form, or carry an underlying method handle and its bound +/// arguments for currying. +/// +/// Each BMH class supports a number of values, each of a particular [BasicType]. +/// This per-class value type and count information is recorded by [SpeciesData]. +/// A [Specializer] manages lookup for any species. +/// +/// Factories are provided by [BoundMethodHandle.SpeciesData#factory()]. +/// Getters are exposed as [BoundMethodHandle.SpeciesData#getter(int)], +/// which can be included as names in lambda forms. +/// +/// [SimpleMethodHandle] (with no bound value) and [Species_L] (with a bound +/// reference value) are explicitly provided to prevent bootstrap loops; the +/// rest may be generated on demand, or may be pregenerated by +/// [GenerateJLIClassesHelper]. @AOTSafeClassInitializer /*non-public*/ abstract non-sealed class BoundMethodHandle extends MethodHandle { @@ -465,18 +475,10 @@ abstract non-sealed class BoundMethodHandle extends MethodHandle { assert(BMH_TRANSFORMS.size() == TYPE_LIMIT); } - /** - * Generation of concrete BMH classes. - * - * A concrete BMH species is fit for binding a number of values adhering to a - * given type pattern. Reference types are erased. - * - * BMH species are cached by type pattern. - * - * A BMH species has a number of fields with the concrete (possibly erased) types of - * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs, - * which can be included as names in lambda forms. - */ + /// Generates concrete BMH classes. + /// + /// [GenerateJLIClassesHelper] can pre-generate species that are known + /// to be loaded from [MethodHandleStatics#traceSpeciesType]. class Factory extends ClassSpecializer.Factory { @Override protected String chooseFieldName(Class type, int index) { diff --git a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java index 992c011ae98..f0d98c6dca6 100644 --- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -196,7 +196,13 @@ abstract sealed class DelegatingMethodHandle extends MethodHandle UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for DelegatingMethodHandles generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by DelegatingMethodHandle. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index b60304dcd7b..b5738ad6fba 100644 --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -939,7 +939,13 @@ sealed class DirectMethodHandle extends MethodHandle { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for DirectMethodHandles generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by DirectMethodHandle. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java index 6d9f32575c8..c8d910e7456 100644 --- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java +++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java @@ -47,11 +47,72 @@ import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.LambdaForm.Kind.*; import static java.lang.invoke.MethodTypeForm.*; -/** - * Helper class to assist the GenerateJLIClassesPlugin to get access to - * generate classes ahead of time. - */ -class GenerateJLIClassesHelper { +/// Generates bound method handle species classes, and classes with methods that +/// hold compiled lambda form bytecode ahead of time, so certain lambda forms +/// no longer need to spin classes because they can find existing bytecode. +/// Bytecode pre-generation reduces static initialization costs, footprint costs, +/// and circular dependencies that may arise if a class is generated per +/// LambdaForm by [InvokerBytecodeGenerator]. +/// +/// Since lambda forms and bound method handle species are closely tied to +/// method types, which have many varieties, this generator needs *traces* to +/// detect which method types are used, so generation matches the actual usage. +/// See the main entrypoint [#generateHolderClasses(Stream)] for more details +/// about *traces*. +/// +/// Note this pregeneration does not cover all lambda forms that can be created. +/// For example, forms created by [LambdaFormEditor] are not captured. +/// +/// Pregenerated species classes are resolved in [ClassSpecializer.Factory#loadSpecies] +/// and behave identically to on-demand generated ones. Pregenerated lambda +/// forms are resolved in [InvokerBytecodeGenerator#lookupPregenerated], which +/// looks up methods for code from the following 4 possibly-generated classes: +/// - [Invokers.Holder] +/// - [DirectMethodHandle.Holder] +/// - [DelegatingMethodHandle.Holder] +/// - [LambdaForm.Holder] +/// +/// [VarHandle] linker forms, analogous to invoker forms in [Invokers.Holder], +/// have a similar pre-generation system except it is done at source generation; +/// they reside in [VarHandleGuards]. +/// +/// ## Usages of this generator +/// Currently, `GenerateJLIClassesHelper` is invoked when creating a modular JDK +/// image or generating an AOT cache. +/// +/// #### Modular Image +/// When creating a modular JDK image, +/// `jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin` passes the +/// *traces* in the file `jdk/tools/jlink/internal/plugins/default_jli_trace.txt` +/// in `$JAVA_HOME/lib/modules` to this generator. The *traces* are generated +/// from the execution of `build.tools.classlist.HelloClasslist` in the build +/// process of the JDK. +/// +/// > To list all the Species classes in a JDK image: +/// > ``` +/// > jimage list $JAVA_HOME/lib/modules | grep BoundMethodHandle.Species_ +/// > ``` +/// +/// > All these pregenerated classes can be examined by javap in the same image: +/// > (Note to escape `$` in bash) +/// > ``` +/// > javap -c -p -v java.lang.invoke.LambdaForm\$Holder +/// > ``` +/// +/// #### AOT Cache +/// When creating an AOT cache, *traces* generated from the training run are +/// captured and stored inside the AOT configuration file, and are accessed with +/// the C++ `FinalImageRecipes` class. Classes regenerated from these *traces* +/// are linked in assembly phase; see `regeneratedClasses.hpp`. +/// +/// @see #generateHolderClasses(Stream) +/// @see BoundMethodHandle.Specializer +/// @see DelegatingMethodHandle.Holder +/// @see DirectMethodHandle.Holder +/// @see Invokers.Holder +/// @see LambdaForm.Holder +/// @see VarHandleGuards +final class GenerateJLIClassesHelper { // Map from DirectMethodHandle method type name to index to LambdaForms static final Map DMH_METHOD_TYPE_MAP = Map.of( @@ -321,13 +382,23 @@ class GenerateJLIClassesHelper { } } - /* - * Returns a map of class name in internal form to the corresponding class bytes - * per the given stream of SPECIES_RESOLVE and LF_RESOLVE trace logs. - * - * Used by GenerateJLIClassesPlugin to pre-generate holder classes during - * jlink phase. - */ + /// Returns a map from class names in internal form to the corresponding + /// class bytes. + /// + /// A few known lambda forms, such as field accessors, can be comprehensively + /// generated. Most others lambda forms are associated with unique method + /// types; thus they are generated per the given stream of SPECIES_RESOLVE + /// and LF_RESOLVE *trace* logs, which are created according to {@link + /// MethodHandleStatics#TRACE_RESOLVE} configuration. + /// + /// The names of methods in the generated classes are internal tokens + /// recognized by [InvokerBytecodeGenerator#lookupPregenerated] and are + /// subject to change. + /// + /// @param traces the *traces* to determine the lambda forms and species + /// to generate + /// @see MethodHandleStatics#traceLambdaForm + /// @see MethodHandleStatics#traceSpeciesType static Map generateHolderClasses(Stream traces) { Objects.requireNonNull(traces); HolderClassBuilder builder = new HolderClassBuilder(); diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index b3d2ff2c880..2ac9f15272f 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -445,6 +445,7 @@ class InvokerBytecodeGenerator { return resolvedMember; } + /// Look up a method that may have been generated by [GenerateJLIClassesHelper]. private static MemberName lookupPregenerated(LambdaForm form, MethodType invokerType) { if (form.customized != null) { // No pre-generated version for customized LF diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java index 478ef2b9068..bd97307ac27 100644 --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -697,7 +697,13 @@ class Invokers { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for Invokers generated ahead of time */ + /// Holds pre-generated bytecode for lambda forms used by method type invokers. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} } diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 9030a063fad..f36d3feba9c 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -139,13 +139,16 @@ class LambdaForm { public static final int VOID_RESULT = -1, LAST_RESULT = -2; + /// Represents the "basic" types that exist in the JVM linkage and stack/locals. + /// All objects are erased to a reference. + /// All subwords (boolean, byte, char, short) are promoted to int. enum BasicType { - L_TYPE('L', Object.class, Wrapper.OBJECT, TypeKind.REFERENCE), // all reference types + L_TYPE('L', Object.class, Wrapper.OBJECT, TypeKind.REFERENCE), I_TYPE('I', int.class, Wrapper.INT, TypeKind.INT), J_TYPE('J', long.class, Wrapper.LONG, TypeKind.LONG), F_TYPE('F', float.class, Wrapper.FLOAT, TypeKind.FLOAT), - D_TYPE('D', double.class, Wrapper.DOUBLE, TypeKind.DOUBLE), // all primitive types - V_TYPE('V', void.class, Wrapper.VOID, TypeKind.VOID); // not valid in all contexts + D_TYPE('D', double.class, Wrapper.DOUBLE, TypeKind.DOUBLE), // end arg types + V_TYPE('V', void.class, Wrapper.VOID, TypeKind.VOID); // only valid in method return static final @Stable BasicType[] ALL_TYPES = BasicType.values(); static final @Stable BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1); @@ -1730,7 +1733,13 @@ class LambdaForm { UNSAFE.ensureClassInitialized(Holder.class); } - /* Placeholder class for identity and constant forms generated ahead of time */ + /// Holds pre-generated bytecode for common lambda forms. + /// + /// This class may be substituted in the JDK's modules image, or in an AOT + /// cache, by a version generated by [GenerateJLIClassesHelper]. + /// + /// The method names of this class are internal tokens recognized by + /// [InvokerBytecodeGenerator#lookupPregenerated] and are subject to change. @AOTSafeClassInitializer final class Holder {} From 9cca4f7c760bea9bf79f7c03f37a70449acad51e Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 5 Sep 2025 16:44:08 +0000 Subject: [PATCH 383/471] 8358751: C2: Recursive inlining check for compiled lambda forms is broken Reviewed-by: dlong, roland --- src/hotspot/share/opto/bytecodeInfo.cpp | 33 ++++++++++-------- src/hotspot/share/opto/callnode.cpp | 23 +++++++++++-- src/hotspot/share/opto/callnode.hpp | 46 ++++++++++++++++--------- src/hotspot/share/opto/parse1.cpp | 7 ++++ 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/opto/bytecodeInfo.cpp b/src/hotspot/share/opto/bytecodeInfo.cpp index 547cf2f6a38..5b48b33aa46 100644 --- a/src/hotspot/share/opto/bytecodeInfo.cpp +++ b/src/hotspot/share/opto/bytecodeInfo.cpp @@ -60,6 +60,7 @@ InlineTree::InlineTree(Compile* c, // Keep a private copy of the caller_jvms: _caller_jvms = new (C) JVMState(caller_jvms->method(), caller_tree->caller_jvms()); _caller_jvms->set_bci(caller_jvms->bci()); + _caller_jvms->set_receiver_info(caller_jvms->receiver_info()); assert(!caller_jvms->should_reexecute(), "there should be no reexecute bytecode with inlining"); assert(_caller_jvms->same_calls_as(caller_jvms), "consistent JVMS"); } @@ -437,24 +438,26 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, // detect direct and indirect recursive inlining { - // count the current method and the callee const bool is_compiled_lambda_form = callee_method->is_compiled_lambda_form(); - int inline_level = 0; - if (!is_compiled_lambda_form) { - if (method() == callee_method) { - inline_level++; - } + const bool is_method_handle_invoker = is_compiled_lambda_form && !jvms->method()->is_compiled_lambda_form(); + + ciInstance* lform_callee_recv = nullptr; + if (is_compiled_lambda_form && !is_method_handle_invoker) { // MH invokers don't have a receiver + lform_callee_recv = jvms->compute_receiver_info(callee_method); } - // count callers of current method and callee - Node* callee_argument0 = is_compiled_lambda_form ? jvms->map()->argument(jvms, 0)->uncast() : nullptr; - for (JVMState* j = jvms->caller(); j != nullptr && j->has_method(); j = j->caller()) { + + int inline_level = 0; + for (JVMState* j = jvms; j != nullptr && j->has_method(); j = j->caller()) { if (j->method() == callee_method) { - if (is_compiled_lambda_form) { - // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly - // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the - // compiler stack. - Node* caller_argument0 = j->map()->argument(j, 0)->uncast(); - if (caller_argument0 == callee_argument0) { + // Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly + // a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the + // compiler stack. + if (lform_callee_recv != nullptr) { + ciInstance* lform_caller_recv = j->receiver_info(); + assert(lform_caller_recv != nullptr || j->depth() == 1 || + !j->caller()->method()->is_compiled_lambda_form(), // MH invoker + "missing receiver info"); + if (lform_caller_recv == lform_callee_recv || lform_caller_recv == nullptr) { inline_level++; } } else { diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 728093851b0..995208ba24f 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -262,7 +262,8 @@ uint TailJumpNode::match_edge(uint idx) const { //============================================================================= JVMState::JVMState(ciMethod* method, JVMState* caller) : - _method(method) { + _method(method), + _receiver_info(nullptr) { assert(method != nullptr, "must be valid call site"); _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; @@ -278,7 +279,8 @@ JVMState::JVMState(ciMethod* method, JVMState* caller) : _sp = 0; } JVMState::JVMState(int stack_size) : - _method(nullptr) { + _method(nullptr), + _receiver_info(nullptr) { _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; DEBUG_ONLY(_map = (SafePointNode*)-1); @@ -613,6 +615,7 @@ JVMState* JVMState::clone_shallow(Compile* C) const { n->set_endoff(_endoff); n->set_sp(_sp); n->set_map(_map); + n->set_receiver_info(_receiver_info); return n; } @@ -687,6 +690,20 @@ int JVMState::interpreter_frame_size() const { return size + Deoptimization::last_frame_adjust(0, callee_locals) * BytesPerWord; } +// Compute receiver info for a compiled lambda form at call site. +ciInstance* JVMState::compute_receiver_info(ciMethod* callee) const { + assert(callee != nullptr && callee->is_compiled_lambda_form(), ""); + if (has_method() && method()->is_compiled_lambda_form()) { // callee is not a MH invoker + Node* recv = map()->argument(this, 0); + assert(recv != nullptr, ""); + const TypeOopPtr* recv_toop = recv->bottom_type()->isa_oopptr(); + if (recv_toop != nullptr && recv_toop->const_oop() != nullptr) { + return recv_toop->const_oop()->as_instance(); + } + } + return nullptr; +} + //============================================================================= bool CallNode::cmp( const Node &n ) const { return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; } @@ -1364,7 +1381,7 @@ void CallLeafNode::dump_spec(outputStream *st) const { //============================================================================= -void SafePointNode::set_local(JVMState* jvms, uint idx, Node *c) { +void SafePointNode::set_local(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); int loc = jvms->locoff() + idx; if (in(loc)->is_top() && idx > 0 && !c->is_top() ) { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 96706683f51..093c47194ef 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -217,6 +217,7 @@ private: int _bci; // Byte Code Index of this JVM point ReexecuteState _reexecute; // Whether this bytecode need to be re-executed ciMethod* _method; // Method Pointer + ciInstance* _receiver_info; // Constant receiver instance for compiled lambda forms SafePointNode* _map; // Map node associated with this scope public: friend class Compile; @@ -259,6 +260,7 @@ public: bool is_reexecute_undefined() const { return _reexecute==Reexecute_Undefined; } bool has_method() const { return _method != nullptr; } ciMethod* method() const { assert(has_method(), ""); return _method; } + ciInstance* receiver_info() const { assert(has_method(), ""); return _receiver_info; } JVMState* caller() const { return _caller; } SafePointNode* map() const { return _map; } uint depth() const { return _depth; } @@ -304,6 +306,7 @@ public: // _reexecute is initialized to "undefined" for a new bci void set_bci(int bci) {if(_bci != bci)_reexecute=Reexecute_Undefined; _bci = bci; } void set_should_reexecute(bool reexec) {_reexecute = reexec ? Reexecute_True : Reexecute_False;} + void set_receiver_info(ciInstance* recv) { assert(has_method() || recv == nullptr, ""); _receiver_info = recv; } // Miscellaneous utility functions JVMState* clone_deep(Compile* C) const; // recursively clones caller chain @@ -311,6 +314,7 @@ public: void set_map_deep(SafePointNode *map);// reset map for all callers void adapt_position(int delta); // Adapt offsets in in-array after adding an edge. int interpreter_frame_size() const; + ciInstance* compute_receiver_info(ciMethod* callee) const; #ifndef PRODUCT void print_method_with_lineno(outputStream* st, bool show_name) const; @@ -374,7 +378,7 @@ public: } private: - void verify_input(JVMState* jvms, uint idx) const { + void verify_input(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); Node* n = in(idx); assert((!n->bottom_type()->isa_long() && !n->bottom_type()->isa_double()) || @@ -383,34 +387,44 @@ public: public: // Functionality from old debug nodes which has changed - Node *local(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->locoff() + idx); - return in(jvms->locoff() + idx); + Node* local(const JVMState* jvms, uint idx) const { + uint loc_idx = jvms->locoff() + idx; + assert(jvms->is_loc(loc_idx), "not a local slot"); + verify_input(jvms, loc_idx); + return in(loc_idx); } - Node *stack(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->stkoff() + idx); - return in(jvms->stkoff() + idx); + Node* stack(const JVMState* jvms, uint idx) const { + uint stk_idx = jvms->stkoff() + idx; + assert(jvms->is_stk(stk_idx), "not a stack slot"); + verify_input(jvms, stk_idx); + return in(stk_idx); } - Node *argument(JVMState* jvms, uint idx) const { - verify_input(jvms, jvms->argoff() + idx); + Node* argument(const JVMState* jvms, uint idx) const { + uint arg_idx = jvms->argoff() + idx; + assert(jvms->is_stk(arg_idx), "not an argument slot"); + verify_input(jvms, arg_idx); return in(jvms->argoff() + idx); } - Node *monitor_box(JVMState* jvms, uint idx) const { + Node* monitor_box(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); - return in(jvms->monitor_box_offset(idx)); + uint mon_box_idx = jvms->monitor_box_offset(idx); + assert(jvms->is_monitor_box(mon_box_idx), "not a monitor box offset"); + return in(mon_box_idx); } - Node *monitor_obj(JVMState* jvms, uint idx) const { + Node* monitor_obj(const JVMState* jvms, uint idx) const { assert(verify_jvms(jvms), "jvms must match"); - return in(jvms->monitor_obj_offset(idx)); + uint mon_obj_idx = jvms->monitor_obj_offset(idx); + assert(jvms->is_mon(mon_obj_idx) && !jvms->is_monitor_box(mon_obj_idx), "not a monitor obj offset"); + return in(mon_obj_idx); } - void set_local(JVMState* jvms, uint idx, Node *c); + void set_local(const JVMState* jvms, uint idx, Node *c); - void set_stack(JVMState* jvms, uint idx, Node *c) { + void set_stack(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); set_req(jvms->stkoff() + idx, c); } - void set_argument(JVMState* jvms, uint idx, Node *c) { + void set_argument(const JVMState* jvms, uint idx, Node *c) { assert(verify_jvms(jvms), "jvms must match"); set_req(jvms->argoff() + idx, c); } diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index f7e11f0d213..7aa96d2ace3 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1149,6 +1149,13 @@ SafePointNode* Parse::create_entry_map() { // Create an initial safepoint to hold JVM state during parsing JVMState* jvms = new (C) JVMState(method(), _caller->has_method() ? _caller : nullptr); set_map(new SafePointNode(len, jvms)); + + // Capture receiver info for compiled lambda forms. + if (method()->is_compiled_lambda_form()) { + ciInstance* recv_info = _caller->compute_receiver_info(method()); + jvms->set_receiver_info(recv_info); + } + jvms->set_map(map()); record_for_igvn(map()); assert(jvms->endoff() == len, "correct jvms sizing"); From a17058b5bb2dcc89ed276600ceac905e7e986426 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 5 Sep 2025 17:45:37 +0000 Subject: [PATCH 384/471] 8365569: Remove finalize from JavaSoundAudioClip.java Reviewed-by: kizune, tr --- .../sun/media/sound/JavaSoundAudioClip.java | 430 ++--------------- .../sound/JavaSoundAudioClipDelegate.java | 455 ++++++++++++++++++ 2 files changed, 490 insertions(+), 395 deletions(-) create mode 100644 src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java index 6b81eaf008e..9eb32f9b439 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java @@ -25,82 +25,25 @@ package com.sun.media.sound; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.net.URLConnection; -import javax.sound.SoundClip; -import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.MetaEventListener; -import javax.sound.midi.MetaMessage; -import javax.sound.midi.MidiFileFormat; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Sequence; import javax.sound.midi.Sequencer; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.SoundClip; +import sun.java2d.Disposer; +import sun.java2d.DisposerRecord; /** * Java Sound audio clip; * - * @author Arthur van Hoff, Kara Kytle, Jan Borgersen - * @author Florian Bomers */ -public final class JavaSoundAudioClip implements MetaEventListener, LineListener { - - private long lastPlayCall = 0; - private static final int MINIMUM_PLAY_DELAY = 30; - - private byte[] loadedAudio = null; - private int loadedAudioByteLength = 0; - private AudioFormat loadedAudioFormat = null; - - private AutoClosingClip clip = null; - private boolean clipLooping = false; - private boolean clipPlaying = false; - - private DataPusher datapusher = null; - private boolean daemonThread = false; - - private Sequencer sequencer = null; - private Sequence sequence = null; - private boolean sequencerloop = false; - private volatile boolean success; - - /** - * used for determining how many samples is the - * threshold between playing as a Clip and streaming - * from the file. - * - * $$jb: 11.07.99: the engine has a limit of 1M - * samples to play as a Clip, so compare this number - * with the number of samples in the stream. - * - */ - private static final long CLIP_THRESHOLD = 1048576; - private static final int STREAM_BUFFER_SIZE = 1024; +public final class JavaSoundAudioClip { public static JavaSoundAudioClip create(final File file) throws IOException { - JavaSoundAudioClip clip = new JavaSoundAudioClip(); - clip.daemonThread = true; // used only by javax.sound.SoundClip - try (FileInputStream stream = new FileInputStream(file)) { - clip.init(stream); - } - return clip; + return new JavaSoundAudioClip(file); } /* Used [only] by sun.awt.www.content.MultiMediaContentHandlers */ @@ -127,192 +70,32 @@ public final class JavaSoundAudioClip implements MetaEventListener, LineListener return null; } - private void init(InputStream in) throws IOException { - BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE); - bis.mark(STREAM_BUFFER_SIZE); - try { - AudioInputStream as = AudioSystem.getAudioInputStream(bis); - // load the stream data into memory - success = loadAudioData(as); + private JavaSoundAudioClipDelegate delegate; - if (success) { - success = false; - if (loadedAudioByteLength < CLIP_THRESHOLD) { - success = createClip(); - } - if (!success) { - success = createSourceDataLine(); - } - } - } catch (UnsupportedAudioFileException e) { - try { - MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis); - success = createSequencer(bis); - } catch (InvalidMidiDataException e1) { - success = false; - } - } + public JavaSoundAudioClip(final File file) throws IOException { + disposerRecord = new AudioClipDisposerRecord(); + Disposer.addRecord(this, disposerRecord); + delegate = new JavaSoundAudioClipDelegate(file, disposerRecord); } public synchronized boolean canPlay() { - return success; + return delegate.canPlay(); } public synchronized boolean isPlaying() { - if (!canPlay()) { - return false; - } else if (clip != null) { - return clipPlaying; - } else if (datapusher != null) { - return datapusher.isPlaying(); - } else if (sequencer != null) { - return sequencer.isRunning(); - } - return false; + return delegate.isPlaying(); } public synchronized void play() { - if (!success) { - return; - } - startImpl(false); + delegate.play(); } public synchronized void loop() { - if (!success) { - return; - } - startImpl(true); - } - - private synchronized void startImpl(boolean loop) { - // hack for some applications that call the start method very rapidly... - long currentTime = System.currentTimeMillis(); - long diff = currentTime - lastPlayCall; - if (diff < MINIMUM_PLAY_DELAY) { - return; - } - lastPlayCall = currentTime; - try { - if (clip != null) { - // We need to disable autoclosing mechanism otherwise the clip - // can be closed after "!clip.isOpen()" check, because of - // previous inactivity. - clip.setAutoClosing(false); - try { - if (!clip.isOpen()) { - clip.open(loadedAudioFormat, loadedAudio, 0, - loadedAudioByteLength); - } else { - clip.flush(); - if (loop != clipLooping) { - // need to stop in case the looped status changed - clip.stop(); - } - } - clip.setFramePosition(0); - if (loop) { - clip.loop(Clip.LOOP_CONTINUOUSLY); - } else { - clip.start(); - } - clipLooping = loop; - } finally { - clip.setAutoClosing(true); - } - } else if (datapusher != null ) { - datapusher.start(loop); - - } else if (sequencer != null) { - sequencerloop = loop; - if (sequencer.isRunning()) { - sequencer.setMicrosecondPosition(0); - } - if (!sequencer.isOpen()) { - try { - sequencer.open(); - sequencer.setSequence(sequence); - - } catch (InvalidMidiDataException | MidiUnavailableException e) { - if (Printer.err) e.printStackTrace(); - } - } - sequencer.addMetaEventListener(this); - try { - sequencer.start(); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - } - } - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - } + delegate.loop(); } public synchronized void stop() { - if (!success) { - return; - } - lastPlayCall = 0; - - if (clip != null) { - try { - clip.flush(); - } catch (Exception e1) { - if (Printer.err) e1.printStackTrace(); - } - try { - clip.stop(); - } catch (Exception e2) { - if (Printer.err) e2.printStackTrace(); - } - } else if (datapusher != null) { - datapusher.stop(); - } else if (sequencer != null) { - try { - sequencerloop = false; - sequencer.removeMetaEventListener(this); - sequencer.stop(); - } catch (Exception e3) { - if (Printer.err) e3.printStackTrace(); - } - try { - sequencer.close(); - } catch (Exception e4) { - if (Printer.err) e4.printStackTrace(); - } - } - } - - // Event handlers (for debugging) - - @Override - public synchronized void update(LineEvent event) { - if (clip != null) { - if (clip == event.getSource()) { - if (event.getType() == LineEvent.Type.START) { - clipPlaying = true; - } else if ((event.getType() == LineEvent.Type.STOP) || - (event.getType() == LineEvent.Type.CLOSE)) { - clipPlaying = false; - } - } - } - } - - // handle MIDI track end meta events for looping - - @Override - public synchronized void meta(MetaMessage message) { - if( message.getType() == 47 ) { - if (sequencerloop){ - //notifyAll(); - sequencer.setMicrosecondPosition(0); - loop(); - } else { - stop(); - } - } + delegate.stop(); } @Override @@ -320,180 +103,37 @@ public final class JavaSoundAudioClip implements MetaEventListener, LineListener return getClass().toString(); } - @Override - @SuppressWarnings("removal") - protected void finalize() { + private AudioClipDisposerRecord disposerRecord; + static class AudioClipDisposerRecord implements DisposerRecord { - if (clip != null) { - clip.close(); + private volatile AutoClosingClip clip; + private volatile DataPusher datapusher; + private volatile Sequencer sequencer; + + void setClip(AutoClosingClip clip) { + this.clip = clip; } - //$$fb 2001-09-26: may improve situation related to bug #4302884 - if (datapusher != null) { - datapusher.close(); + void setDataPusher(DataPusher datapusher) { + this.datapusher = datapusher; } - if (sequencer != null) { - sequencer.close(); - } - } - - // FILE LOADING METHODS - - private boolean loadAudioData(AudioInputStream as) throws IOException, UnsupportedAudioFileException { - // first possibly convert this stream to PCM - as = Toolkit.getPCMConvertedAudioInputStream(as); - if (as == null) { - return false; + void setSequencer(Sequencer sequencer) { + this.sequencer = sequencer; } - loadedAudioFormat = as.getFormat(); - long frameLen = as.getFrameLength(); - int frameSize = loadedAudioFormat.getFrameSize(); - long byteLen = AudioSystem.NOT_SPECIFIED; - if (frameLen != AudioSystem.NOT_SPECIFIED - && frameLen > 0 - && frameSize != AudioSystem.NOT_SPECIFIED - && frameSize > 0) { - byteLen = frameLen * frameSize; - } - if (byteLen != AudioSystem.NOT_SPECIFIED) { - // if the stream length is known, it can be efficiently loaded into memory - readStream(as, byteLen); - } else { - // otherwise we use a ByteArrayOutputStream to load it into memory - readStream(as); - } - - // if everything went fine, we have now the audio data in - // loadedAudio, and the byte length in loadedAudioByteLength - return true; - } - - private void readStream(AudioInputStream as, long byteLen) throws IOException { - // arrays "only" max. 2GB - int intLen; - if (byteLen > 2147483647) { - intLen = 2147483647; - } else { - intLen = (int) byteLen; - } - loadedAudio = new byte[intLen]; - loadedAudioByteLength = 0; - - // this loop may throw an IOException - while (true) { - int bytesRead = as.read(loadedAudio, loadedAudioByteLength, intLen - loadedAudioByteLength); - if (bytesRead <= 0) { - as.close(); - break; + public void dispose() { + if (clip != null) { + clip.close(); } - loadedAudioByteLength += bytesRead; - } - } - private void readStream(AudioInputStream as) throws IOException { - - DirectBAOS baos = new DirectBAOS(); - int totalBytesRead; - try (as) { - totalBytesRead = (int) as.transferTo(baos); - } - loadedAudio = baos.getInternalBuffer(); - loadedAudioByteLength = totalBytesRead; - } - - // METHODS FOR CREATING THE DEVICE - - private boolean createClip() { - try { - DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat); - if (!(AudioSystem.isLineSupported(info)) ) { - if (Printer.err) Printer.err("Clip not supported: "+loadedAudioFormat); - // fail silently - return false; + if (datapusher != null) { + datapusher.close(); } - Object line = AudioSystem.getLine(info); - if (!(line instanceof AutoClosingClip)) { - if (Printer.err) Printer.err("Clip is not auto closing!"+clip); - // fail -> will try with SourceDataLine - return false; + + if (sequencer != null) { + sequencer.close(); } - clip = (AutoClosingClip) line; - clip.setAutoClosing(true); - clip.addLineListener(this); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - // fail silently - return false; } - - if (clip==null) { - // fail silently - return false; - } - return true; } - - private boolean createSourceDataLine() { - try { - DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat); - if (!(AudioSystem.isLineSupported(info)) ) { - if (Printer.err) Printer.err("Line not supported: "+loadedAudioFormat); - // fail silently - return false; - } - SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info); - datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength, daemonThread); - } catch (Exception e) { - if (Printer.err) e.printStackTrace(); - // fail silently - return false; - } - - if (datapusher==null) { - // fail silently - return false; - } - return true; - } - - private boolean createSequencer(BufferedInputStream in) throws IOException { - // get the sequencer - try { - sequencer = MidiSystem.getSequencer( ); - } catch(MidiUnavailableException me) { - if (Printer.err) me.printStackTrace(); - return false; - } - if (sequencer==null) { - return false; - } - - try { - sequence = MidiSystem.getSequence(in); - if (sequence == null) { - return false; - } - } catch (InvalidMidiDataException e) { - if (Printer.err) e.printStackTrace(); - return false; - } - return true; - } - - /* - * private inner class representing a ByteArrayOutputStream - * which allows retrieval of the internal array - */ - private static class DirectBAOS extends ByteArrayOutputStream { - DirectBAOS() { - super(); - } - - public byte[] getInternalBuffer() { - return buf; - } - - } // class DirectBAOS } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java new file mode 100644 index 00000000000..1bd9987aaaf --- /dev/null +++ b/src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClipDelegate.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.media.sound; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.SoundClip; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiFileFormat; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.UnsupportedAudioFileException; +import com.sun.media.sound.JavaSoundAudioClip.AudioClipDisposerRecord; + +/** + * Java Sound audio clip; + * + */ +public final class JavaSoundAudioClipDelegate implements MetaEventListener, LineListener { + + private long lastPlayCall = 0; + private static final int MINIMUM_PLAY_DELAY = 30; + + private byte[] loadedAudio = null; + private int loadedAudioByteLength = 0; + private AudioFormat loadedAudioFormat = null; + + private AutoClosingClip clip = null; + private boolean clipLooping = false; + private boolean clipPlaying = false; + + private DataPusher datapusher = null; + + private Sequencer sequencer = null; + private Sequence sequence = null; + private boolean sequencerloop = false; + private volatile boolean success; + + /** + * used for determining how many samples is the + * threshold between playing as a Clip and streaming + * from the file. + * + * $$jb: 11.07.99: the engine has a limit of 1M + * samples to play as a Clip, so compare this number + * with the number of samples in the stream. + * + */ + private static final long CLIP_THRESHOLD = 1048576; + private static final int STREAM_BUFFER_SIZE = 1024; + + private AudioClipDisposerRecord disposerRecord; + JavaSoundAudioClipDelegate(File file, AudioClipDisposerRecord record) throws IOException { + this.disposerRecord = record; + try (FileInputStream stream = new FileInputStream(file)) { + init(stream); + } + + } + + private void init(InputStream in) throws IOException { + BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE); + bis.mark(STREAM_BUFFER_SIZE); + try { + AudioInputStream as = AudioSystem.getAudioInputStream(bis); + // load the stream data into memory + success = loadAudioData(as); + + if (success) { + success = false; + if (loadedAudioByteLength < CLIP_THRESHOLD) { + success = createClip(); + } + if (!success) { + success = createSourceDataLine(); + } + } + } catch (UnsupportedAudioFileException e) { + try { + MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis); + success = createSequencer(bis); + } catch (InvalidMidiDataException e1) { + success = false; + } + } + } + + public synchronized boolean canPlay() { + return success; + } + + public synchronized boolean isPlaying() { + if (!canPlay()) { + return false; + } else if (clip != null) { + return clipPlaying; + } else if (datapusher != null) { + return datapusher.isPlaying(); + } else if (sequencer != null) { + return sequencer.isRunning(); + } + return false; + } + + public synchronized void play() { + if (!success) { + return; + } + startImpl(false); + } + + public synchronized void loop() { + if (!success) { + return; + } + startImpl(true); + } + + private synchronized void startImpl(boolean loop) { + // hack for some applications that call the start method very rapidly... + long currentTime = System.currentTimeMillis(); + long diff = currentTime - lastPlayCall; + if (diff < MINIMUM_PLAY_DELAY) { + return; + } + lastPlayCall = currentTime; + try { + if (clip != null) { + // We need to disable autoclosing mechanism otherwise the clip + // can be closed after "!clip.isOpen()" check, because of + // previous inactivity. + clip.setAutoClosing(false); + try { + if (!clip.isOpen()) { + clip.open(loadedAudioFormat, loadedAudio, 0, + loadedAudioByteLength); + } else { + clip.flush(); + if (loop != clipLooping) { + // need to stop in case the looped status changed + clip.stop(); + } + } + clip.setFramePosition(0); + if (loop) { + clip.loop(Clip.LOOP_CONTINUOUSLY); + } else { + clip.start(); + } + clipLooping = loop; + } finally { + clip.setAutoClosing(true); + } + } else if (datapusher != null ) { + datapusher.start(loop); + + } else if (sequencer != null) { + sequencerloop = loop; + if (sequencer.isRunning()) { + sequencer.setMicrosecondPosition(0); + } + if (!sequencer.isOpen()) { + try { + sequencer.open(); + sequencer.setSequence(sequence); + + } catch (InvalidMidiDataException | MidiUnavailableException e) { + if (Printer.err) e.printStackTrace(); + } + } + sequencer.addMetaEventListener(this); + try { + sequencer.start(); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + } + } + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + } + } + + public synchronized void stop() { + if (!success) { + return; + } + lastPlayCall = 0; + + if (clip != null) { + try { + clip.flush(); + } catch (Exception e1) { + if (Printer.err) e1.printStackTrace(); + } + try { + clip.stop(); + } catch (Exception e2) { + if (Printer.err) e2.printStackTrace(); + } + } else if (datapusher != null) { + datapusher.stop(); + } else if (sequencer != null) { + try { + sequencerloop = false; + sequencer.removeMetaEventListener(this); + sequencer.stop(); + } catch (Exception e3) { + if (Printer.err) e3.printStackTrace(); + } + try { + sequencer.close(); + } catch (Exception e4) { + if (Printer.err) e4.printStackTrace(); + } + } + } + + // Event handlers (for debugging) + + @Override + public synchronized void update(LineEvent event) { + if (clip != null) { + if (clip == event.getSource()) { + if (event.getType() == LineEvent.Type.START) { + clipPlaying = true; + } else if ((event.getType() == LineEvent.Type.STOP) || + (event.getType() == LineEvent.Type.CLOSE)) { + clipPlaying = false; + } + } + } + } + + // handle MIDI track end meta events for looping + + @Override + public synchronized void meta(MetaMessage message) { + if( message.getType() == 47 ) { + if (sequencerloop){ + //notifyAll(); + sequencer.setMicrosecondPosition(0); + loop(); + } else { + stop(); + } + } + } + + @Override + public String toString() { + return getClass().toString(); + } + + // FILE LOADING METHODS + + private boolean loadAudioData(AudioInputStream as) throws IOException, UnsupportedAudioFileException { + // first possibly convert this stream to PCM + as = Toolkit.getPCMConvertedAudioInputStream(as); + if (as == null) { + return false; + } + + loadedAudioFormat = as.getFormat(); + long frameLen = as.getFrameLength(); + int frameSize = loadedAudioFormat.getFrameSize(); + long byteLen = AudioSystem.NOT_SPECIFIED; + if (frameLen != AudioSystem.NOT_SPECIFIED + && frameLen > 0 + && frameSize != AudioSystem.NOT_SPECIFIED + && frameSize > 0) { + byteLen = frameLen * frameSize; + } + if (byteLen != AudioSystem.NOT_SPECIFIED) { + // if the stream length is known, it can be efficiently loaded into memory + readStream(as, byteLen); + } else { + // otherwise we use a ByteArrayOutputStream to load it into memory + readStream(as); + } + + // if everything went fine, we have now the audio data in + // loadedAudio, and the byte length in loadedAudioByteLength + return true; + } + + private void readStream(AudioInputStream as, long byteLen) throws IOException { + // arrays "only" max. 2GB + int intLen; + if (byteLen > 2147483647) { + intLen = 2147483647; + } else { + intLen = (int) byteLen; + } + loadedAudio = new byte[intLen]; + loadedAudioByteLength = 0; + + // this loop may throw an IOException + while (true) { + int bytesRead = as.read(loadedAudio, loadedAudioByteLength, intLen - loadedAudioByteLength); + if (bytesRead <= 0) { + as.close(); + break; + } + loadedAudioByteLength += bytesRead; + } + } + + private void readStream(AudioInputStream as) throws IOException { + + DirectBAOS baos = new DirectBAOS(); + int totalBytesRead; + try (as) { + totalBytesRead = (int) as.transferTo(baos); + } + loadedAudio = baos.getInternalBuffer(); + loadedAudioByteLength = totalBytesRead; + } + + // METHODS FOR CREATING THE DEVICE + + private boolean createClip() { + try { + DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat); + if (!(AudioSystem.isLineSupported(info)) ) { + if (Printer.err) Printer.err("Clip not supported: "+loadedAudioFormat); + // fail silently + return false; + } + Object line = AudioSystem.getLine(info); + if (!(line instanceof AutoClosingClip)) { + if (Printer.err) Printer.err("Clip is not auto closing!"+clip); + // fail -> will try with SourceDataLine + return false; + } + clip = (AutoClosingClip) line; + disposerRecord.setClip(clip); + clip.setAutoClosing(true); + clip.addLineListener(this); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + // fail silently + return false; + } + + if (clip==null) { + // fail silently + return false; + } + return true; + } + + private boolean createSourceDataLine() { + try { + DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat); + if (!(AudioSystem.isLineSupported(info)) ) { + if (Printer.err) Printer.err("Line not supported: "+loadedAudioFormat); + // fail silently + return false; + } + SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info); + datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength, true); + disposerRecord.setDataPusher(datapusher); + } catch (Exception e) { + if (Printer.err) e.printStackTrace(); + // fail silently + return false; + } + + if (datapusher==null) { + // fail silently + return false; + } + return true; + } + + private boolean createSequencer(BufferedInputStream in) throws IOException { + // get the sequencer + try { + sequencer = MidiSystem.getSequencer( ); + disposerRecord.setSequencer(sequencer); + } catch(MidiUnavailableException me) { + if (Printer.err) me.printStackTrace(); + return false; + } + if (sequencer==null) { + return false; + } + + try { + sequence = MidiSystem.getSequence(in); + if (sequence == null) { + return false; + } + } catch (InvalidMidiDataException e) { + if (Printer.err) e.printStackTrace(); + return false; + } + return true; + } + + /* + * private inner class representing a ByteArrayOutputStream + * which allows retrieval of the internal array + */ + private static class DirectBAOS extends ByteArrayOutputStream { + DirectBAOS() { + super(); + } + + public byte[] getInternalBuffer() { + return buf; + } + + } // class DirectBAOS +} From c6c451ac392cdb545ab43dd46918eca6c47cc5f0 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 5 Sep 2025 18:42:58 +0000 Subject: [PATCH 385/471] 8353468: [ubsan] arguments.cpp:2422:23: runtime error: 2.14748e+11 is outside the range of representable values of type 'int' Reviewed-by: stefank, dholmes --- src/hotspot/share/runtime/arguments.cpp | 48 ++++++++++---- .../jtreg/gc/arguments/TestHeapFreeRatio.java | 64 ++++++++++++++----- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0d4adc7f587..2ebc15d0e1a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2414,30 +2414,54 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin // Xmaxf } else if (match_option(option, "-Xmaxf", &tail)) { char* err; - int maxf = (int)(strtod(tail, &err) * 100); + double dmaxf = strtod(tail, &err); if (*err != '\0' || *tail == '\0') { jio_fprintf(defaultStream::error_stream(), - "Bad max heap free percentage size: %s\n", + "Bad max heap free ratio: %s\n", option->optionString); return JNI_EINVAL; - } else { - if (FLAG_SET_CMDLINE(MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } + } + if (dmaxf < 0.0 || dmaxf > 1.0) { + jio_fprintf(defaultStream::error_stream(), + "-Xmaxf value (%s) is outside the allowed range [ 0.0 ... 1.0 ]\n", + option->optionString); + return JNI_EINVAL; + } + const uintx umaxf = (uintx)(dmaxf * 100); + if (MinHeapFreeRatio > umaxf) { + jio_fprintf(defaultStream::error_stream(), + "-Xmaxf value (%s) must be greater than or equal to the implicit -Xminf value (%.2f)\n", + tail, MinHeapFreeRatio / 100.0f); + return JNI_EINVAL; + } + if (FLAG_SET_CMDLINE(MaxHeapFreeRatio, umaxf) != JVMFlag::SUCCESS) { + return JNI_EINVAL; } // Xminf } else if (match_option(option, "-Xminf", &tail)) { char* err; - int minf = (int)(strtod(tail, &err) * 100); + double dminf = strtod(tail, &err); if (*err != '\0' || *tail == '\0') { jio_fprintf(defaultStream::error_stream(), - "Bad min heap free percentage size: %s\n", + "Bad min heap free ratio: %s\n", option->optionString); return JNI_EINVAL; - } else { - if (FLAG_SET_CMDLINE(MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } + } + if (dminf < 0.0 || dminf > 1.0) { + jio_fprintf(defaultStream::error_stream(), + "-Xminf value (%s) is outside the allowed range [ 0.0 ... 1.0 ]\n", + tail); + return JNI_EINVAL; + } + const uintx uminf = (uintx)(dminf * 100); + if (MaxHeapFreeRatio < uminf) { + jio_fprintf(defaultStream::error_stream(), + "-Xminf value (%s) must be less than or equal to the implicit -Xmaxf value (%.2f)\n", + tail, MaxHeapFreeRatio / 100.0f); + return JNI_EINVAL; + } + if (FLAG_SET_CMDLINE(MinHeapFreeRatio, uminf) != JVMFlag::SUCCESS) { + return JNI_EINVAL; } // -Xss } else if (match_option(option, "-Xss", &tail)) { diff --git a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java index 066d3c03603..46c8f74db45 100644 --- a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java +++ b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -47,24 +47,19 @@ public class TestHeapFreeRatio { COMBINATION_INVALID } - private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { - OutputAnalyzer output = GCArguments.executeTestJava( - "-Xminf" + min, - "-Xmaxf" + max, - "-version"); - + private static void checkValidity(OutputAnalyzer output, String min, String max, Validation type) { switch (type) { case VALID: output.shouldNotContain("Error"); output.shouldHaveExitValue(0); break; case MIN_INVALID: - output.shouldContain("Bad min heap free percentage size: -Xminf" + min); + output.shouldContain("Bad min heap free ratio: -Xminf" + min); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; case MAX_INVALID: - output.shouldContain("Bad max heap free percentage size: -Xmaxf" + max); + output.shouldContain("Bad max heap free ratio: -Xmaxf" + max); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; @@ -74,7 +69,7 @@ public class TestHeapFreeRatio { output.shouldHaveExitValue(1); break; case COMBINATION_INVALID: - output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); + output.shouldMatch("must be (less|greater) than or equal to the implicit -Xm..f value"); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; @@ -85,10 +80,29 @@ public class TestHeapFreeRatio { System.out.println(output.getOutput()); } + private static void testMinMaxFreeRatio_Reordered(String min, String max, Validation type) throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( + "-Xmaxf" + max, + "-Xminf" + min, + "-version"); + + checkValidity(output, min, max, type); + } + + private static void testMinMaxFreeRatio(String min, String max, Validation type) throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( + "-Xminf" + min, + "-Xmaxf" + max, + "-version"); + + checkValidity(output, min, max, type); + } + public static void main(String args[]) throws Exception { - testMinMaxFreeRatio( "0.1", "0.5", Validation.VALID); - testMinMaxFreeRatio( ".1", ".5", Validation.VALID); - testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID); + testMinMaxFreeRatio( "0.1", "0.5", Validation.VALID); + testMinMaxFreeRatio( ".1", ".5", Validation.VALID); + testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID); + testMinMaxFreeRatio( "0.0","0.001", Validation.VALID); testMinMaxFreeRatio("=0.1", "0.5", Validation.MIN_INVALID); testMinMaxFreeRatio("0.1f", "0.5", Validation.MIN_INVALID); @@ -103,14 +117,30 @@ public class TestHeapFreeRatio { testMinMaxFreeRatio("-0.1", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "1.1", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( - "2147483647", "0.5", Validation.OUT_OF_RANGE); + "2147483647", "0.5", Validation.OUT_OF_RANGE); + testMinMaxFreeRatio( + "-2147483647", "0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "-0.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "1.5", Validation.OUT_OF_RANGE); testMinMaxFreeRatio( "0.1", "2147483647", Validation.OUT_OF_RANGE); + testMinMaxFreeRatio( + "0.1", "-2147483647", Validation.OUT_OF_RANGE); - testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID); - testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID); - testMinMaxFreeRatio("0.12","0.100", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID); + testMinMaxFreeRatio("0.12", "0.100", Validation.COMBINATION_INVALID); + + // Default range is [0.40, 0.70] + // setting minf to 0.80 violates minf < maxf + testMinMaxFreeRatio("0.80", "0.90", Validation.COMBINATION_INVALID); + + // Options are re-ordered: -Xmaxf is given before -Xminf + + // valid range, but acceptable only if maxf be set first + testMinMaxFreeRatio_Reordered("0.80", "0.90", Validation.VALID); + + // although a valid range, but setting maxf first violates minf < maxf + testMinMaxFreeRatio_Reordered("0.10", "0.30", Validation.COMBINATION_INVALID); } } From e2a503e26ee2a3c428c5db0cd4cbe71cdc7d837f Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Fri, 5 Sep 2025 19:50:52 +0000 Subject: [PATCH 386/471] 8347277: java/awt/Focus/ComponentLostFocusTest.java fails intermittently Reviewed-by: serb --- .../awt/Focus/ComponentLostFocusTest.java | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/test/jdk/java/awt/Focus/ComponentLostFocusTest.java b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java index 6af8322b2cd..8045ace43d5 100644 --- a/test/jdk/java/awt/Focus/ComponentLostFocusTest.java +++ b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. 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 @@ -35,13 +35,20 @@ import java.awt.FlowLayout; import java.awt.Frame; import java.awt.KeyboardFocusManager; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; import java.awt.TextField; +import java.awt.Toolkit; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.imageio.ImageIO; public class ComponentLostFocusTest { @@ -49,10 +56,10 @@ public class ComponentLostFocusTest { static TextField tf; static Robot r; static Dialog dialog = null; - static volatile boolean passed; static volatile Point loc; static volatile int width; static volatile int top; + static final CountDownLatch focusGainedLatch = new CountDownLatch(1); private static void createTestUI() { @@ -75,11 +82,7 @@ public class ComponentLostFocusTest { public static void doTest() { System.out.println("dialog.setVisible.... "); - new Thread(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }).start(); + new Thread(() -> dialog.setVisible(true)).start(); // The bug is that this construction leads to the redundant xRequestFocus // By the way, the requestFocusInWindow() works fine before the fix @@ -98,7 +101,7 @@ public class ComponentLostFocusTest { tf.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { System.out.println("TextField gained focus: " + e); - passed = true; + focusGainedLatch.countDown(); } }); @@ -116,6 +119,17 @@ public class ComponentLostFocusTest { tf.requestFocus(); } + private static void captureScreen() { + try { + final Rectangle screenBounds = new Rectangle( + Toolkit.getDefaultToolkit().getScreenSize()); + ImageIO.write(r.createScreenCapture(screenBounds), + "png", new File("ComponentLostFocusTest.png")); + } catch (Exception e) { + e.printStackTrace(); + } + } + public static final void main(String args[]) throws Exception { r = new Robot(); r.setAutoDelay(100); @@ -138,9 +152,10 @@ public class ComponentLostFocusTest { System.out.println("Focus owner: " + KeyboardFocusManager.getCurrentKeyboardFocusManager(). getFocusOwner()); - - if (!passed) { - throw new RuntimeException("TextField got no focus! Test failed."); + if (!focusGainedLatch.await(5, TimeUnit.SECONDS)) { + captureScreen(); + throw new RuntimeException("Waited too long, " + + "TextField got no focus! Test failed."); } } finally { EventQueue.invokeAndWait(() -> { @@ -151,4 +166,3 @@ public class ComponentLostFocusTest { } } } - From 4ab2b5bdb4e6d40a747d4088a25f7c6351131759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Fri, 5 Sep 2025 19:59:03 +0000 Subject: [PATCH 387/471] 8366569: Disable CompileTaskTimeout for known long-running test cases Reviewed-by: dlong --- .../compiler/c2/TestScalarReplacementMaxLiveNodes.java | 1 + .../codegen/TestAntiDependenciesHighMemUsage.java | 5 ++++- .../codegen/TestAntiDependenciesHighMemUsage2.java | 8 ++++++-- .../compiler/loopopts/TestMaxLoopOptsCountReached.java | 5 ++++- .../vectorapi/VectorReplicateLongSpecialImmTest.java | 7 ++++++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java index f133e91a1ee..b5e349307c3 100644 --- a/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java +++ b/test/hotspot/jtreg/compiler/c2/TestScalarReplacementMaxLiveNodes.java @@ -38,6 +38,7 @@ * -XX:CompileCommand=dontinline,*String*::substring * -XX:NodeCountInliningCutoff=220000 * -XX:DesiredMethodLimit=100000 + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 * compiler.c2.TestScalarReplacementMaxLiveNodes */ package compiler.c2; diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java index 5ca215d95ef..36bcbd866f4 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,7 +26,9 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage::test1 -Xcomp TestAntiDependenciesHighMemUsage + * @run main/othervm -XX:CompileOnly=TestAntiDependenciesHighMemUsage::test1 -Xcomp + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestAntiDependenciesHighMemUsage */ public class TestAntiDependenciesHighMemUsage { diff --git a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java index cfe884c269f..5c5f95b6f7f 100644 --- a/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java +++ b/test/hotspot/jtreg/compiler/codegen/TestAntiDependenciesHighMemUsage2.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,8 +26,11 @@ * @test * @bug 8333258 * @summary C2: high memory usage in PhaseCFG::raise_above_anti_dependences() - * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 -XX:-ClipInlining - * -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement TestAntiDependenciesHighMemUsage2 + * @run main/othervm/timeout=480 -XX:CompileOnly=TestAntiDependenciesHighMemUsage2::test1 + * -XX:-ClipInlining -XX:-BackgroundCompilation + * -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestAntiDependenciesHighMemUsage2 */ public class TestAntiDependenciesHighMemUsage2 { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java index a529c69dae8..e8e603b84d3 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestMaxLoopOptsCountReached.java @@ -26,7 +26,10 @@ * @bug 8284944 * @requires vm.compiler2.enabled * @summary triggers the loop optimization phase `LoopOptsCount` many times - * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test TestMaxLoopOptsCountReached + * @run main/othervm/timeout=480 -Xcomp -XX:-PartialPeelLoop + * -XX:CompileCommand=compileonly,TestMaxLoopOptsCountReached::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0 + * TestMaxLoopOptsCountReached */ import java.lang.System.Logger.Level; diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java index b885abb632a..f9cb7d163d0 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java @@ -36,7 +36,12 @@ import org.testng.annotations.Test; * @library /test/lib * @requires os.arch == "aarch64" * @modules jdk.incubator.vector - * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:+IgnoreUnrecognizedVMOptions -XX:CompileCommand=MemLimit,*.*,0 compiler.vectorapi.VectorReplicateLongSpecialImmTest + * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation + * -XX:CompileThreshold=100 + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 + * -XX:CompileTaskTimeout=0 + * compiler.vectorapi.VectorReplicateLongSpecialImmTest */ public class VectorReplicateLongSpecialImmTest { From 3824c7cd06645b1dab5322015e8e6cf604afa754 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 5 Sep 2025 20:20:11 +0000 Subject: [PATCH 388/471] 8366517: Refine null locale processing of ctor/factory methods in `Date/DecimalFormatSymbols` Reviewed-by: jlu, rriggs --- .../share/classes/java/text/DateFormatSymbols.java | 5 ++++- .../share/classes/java/text/DecimalFormatSymbols.java | 4 +++- .../Format/DateFormat/IntlTestDateFormatSymbols.java | 10 +++++++++- .../NumberFormat/IntlTestDecimalFormatSymbols.java | 11 +++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index 9fff6a7c4d4..c8542ff17ee 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -145,10 +145,12 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @throws java.util.MissingResourceException * if the resources for the specified locale cannot be * found or cannot be loaded. + * @throws NullPointerException if {@code locale} is null */ public DateFormatSymbols(Locale locale) { - initializeData(locale); + initializeData(Objects.requireNonNull(locale, + "locale should not be null")); } /** @@ -344,6 +346,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @since 1.6 */ public static final DateFormatSymbols getInstance(Locale locale) { + Objects.requireNonNull(locale, "locale should not be null"); DateFormatSymbols dfs = getProviderInstance(locale); if (dfs != null) { return dfs; diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index c255b93bd98..fe512e9cc26 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -115,7 +115,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @throws NullPointerException if {@code locale} is null */ public DecimalFormatSymbols(Locale locale) { - initialize(locale); + initialize(Objects.requireNonNull(locale, + "locale should not be null")); } /** @@ -180,6 +181,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * @since 1.6 */ public static final DecimalFormatSymbols getInstance(Locale locale) { + Objects.requireNonNull(locale, "locale should not be null"); LocaleProviderAdapter adapter; adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); DecimalFormatSymbolsProvider provider = adapter.getDecimalFormatSymbolsProvider(); diff --git a/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java b/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java index e3cb841b5c6..84b828f36c5 100644 --- a/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java +++ b/test/jdk/java/text/Format/DateFormat/IntlTestDateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -24,6 +24,7 @@ /* * @test * @summary test International Date Format Symbols + * @bug 8366517 * @run junit IntlTestDateFormatSymbols */ /* @@ -43,6 +44,7 @@ import java.util.*; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; public class IntlTestDateFormatSymbols @@ -205,4 +207,10 @@ public class IntlTestDateFormatSymbols fail("ERROR: Clone failed"); } } + + @Test + void nullLocaleTest() { + assertThrows(NullPointerException.class, () -> new DateFormatSymbols(null)); + assertThrows(NullPointerException.class, () -> DateFormatSymbols.getInstance(null)); + } } diff --git a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java index 75c9199c95b..c370440c932 100644 --- a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java +++ b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8282625 + * @bug 8282625 8366517 * @summary test International Decimal Format Symbols * @run junit IntlTestDecimalFormatSymbols */ @@ -44,6 +44,7 @@ import java.util.*; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; public class IntlTestDecimalFormatSymbols @@ -146,4 +147,10 @@ public class IntlTestDecimalFormatSymbols fail("ERROR: Clone failed"); } } + + @Test + void nullLocaleTest() { + assertThrows(NullPointerException.class, () -> new DecimalFormatSymbols(null)); + assertThrows(NullPointerException.class, () -> DecimalFormatSymbols.getInstance(null)); + } } From b674a425531974bb78c4622e0f1d9b46a117f575 Mon Sep 17 00:00:00 2001 From: Sarvesh Kumar Jain Date: Fri, 5 Sep 2025 20:35:30 +0000 Subject: [PATCH 389/471] 8366750: Remove test 'java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java' from problemlist Reviewed-by: psadhukhan, serb --- test/jdk/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 58fb2c51397..aac9d9a8a21 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -260,7 +260,7 @@ java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469,8273617 java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 8273617 macosx-all java/awt/print/PrinterJob/PSQuestionMark.java 7003378 generic-all java/awt/print/PrinterJob/GlyphPositions.java 7003378 generic-all -java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 6849371 macosx-all,linux-all +java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 8366852 generic-all java/awt/Component/GetScreenLocTest/GetScreenLocTest.java 4753654 generic-all java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java 8165863 macosx-all java/awt/Clipboard/PasteNullToTextComponentsTest.java 8234140 macosx-all,windows-all From 1ebe949507b48a6b62dd36e08f0ae80da2ee1dcc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 5 Sep 2025 20:47:48 +0000 Subject: [PATCH 390/471] 8314488: Compiling the JDK with C++17 Reviewed-by: dholmes, stefank, ayang, kvn, iwalulya, jsjolen, ihse --- doc/hotspot-style.html | 617 ++++++++++++++++-- doc/hotspot-style.md | 606 ++++++++++++++++- make/autoconf/flags-cflags.m4 | 6 +- .../vscode/hotspot/indexers/ccls-settings.txt | 2 +- .../hotspot/indexers/clangd-settings.txt | 2 +- .../hotspot/indexers/cpptools-settings.txt | 2 +- .../hotspot/indexers/rtags-settings.txt | 2 +- 7 files changed, 1150 insertions(+), 87 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 88ec07475fd..98d813242a5 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -50,6 +50,9 @@ id="toc-factoring-and-class-design">Factoring and Class Design

          4. Commenting
          5. Macros
          6. Whitespace
          7. +
          8. Avoid implicit conversions +to bool
          9. Miscellaneous
        @@ -72,28 +75,74 @@ Standard Library Deduction
      • Expression SFINAE
      • +
      • Non-type template parameter +values
      • enum
      • alignas
      • thread_local
      • nullptr
      • <atomic>
      • +
      • Inline +Variables
      • Initializing variables with static storage duration
      • Uniform Initialization
      • +
      • Mandatory Copy Elision
      • Local Function Objects
      • Inheriting constructors
      • Attributes
      • noexcept
      • +
      • Enhanced selection +statements
      • +
      • Expression Evaluation +Order
      • +
      • Compatibility with C11
      • Additional Permitted Features
      • +
      • Excluded +Features +
      • Undecided +Features +
      • @@ -418,22 +467,25 @@ adjust new lines horizontally to be consistent with that organization. (E.g., trailing backslashes on long macro definitions often align.)

        -

        Miscellaneous

        -
          -
        • Use the Resource Acquisition Is -Initialization (RAII) design pattern to manage bracketed critical -sections. See class ResourceMark for an example.

        • -
        • Avoid implicit conversions to bool.

          +

          Avoid implicit conversions +to bool

          • Use bool for boolean values.
          • Do not use ints or pointers as (implicit) booleans with &&, ||, if, while. Instead, compare explicitly, i.e. if (x != 0) or if (ptr != nullptr), etc.
          • -
          • Do not use declarations in condition forms, i.e. don't use -if (T v = value) { ... }.
          • -
        • +
        • Do not use non-boolean declarations in condition forms, +i.e. don't use if (T v = value) { ... }. But see Enhanced selection +statements.
        • +
        +

        Miscellaneous

        +
          +
        • Use the Resource Acquisition Is +Initialization (RAII) design pattern to manage bracketed critical +sections. See class ResourceMark for an example.

        • Use functions from globalDefinitions.hpp and related files when performing bitwise operations on integers. Do not code directly as C operators, unless they are extremely simple. (Examples: @@ -445,16 +497,16 @@ default case. It is ok to have an empty default with comment.

        Use of C++ Features

        HotSpot was originally written in a subset of the C++98/03 language. -More recently, support for C++14 is provided, though again, HotSpot only +More recently, support for C++17 is provided, though again, HotSpot only uses a subset. (Backports to JDK versions lacking support for more recent Standards must of course stick with the original C++98/03 subset.)

        This section describes that subset. Features from the C++98/03 language may be used unless explicitly excluded here. Features from -C++11 and C++14 may be explicitly permitted or explicitly excluded, and -discussed accordingly here. There is a third category, undecided -features, about which HotSpot developers have not yet reached a -consensus, or perhaps have not discussed at all. Use of these features +C++11, C++14, and C++17 may be explicitly permitted or explicitly +excluded, and discussed accordingly here. There is a third category, +undecided features, about which HotSpot developers have not yet reached +a consensus, or perhaps have not discussed at all. Use of these features is also excluded.

        (The use of some features may not be immediately obvious and may slip in anyway, since the compiler will accept them. The code review process @@ -463,9 +515,9 @@ is the main defense against this.)

        provide more extensive discussion or rationale for limitations. Features that don't have their own subsection are listed in omnibus feature sections for permitted, excluded, and undecided features.

        -

        Lists of new features for C++11 and C++14, along with links to their -descriptions, can be found in the online documentation for some of the -compilers and libraries. The C++14 Standard is the definitive +

        Lists of new features for C++11, C++14, and C++17, along with links +to their descriptions, can be found in the online documentation for some +of the compilers and libraries. The C++17 Standard is the definitive description.

        • C++ Standards @@ -662,12 +714,39 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">n1984
        • +
        • auto for non-type template parameters (p0127r2)
          auto may +be used as a placeholder for the type of a non-type template parameter. +The type is deduced from the value provided in a template +instantiation.

        • Function return type deduction (n3638)
          Only use if the function body has a very small number of return statements, and generally relatively little other code.

        • +
        • Class template argument deduction (n3602, p0091r3)
          The template arguments +of a class template may be deduced from the arguments to a constructor. +This is similar to ordinary function argument deduction, though partial +deduction with only some template arguments explicitly provided +is not permitted for class template argument deduction. Deduction guides +may be used to provide additional control over the deduction. As with +auto variable declarations, excessive use can make code +harder to understand, because explicit type information is lacking. But +it can also remove the need to be explicit about types that are either +obvious, or that are very hard to write. For example, these allow the +addition of a scope-guard mechanism with nice syntax; something like +this

        • +
        +
          ScopeGuard guard{[&]{ ... cleanup code ... }};
        +
        • Also see lambda expressions.

        • +
        • decltype(auto) should be avoided, whether for +variables, for non-type template parameters, or for function return +types. There are subtle and complex differences between this placeholder +type and auto. Any use would need very careful +explanation.

        Expression SFINAE

        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468
        https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html

        +

        Non-type template parameter +values

        +

        C++17 extended the arguments permitted for non-type template +parameters (n4268). The kinds of +values (the parameter types) aren't changed. However, the values can now +be the result of arbitrary constant expressions (with a few restrictions +on the result), rather than a much more limited and restrictive set of +expressions. In particular, the argument for a pointer or reference type +parameter can now be the result of a constexpr function.

        enum

        Where appropriate, scoped-enums should be used. (n2347)

        @@ -805,6 +893,34 @@ differ from what the Java compilers implement.

        "conservative" memory ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering.

        +

        Inline Variables

        +

        Variables with static storage duration may be declared +inline (p0386r2). +This has similar effects as for declaring a function inline: it can be +defined, identically, in multiple translation units, must be defined in +every translation unit in which it is ODR used, and the behavior of the +program is as if there is exactly one variable.

        +

        Declaring a variable inline allows the complete definition to be in a +header file, rather than having a declaration in a header and the +definition in a .cpp file. The guidance on initialization +of such variables still applies. Inline variables with dynamic +initializations can make initialization order problems worse. The few +ordering constraints that exist for non-inline variables don't apply, as +there isn't a single program-designated translation unit containing the +definition.

        +

        A constexpr static data member is implicitly +inline. As a consequence, an ODR use of such a variable doesn't +require a definition in some .cpp file. (This is a change from +pre-C++17. Beginning with C++17, such a definition is considered a +duplicate definition, and is deprecated.)

        +

        Declaring a thread_local variable inline is +forbidden for HotSpot code. The use of +thread_local is already heavily restricted.

        Initializing variables with static storage duration

        @@ -856,6 +972,45 @@ initialization

        Although related, the use of std::initializer_list remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code.

        +

        Mandatory Copy Elision

        +

        Copy elision +(or here) +is a compiler optimization used to avoid potentially expensive copies in +certain situations. It is critical to making practical the performance +of return by value or pass by value. It is also unusual in not following +the as-if rule for optimizations - copy elision can be applied even if +doing so bypasses side-effects of copying/moving the object. The C++ +standard explicitly permits this.

        +

        However, because it's an optional optimization, the relevant +copy/move constructor must be available and accessible, in case the +compiler chooses to not apply the optimization even in a situation where +permitted.

        +

        C++17 changed some cases of copy elision so that there is never a +copy/move in these cases (p0135r1). The interesting cases +involve a function that returns an unnamed temporary object, and +constructors. In such cases the object being initialized from the +temporary is always direct initialized, with no copy/move ever involved; +see RVO and more specifically URVO.

        +

        Since this is now standard behavior it can't be avoided in the +covered situations. This could change the behavior of code that relied +on side effects by constructors, but that's both uncommon and was +already problematic because of the previous optional copy elision. But +HotSpot code can, and should, explicitly take advantage of this newly +required behavior where it makes sense to do so.

        +

        For example, it may be beneficial to delay construction of the result +of a function until the return statement, rather than having a local +variable that is modified into the desired state and then returned. +(Though NRVO may apply in that +case.)

        +

        It is also now possible to define a factory function for a class that +is neither movable nor copyable, if it can be written in a way that +makes use of this feature.

        Local Function Objects

        • Local function objects, including lambda expressions, may be @@ -928,6 +1083,13 @@ href="https://en.wikipedia.org/wiki/Partial_application" title="Partial Application">partial application. Again here, lambdas are typically much simpler and less verbose than function object classes.

          +

          A lambda is a constexpr function if either the parameter declaration +clause is followed by constexpr, or it satisfies the +requirements for a constexpr function (p0170r1). +Thus, using a lambda to package up some computation doesn't incur +unnecessary overhead or prevent use in a context required to be +compile-time evaluated (such as an array size).

          Because of these benefits, lambda expressions are permitted in HotSpot code, with some restrictions and usage guidance. An anonymous lambda is one which is passed directly as an argument. A named lambda is @@ -975,6 +1137,18 @@ making the captured value unaffected by modifications to the outer variable. But this only applies to captured auto variables, not member variables, and is inconsistent with referential transparency.

        +
      • By-value capture of this (using a capture list like +[*this] (p0018r3)) +is also not permitted. One of the motivating use-cases is when the +lifetime of the lambda exceeds the lifetime of the object for the +containing member function. That is, we have an upward lambda that is +capturing this of the enclosing method. But again, that +use-case doesn't apply if only downward lambdas are used. Another +use-case is when we simply want the lambda to be operating on a copy of +this for some reason. This is sufficiently uncommon that it +can be handled by manual copying, so readers don't need to understand +this rare syntax.

      • Non-capturing lambdas (with an empty capture list - []) have limited utility. There are cases where no captures are required (pure functions, for example), but if the function is small @@ -984,14 +1158,15 @@ href="https://isocpp.org/files/papers/N3649.html">N3649) are not permitted. Capture initializers inherently increase the complexity of the capture list, and provide little benefit over an additional in-scope local variable.

      • - -

        The use of mutable lambda expressions is forbidden +

      • The use of mutable lambda expressions is forbidden because there don't seem to be many, if any, good use-cases for them in HotSpot. A lambda expression needs to be mutable in order to modify a by-value captured value. But with only downward lambdas, such usage seems likely to be rare and complicated. It is better to use a function object class in any such cases that arise, rather than requiring all -HotSpot developers to understand this relatively obscure feature.

        +HotSpot developers to understand this relatively obscure +feature.

      • +

        While it is possible to directly invoke an anonymous lambda expression, that feature should not be used, as such a form can be confusing to readers. Instead, name the lambda and call it by name.

        @@ -1109,23 +1284,12 @@ href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">n2540C++11 provides simple syntax allowing a class to inherit the constructors of a base class. Unfortunately there are a number of problems with the original specification, and C++17 contains significant -revisions (p0136r1 opens with a list of 8 Core Issues). Since -HotSpot doesn't support use of C++17, use of inherited constructors -could run into those problems. Such uses might also change behavior in a -future HotSpot update to use C++17 or later, potentially in subtle ways -that could lead to hard to diagnose problems. Because of this, HotSpot -code must not use inherited constructors.

        -

        Note that gcc7 provides the -fnew-inheriting-ctors -option to use the p0136r1 semantics. This is enabled by default when -using C++17 or later. It is also enabled by default for -fabi-version=11 (introduced by gcc7) or higher when using -C++11/14, as the change is considered a Defect Report that applies to -those versions. Earlier versions of gcc don't have that option, and -other supported compilers may not have anything similar.

        +revisions (p0136r1 +opens with a list of 8 Core Issues). Although those issues have been +addressed, the benefits from this feature are small compared to the +complexity. Because of this, HotSpot code must not use inherited +constructors.

        +

        p0195r0

        Attributes

        The use of some attributes (n2761) @@ -1141,9 +1305,17 @@ those cases HotSpot has a preferred location.

        beginning of the function's declaration, rather than between the function name and the parameter list. +

        p0068r0 is the initial +proposal for the attributes added by C++17.)

        Only the following attributes are permitted:

        The following attributes are expressly forbidden:

          @@ -1151,6 +1323,23 @@ function name and the parameter list. memory_order_consume.
        • [[deprecated]] - Not relevant in HotSpot code.
        +

        Direct use of non-standard (and presumably scoped) attributes in +shared code is also forbidden. Using such would depend on the C++17 +feature that an attribute not recognized by the implementation is +ignored (p0283r2). If such an +attribute is needed in shared code, the well-established technique of +providing an ATTRIBUTE_XXX macro with per-compiler +definitions (sometimes empty) should be used. Compilers may warn about +unrecognized attributes (whether by name or by location), in order to +report typos or misuse. Disabling such warnings globally would not be +desirable.

        +

        The use of using directives in attribute lists is also +forbidden. (p0028r0) (p0028r4) We don't generally use +scoped attributes in attribute lists with other attributes. Rather, uses +of scoped attributes (which are implementation defined) are generally +hidden behind a portability macro that includes the surrounding +brackets.

        noexcept

        Use of noexcept exception specifications (n3050) are permitted with restrictions @@ -1200,9 +1389,72 @@ Standard Library facilities.

        functions not declared noexcept. So HotSpot code doesn't ever need to check, either with conditional exception specifications or with noexcept expressions.

        +

        The exception specification is part of the type of a function (p0012r1. This likely has little +impact on HotSpot code, since the use of noexcept is +expected to be rare.

        Dynamic exception specifications were deprecated in C++11. C++17 removed all but throw(), with that remaining a deprecated equivalent to noexcept.

        +

        Enhanced selection +statements

        +

        C++17 modified the condition part of if and +switch statements, permitting an init-statement to +be included (p0305r1).

        +

        Use of this feature is permitted. (However, complex uses may +interfere with readability.) Limiting the scope of a variable involved +in the condition, while also making the value available to the +statement's body, can improve readability. The alternative method of +scope-limiting by introducing a nested scope isn't very popular and is +rarely used.

        +

        This new syntax is in addition to the condition being a +declaration with a brace-or-equal-initializer. For an +if statement this new sytax gains that benefit without +violating the long-standing guidance against using implicit conversions to +bool, which still stands.

        +

        For example, uses of Unified Logging sometimes explicitly check +whether a LogTarget is enabled. Instead of

        +
          LogTarget(...) lt;
        +  if (lt.is_enabled()) {
        +    LogStream log(lt);
        +    ... use log ...
        +  }
        +  ... lt is accessible but probably not needed here ...
        +

        using this feature one could write

        +
          if (LogTarget(...) lt; lt.is_enabled()) {
        +    LogStream log(lt);
        +    ... use log ...
        +  }
        +

        C++17 also added compile-time if statements (p0292r2). Use of +if constexpr is permitted. This feature can replace and +(sometimes vastly) simplify many uses of SFINAE. The same +declaration and initialization guidance for the condition part +apply here as for ordinary if statements.

        +

        Expression Evaluation Order

        +

        C++17 tightened up the evaluation order for some kinds of +subexpressions (p0138r2). Note, +however, that the Alternate Evaluation Order for Function Calls +alternative in that paper was adopted, rather than the strict left to +right order of evaluation for function call arguments that was proposed +in the main body of the paper.

        +

        The primary purpose of this change seems to be to make certain kinds +of call chaining well defined. That's not a style widely used in +HotSpot. In general it is better to continue to avoid questions in this +area by isolating operations with side effects from other statements. In +particular, continue to avoid modifying a value in an expression where +it is also used.

        +

        Compatibility with C11

        +

        C++17 refers to C11 rather than C99. This means that C11 libraries +and functions may be used in HotSpot. There may be limitations because +of differing levels of compatibility among various compilers and +versions of those compilers.

        +

        Note that the C parts of the JDK have been built with C11 selected +for some time (JDK-8292008).

        Additional Permitted Features

          @@ -1218,8 +1470,10 @@ href="https://isocpp.org/files/papers/n3778.html">n3778)

          href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">n2242) (n2555)

          -
        • Static assertions (n1720)

        • +
        • Static assertions (n1720) +(n3928)
          Both the original +(C++11) two-argument form and the new (C++17) single-argument form are +permitted.

        • decltype (n2343) (n2930< href="https://en.cppreference.com/w/cpp/language/range-for">range-for)

        • Unrestricted Unions (n2544)

        • +
        • Preprocessor Condition __has_include (p0061r0) (p0061r1)

        • +
        • Hexadecimal Floating-Point Literals (p0245r1)

        • +
        • Construction Rules for enum class Values (p0138r2)

        • +
        • Allow typename in template template parameter (n4051) — template template parameters +are barely used (if at all) in HotSpot, but there's no reason to +artificially disallow this syntactic regularization in any such +uses.

        -

        Excluded Features

        +

        Excluded Features

        +

        Structured Bindings

        +

        The use of structured bindings p0217r3 is forbidden. Preferred +approaches for handling functions with multiple return values +include

        +
          +
        • Return a named class/struct intended for that purpose, with named +and typed members/accessors.

        • +
        • Return a value along with out parameters (usually pointers, +sometimes references).

        • +
        • Designate a sentinel "failure" value in the normal return value +type, with some out of band location for additional information. For +example, this is the model typically used with errno, where +a function returns a normal result, or -1 to indicate an error, with +additional error information in errno.

        • +
        +

        There is a strong preference for names and explicit types, as opposed +to offsets and implicit types. For example, there are folks who strongly +dislike that some of the Standard Library functions return +std::pair because first and +second members don't carry any useful information.

        +

        File System Library

        +

        The use of the File System library is forbidden. HotSpot doesn't do +very much with files, and already has adequate mechanisms for its needs. +Rewriting in terms of this new library doesn't provide any obviously +significant benefits. Having a mix of the existing usage and uses of +this new library would be confusing.

        +

        n4100 p0218r0 p0219r1 p0317r1 p0392r0 p0430r2 p0492r2 p1164r1

        +

        Aggregate Extensions

        +

        Aggregates with base classes are forbidden. C++17 allows aggregate +initialization for classes with base classes (p0017r1). HotSpot makes very little +use of aggregate classes, preferring explicit constructors even for very +simple classes.

        +

        Additional Excluded Features

        • New string and character literals

            @@ -1295,22 +1603,239 @@ useful.

            operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation.

          • Avoid most implicit conversion constructors and (implicit or -explicit) conversion operators. (Note that conversion to -bool isn't needed in HotSpot code because of the "no -implicit boolean" guideline.)

          • +explicit) conversion operators. Conversion to bool +operators aren't needed because of the no implicit boolean +guideline.)

          • Avoid goto statements.

          • +
          • Attributes for namespaces and enumerators (n4266 — The only applicable attribute +is [[deprecated]], which is +forbidden.

          • +
          • Variadic using declarations (p0195r2)

          • +
          • std::variant<> (p0088r3) — Even if more of the C++ +Standard Library is permitted, this class will remain forbidded. Invalid +accesses are indicated by throwing exceptions.

          • +
          • std::any (p0220r1) — Even if more of the C++ +Standard Library is permitted, this class will remain forbidden. It may +require allocation, and always uses the standard allocator. It requires +RTTI.

          • +
          • std::as_const() (p0007r1) — If sufficiently useful, +HotSpot could add such a function. It would likely be added to +globalDefinitions.hpp, where there are already some similar small +utilities.

          • +
          • std::clamp() (p002501) — This function is already +provided in globalDefinitions.hpp.

          • +
          • Parallel STL Algorithms (p0024r2) — Even if more of the C++ +Standard Library is permitted, these will remain forbidden. They are +built on the standard C++ threading mechanisms. HotSpot doesn't use +those mechanisms, instead providing and using its own.

          • +
          • Cache Line Sizes p0154r1 — +HotSpot has its own mechanisms for this, using values like +DEFAULT_CACHE_LINE_SIZE. The platform-specific +implementation of the HotSpot mechanisms might use these library +functions, but there is no reason to move away from the current +approach. Quoting from JOSUTTIS: "... if you know better, +use specific values, but using these values is better than any assumed +fixed size for code supporting multiple platforms."

          • +
          • register storage class removal p0001r1 — The register +storage class has been removed. register is still a +keyword, so still can't be used for normal purposes. Also, this doesn't +affect the use of register for gcc-style extended asm code; +that's a different syntactic element with a different meaning.

          • +
          • Value of __cplusplus — Testing whether +__cplusplus is defined or not is permitted, and indeed +required. But the value should not need to be examined. The value is +changed with each revision of the Standard. But we build HotSpot and +(most of) the rest of the JDK with a specifically selected version of +the Standard. The value of __cplusplus should be known and +unchanging until we change the project's build configuration again. So +examining the value shouldn't ever be necessary.

          • +
          • Removal of ++ for bool (p0003r1)

          • +
          • Removal of trigraphs (n4086)

          -

          Undecided Features

          +

          Undecided Features

          This list is incomplete; it serves to explicitly call out some features that have not yet been discussed.

          +

          Some features are undecided (so implicitly forbidden) because we +don't expect to use them at all. This might be reconsidered if someone +finds a good use case.

          +

          Some Standard Library features are undecided (so implicitly +forbidden) because, while this Style Guide forbids the use of such, they +may be sufficiently useful that we want to permit them anyway. Doing so +may require some idiomatic mechanism for addressing things like +assert incompatibility, incompatibility with HotSpot's +FORBID_C_FUNCTION mechanism, and the like.

          +

          std::optional<>

          +

          It is undecided whether to permit the use of +std::optional<> (p0220r1). It may be sufficiently +useful that it should be permitted despite the usual prohibition against +using Standard Library facilities. Use of the value() +member function must be forbidden, as it reports an invalid access by +throwing an exception.

          +

          std::byte

          +

          It is undecided whether to permit the use of the +std::byte type (p0298r3). It may be sufficiently +useful that it should be permitted despite the usual prohibition against +using Standard Library facilities.

          +

          It has been suggested that changing the HotSpot address +type to use std::byte has some benefits. That is, +replace

          +
          typedef u_char*       address;
          +typedef const u_char* const_address;
          +
          using address       = std::byte*;
          +using const_address = const std::byte*;
          +

          in globalDefinitions.hpp.

          +

          A specific benefit that was mentioned is that it might improve the +horrible way that gdb handles our current definition of the +address type.

          +
          #include <cstddef>
          +
          +typedef unsigned char* address;
          +typedef std::byte* address_b;
          +
          +int main() {
          +
          +  char* mem;
          +
          +  address addr = (address)mem;
          +  address_b addr_b = (address_b)mem;
          +
          +  return 0;
          +}
          +
          (gdb) p addr
          +$1 = (address) 0x7ffff7fe4fa0 <dl_main> "\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002"
          +(gdb) p addr_b
          +$2 = (address_b) 0x7ffff7fe4fa0 <dl_main>
          +

          This needs to be explored. Some folks have said they will do so.

          +

          String Views

          +

          It is undecided whether to permit the use of +std::string_view (p0220r1).

          +

          HotSpot doesn't use std::string, but uses +char* strings a lot. Wrapping such in a +std::string_view to enable the use of various algorithms +could be useful. But since HotSpot also doesn't permit use of +<algorithm> and the like, that only gets the limited +set of algorithms provided by the view class directly.

          +

          There is also the issue of NUL termination; string views +are not necessarily NUL terminated. Moreover, if one goes +to the work of making one that is NUL terminated, that +terminator is included in the size.

          +

          There are other caveats. Permitting use of string views would require +discussion of those.

          +

          Substring and Subsequence +Searching

          +

          In addition to simple substring searching, the Standard Library now +includes Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone +wants to search really large texts. That seems an unlikely use-case for +HotSpot. See p0220r1.

          +

          new and +delete with Over-Aligned Data

          +

          It is undecided whether to permit the use of dynamic allocation of +overaligned types (n3396).

          +

          HotSpot currently only has a couple of over-aligned types that are +dynamically allocated. These are handled manually, not going through +new expressions, as that couldn't work before C++17.

          +

          One of the ways an over-aligned type might arise is by aligning a +data member. This might be done to avoid destructive interference for +concurrent accesses. But HotSpot uses a different approach, using +explicit padding. Again, this is in part because new and +delete of overaligned types didn't work. But we might +prefer to continue this approach.

          +

          We would need to add operator new overloads to +CHeapObj<> and possibly in other places in order to +support this. However, it has been suggested that implementing it +(efficiently) on top of NMT might be difficult. Note that +posix_memalign / _aligned_malloc don't help +here, because of NMT's use of malloc headers.

          +

          If we don't support it we may want to add operator new +overloads that are deleted, to prevent attempted uses.

          +

          Alignment usage in non-HotSpot parts of the OpenJDK:

          +
            +
          • alignas used once in harfbuzz, to align a +variable.

          • +
          • libpipewire has #define SPA_ALIGNED macro using gcc +aligned attribute, but doesn't use it.

          • +
          • libsleef has #define ALIGNED macro using gcc +aligned attribute. It is not used for class or member +declarations.

          • +
          +

          std::to_chars() and +std::from_chars

          +

          It is undecided whether to permit the use of +std::to_chars() and std::from_chars() (p0067r5).

          +

          These functions provide low-level conversions between character +sequences and numeric values. This seems like a good candidate for use +in HotSpot, potentially replacing various clumsy or less performant +alternatives. There is no memory allocation. Parsing failures are +indicated via error codes rather than exceptions. Various other nice for +HotSpot properties.

          +

          Note that the published C++17 Standard puts these in +<utility>, but a defect report moved them to +<charconv>. This also needs +<system_error>.

          +

          This would require upgrading the minimum gcc version to 11.1 for +floating point conversion support. The minimum Visual Studio version is +already sufficient. The minimum clang version requirement hasn't been +determined yet.

          +

          std::launder()

          +

          It is undecided whether to permit the use of +std::launder() (p0137r1).

          +

          Change to permitted if we discover a place where we need it. Or maybe +we should just permit it, but hope we don't need it.

          +

          Also, C++20 revised the relevant part of Object Lifetime in a way +that seems more permissive and with less need of laundering. We don't +know if implementations of prior versions take advantage of the +difference.

          +

          See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8

          +

          Additional Undecided +Features

          • Trailing return type syntax for functions (n2541)

          • Variable templates (n3651)

          • +href="https://isocpp.org/files/papers/N3651.pdf">n3651, p0127r2)

          • Member initializers and aggregates (n3653)

          • Rvalue references and move semantics

          • +
          • Shorthand for nested namespaces (n4230) — HotSpot makes very little use +of namespaces, so this seemingly innocuous feature probably isn't useful +to us.

          • +
          • Direct list initialization with auto (n3681) — This change fixed some issues +with direct list initialization and auto. But we don't use +that feature much, if at all. And perhaps shouldn't be using +it.

          • +
          • UTF-8 Character Literals (n4267) — Do we have a use-case for +this?

          • +
          • Fold Expressions (n4295) — +Provides a simple way to apply operators to a parameter pack. HotSpot +doesn't use variadic templates very much. That makes it questionable +that developers should need to know about this feature. But if someone +does come up with a good use-case, it's likely that the alternatives are +significantly worse, because pack manipulation without this can be +complicated.

          • +
          • std::invoke<>() (n4169)

          diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 322bdc8458e..e3ba4b470ce 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -377,20 +377,22 @@ adjust new lines horizontally to be consistent with that organization. (E.g., trailing backslashes on long macro definitions often align.) +### Avoid implicit conversions to bool + +* Use `bool` for boolean values. +* Do not use ints or pointers as (implicit) booleans with `&&`, `||`, +`if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or +`if (ptr != nullptr)`, etc. +* Do not use non-boolean declarations in _condition_ forms, i.e. don't use +`if (T v = value) { ... }`. But see +[Enhanced selection statements](#enhanced-selection-statements). + ### Miscellaneous * Use the [Resource Acquisition Is Initialization][RAII] (RAII) design pattern to manage bracketed critical sections. See class `ResourceMark` for an example. -* Avoid implicit conversions to `bool`. - * Use `bool` for boolean values. - * Do not use ints or pointers as (implicit) booleans with `&&`, `||`, - `if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or - `if (ptr != nullptr)`, etc. - * Do not use declarations in _condition_ forms, i.e. don't use - `if (T v = value) { ... }`. - * Use functions from globalDefinitions.hpp and related files when performing bitwise operations on integers. Do not code directly as C operators, unless @@ -402,18 +404,17 @@ they are extremely simple. (Examples: `align_up`, `is_power_of_2`, * Always enumerate all cases in a switch statement or provide a default case. It is ok to have an empty default with comment. - ## Use of C++ Features HotSpot was originally written in a subset of the C++98/03 language. -More recently, support for C++14 is provided, though again, +More recently, support for C++17 is provided, though again, HotSpot only uses a subset. (Backports to JDK versions lacking support for more recent Standards must of course stick with the original C++98/03 subset.) This section describes that subset. Features from the C++98/03 language may be used unless explicitly excluded here. Features from -C++11 and C++14 may be explicitly permitted or explicitly excluded, +C++11, C++14, and C++17 may be explicitly permitted or explicitly excluded, and discussed accordingly here. There is a third category, undecided features, about which HotSpot developers have not yet reached a consensus, or perhaps have not discussed at all. Use of these @@ -428,9 +429,9 @@ more extensive discussion or rationale for limitations. Features that don't have their own subsection are listed in omnibus feature sections for permitted, excluded, and undecided features. -Lists of new features for C++11 and C++14, along with links to their +Lists of new features for C++11, C++14, and C++17, along with links to their descriptions, can be found in the online documentation for some of the -compilers and libraries. The C++14 Standard is the definitive +compilers and libraries. The C++17 Standard is the definitive description. * [C++ Standards Support in GCC](https://gcc.gnu.org/projects/cxx-status.html) @@ -635,13 +636,40 @@ For local variables, this can be used to make the code clearer by eliminating type information that is obvious or irrelevant. Excessive use can make code much harder to understand. +* `auto` for non-type template parameters +([p0127r2](http://wg21.link/p0127r2))
          +`auto` may be used as a placeholder for the type of a non-type template +parameter. The type is deduced from the value provided in a template +instantiation. + * Function return type deduction ([n3638](https://isocpp.org/files/papers/N3638.html))
          Only use if the function body has a very small number of `return` statements, and generally relatively little other code. +* Class template argument deduction +([n3602](http://wg21.link/n3602), [p0091r3](http://wg21.link/p0091r3))
          +The template arguments of a class template may be deduced from the arguments +to a constructor. This is similar to ordinary function argument deduction, +though partial deduction with only _some_ template arguments explicitly +provided is not permitted for class template argument deduction. Deduction +guides may be used to provide additional control over the deduction. As with +`auto` variable declarations, excessive use can make code harder to +understand, because explicit type information is lacking. But it can also +remove the need to be explicit about types that are either obvious, or that +are very hard to write. For example, these allow the addition of a scope-guard +mechanism with nice syntax; something like this +``` + ScopeGuard guard{[&]{ ... cleanup code ... }}; +``` + * Also see [lambda expressions](#lambdaexpressions). +* `decltype(auto)` should be avoided, whether for variables, for non-type +template parameters, or for function return types. There are subtle and +complex differences between this placeholder type and `auto`. Any use would +need very careful explanation. + ### Expression SFINAE [Substitution Failure Is Not An Error][SFINAE] (SFINAE) @@ -663,6 +691,16 @@ Here are a few closely related example bugs:

          +### Non-type template parameter values + +C++17 extended the arguments permitted for non-type template parameters +([n4268](http://wg21.link/n4268)). The kinds of values (the parameter types) +aren't changed. However, the values can now be the result of arbitrary +constant expressions (with a few restrictions on the result), rather than a +much more limited and restrictive set of expressions. In particular, the +argument for a pointer or reference type parameter can now be the result of a +constexpr function. + ### enum Where appropriate, _scoped-enums_ should be used. @@ -781,6 +819,32 @@ ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering. +### Inline Variables + +Variables with static storage duration may be declared `inline` +([p0386r2](https://wg21.link/p0386r2)). This has similar effects as for +declaring a function inline: it can be defined, identically, in multiple +translation units, must be defined in every translation unit in which it is +[ODR used][ODR], and the behavior of the program is as if there is exactly one +variable. + +Declaring a variable inline allows the complete definition to be in a header +file, rather than having a declaration in a header and the definition in a +.cpp file. The guidance on +[initialization](#initializing-variables-with-static-storage-duration) of such +variables still applies. Inline variables with dynamic initializations can +make initialization order problems worse. The few ordering constraints +that exist for non-inline variables don't apply, as there isn't a single +program-designated translation unit containing the definition. + +A `constexpr` static data member is implicitly `inline`. As a consequence, an +[ODR use][ODR] of such a variable doesn't require a definition in some .cpp +file. (This is a change from pre-C++17. Beginning with C++17, such a +definition is considered a duplicate definition, and is deprecated.) + +Declaring a `thread_local` variable `inline` is forbidden for HotSpot code. +[The use of `thread_local`](#thread_local) is already heavily restricted. + ### Initializing variables with static storage duration Variables with static storage duration and _dynamic initialization_ @@ -824,6 +888,53 @@ Some relevant sections from cppreference.com: Although related, the use of `std::initializer_list` remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code. +### Mandatory Copy Elision + +[Copy elision](https://en.wikipedia.org/wiki/Copy_elision) +(or [here](https://cn.cppreference.com/w/cpp/language/copy_elision.html)) +is a compiler optimization used to avoid potentially expensive copies in +certain situations. It is critical to making practical the performance of +return by value or pass by value. It is also unusual in not following the +as-if rule for optimizations - copy elision can be applied even if doing so +bypasses side-effects of copying/moving the object. The C++ standard +explicitly permits this. + +However, because it's an optional optimization, the relevant copy/move +constructor must be available and accessible, in case the compiler chooses to +not apply the optimization even in a situation where permitted. + +C++17 changed some cases of copy elision so that there is never a copy/move in +these cases ([p0135r1](http://wg21.link/p0135r1)). The interesting cases +involve a function that returns an unnamed temporary object, and constructors. +In such cases the object being initialized from the temporary is always direct +initialized, with no copy/move ever involved; see [RVO] and more specifically +[URVO]. + +Since this is now standard behavior it can't be avoided in the covered +situations. This could change the behavior of code that relied on side effects +by constructors, but that's both uncommon and was already problematic because +of the previous optional copy elision. But HotSpot code can, and should, +explicitly take advantage of this newly required behavior where it makes sense +to do so. + +For example, it may be beneficial to delay construction of the result of a +function until the return statement, rather than having a local variable that +is modified into the desired state and then returned. (Though [NRVO] may apply +in that case.) + +It is also now possible to define a factory function for a class that is +neither movable nor copyable, if it can be written in a way that makes use of +this feature. + +[RVO]: https://en.wikipedia.org/wiki/Copy_elision#RVO + "Return Value Optimization" + +[NRVO]: https://en.wikipedia.org/wiki/Copy_elision#NRVO + "Named Return Value Optimization" + +[URVO]: https://cn.cppreference.com/w/cpp/language/copy_elision.html + "Unnamed Return Value Optimization" + ### Local Function Objects * Local function objects, including lambda expressions, may be used. @@ -892,6 +1003,12 @@ Another use for local functions is [partial application][PARTIALAPP]. Again here, lambdas are typically much simpler and less verbose than function object classes. +A lambda is a constexpr function if either the parameter declaration clause is +followed by `constexpr`, or it satisfies the requirements for a constexpr +function ([p0170r1]). Thus, using a lambda to package up some computation +doesn't incur unnecessary overhead or prevent use in a context required to be +compile-time evaluated (such as an array size). + Because of these benefits, lambda expressions are permitted in HotSpot code, with some restrictions and usage guidance. An anonymous lambda is one which is passed directly as an argument. A named lambda is the value of a @@ -943,6 +1060,17 @@ the most part they don't apply to HotSpot code, given other usage restrictions. applies to captured auto variables, not member variables, and is inconsistent with referential transparency. +* By-value capture of `this` (using a capture list like `[*this]` ([p0018r3])) +is also not permitted. One of the motivating use-cases is when the lifetime of +the lambda exceeds the lifetime of the object for the containing member +function. That is, we have an upward lambda that is capturing `this` of the +enclosing method. But again, that use-case doesn't apply if only downward +lambdas are used. + Another use-case is when we simply want the lambda to be operating on a copy +of `this` for some reason. This is sufficiently uncommon that it can be +handled by manual copying, so readers don't need to understand this rare +syntax. + * Non-capturing lambdas (with an empty capture list - `[]`) have limited utility. There are cases where no captures are required (pure functions, for example), but if the function is small and simple then that's obvious @@ -952,7 +1080,7 @@ anyway. Capture initializers inherently increase the complexity of the capture list, and provide little benefit over an additional in-scope local variable. -The use of `mutable` lambda expressions is forbidden because there don't +* The use of `mutable` lambda expressions is forbidden because there don't seem to be many, if any, good use-cases for them in HotSpot. A lambda expression needs to be mutable in order to modify a by-value captured value. But with only downward lambdas, such usage seems likely to be rare and @@ -1099,21 +1227,12 @@ Do not use _inheriting constructors_ C++11 provides simple syntax allowing a class to inherit the constructors of a base class. Unfortunately there are a number of problems with the original specification, and C++17 contains significant revisions ([p0136r1] opens with -a list of 8 Core Issues). Since HotSpot doesn't support use of C++17, use of -inherited constructors could run into those problems. Such uses might also -change behavior in a future HotSpot update to use C++17 or later, potentially -in subtle ways that could lead to hard to diagnose problems. Because of this, -HotSpot code must not use inherited constructors. +a list of 8 Core Issues). Although those issues have been addressed, the +benefits from this feature are small compared to the complexity. Because of +this, HotSpot code must not use inherited constructors. -Note that gcc7 provides the `-fnew-inheriting-ctors` option to use the -[p0136r1] semantics. This is enabled by default when using C++17 or later. -It is also enabled by default for `fabi-version=11` (introduced by gcc7) or -higher when using C++11/14, as the change is considered a Defect Report that -applies to those versions. Earlier versions of gcc don't have that option, -and other supported compilers may not have anything similar. - -[p0136r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html - "p0136r1" +[p0136r1]: http:/wg21.link/p0136r1 "p0136r1" +[p0195r0](http://wg21.link/p0195r0) ### Attributes @@ -1132,15 +1251,39 @@ preferred location. function's declaration, rather than between the function name and the parameter list. +[p0068r0](http://wg21.link/p0068r0) is the initial proposal for the attributes +added by C++17.) + Only the following attributes are permitted: * `[[noreturn]]` +* `[[nodiscard]]` ([p0189r1](http://wg21.link/p0189r1)) +* `[[maybe_unused]]` ([p0212r1](http://wg21.link/p0212r1)) +* `[[fallthrough]]` ([p0188r1](http://wg21.link/p0188)) The following attributes are expressly forbidden: * `[[carries_dependency]]` - Related to `memory_order_consume`. * `[[deprecated]]` - Not relevant in HotSpot code. +Direct use of non-standard (and presumably scoped) attributes in shared code +is also forbidden. Using such would depend on the C++17 feature that an +attribute not recognized by the implementation is ignored +([p0283r2](http://wg21.link/p0283r2)). If such an attribute is needed in +shared code, the well-established technique of providing an `ATTRIBUTE_XXX` +macro with per-compiler definitions (sometimes empty) should be +used. Compilers may warn about unrecognized attributes (whether by name or by +location), in order to report typos or misuse. Disabling such warnings +globally would not be desirable. + +The use of `using` directives in attribute lists is also forbidden. +([p0028r0](http://wg21.link/p0028r0)) +([p0028r4](http://wg21.link/p0028r4)) +We don't generally use scoped attributes in attribute lists with other +attributes. Rather, uses of scoped attributes (which are implementation +defined) are generally hidden behind a portability macro that includes the +surrounding brackets. + ### noexcept Use of `noexcept` exception specifications @@ -1189,9 +1332,79 @@ HotSpot code can assume no exceptions will ever be thrown, even from functions not declared `noexcept`. So HotSpot code doesn't ever need to check, either with conditional exception specifications or with `noexcept` expressions. +The exception specification is part of the type of a function +([p0012r1](http://wg21.link/p0012r1). This likely has little impact on HotSpot +code, since the use of `noexcept` is expected to be rare. + Dynamic exception specifications were deprecated in C++11. C++17 removed all but `throw()`, with that remaining a deprecated equivalent to `noexcept`. +### Enhanced selection statements + +C++17 modified the _condition_ part of `if` and `switch` statements, permitting +an _init-statement_ to be included +([p0305r1](http://wg21.link/p0305r1)). + +Use of this feature is permitted. (However, complex uses may interfere with +readability.) Limiting the scope of a variable involved in the condition, +while also making the value available to the statement's body, can improve +readability. The alternative method of scope-limiting by introducing a nested +scope isn't very popular and is rarely used. + +This new syntax is in addition to the _condition_ being a declaration with a +_brace-or-equal-initializer_. For an `if` statement this new sytax gains that +benefit without violating the long-standing guidance against using +[implicit conversions to `bool`](#avoid-implicit-conversions-to-bool), +which still stands. + +For example, uses of Unified Logging sometimes explicitly check whether a +`LogTarget` is enabled. Instead of +``` + LogTarget(...) lt; + if (lt.is_enabled()) { + LogStream log(lt); + ... use log ... + } + ... lt is accessible but probably not needed here ... +``` +using this feature one could write +``` + if (LogTarget(...) lt; lt.is_enabled()) { + LogStream log(lt); + ... use log ... + } +``` + +C++17 also added compile-time `if` statements +([p0292r2](http://wg21.link/p0292r2)). Use of `if constexpr` is +permitted. This feature can replace and (sometimes vastly) simplify many uses +of [SFINAE]. The same declaration and initialization guidance for the +_condition_ part apply here as for ordinary `if` statements. + +### Expression Evaluation Order + +C++17 tightened up the evaluation order for some kinds of subexpressions +([p0138r2](http://wg21.link/p0138r2)). Note, however, that the Alternate +Evaluation Order for Function Calls alternative in that paper was adopted, +rather than the strict left to right order of evaluation for function call +arguments that was proposed in the main body of the paper. + +The primary purpose of this change seems to be to make certain kinds of call +chaining well defined. That's not a style widely used in HotSpot. In general +it is better to continue to avoid questions in this area by isolating +operations with side effects from other statements. In particular, continue to +avoid modifying a value in an expression where it is also used. + +### Compatibility with C11 + +C++17 refers to C11 rather than C99. This means that C11 libraries and +functions may be used in HotSpot. There may be limitations because of +differing levels of compatibility among various compilers and versions of +those compilers. + +Note that the C parts of the JDK have been built with C11 selected for some +time ([JDK-8292008](https://bugs.openjdk.org/browse/JDK-8292008)). + ### Additional Permitted Features * `alignof` @@ -1209,7 +1422,10 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`. ([n2555](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf)) * Static assertions -([n1720](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html)) +([n1720](http://wg21.link/n1720)) +([n3928](http://wg21.link/n3928))
          +Both the original (C++11) two-argument form and the new (C++17) +single-argument form are permitted. * `decltype` ([n2343](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf)) @@ -1256,7 +1472,72 @@ but `throw()`, with that remaining a deprecated equivalent to `noexcept`. * Unrestricted Unions ([n2544](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf)) -### Excluded Features +* Preprocessor Condition `__has_include` +([p0061r0](http://wg21.link/p0061r0)) +([p0061r1](http://wg21.link/p0061r1)) + +* Hexadecimal Floating-Point Literals +([p0245r1](http://wg21.link/p0245r1)) + +* Construction Rules for `enum class` Values +([p0138r2](http://wg21.link/p0138r2)) + +* Allow `typename` in template template parameter +([n4051](http://wg21.link/n4051)) — template template parameters are +barely used (if at all) in HotSpot, but there's no reason to artificially +disallow this syntactic regularization in any such uses. + +## Excluded Features + +### Structured Bindings + +The use of structured bindings [p0217r3](http://wg21.link/p0217r3) is +forbidden. Preferred approaches for handling functions with multiple return +values include + +* Return a named class/struct intended for that purpose, with named and typed +members/accessors. + +* Return a value along with out parameters (usually pointers, sometimes +references). + +* Designate a sentinel "failure" value in the normal return value type, with +some out of band location for additional information. For example, this is +the model typically used with `errno`, where a function returns a normal +result, or -1 to indicate an error, with additional error information in +`errno`. + +There is a strong preference for names and explicit types, as opposed to +offsets and implicit types. For example, there are folks who strongly dislike +that some of the Standard Library functions return `std::pair` because `first` +and `second` members don't carry any useful information. + +### File System Library + +The use of the File System library is forbidden. HotSpot doesn't do very much +with files, and already has adequate mechanisms for its needs. Rewriting in +terms of this new library doesn't provide any obviously significant +benefits. Having a mix of the existing usage and uses of this new library +would be confusing. + +[n4100](http://wg21.link/n4100) +[p0218r0](http://wg21.link/p0218r0) +[p0219r1](http://wg21.link/p0219r1) +[p0317r1](http://wg21.link/p0317r1) +[p0392r0](http://wg21.link/p0392r0) +[p0430r2](http://wg21.link/p0430r2) +[p0492r2](http://wg21.link/p0492r2) +[p1164r1](http://wg21.link/p1164r1) + +### Aggregate Extensions + +Aggregates with base classes are forbidden. C++17 allows aggregate +initialization for classes with base classes +([p0017r1](https://wg21.link/p0017r1)). HotSpot makes very little use of +aggregate classes, preferring explicit constructors even for very simple +classes. + +### Additional Excluded Features * New string and character literals * New character types @@ -1292,27 +1573,281 @@ operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation. * Avoid most implicit conversion constructors and (implicit or explicit) -conversion operators. (Note that conversion to `bool` isn't needed -in HotSpot code because of the "no implicit boolean" guideline.) +conversion operators. Conversion to `bool` operators aren't needed +because of the +[no implicit boolean](#avoid-implicit-conversions-to-bool) +guideline.) * Avoid `goto` statements. -### Undecided Features +* Attributes for namespaces and enumerators +([n4266](http://wg21.link/n4266) — +The only applicable attribute is [`[[deprecated]]`](#attributes), which is +forbidden. + +* Variadic `using` declarations +([p0195r2](http://wg21.link/p0195r2)) + +* `std::variant<>` +([p0088r3](http://wg21.link/p0088r3)) — +Even if more of the C++ Standard Library is permitted, this class will remain +forbidded. Invalid accesses are indicated by throwing exceptions. + +* `std::any` +([p0220r1](http://wg21.link/p0220r1)) — +Even if more of the C++ Standard Library is permitted, this class will remain +forbidden. It may require allocation, and always uses the standard +allocator. It requires [RTTI]. + +* `std::as_const()` +([p0007r1](http://wg21.link/p0007r1)) — +If sufficiently useful, HotSpot could add such a function. It would likely be +added to globalDefinitions.hpp, where there are already some similar small +utilities. + +* `std::clamp()` +([p002501](http://wg21.link/p002501)) — +This function is already provided in globalDefinitions.hpp. + +* Parallel STL Algorithms +([p0024r2](http://wg21.link/p0024r2)) — +Even if more of the C++ Standard Library is permitted, these will remain +forbidden. They are built on the standard C++ threading mechanisms. HotSpot +doesn't use those mechanisms, instead providing and using its own. + +* Cache Line Sizes +[p0154r1](http://wg21.link/p0154r1) — +HotSpot has its own mechanisms for this, using values like +`DEFAULT_CACHE_LINE_SIZE`. The platform-specific implementation of the HotSpot +mechanisms might use these library functions, but there is no reason to move +away from the current approach. Quoting from [JOSUTTIS]: "... if you know better, +use specific values, but using these values is better than any assumed fixed +size for code supporting multiple platforms." + +* `register` storage class removal +[p0001r1](http://wg21.link/p0001r1) — +The `register` storage class has been removed. `register` is still a keyword, +so still can't be used for normal purposes. Also, this doesn't affect the use +of `register` for gcc-style extended asm code; that's a different syntactic +element with a different meaning. + +* Value of `__cplusplus` — +Testing whether `__cplusplus` is defined or not is permitted, and indeed +required. But the value should not need to be examined. The value is changed +with each revision of the Standard. But we build HotSpot and (most of) the +rest of the JDK with a specifically selected version of the Standard. The +value of `__cplusplus` should be known and unchanging until we change the +project's build configuration again. So examining the value shouldn't ever be +necessary. + +* Removal of `++` for `bool` +([p0003r1](http://wg21.link/p0003r1)) + +* Removal of trigraphs +([n4086](http://wg21.link/n4086)) + +## Undecided Features This list is incomplete; it serves to explicitly call out some features that have not yet been discussed. +Some features are undecided (so implicitly forbidden) because we don't expect +to use them at all. This might be reconsidered if someone finds a good use +case. + +Some Standard Library features are undecided (so implicitly forbidden) +because, while this Style Guide forbids the use of such, they may be +sufficiently useful that we want to permit them anyway. Doing so may require +some idiomatic mechanism for addressing things like `assert` incompatibility, +incompatibility with HotSpot's `FORBID_C_FUNCTION` mechanism, and the like. + +### std::optional<> + +It is undecided whether to permit the use of `std::optional<>` +([p0220r1](http://wg21.link/p0220r1)). It may be sufficiently useful that it +should be permitted despite the usual prohibition against using Standard +Library facilities. Use of the `value()` member function must be forbidden, as +it reports an invalid access by throwing an exception. + +### std::byte + +It is undecided whether to permit the use of the `std::byte` type +([p0298r3](http://wg21.link/p0298r3)). It may be sufficiently useful that it +should be permitted despite the usual prohibition against using Standard +Library facilities. + +It has been suggested that changing the HotSpot `address` type to use +`std::byte` has some benefits. That is, replace +``` +typedef u_char* address; +typedef const u_char* const_address; +``` +``` +using address = std::byte*; +using const_address = const std::byte*; +``` +in globalDefinitions.hpp. + +A specific benefit that was mentioned is that it might improve the horrible +way that gdb handles our current definition of the `address` type. +``` +#include + +typedef unsigned char* address; +typedef std::byte* address_b; + +int main() { + + char* mem; + + address addr = (address)mem; + address_b addr_b = (address_b)mem; + + return 0; +} +``` + +``` +(gdb) p addr +$1 = (address) 0x7ffff7fe4fa0 "\363\017\036\372Uf\017\357\300H\211\345AWI\211\377AVAUATSH\201\354\210\002" +(gdb) p addr_b +$2 = (address_b) 0x7ffff7fe4fa0 +``` + +This needs to be explored. Some folks have said they will do so. + +### String Views + +It is undecided whether to permit the use of `std::string_view` +([p0220r1](http://wg21.link/p0220r1)). + +HotSpot doesn't use `std::string`, but uses `char*` strings a lot. Wrapping +such in a `std::string_view` to enable the use of various algorithms could be +useful. But since HotSpot also doesn't permit use of `` and the +like, that only gets the limited set of algorithms provided by the view class +directly. + +There is also the issue of `NUL` termination; string views are not necessarily +`NUL` terminated. Moreover, if one goes to the work of making one that is +`NUL` terminated, that terminator is included in the size. + +There are other caveats. Permitting use of string views would require +discussion of those. + +### Substring and Subsequence Searching + +In addition to simple substring searching, the Standard Library now includes +Boyer-Moore and Boyer-Moore-Horspool searchers, in case someone wants to +search really large texts. That seems an unlikely use-case for HotSpot. See +[p0220r1](http://wg21.link/p0220r1). + +### `new` and `delete` with Over-Aligned Data + +It is undecided whether to permit the use of dynamic allocation of overaligned +types ([n3396](http://wg21.link/n3396)). + +HotSpot currently only has a couple of over-aligned types that are dynamically +allocated. These are handled manually, not going through `new` expressions, as +that couldn't work before C++17. + +One of the ways an over-aligned type might arise is by aligning a data member. +This might be done to avoid destructive interference for concurrent accesses. +But HotSpot uses a different approach, using explicit padding. Again, this is +in part because `new` and `delete` of overaligned types didn't work. But we +might prefer to continue this approach. + +We would need to add `operator new` overloads to `CHeapObj<>` and possibly in +other places in order to support this. However, it has been suggested that +implementing it (efficiently) on top of NMT might be difficult. Note that +`posix_memalign` / `_aligned_malloc` don't help here, because of NMT's use of +malloc headers. + +If we don't support it we may want to add `operator new` overloads that are +deleted, to prevent attempted uses. + +Alignment usage in non-HotSpot parts of the OpenJDK: + +* `alignas` used once in harfbuzz, to align a variable. + +* libpipewire has `#define SPA_ALIGNED` macro using gcc `aligned` attribute, +but doesn't use it. + +* libsleef has `#define ALIGNED` macro using gcc `aligned` attribute. It is +not used for class or member declarations. + +### `std::to_chars()` and `std::from_chars` + +It is undecided whether to permit the use of `std::to_chars()` and +`std::from_chars()` ([p0067r5](http://wg21.link/p0067r5)). + +These functions provide low-level conversions between character sequences and +numeric values. This seems like a good candidate for use in HotSpot, +potentially replacing various clumsy or less performant alternatives. There is +no memory allocation. Parsing failures are indicated via error codes rather +than exceptions. Various other nice for HotSpot properties. + +Note that the published C++17 Standard puts these in ``, but a defect +report moved them to ``. This also needs ``. + +This would require upgrading the minimum gcc version to 11.1 for floating +point conversion support. The minimum Visual Studio version is already +sufficient. The minimum clang version requirement hasn't been determined yet. + +### `std::launder()` + +It is undecided whether to permit the use of `std::launder()` +([p0137r1](http://wg21.link/p0137r1)). + +Change to permitted if we discover a place where we need it. Or maybe we +should just permit it, but hope we don't need it. + +Also, C++20 revised the relevant part of Object Lifetime in a way that seems +more permissive and with less need of laundering. We don't know if +implementations of prior versions take advantage of the difference. + +See Object Lifetime: C++17 6.8/8, C++20 6.7.3/8 + +### Additional Undecided Features + * Trailing return type syntax for functions ([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)) * Variable templates -([n3651](https://isocpp.org/files/papers/N3651.pdf)) +([n3651](https://isocpp.org/files/papers/N3651.pdf), +[p0127r2](http://wg21.link/p0127r2)) * Member initializers and aggregates ([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html)) * Rvalue references and move semantics +* Shorthand for nested namespaces +([n4230](http://wg21.link/n4230)) — +HotSpot makes very little use of namespaces, so this seemingly innocuous +feature probably isn't useful to us. + +* Direct list initialization with `auto` +([n3681](http://wg21.link/n3681)) — +This change fixed some issues with direct list initialization and `auto`. But +we don't use that feature much, if at all. And perhaps shouldn't be using it. + +* UTF-8 Character Literals +([n4267](http://wg21.link/n4267)) — +Do we have a use-case for this? + +* Fold Expressions +([n4295](http://wg21.link/n4295)) — +Provides a simple way to apply operators to a parameter pack. HotSpot doesn't +use variadic templates very much. That makes it questionable that developers +should need to know about this feature. But if someone does come up with a +good use-case, it's likely that the alternatives are significantly worse, +because pack manipulation without this can be complicated. + +* `std::invoke<>()` +([n4169](http://wg21.link/n4169)) + + + [ADL]: https://en.cppreference.com/w/cpp/language/adl "Argument Dependent Lookup" @@ -1330,3 +1865,6 @@ features that have not yet been discussed. [PARTIALAPP]: https://en.wikipedia.org/wiki/Partial_application "Partial Application" + +[JOSUTTIS]: https://www.cppstd17.com + "C++17: The Complete Guide" diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 3a61840e8c9..6072cbc74dd 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -597,11 +597,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], # CXXFLAGS C++ language level for all of JDK, including Hotspot. if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then - LANGSTD_CXXFLAGS="-std=c++14" + LANGSTD_CXXFLAGS="-std=c++17" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - LANGSTD_CXXFLAGS="-std:c++14" + LANGSTD_CXXFLAGS="-std:c++17" else - AC_MSG_ERROR([Cannot enable C++14 for this toolchain]) + AC_MSG_ERROR([Cannot enable C++17 for this toolchain]) fi TOOLCHAIN_CFLAGS_JDK_CXXONLY="$TOOLCHAIN_CFLAGS_JDK_CXXONLY $LANGSTD_CXXFLAGS" TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $LANGSTD_CXXFLAGS" diff --git a/make/ide/vscode/hotspot/indexers/ccls-settings.txt b/make/ide/vscode/hotspot/indexers/ccls-settings.txt index bacc49c6112..fed586e5488 100644 --- a/make/ide/vscode/hotspot/indexers/ccls-settings.txt +++ b/make/ide/vscode/hotspot/indexers/ccls-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure ccls diff --git a/make/ide/vscode/hotspot/indexers/clangd-settings.txt b/make/ide/vscode/hotspot/indexers/clangd-settings.txt index 2a5b5e4a8cb..795229bb870 100644 --- a/make/ide/vscode/hotspot/indexers/clangd-settings.txt +++ b/make/ide/vscode/hotspot/indexers/clangd-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure clangd diff --git a/make/ide/vscode/hotspot/indexers/cpptools-settings.txt b/make/ide/vscode/hotspot/indexers/cpptools-settings.txt index ec266fa79c3..53bfe7889e2 100644 --- a/make/ide/vscode/hotspot/indexers/cpptools-settings.txt +++ b/make/ide/vscode/hotspot/indexers/cpptools-settings.txt @@ -1,5 +1,5 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", diff --git a/make/ide/vscode/hotspot/indexers/rtags-settings.txt b/make/ide/vscode/hotspot/indexers/rtags-settings.txt index 75727ae17f1..be417bfeeab 100644 --- a/make/ide/vscode/hotspot/indexers/rtags-settings.txt +++ b/make/ide/vscode/hotspot/indexers/rtags-settings.txt @@ -1,7 +1,7 @@ // Configure cpptools IntelliSense "C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode", "C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json", - "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cppStandard": "c++17", "C_Cpp.default.compilerPath": "{{COMPILER}}", // Configure RTags From cdc8b5eb83ed6335a65b93cfa0cf38932486c7e3 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 5 Sep 2025 21:08:29 +0000 Subject: [PATCH 391/471] 8366455: Move VarHandles.GuardMethodGenerator to execute on build Reviewed-by: psandoz, redestad, erikj --- make/ToolsJdk.gmk | 3 + .../VarHandleGuardMethodGenerator.java | 325 ++++ .../java.base/gensrc/GensrcVarHandles.gmk | 12 + .../java/lang/invoke/VarHandleGuards.java | 1619 ----------------- .../classes/java/lang/invoke/VarHandles.java | 238 --- 5 files changed, 340 insertions(+), 1857 deletions(-) create mode 100644 make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java delete mode 100644 src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index a7a2289f78a..629cadbf83a 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -130,6 +130,9 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_clas TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.fixuppandoc.Main +TOOL_VARHANDLEGUARDMETHODGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + build.tools.methodhandle.VarHandleGuardMethodGenerator + ################################################################################ # Executable javascript filter for man page generation using pandoc. diff --git a/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java b/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java new file mode 100644 index 00000000000..4cb833dffe2 --- /dev/null +++ b/make/jdk/src/classes/build/tools/methodhandle/VarHandleGuardMethodGenerator.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.methodhandle; + +import java.io.PrintWriter; +import java.lang.classfile.TypeKind; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * A helper program to generate the VarHandleGuards class with a set of + * static guard methods each of which corresponds to a particular shape and + * performs a type check of the symbolic type descriptor with the VarHandle + * type descriptor before linking/invoking to the underlying operation as + * characterized by the operation member name on the VarForm of the + * VarHandle. + *

          + * The generated class essentially encapsulates pre-compiled LambdaForms, + * one for each method, for the most common set of method signatures. + * This reduces static initialization costs, footprint costs, and circular + * dependencies that may arise if a class is generated per LambdaForm. + *

          + * A maximum of L*T*S methods will be generated where L is the number of + * access modes kinds (or unique operation signatures) and T is the number + * of variable types and S is the number of shapes (such as instance field, + * static field, or array access). + * If there are 4 unique operation signatures, 5 basic types (Object, int, + * long, float, double), and 3 shapes then a maximum of 60 methods will be + * generated. However, the number is likely to be less since there may + * be duplicate signatures. + *

          + * Each method is annotated with @LambdaForm.Compiled to inform the runtime + * that such methods should be treated as if a method of a class that is the + * result of compiling a LambdaForm. Annotation of such methods is + * important for correct evaluation of certain assertions and method return + * type profiling in HotSpot. + * + * @see java.lang.invoke.GenerateJLIClassesHelper + */ +public final class VarHandleGuardMethodGenerator { + + static final String CLASS_HEADER = """ + /* + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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. Oracle 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package java.lang.invoke; + + import jdk.internal.vm.annotation.AOTSafeClassInitializer; + import jdk.internal.vm.annotation.ForceInline; + import jdk.internal.vm.annotation.Hidden; + + // This file is generated by build.tools.methodhandle.VarHandleGuardMethodGenerator. + // Do not edit! + @AOTSafeClassInitializer + final class VarHandleGuards { + """; + + static final String GUARD_METHOD_SIG_TEMPLATE = " _()"; + + static final String GUARD_METHOD_TEMPLATE = + """ + @ForceInline + @LambdaForm.Compiled + @Hidden + static final throws Throwable { + boolean direct = handle.checkAccessModeThenIsDirect(ad); + if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else { + MethodHandle mh = handle.getMethodHandle(ad.mode); + mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); + } + }"""; + + static final String GUARD_METHOD_TEMPLATE_V = + """ + @ForceInline + @LambdaForm.Compiled + @Hidden + static final throws Throwable { + boolean direct = handle.checkAccessModeThenIsDirect(ad); + if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + MethodHandle.linkToStatic(); + } else { + MethodHandle mh = handle.getMethodHandle(ad.mode); + mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); + } + }"""; + + // A template for deriving the operations + // could be supported by annotating VarHandle directly with the + // operation kind and shape + interface VarHandleTemplate { + Object get(); + + void set(Object value); + + boolean compareAndSet(Object actualValue, Object expectedValue); + + Object compareAndExchange(Object actualValue, Object expectedValue); + + Object getAndUpdate(Object value); + } + + record HandleType(Class receiver, Class... intermediates) { + } + + public static void main(String... args) throws Throwable { + if (args.length != 1) { + System.err.println("Usage: java VarHandleGuardMethodGenerator VarHandleGuards.java"); + System.exit(1); + } + + Path outputFile = Path.of(args[0]); + + try (PrintWriter pw = new PrintWriter(Files.newBufferedWriter( + outputFile, + StandardCharsets.UTF_8, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING))) { + print(pw); + } + } + + public static void print(PrintWriter pw) { + pw.println(CLASS_HEADER); + + // Declare the stream of shapes + List hts = List.of( + // Object->T + new HandleType(Object.class), + + // ->T + new HandleType(null), + + // Array[index]->T + new HandleType(Object.class, int.class), + + // MS[base]->T + new HandleType(Object.class, long.class), + + // MS[base][offset]->T + new HandleType(Object.class, long.class, long.class) + ); + + // The 5 JVM calling convention types + List> basicTypes = List.of(Object.class, int.class, long.class, float.class, double.class); + + Stream.of(VarHandleTemplate.class.getMethods()). + mapMulti((m, sink) -> { + for (var ht : hts) { + for (var bt : basicTypes) { + sink.accept(generateMethodType(m, ht.receiver, bt, ht.intermediates)); + } + } + }). + distinct(). + map(VarHandleGuardMethodGenerator::generateMethod). + forEach(pw::println); + + pw.println("}"); + } + + static MethodType generateMethodType(Method m, Class receiver, Class value, Class... intermediates) { + Class returnType = m.getReturnType() == Object.class + ? value : m.getReturnType(); + + List> params = new ArrayList<>(); + if (receiver != null) + params.add(receiver); + Collections.addAll(params, intermediates); + for (var p : m.getParameters()) { + params.add(value); + } + return MethodType.methodType(returnType, params); + } + + static String generateMethod(MethodType mt) { + Class returnType = mt.returnType(); + + var params = new LinkedHashMap(); + params.put("handle", className(VarHandle.class)); + for (int i = 0; i < mt.parameterCount(); i++) { + params.put("arg" + i, className(mt.parameterType(i))); + } + params.put("ad", "VarHandle.AccessDescriptor"); + + // Generate method signature line + String RETURN = className(returnType); + String NAME = "guard"; + String SIGNATURE = getSignature(mt); + String PARAMS = params.entrySet().stream(). + map(e -> e.getValue() + " " + e.getKey()). + collect(Collectors.joining(", ")); + String METHOD = GUARD_METHOD_SIG_TEMPLATE. + replace("", RETURN). + replace("", NAME). + replace("", SIGNATURE). + replace("", PARAMS); + + // Generate method + params.remove("ad"); + + List LINK_TO_STATIC_ARGS = new ArrayList<>(params.keySet()); + LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); + + List LINK_TO_INVOKER_ARGS = new ArrayList<>(params.keySet()); + LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()"); + + RETURN = returnType == void.class + ? "" + : returnType == Object.class + ? "return " + : "return (" + returnType.getName() + ") "; + + String RESULT_ERASED = returnType == void.class + ? "" + : returnType != Object.class + ? "return (" + returnType.getName() + ") " + : "Object r = "; + + String RETURN_ERASED = returnType != Object.class + ? "" + : "\n return ad.returnType.cast(r);"; + + String template = returnType == void.class + ? GUARD_METHOD_TEMPLATE_V + : GUARD_METHOD_TEMPLATE; + return template. + replace("", METHOD). + replace("", NAME). + replaceAll("", RETURN). + replace("", RESULT_ERASED). + replace("", RETURN_ERASED). + replaceAll("", String.join(", ", LINK_TO_STATIC_ARGS)). + replace("", String.join(", ", LINK_TO_INVOKER_ARGS)) + .indent(4); + } + + static String className(Class c) { + String n = c.getCanonicalName(); + if (n == null) + throw new IllegalArgumentException("Not representable in source code: " + c); + if (!c.isPrimitive() && c.getPackageName().equals("java.lang")) { + n = n.substring("java.lang.".length()); + } else if (c.getPackageName().equals("java.lang.invoke")) { + n = n.substring("java.lang.invoke.".length()); + } + return n; + } + + static String getSignature(MethodType m) { + StringBuilder sb = new StringBuilder(m.parameterCount() + 1); + + for (int i = 0; i < m.parameterCount(); i++) { + Class pt = m.parameterType(i); + sb.append(getCharType(pt)); + } + + sb.append('_').append(getCharType(m.returnType())); + + return sb.toString(); + } + + static char getCharType(Class pt) { + return TypeKind.from(pt).upperBound().descriptorString().charAt(0); + } +} diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index 899f827462c..ec1aec5c764 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -302,5 +302,17 @@ TARGETS += $(GENSRC_VARHANDLES) ################################################################################ +GENSRC_VARHANDLEGUARDS := $(VARHANDLES_GENSRC_DIR)/VarHandleGuards.java + +$(GENSRC_VARHANDLEGUARDS): $(BUILD_TOOLS_JDK) + $(call LogInfo, Generating $@) + $(call MakeTargetDir) + $(TOOL_VARHANDLEGUARDMETHODGENERATOR) \ + $(GENSRC_VARHANDLEGUARDS) + +TARGETS += $(GENSRC_VARHANDLEGUARDS) + +################################################################################ + endif # include guard include MakeIncludeEnd.gmk diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java deleted file mode 100644 index 49408a22cef..00000000000 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java +++ /dev/null @@ -1,1619 +0,0 @@ -/* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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. Oracle 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang.invoke; - -import jdk.internal.vm.annotation.AOTSafeClassInitializer; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Hidden; - -// This class is auto-generated by java.lang.invoke.VarHandles$GuardMethodGenerator. Do not edit. -@AOTSafeClassInitializer -final class VarHandleGuards { - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_L_L(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_L_I(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_L_J(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_L_F(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_L_D(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard__L(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard__I(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard__J(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard__F(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard__D(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LI_L(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LI_I(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LI_J(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LI_F(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LI_D(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJ_L(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJ_I(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJ_J(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJ_F(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJ_D(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJ_L(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJ_I(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJ_F(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJ_D(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LL_V(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LI_V(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJ_V(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LF_V(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LD_V(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_L_V(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_I_V(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_J_V(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_F_V(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_D_V(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIL_V(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LII_V(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIJ_V(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LIF_V(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LID_V(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJL_V(VarHandle handle, Object arg0, long arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJI_V(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJF_V(VarHandle handle, Object arg0, long arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJD_V(VarHandle handle, Object arg0, long arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJL_V(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJI_V(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJF_V(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final void guard_LJJD_V(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { - MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LLL_Z(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LII_Z(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LFF_Z(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LDD_Z(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LL_Z(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_II_Z(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_JJ_Z(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_FF_Z(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_DD_Z(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LILL_Z(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIII_Z(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIJJ_Z(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIFF_Z(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LIDD_Z(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJLL_Z(VarHandle handle, Object arg0, long arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJII_Z(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJFF_Z(VarHandle handle, Object arg0, long arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJDD_Z(VarHandle handle, Object arg0, long arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJLL_Z(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, Object arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJII_Z(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, int arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, long arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJFF_Z(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, float arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final boolean guard_LJJDD_Z(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, double arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LLL_L(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LII_I(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LFF_F(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LDD_D(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LL_L(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_II_I(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_JJ_J(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_FF_F(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_DD_D(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LILL_L(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LIII_I(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LIJJ_J(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LIFF_F(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LIDD_D(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJLL_L(VarHandle handle, Object arg0, long arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJII_I(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJFF_F(VarHandle handle, Object arg0, long arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJDD_D(VarHandle handle, Object arg0, long arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJLL_L(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, Object arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJII_I(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, int arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LJJJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, long arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJFF_F(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, float arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJDD_D(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, double arg4, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, arg4, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3, arg4); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LF_F(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LD_D(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_I_I(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_J_J(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_F_F(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_D_D(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LIL_L(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final long guard_LIJ_J(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LIF_F(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LID_D(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJL_L(VarHandle handle, Object arg0, long arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJI_I(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJF_F(VarHandle handle, Object arg0, long arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJD_D(VarHandle handle, Object arg0, long arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final Object guard_LJJL_L(VarHandle handle, Object arg0, long arg1, long arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final int guard_LJJI_I(VarHandle handle, Object arg0, long arg1, long arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final float guard_LJJF_F(VarHandle handle, Object arg0, long arg1, long arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - - @ForceInline - @LambdaForm.Compiled - @Hidden - static final double guard_LJJD_D(VarHandle handle, Object arg0, long arg1, long arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - boolean direct = handle.checkAccessModeThenIsDirect(ad); - if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } else { - MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); - } - } - -} diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index 571587ab42f..c97d44ba5d3 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -657,242 +657,4 @@ final class VarHandles { !RuntimeException.class.isAssignableFrom(clazz) && !Error.class.isAssignableFrom(clazz); } - -// /** -// * A helper program to generate the VarHandleGuards class with a set of -// * static guard methods each of which corresponds to a particular shape and -// * performs a type check of the symbolic type descriptor with the VarHandle -// * type descriptor before linking/invoking to the underlying operation as -// * characterized by the operation member name on the VarForm of the -// * VarHandle. -// *

          -// * The generated class essentially encapsulates pre-compiled LambdaForms, -// * one for each method, for the most set of common method signatures. -// * This reduces static initialization costs, footprint costs, and circular -// * dependencies that may arise if a class is generated per LambdaForm. -// *

          -// * A maximum of L*T*S methods will be generated where L is the number of -// * access modes kinds (or unique operation signatures) and T is the number -// * of variable types and S is the number of shapes (such as instance field, -// * static field, or array access). -// * If there are 4 unique operation signatures, 5 basic types (Object, int, -// * long, float, double), and 3 shapes then a maximum of 60 methods will be -// * generated. However, the number is likely to be less since there -// * be duplicate signatures. -// *

          -// * Each method is annotated with @LambdaForm.Compiled to inform the runtime -// * that such methods should be treated as if a method of a class that is the -// * result of compiling a LambdaForm. Annotation of such methods is -// * important for correct evaluation of certain assertions and method return -// * type profiling in HotSpot. -// */ -// public static class GuardMethodGenerator { -// -// static final String GUARD_METHOD_SIG_TEMPLATE = " _()"; -// -// static final String GUARD_METHOD_TEMPLATE = -// """ -// @ForceInline -// @LambdaForm.Compiled -// @Hidden -// static final throws Throwable { -// boolean direct = handle.checkAccessModeThenIsDirect(ad); -// if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else { -// MethodHandle mh = handle.getMethodHandle(ad.mode); -// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); -// } -// }"""; -// -// static final String GUARD_METHOD_TEMPLATE_V = -// """ -// @ForceInline -// @LambdaForm.Compiled -// @Hidden -// static final throws Throwable { -// boolean direct = handle.checkAccessModeThenIsDirect(ad); -// if (direct && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else if (direct && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { -// MethodHandle.linkToStatic(); -// } else { -// MethodHandle mh = handle.getMethodHandle(ad.mode); -// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); -// } -// }"""; -// -// // A template for deriving the operations -// // could be supported by annotating VarHandle directly with the -// // operation kind and shape -// interface VarHandleTemplate { -// Object get(); -// -// void set(Object value); -// -// boolean compareAndSet(Object actualValue, Object expectedValue); -// -// Object compareAndExchange(Object actualValue, Object expectedValue); -// -// Object getAndUpdate(Object value); -// } -// -// record HandleType(Class receiver, Class... intermediates) { -// } -// -// /** -// * @param args parameters -// */ -// public static void main(String[] args) { -// System.out.println("package java.lang.invoke;"); -// System.out.println(); -// System.out.println("import jdk.internal.vm.annotation.AOTSafeClassInitializer;"); -// System.out.println("import jdk.internal.vm.annotation.ForceInline;"); -// System.out.println("import jdk.internal.vm.annotation.Hidden;"); -// System.out.println(); -// System.out.println("// This class is auto-generated by " + -// GuardMethodGenerator.class.getName() + -// ". Do not edit."); -// System.out.println("@AOTSafeClassInitializer"); -// System.out.println("final class VarHandleGuards {"); -// -// System.out.println(); -// -// // Declare the stream of shapes -// List hts = List.of( -// // Object->T -// new HandleType(Object.class), -// -// // ->T -// new HandleType(null), -// -// // Array[index]->T -// new HandleType(Object.class, int.class), -// -// // MS[base]->T -// new HandleType(Object.class, long.class), -// -// // MS[base][offset]->T -// new HandleType(Object.class, long.class, long.class) -// ); -// -// Stream.of(VarHandleTemplate.class.getMethods()). -// mapMulti((m, sink) -> { -// for (var ht : hts) { -// for (var bt : LambdaForm.BasicType.ARG_TYPES) { -// sink.accept(generateMethodType(m, ht.receiver, bt.btClass, ht.intermediates)); -// } -// } -// }). -// distinct(). -// map(GuardMethodGenerator::generateMethod). -// forEach(System.out::println); -// -// System.out.println("}"); -// } -// -// static MethodType generateMethodType(Method m, Class receiver, Class value, Class... intermediates) { -// Class returnType = m.getReturnType() == Object.class -// ? value : m.getReturnType(); -// -// List> params = new ArrayList<>(); -// if (receiver != null) -// params.add(receiver); -// java.util.Collections.addAll(params, intermediates); -// for (var p : m.getParameters()) { -// params.add(value); -// } -// return MethodType.methodType(returnType, params); -// } -// -// static String generateMethod(MethodType mt) { -// Class returnType = mt.returnType(); -// -// var params = new java.util.LinkedHashMap>(); -// params.put("handle", VarHandle.class); -// for (int i = 0; i < mt.parameterCount(); i++) { -// params.put("arg" + i, mt.parameterType(i)); -// } -// params.put("ad", VarHandle.AccessDescriptor.class); -// -// // Generate method signature line -// String RETURN = className(returnType); -// String NAME = "guard"; -// String SIGNATURE = getSignature(mt); -// String PARAMS = params.entrySet().stream(). -// map(e -> className(e.getValue()) + " " + e.getKey()). -// collect(java.util.stream.Collectors.joining(", ")); -// String METHOD = GUARD_METHOD_SIG_TEMPLATE. -// replace("", RETURN). -// replace("", NAME). -// replace("", SIGNATURE). -// replace("", PARAMS); -// -// // Generate method -// params.remove("ad"); -// -// List LINK_TO_STATIC_ARGS = new ArrayList<>(params.keySet()); -// LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)"); -// -// List LINK_TO_INVOKER_ARGS = new ArrayList<>(params.keySet()); -// LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()"); -// -// RETURN = returnType == void.class -// ? "" -// : returnType == Object.class -// ? "return " -// : "return (" + returnType.getName() + ") "; -// -// String RESULT_ERASED = returnType == void.class -// ? "" -// : returnType != Object.class -// ? "return (" + returnType.getName() + ") " -// : "Object r = "; -// -// String RETURN_ERASED = returnType != Object.class -// ? "" -// : "\n return ad.returnType.cast(r);"; -// -// String template = returnType == void.class -// ? GUARD_METHOD_TEMPLATE_V -// : GUARD_METHOD_TEMPLATE; -// return template. -// replace("", METHOD). -// replace("", NAME). -// replaceAll("", RETURN). -// replace("", RESULT_ERASED). -// replace("", RETURN_ERASED). -// replaceAll("", String.join(", ", LINK_TO_STATIC_ARGS)). -// replace("", String.join(", ", LINK_TO_INVOKER_ARGS)) -// .indent(4); -// } -// -// static String className(Class c) { -// String n = c.getName(); -// if (n.startsWith("java.lang.")) { -// n = n.replace("java.lang.", ""); -// if (n.startsWith("invoke.")) { -// n = n.replace("invoke.", ""); -// } -// } -// return n.replace('$', '.'); -// } -// -// static String getSignature(MethodType m) { -// StringBuilder sb = new StringBuilder(m.parameterCount() + 1); -// -// for (int i = 0; i < m.parameterCount(); i++) { -// Class pt = m.parameterType(i); -// sb.append(getCharType(pt)); -// } -// -// sb.append('_').append(getCharType(m.returnType())); -// -// return sb.toString(); -// } -// -// static char getCharType(Class pt) { -// return Wrapper.forBasicType(pt).basicTypeChar(); -// } -// } } From dbf4ffffe3fbbb513122081bbcc04c543473082e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 5 Sep 2025 23:55:13 +0000 Subject: [PATCH 392/471] 8366477: Refactor AOT-related flag bits in klass.hpp Reviewed-by: liach, asmehra, kvn --- src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 +- .../classfile/systemDictionaryShared.cpp | 2 +- src/hotspot/share/oops/instanceKlass.hpp | 8 --- src/hotspot/share/oops/instanceKlassFlags.hpp | 2 - src/hotspot/share/oops/klass.cpp | 2 +- src/hotspot/share/oops/klass.hpp | 70 ++++++++++++------- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 7a6c91e503e..42d575a012f 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -942,7 +942,7 @@ void ArchiveBuilder::make_klasses_shareable() { old = " old"; } - if (ik->is_generated_shared_class()) { + if (ik->is_aot_generated_class()) { generated = " generated"; } if (aotlinked) { diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 966b3eab298..e8900f43d43 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -184,7 +184,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { klass->set_shared_classpath_index(0); // Set the "generated" bit, so it won't interfere with JVMTI. // See SystemDictionaryShared::find_builtin_class(). - klass->set_is_generated_shared_class(); + klass->set_is_aot_generated_class(); } } else { int len = h_bytes->length(); @@ -222,7 +222,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, AOTMetaspace::try_link_class(THREAD, result); assert(!HAS_PENDING_EXCEPTION, "Invariant"); - result->set_is_generated_shared_class(); + result->set_is_aot_generated_class(); if (!klass->in_aot_cache()) { log_info(aot, lambda)("regenerate_class excluding klass %s %s", class_name, klass->name()->as_C_string()); SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index df22db82165..45a5dc2328c 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1146,7 +1146,7 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) { DEBUG_ONLY(check_klass_after_loading(record->klass());) // We did not save the classfile data of the generated LambdaForm invoker classes, // so we cannot support CLFH for such classes. - if (record->klass()->is_generated_shared_class() && JvmtiExport::should_post_class_file_load_hook()) { + if (record->klass()->is_aot_generated_class() && JvmtiExport::should_post_class_file_load_hook()) { return nullptr; } return record->klass(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 3338b5cd446..dfd134857b8 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -764,14 +764,6 @@ public: bool has_final_method() const { return _misc_flags.has_final_method(); } void set_has_final_method() { _misc_flags.set_has_final_method(true); } - // Indicates presence of @AOTSafeClassInitializer. Also see AOTClassInitializer for more details. - bool has_aot_safe_initializer() const { return _misc_flags.has_aot_safe_initializer(); } - void set_has_aot_safe_initializer() { _misc_flags.set_has_aot_safe_initializer(true); } - - // Indicates @AOTRuntimeSetup private static void runtimeSetup() presence. - bool is_runtime_setup_required() const { return _misc_flags.is_runtime_setup_required(); } - void set_is_runtime_setup_required() { _misc_flags.set_is_runtime_setup_required(true); } - // for adding methods, ConstMethod::UNSET_IDNUM means no more ids available inline u2 next_method_idnum(); void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; } diff --git a/src/hotspot/share/oops/instanceKlassFlags.hpp b/src/hotspot/share/oops/instanceKlassFlags.hpp index 1872c3bc998..18a9c76103d 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.hpp +++ b/src/hotspot/share/oops/instanceKlassFlags.hpp @@ -54,8 +54,6 @@ class InstanceKlassFlags { flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \ flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \ flag(has_final_method , 1 << 13) /* True if klass has final method */ \ - flag(has_aot_safe_initializer , 1 << 14) /* has @AOTSafeClassInitializer annotation */ \ - flag(is_runtime_setup_required , 1 << 15) /* has a runtimeSetup method to be called */ \ /* end of list */ #define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value, diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index f4ae128aef7..92bcaebec4a 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -302,7 +302,7 @@ Klass::Klass() : _kind(UnknownKlassKind) { Klass::Klass(KlassKind kind) : _kind(kind), _prototype_header(make_prototype(this)), _shared_class_path_index(-1) { - CDS_ONLY(_shared_class_flags = 0;) + CDS_ONLY(_aot_class_flags = 0;) CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;) _primary_supers[0] = this; set_super_check_offset(in_bytes(primary_supers_offset())); diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index d62f3f21ee2..ad03c1e2ed6 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -174,18 +174,20 @@ private: #if INCLUDE_CDS // Various attributes for shared classes. Should be zero for a non-shared class. - u2 _shared_class_flags; - enum CDSSharedClassFlags { + u2 _aot_class_flags; + enum { _in_aot_cache = 1 << 0, _archived_lambda_proxy_is_available = 1 << 1, _has_value_based_class_annotation = 1 << 2, _verified_at_dump_time = 1 << 3, _has_archived_enum_objs = 1 << 4, - // This class was not loaded from a classfile in the module image - // or classpath. - _is_generated_shared_class = 1 << 5, - // archived mirror already initialized by AOT-cache assembly: no further need to call - _has_aot_initialized_mirror = 1 << 6, + _is_aot_generated_class = 1 << 5, // this class was not loaded from a classfile in the module image + // or classpath, but was generated during AOT cache assembly. + _has_aot_initialized_mirror = 1 << 6, // archived mirror already initialized by AOT cache assembly. + // no further need to call + _has_aot_safe_initializer = 1 << 7, // has @AOTSafeClassInitializer annotation + _is_runtime_setup_required = 1 << 8, // has a runtimeSetup method to be called when + // this class is loaded from AOT cache }; #endif @@ -325,66 +327,84 @@ protected: void clear_archived_mirror_index() NOT_CDS_JAVA_HEAP_RETURN; void set_lambda_proxy_is_available() { - CDS_ONLY(_shared_class_flags |= _archived_lambda_proxy_is_available;) + CDS_ONLY(_aot_class_flags |= _archived_lambda_proxy_is_available;) } void clear_lambda_proxy_is_available() { - CDS_ONLY(_shared_class_flags &= (u2)(~_archived_lambda_proxy_is_available);) + CDS_ONLY(_aot_class_flags &= (u2)(~_archived_lambda_proxy_is_available);) } bool lambda_proxy_is_available() const { - CDS_ONLY(return (_shared_class_flags & _archived_lambda_proxy_is_available) != 0;) + CDS_ONLY(return (_aot_class_flags & _archived_lambda_proxy_is_available) != 0;) NOT_CDS(return false;) } void set_has_value_based_class_annotation() { - CDS_ONLY(_shared_class_flags |= _has_value_based_class_annotation;) + CDS_ONLY(_aot_class_flags |= _has_value_based_class_annotation;) } void clear_has_value_based_class_annotation() { - CDS_ONLY(_shared_class_flags &= (u2)(~_has_value_based_class_annotation);) + CDS_ONLY(_aot_class_flags &= (u2)(~_has_value_based_class_annotation);) } bool has_value_based_class_annotation() const { - CDS_ONLY(return (_shared_class_flags & _has_value_based_class_annotation) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_value_based_class_annotation) != 0;) NOT_CDS(return false;) } void set_verified_at_dump_time() { - CDS_ONLY(_shared_class_flags |= _verified_at_dump_time;) + CDS_ONLY(_aot_class_flags |= _verified_at_dump_time;) } bool verified_at_dump_time() const { - CDS_ONLY(return (_shared_class_flags & _verified_at_dump_time) != 0;) + CDS_ONLY(return (_aot_class_flags & _verified_at_dump_time) != 0;) NOT_CDS(return false;) } void set_has_archived_enum_objs() { - CDS_ONLY(_shared_class_flags |= _has_archived_enum_objs;) + CDS_ONLY(_aot_class_flags |= _has_archived_enum_objs;) } bool has_archived_enum_objs() const { - CDS_ONLY(return (_shared_class_flags & _has_archived_enum_objs) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_archived_enum_objs) != 0;) NOT_CDS(return false;) } - void set_is_generated_shared_class() { - CDS_ONLY(_shared_class_flags |= _is_generated_shared_class;) + void set_is_aot_generated_class() { + CDS_ONLY(_aot_class_flags |= _is_aot_generated_class;) } - bool is_generated_shared_class() const { - CDS_ONLY(return (_shared_class_flags & _is_generated_shared_class) != 0;) + bool is_aot_generated_class() const { + CDS_ONLY(return (_aot_class_flags & _is_aot_generated_class) != 0;) NOT_CDS(return false;) } void set_has_aot_initialized_mirror() { - CDS_ONLY(_shared_class_flags |= _has_aot_initialized_mirror;) + CDS_ONLY(_aot_class_flags |= _has_aot_initialized_mirror;) } bool has_aot_initialized_mirror() const { - CDS_ONLY(return (_shared_class_flags & _has_aot_initialized_mirror) != 0;) + CDS_ONLY(return (_aot_class_flags & _has_aot_initialized_mirror) != 0;) + NOT_CDS(return false;) + } + + // Indicates presence of @AOTSafeClassInitializer. Also see AOTClassInitializer for more details. + void set_has_aot_safe_initializer() { + CDS_ONLY(_aot_class_flags |= _has_aot_safe_initializer;) + } + bool has_aot_safe_initializer() const { + CDS_ONLY(return (_aot_class_flags & _has_aot_safe_initializer) != 0;) + NOT_CDS(return false;) + } + + // Indicates @AOTRuntimeSetup private static void runtimeSetup() presence. + void set_is_runtime_setup_required() { + CDS_ONLY(_aot_class_flags |= _is_runtime_setup_required;) + } + bool is_runtime_setup_required() const { + CDS_ONLY(return (_aot_class_flags & _is_runtime_setup_required) != 0;) NOT_CDS(return false;) } bool in_aot_cache() const { // shadows MetaspaceObj::in_aot_cache)() - CDS_ONLY(return (_shared_class_flags & _in_aot_cache) != 0;) + CDS_ONLY(return (_aot_class_flags & _in_aot_cache) != 0;) NOT_CDS(return false;) } void set_in_aot_cache() { - CDS_ONLY(_shared_class_flags |= _in_aot_cache;) + CDS_ONLY(_aot_class_flags |= _in_aot_cache;) } // Obtain the module or package for this class From e8c7d2aaf3cdbbe07b8cdcc68dd7ec9645956bf2 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Sat, 6 Sep 2025 09:00:51 +0000 Subject: [PATCH 393/471] 8332872: SetupExecute should cd to temp directory Reviewed-by: erikj --- make/CreateJmods.gmk | 1 + make/UpdateSleefSource.gmk | 16 ++++----- make/common/Execute.gmk | 20 +++++++---- test/make/TestExecute.gmk | 74 ++++++++++++++++++++++++++++++++++++++ test/make/TestMake.gmk | 5 ++- 5 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 test/make/TestExecute.gmk diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index a26042fb0d5..3280b24924a 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -257,6 +257,7 @@ $(eval $(call SetupExecute, create_$(JMOD_FILE), \ WARN := Creating $(INTERIM_MSG)$(JMOD_FILE), \ DEPS := $(DEPS), \ OUTPUT_FILE := $(JMODS_DIR)/$(JMOD_FILE), \ + WORKING_DIR := $(WORKSPACE_ROOT), \ SUPPORT_DIR := $(JMODS_SUPPORT_DIR), \ PRE_COMMAND := $(RM) $(JMODS_DIR)/$(JMOD_FILE) $(JMODS_SUPPORT_DIR)/$(JMOD_FILE), \ COMMAND := $(JMOD) $(JMOD_SMALL_FLAGS) create --module-version $(VERSION_SHORT) \ diff --git a/make/UpdateSleefSource.gmk b/make/UpdateSleefSource.gmk index c7fdfdb41d9..d7b8f8e141b 100644 --- a/make/UpdateSleefSource.gmk +++ b/make/UpdateSleefSource.gmk @@ -81,8 +81,8 @@ SLEEF_CMAKE_FILE := toolchains/$(OPENJDK_TARGET_CPU)-$(SLEEF_TOOLCHAIN_TYPE).cma $(eval $(call SetupExecute, sleef_native_config, \ INFO := Configuring native sleef build, \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \ - $(SLEEF_NATIVE_BUILD_DIR), \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) -S . -B $(SLEEF_NATIVE_BUILD_DIR), \ )) TARGETS := $(sleef_native_config) @@ -91,8 +91,8 @@ $(eval $(call SetupExecute, sleef_native_build, \ INFO := Building native sleef, \ DEPS := $(sleef_native_config), \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \ - $(SLEEF_NATIVE_BUILD_DIR) -j, \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) --build $(SLEEF_NATIVE_BUILD_DIR) -j, \ )) TARGETS := $(sleef_native_build) @@ -101,8 +101,8 @@ $(eval $(call SetupExecute, sleef_cross_config, \ INFO := Configuring cross-compiling sleef build, \ DEPS := $(sleef_native_build), \ OUTPUT_DIR := $(SLEEF_CROSS_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) -S . -B \ - $(SLEEF_CROSS_BUILD_DIR) \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) -S . -B $(SLEEF_CROSS_BUILD_DIR) \ -DCMAKE_C_COMPILER=$(CC) \ -DCMAKE_TOOLCHAIN_FILE=$(SLEEF_CMAKE_FILE) \ -DNATIVE_BUILD_DIR=$(SLEEF_NATIVE_BUILD_DIR) \ @@ -116,8 +116,8 @@ $(eval $(call SetupExecute, sleef_cross_build, \ INFO := Building cross-compiling sleef, \ DEPS := $(sleef_cross_config), \ OUTPUT_DIR := $(SLEEF_NATIVE_BUILD_DIR), \ - COMMAND := cd $(SLEEF_SOURCE_DIR) && $(CMAKE) --build \ - $(SLEEF_CROSS_BUILD_DIR) -j, \ + WORKING_DIR := $(SLEEF_SOURCE_DIR), \ + COMMAND := $(CMAKE) --build $(SLEEF_CROSS_BUILD_DIR) -j, \ )) TARGETS := $(sleef_cross_build) diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index bf108c30c05..1ee3c28261b 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -45,6 +45,9 @@ ifeq ($(INCLUDE), true) # e.g. a simple sed replacement on the input file. If the operations are # unrelated to the main COMMAND, this is not a suitable solution. # +# Before execution, the current working directory is changed to SUPPORT_DIR. +# This can be overridden with WORKING_DIR. +# # If your command outputs a variety of files, or if it's really a single file # but you don't really care about the output from the perspective, you can just # supply an OUTPUT_DIR. You are supposed to make sure the command creates files @@ -75,6 +78,7 @@ ifeq ($(INCLUDE), true) # OUTPUT_DIR : The directory that will contain the result from the command # OUTPUT_FILE : Use this if the command results in a single output file # SUPPORT_DIR : Where to store generated support files +# WORKING_DIR : Directory to cd to before executing the command # INFO : Message to display at LOG=info level when running command (optional) # WARN : Message to display at LOG=warn level when running command (optional) # DEPS : Dependencies for the execution to take place @@ -133,6 +137,10 @@ define SetupExecuteBody endif + ifeq ($$($1_WORKING_DIR), ) + $1_WORKING_DIR := $$($1_SUPPORT_DIR) + endif + ifeq ($$($1_INFO)$$($1_WARN), ) # If neither info nor warn is provided, add basic info text. $1_INFO := Running commands for $1 @@ -147,14 +155,14 @@ define SetupExecuteBody ifneq ($$($1_INFO), ) $$(call LogInfo, $$($1_INFO)) endif - $$(call MakeDir, $$($1_SUPPORT_DIR) $$($1_OUTPUT_DIR)) + $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) $$(call ExecuteWithLog, $$($1_BASE)_pre, \ - $$($1_PRE_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_PRE_COMMAND)) $$(TOUCH) $$@ $$($1_EXEC_RESULT): $$($1_PRE_MARKER) $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - $$($1_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -168,9 +176,9 @@ define SetupExecuteBody ifneq ($$($1_INFO), ) $$(call LogInfo, $$($1_INFO)) endif - $$(call MakeDir, $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) + $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - $$($1_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -182,7 +190,7 @@ define SetupExecuteBody $$($1_FINAL_RESULT): $$($1_EXEC_RESULT) $$(call ExecuteWithLog, $$($1_BASE)_post, \ - $$($1_POST_COMMAND)) + cd $$($1_WORKING_DIR) && $$($1_POST_COMMAND)) $$(TOUCH) $$@ $1 += $$($1_FINAL_RESULT) diff --git a/test/make/TestExecute.gmk b/test/make/TestExecute.gmk new file mode 100644 index 00000000000..f71a402502e --- /dev/null +++ b/test/make/TestExecute.gmk @@ -0,0 +1,74 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. 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. +# +# 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. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include MakeFileStart.gmk + +################################################################################ + +include Execute.gmk +include UtilsForTests.gmk + +THIS_FILE := $(TOPDIR)/test/make/TestExecute.gmk +DEPS := $(THIS_FILE) \ + $(TOPDIR)/make/common/MakeBase.gmk \ + # + +OUTPUT_DIR := $(TESTMAKE_OUTPUTDIR)/execute +$(call MakeDir, $(OUTPUT_DIR)) + +################################################################################ +# Test SetupExecute + +$(eval $(call SetupExecute, EXEC_1, \ + INFO := Testing that SetupExecute runs from SUPPORT_DIR, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_1, \ + SUPPORT_DIR := $(OUTPUT_DIR)/exec_1/support, \ + COMMAND := $(ECHO) "Generating junk file" > ./junkfile, \ +)) + +run-test1: $(EXEC_1) + test -f $(OUTPUT_DIR)/exec_1/support/junkfile + +$(eval $(call SetupExecute, EXEC_2, \ + INFO := Testing that SetupExecute runs from SUPPORT_DIR, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_2, \ + SUPPORT_DIR := $(OUTPUT_DIR)/exec_2/support, \ + WORKING_DIR := $(OUTPUT_DIR)/exec_2/special, \ + COMMAND := $(ECHO) "Generating special file" > ./specialfile, \ +)) + +run-test2: $(EXEC_2) + test -f $(OUTPUT_DIR)/exec_2/special/specialfile + + +TEST_TARGETS += run-test1 run-test2 + +.PHONY: run-test1 run-test2 + +################################################################################ + +all: $(TEST_TARGETS) + +################################################################################ + +include MakeFileEnd.gmk diff --git a/test/make/TestMake.gmk b/test/make/TestMake.gmk index a017b573d0c..8c4141c1c89 100644 --- a/test/make/TestMake.gmk +++ b/test/make/TestMake.gmk @@ -34,6 +34,9 @@ java-compilation: copy-files: +$(MAKE) -f TestCopyFiles.gmk $(TEST_SUBTARGET) +execute: + +$(MAKE) -f TestExecute.gmk $(TEST_SUBTARGET) + fix-deps-file: +$(MAKE) -f TestFixDepsFile.gmk $(TEST_SUBTARGET) @@ -47,7 +50,7 @@ configure: $(BASH) $(TOPDIR)/test/make/autoconf/test-configure.sh \ "$(AUTOCONF)" "$(TOPDIR)" "$(TEST_SUPPORT_DIR)" -TARGETS += make-base java-compilation copy-files fix-deps-file idea \ +TARGETS += make-base java-compilation copy-files execute fix-deps-file idea \ compile-commands configure # Prints targets to TARGETS_FILE which must be set when calling this target. From 6bb15a542b0eb6a4b17cfd9da50a94781d0180eb Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 7 Sep 2025 20:21:23 +0000 Subject: [PATCH 394/471] 8367035: [BACKOUT] Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: kbarrett --- make/RunTests.gmk | 28 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++----------------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 ++--- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index b44243dae76..10f0a2f87ed 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - ) + )) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - ) + )) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - ) + )) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - ) + )) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - ) + )) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 80d6b4538c8..3cf2a4dd136 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ + COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 97ef88932cb..d1bb0396943 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,12 +284,6 @@ else LogCmdlines = endif -# Check if the command line contains redirection, that is <, > or >>, -# and if so, return a value that is interpreted as true in a make $(if) -# construct. -is_redirect = \ - $(if $(filter < > >>, $1), true) - ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -297,23 +291,21 @@ is_redirect = \ # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # +# NOTE: If the command redirects stdout, the caller needs to wrap it in a +# subshell (by adding parentheses around it), otherwise the redirect to the +# subshell tee process will create a race condition where the target file may +# not be fully written when the make recipe is done. +# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: \ - [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ - is_redirect, $2), $(RIGHT_PAREN))]) \ + $(call LogCmdlines, Executing: [$(strip $2)]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && \ - $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ - is_redirect, $2), $(RIGHT_PAREN)) \ - > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ - /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ - /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index c60b49ae85f..1b4a5b76ea1 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) + ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index 7a80bf47285..e71c3cb961d 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,9 +47,8 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) - $(call ExecuteWithLog, $@, \ - $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 14a40fd579b087f061da086f5eb18230c379dce0 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 7 Sep 2025 23:18:07 +0000 Subject: [PATCH 395/471] 8361533: Apply java.io.Serial annotations in java.logging Reviewed-by: rriggs --- .../share/classes/java/util/logging/LoggingPermission.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java.logging/share/classes/java/util/logging/LoggingPermission.java b/src/java.logging/share/classes/java/util/logging/LoggingPermission.java index d9cf9b58bbd..725a2dd19da 100644 --- a/src/java.logging/share/classes/java/util/logging/LoggingPermission.java +++ b/src/java.logging/share/classes/java/util/logging/LoggingPermission.java @@ -26,6 +26,7 @@ package java.util.logging; +import java.io.Serial; /** * This class is for logging permissions. Currently there is only one @@ -48,6 +49,7 @@ package java.util.logging; @Deprecated(since="25", forRemoval=true) public final class LoggingPermission extends java.security.BasicPermission { + @Serial private static final long serialVersionUID = 63564341580231582L; /** From 8a6b8751e1a8ad93646bf3900186802c863d7119 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 7 Sep 2025 23:20:22 +0000 Subject: [PATCH 396/471] 8354871: Replace stack map frame type magics with constants Reviewed-by: liach --- .../attribute/StackMapFrameInfo.java | 19 +++---- .../jdk/internal/classfile/impl/CodeImpl.java | 15 +++--- .../classfile/impl/StackMapDecoder.java | 33 ++++++------ .../classfile/impl/StackMapGenerator.java | 32 +++++++++--- .../impl/verifier/ParserVerifier.java | 18 ++++--- .../impl/verifier/VerificationTable.java | 35 ++++++------- .../impl/verifier/VerificationType.java | 50 +++++++------------ 7 files changed, 99 insertions(+), 103 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 06e9e6d585e..d807cc23f2a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -34,6 +34,7 @@ import java.lang.constant.ClassDesc; import java.util.List; import jdk.internal.classfile.impl.StackMapDecoder; +import jdk.internal.classfile.impl.StackMapGenerator; import jdk.internal.classfile.impl.TemporaryConstantPool; /** @@ -103,31 +104,31 @@ public sealed interface StackMapFrameInfo sealed interface VerificationTypeInfo { /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#TOP TOP}. */ - int ITEM_TOP = 0; + int ITEM_TOP = StackMapGenerator.ITEM_TOP; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#INTEGER INTEGER}. */ - int ITEM_INTEGER = 1; + int ITEM_INTEGER = StackMapGenerator.ITEM_INTEGER; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#FLOAT FLOAT}. */ - int ITEM_FLOAT = 2; + int ITEM_FLOAT = StackMapGenerator.ITEM_FLOAT; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#DOUBLE DOUBLE}. */ - int ITEM_DOUBLE = 3; + int ITEM_DOUBLE = StackMapGenerator.ITEM_DOUBLE; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#LONG LONG}. */ - int ITEM_LONG = 4; + int ITEM_LONG = StackMapGenerator.ITEM_LONG; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#NULL NULL}. */ - int ITEM_NULL = 5; + int ITEM_NULL = StackMapGenerator.ITEM_NULL; /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#UNINITIALIZED_THIS UNINITIALIZED_THIS}. */ - int ITEM_UNINITIALIZED_THIS = 6; + int ITEM_UNINITIALIZED_THIS = StackMapGenerator.ITEM_UNINITIALIZED_THIS; /** The {@link #tag() tag} for verification type info {@link ObjectVerificationTypeInfo OBJECT}. */ - int ITEM_OBJECT = 7; + int ITEM_OBJECT = StackMapGenerator.ITEM_OBJECT; /** The {@link #tag() tag} for verification type info {@link UninitializedVerificationTypeInfo UNINITIALIZED}. */ - int ITEM_UNINITIALIZED = 8; + int ITEM_UNINITIALIZED = StackMapGenerator.ITEM_UNINITIALIZED; /** * {@return the tag of the type info} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index c8c6d254650..e4480d740bd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -39,6 +39,7 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; +import static jdk.internal.classfile.impl.StackMapGenerator.*; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class CodeImpl @@ -292,33 +293,33 @@ public final class CodeImpl for (int i = 0; i < nEntries; ++i) { int frameType = classReader.readU1(p); int offsetDelta; - if (frameType < 64) { + if (frameType <= SAME_FRAME_END) { offsetDelta = frameType; ++p; } - else if (frameType < 128) { + else if (frameType <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { offsetDelta = frameType & 0x3f; p = adjustForObjectOrUninitialized(p + 1); } else switch (frameType) { - case 247 -> { + case SAME_LOCALS_1_STACK_ITEM_EXTENDED -> { offsetDelta = classReader.readU2(p + 1); p = adjustForObjectOrUninitialized(p + 3); } - case 248, 249, 250, 251 -> { + case CHOP_FRAME_START, CHOP_FRAME_START + 1, CHOP_FRAME_END, SAME_FRAME_EXTENDED -> { offsetDelta = classReader.readU2(p + 1); p += 3; } - case 252, 253, 254 -> { + case APPEND_FRAME_START, APPEND_FRAME_START + 1, APPEND_FRAME_END -> { offsetDelta = classReader.readU2(p + 1); - int k = frameType - 251; + int k = frameType - APPEND_FRAME_START + 1; p += 3; for (int c = 0; c < k; ++c) { p = adjustForObjectOrUninitialized(p); } } - case 255 -> { + case FULL_FRAME -> { offsetDelta = classReader.readU2(p + 1); p += 3; int k = classReader.readU2(p); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index c5ce2204c09..d8e24cd2b70 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -44,14 +44,11 @@ import java.util.List; import java.util.Objects; import static java.lang.classfile.ClassFile.ACC_STATIC; -import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; import static java.util.Objects.requireNonNull; +import static jdk.internal.classfile.impl.StackMapGenerator.*; public class StackMapDecoder { - private static final int - SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, - SAME_EXTENDED = 251; private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {}; private final ClassReader classReader; @@ -136,25 +133,25 @@ public class StackMapDecoder { int commonLocalsSize = Math.min(prevLocals.size(), fr.locals().size()); int diffLocalsSize = fr.locals().size() - prevLocals.size(); if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(fr.locals(), prevLocals, commonLocalsSize)) { - if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame out.writeU1(offsetDelta); } else { //chop, same extended or append frame - out.writeU1U2(251 + diffLocalsSize, offsetDelta); + out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta); for (int i=commonLocalsSize; i prevFrame.localsSize ? prevFrame.localsSize : localsSize; int diffLocalsSize = localsSize - prevFrame.localsSize; if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(locals, prevFrame.locals, commonLocalsSize)) { - if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame out.writeU1(offsetDelta); } else { //chop, same extended or append frame - out.writeU1U2(251 + diffLocalsSize, offsetDelta); + out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta); for (int i=commonLocalsSize; i 246) { - if (ft == 247) return 3 + verificationTypeSize(frame.stack().getFirst()); - if (ft < 252) return 3; - if (ft < 255) { + if (ft <= SAME_FRAME_END) return 1; + if (ft <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) return 1 + verificationTypeSize(frame.stack().getFirst()); + if (ft > RESERVED_END) { + if (ft == SAME_LOCALS_1_STACK_ITEM_EXTENDED) return 3 + verificationTypeSize(frame.stack().getFirst()); + if (ft <= SAME_FRAME_EXTENDED) return 3; + if (ft <= APPEND_FRAME_END) { var loc = frame.locals(); int l = 3; - for (int i = loc.size() + 251 - ft; i < loc.size(); i++) { + var k = ft - APPEND_FRAME_START + 1; + for (int i = loc.size() - k; i < loc.size(); i++) { l += verificationTypeSize(loc.get(i)); } return l; } - if (ft == 255) { + if (ft == FULL_FRAME) { int l = 7; for (var vt : frame.stack()) { l += verificationTypeSize(vt); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java index 85342e7106f..04276b8eeb8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -27,9 +27,7 @@ package jdk.internal.classfile.impl.verifier; import java.util.ArrayList; import java.util.List; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Object; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_Uninitialized; -import static jdk.internal.classfile.impl.verifier.VerificationType.ITEM_UninitializedThis; +import static jdk.internal.classfile.impl.StackMapGenerator.*; /// From `stackMapTable.cpp`. class VerificationTable { @@ -158,11 +156,6 @@ class VerificationTable { } } - private static final int - SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, - SAME_EXTENDED = 251, - FULL = 255; - public int get_frame_count() { return _frame_count; } @@ -252,10 +245,10 @@ class VerificationTable { VerificationType parse_verification_type(int[] flags) { int tag = _stream.get_u1(); - if (tag < ITEM_UninitializedThis) { + if (tag < ITEM_UNINITIALIZED_THIS) { return VerificationType.from_tag(tag, _verifier); } - if (tag == ITEM_Object) { + if (tag == ITEM_OBJECT) { int class_index = _stream.get_u2(); int nconstants = _cp.entryCount(); if (class_index <= 0 || class_index >= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { @@ -263,13 +256,13 @@ class VerificationTable { } return VerificationType.reference_type(_cp.classNameAt(class_index)); } - if (tag == ITEM_UninitializedThis) { + if (tag == ITEM_UNINITIALIZED_THIS) { if (flags != null) { flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; } return VerificationType.uninitialized_this_type; } - if (tag == ITEM_Uninitialized) { + if (tag == ITEM_UNINITIALIZED) { int offset = _stream.get_u2(); if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); @@ -285,7 +278,7 @@ class VerificationTable { int offset; VerificationType[] locals = null; int frame_type = _stream.get_u1(); - if (frame_type < 64) { + if (frame_type <= SAME_FRAME_END) { if (_first) { offset = frame_type; if (_prev_frame.locals_size() > 0) { @@ -302,14 +295,14 @@ class VerificationTable { _first = false; return frame; } - if (frame_type < 128) { + if (frame_type <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) { if (_first) { - offset = frame_type - 64; + offset = frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_START; if (_prev_frame.locals_size() > 0) { locals = new VerificationType[_prev_frame.locals_size()]; } } else { - offset = _prev_frame.offset() + frame_type - 63; + offset = _prev_frame.offset() + frame_type - SAME_LOCALS_1_STACK_ITEM_FRAME_START + 1; locals = _prev_frame.locals(); } VerificationType[] stack = new VerificationType[2]; @@ -356,10 +349,10 @@ class VerificationTable { _first = false; return frame; } - if (frame_type <= SAME_EXTENDED) { + if (frame_type <= SAME_FRAME_EXTENDED) { locals = _prev_frame.locals(); int length = _prev_frame.locals_size(); - int chops = SAME_EXTENDED - frame_type; + int chops = SAME_FRAME_EXTENDED - frame_type; int new_length = length; int flags = _prev_frame.flags(); if (chops != 0) { @@ -389,8 +382,8 @@ class VerificationTable { } _first = false; return frame; - } else if (frame_type < SAME_EXTENDED + 4) { - int appends = frame_type - SAME_EXTENDED; + } else if (frame_type <= APPEND_FRAME_END) { + int appends = frame_type - APPEND_FRAME_START + 1; int real_length = _prev_frame.locals_size(); int new_length = real_length + appends*2; locals = new VerificationType[new_length]; @@ -418,7 +411,7 @@ class VerificationTable { _first = false; return frame; } - if (frame_type == FULL) { + if (frame_type == FULL_FRAME) { int flags[] = new int[]{0}; int locals_size = _stream.get_u2(); int real_locals_size = 0; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java index caf230cbdc0..dd9742be305 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationType.java @@ -33,6 +33,7 @@ import java.util.Objects; import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.Util; +import static jdk.internal.classfile.impl.StackMapGenerator.*; import static jdk.internal.classfile.impl.verifier.VerifierImpl.*; /// From `verificationType.cpp`. @@ -40,18 +41,6 @@ class VerificationType { private static final int BitsPerByte = 8; - static final int - ITEM_Top = 0, - ITEM_Integer = 1, - ITEM_Float = 2, - ITEM_Double = 3, - ITEM_Long = 4, - ITEM_Null = 5, - ITEM_UninitializedThis = 6, - ITEM_Object = 7, - ITEM_Uninitialized = 8, - ITEM_Bogus = -1; - VerificationType(String sym) { _data = 0x100; _sym = sym; @@ -92,9 +81,6 @@ class VerificationType { String name() { return _sym; } - private static final int - ITEM_Boolean = 9, ITEM_Byte = 10, ITEM_Short = 11, ITEM_Char = 12, - ITEM_Long_2nd = 13, ITEM_Double_2nd = 14; private static final int TypeMask = 0x00000003, @@ -116,17 +102,17 @@ class VerificationType { Category2_2nd = (Category2_2ndFlag << BitsPerByte) | Primitive, // Primitive values (type discriminator stored in most-significant bytes) // Bogus needs the " | Primitive". Else, isReference(Bogus) returns TRUE. - Bogus = (ITEM_Bogus << 2 * BitsPerByte) | Primitive, - Boolean = (ITEM_Boolean << 2 * BitsPerByte) | Category1, - Byte = (ITEM_Byte << 2 * BitsPerByte) | Category1, - Short = (ITEM_Short << 2 * BitsPerByte) | Category1, - Char = (ITEM_Char << 2 * BitsPerByte) | Category1, - Integer = (ITEM_Integer << 2 * BitsPerByte) | Category1, - Float = (ITEM_Float << 2 * BitsPerByte) | Category1, - Long = (ITEM_Long << 2 * BitsPerByte) | Category2, - Double = (ITEM_Double << 2 * BitsPerByte) | Category2, - Long_2nd = (ITEM_Long_2nd << 2 * BitsPerByte) | Category2_2nd, - Double_2nd = (ITEM_Double_2nd << 2 * BitsPerByte) | Category2_2nd, + Bogus = (ITEM_BOGUS << 2 * BitsPerByte) | Primitive, + Boolean = (ITEM_BOOLEAN << 2 * BitsPerByte) | Category1, + Byte = (ITEM_BYTE << 2 * BitsPerByte) | Category1, + Short = (ITEM_SHORT << 2 * BitsPerByte) | Category1, + Char = (ITEM_CHAR << 2 * BitsPerByte) | Category1, + Integer = (ITEM_INTEGER << 2 * BitsPerByte) | Category1, + Float = (ITEM_FLOAT << 2 * BitsPerByte) | Category1, + Long = (ITEM_LONG << 2 * BitsPerByte) | Category2, + Double = (ITEM_DOUBLE << 2 * BitsPerByte) | Category2, + Long_2nd = (ITEM_LONG_2ND << 2 * BitsPerByte) | Category2_2nd, + Double_2nd = (ITEM_DOUBLE_2ND << 2 * BitsPerByte) | Category2_2nd, // Used by Uninitialized (second and third bytes hold the bci) BciMask = 0xffff << BitsPerByte, // A bci of -1 is an Uninitialized-This @@ -364,12 +350,12 @@ class VerificationType { static VerificationType from_tag(int tag, VerifierImpl context) { switch (tag) { - case ITEM_Top: return bogus_type; - case ITEM_Integer: return integer_type; - case ITEM_Float: return float_type; - case ITEM_Double: return double_type; - case ITEM_Long: return long_type; - case ITEM_Null: return null_type; + case ITEM_TOP: return bogus_type; + case ITEM_INTEGER: return integer_type; + case ITEM_FLOAT: return float_type; + case ITEM_DOUBLE: return double_type; + case ITEM_LONG: return long_type; + case ITEM_NULL: return null_type; default: context.verifyError("Should not reach here"); return bogus_type; From b0ca9bf61e0390a3b022a0915eacabb0cfd92e93 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 04:35:05 +0000 Subject: [PATCH 397/471] 8365776: Convert JShell tests to use JUnit instead of TestNG Reviewed-by: vromero --- .../jdk/jshell/AbstractStopExecutionTest.java | 2 +- test/langtools/jdk/jshell/AnalysisTest.java | 11 +- .../jdk/jshell/AnalyzeSnippetTest.java | 81 +++++----- .../jshell/BadExecutionControlSpecTest.java | 11 +- .../jdk/jshell/ClassMembersTest.java | 26 +-- test/langtools/jdk/jshell/ClassPathTest.java | 13 +- test/langtools/jdk/jshell/ClassesTest.java | 55 +++++-- .../jdk/jshell/CommandCompletionTest.java | 20 ++- .../jdk/jshell/CompilerOptionsTest.java | 13 +- .../jdk/jshell/CompletenessStressTest.java | 10 +- .../jdk/jshell/CompletenessTest.java | 26 ++- .../jdk/jshell/CompletionSuggestionTest.java | 60 ++++++- .../langtools/jdk/jshell/ComputeFQNsTest.java | 20 +-- test/langtools/jdk/jshell/ConsoleTest.java | 18 +-- .../langtools/jdk/jshell/ConsoleToolTest.java | 4 +- .../jdk/jshell/CustomInputToolBuilder.java | 12 +- test/langtools/jdk/jshell/DropTest.java | 18 ++- test/langtools/jdk/jshell/EditorTestBase.java | 28 ++-- test/langtools/jdk/jshell/EmptyTest.java | 13 +- .../jdk/jshell/ErrorRecoveryTest.java | 11 +- .../jdk/jshell/ErrorTranslationTest.java | 26 +-- .../jdk/jshell/ExceptionMessageTest.java | 19 +-- test/langtools/jdk/jshell/ExceptionsTest.java | 46 ++++-- .../jdk/jshell/ExecutionControlSpecTest.java | 14 +- .../jdk/jshell/ExecutionControlTestBase.java | 4 +- .../jdk/jshell/ExpectedDiagnostic.java | 14 +- .../jdk/jshell/ExternalEditorTest.java | 37 ++--- .../FailOverDirectExecutionControlTest.java | 28 ++-- ...ilOverExecutionControlDyingLaunchTest.java | 10 +- ...OverExecutionControlHangingLaunchTest.java | 10 +- ...OverExecutionControlHangingListenTest.java | 10 +- .../jshell/FailOverExecutionControlTest.java | 10 +- .../langtools/jdk/jshell/FileManagerTest.java | 15 +- .../jshell/ForwardReferenceImportTest.java | 24 ++- .../jdk/jshell/ForwardReferenceTest.java | 33 ++-- .../langtools/jdk/jshell/GetResourceTest.java | 13 +- .../langtools/jdk/jshell/HighlightUITest.java | 6 +- test/langtools/jdk/jshell/HistoryTest.java | 34 ++-- test/langtools/jdk/jshell/HistoryUITest.java | 9 +- test/langtools/jdk/jshell/IOTest.java | 17 +- .../langtools/jdk/jshell/IdGeneratorTest.java | 20 ++- test/langtools/jdk/jshell/IgnoreTest.java | 16 +- .../jshell/IllegalArgumentExceptionTest.java | 15 +- test/langtools/jdk/jshell/ImportTest.java | 27 +++- .../jshell/InaccessibleExpressionTest.java | 24 +-- test/langtools/jdk/jshell/IndentUITest.java | 8 +- test/langtools/jdk/jshell/InferTypeTest.java | 8 +- test/langtools/jdk/jshell/InputUITest.java | 8 +- .../langtools/jdk/jshell/JLCollisionTest.java | 10 +- .../langtools/jdk/jshell/JShellQueryTest.java | 18 ++- .../jdk/jshell/JShellStateClosedTest.java | 21 ++- test/langtools/jdk/jshell/JavadocTest.java | 10 +- ...diBadOptionLaunchExecutionControlTest.java | 12 +- ...diBadOptionListenExecutionControlTest.java | 12 +- ...diBogusHostListenExecutionControlTest.java | 12 +- .../JdiFailingLaunchExecutionControlTest.java | 12 +- .../JdiFailingListenExecutionControlTest.java | 12 +- .../JdiHangingLaunchExecutionControlTest.java | 10 +- .../JdiHangingListenExecutionControlTest.java | 10 +- .../JdiLaunchingExecutionControlTest.java | 10 +- .../JdiListeningExecutionControlTest.java | 10 +- ...isteningLocalhostExecutionControlTest.java | 10 +- test/langtools/jdk/jshell/JdiStarterTest.java | 18 +-- .../jshell/KullaCompletenessStressTest.java | 22 +-- test/langtools/jdk/jshell/KullaTesting.java | 150 +++++++++--------- .../jshell/LocalExecutionClassPathTest.java | 8 +- ...LocalExecutionContextLoaderParentTest.java | 12 +- .../jdk/jshell/LocalExecutionTestSupport.java | 6 +- .../jdk/jshell/LocalStopExecutionTest.java | 12 +- test/langtools/jdk/jshell/MethodsTest.java | 49 ++++-- test/langtools/jdk/jshell/ModifiersTest.java | 23 ++- .../jdk/jshell/MultipleDocumentationTest.java | 12 +- .../jdk/jshell/MyExecutionControl.java | 4 +- test/langtools/jdk/jshell/NullTest.java | 8 +- .../jshell/PasteAndMeasurementsUITest.java | 10 +- .../jdk/jshell/PipeInputStreamTest.java | 22 +-- .../jdk/jshell/PrimitiveInstanceOfTest.java | 16 +- test/langtools/jdk/jshell/RecordsTest.java | 20 +-- .../jdk/jshell/RejectedFailedTest.java | 29 ++-- .../langtools/jdk/jshell/ReplToolTesting.java | 21 ++- test/langtools/jdk/jshell/ReplaceTest.java | 29 +++- .../jdk/jshell/SealedClassesTest.java | 12 +- test/langtools/jdk/jshell/ShutdownTest.java | 83 ++++++---- .../jdk/jshell/SimpleRegressionTest.java | 48 ++++-- .../jdk/jshell/SnippetEventToStringTest.java | 18 ++- .../jdk/jshell/SnippetHighlightTest.java | 14 +- .../jdk/jshell/SnippetStatusListenerTest.java | 45 +++--- test/langtools/jdk/jshell/SnippetTest.java | 31 +++- .../langtools/jdk/jshell/SourceLevelTest.java | 14 +- .../langtools/jdk/jshell/StartOptionTest.java | 88 +++++----- .../StartupWithFormatSpecifierTest.java | 8 +- .../jdk/jshell/StopExecutionTest.java | 22 +-- .../jshell/T8146368/JShellTest8146368.java | 8 +- .../T8146368/JShellToolTest8146368.java | 8 +- test/langtools/jdk/jshell/Test8294583.java | 13 +- test/langtools/jdk/jshell/Test8296012.java | 13 +- test/langtools/jdk/jshell/ToolBasicTest.java | 84 +++++++--- .../jdk/jshell/ToolCommandOptionTest.java | 23 ++- .../jdk/jshell/ToolCompletionTest.java | 4 +- .../jshell/ToolEnableNativeAccessTest.java | 9 +- .../jdk/jshell/ToolEnablePreviewTest.java | 9 +- test/langtools/jdk/jshell/ToolFormatTest.java | 42 +++-- .../jdk/jshell/ToolLocalSimpleTest.java | 10 +- .../jdk/jshell/ToolLocaleMessageTest.java | 16 +- .../ToolMultilineSnippetHistoryTest.java | 8 +- .../jdk/jshell/ToolProviderTest.java | 8 +- test/langtools/jdk/jshell/ToolReloadTest.java | 19 ++- test/langtools/jdk/jshell/ToolRetainTest.java | 17 +- .../jdk/jshell/ToolShiftTabTest.java | 13 +- test/langtools/jdk/jshell/ToolSimpleTest.java | 13 +- .../jdk/jshell/ToolTabCommandTest.java | 10 +- .../jdk/jshell/ToolTabSnippetTest.java | 12 +- test/langtools/jdk/jshell/ToolingTest.java | 5 +- test/langtools/jdk/jshell/TypeNameTest.java | 23 ++- test/langtools/jdk/jshell/UITesting.java | 6 +- .../jdk/jshell/UndefinedClassTest.java | 9 +- test/langtools/jdk/jshell/UnicodeTest.java | 13 +- test/langtools/jdk/jshell/UnnamedTest.java | 12 +- .../jdk/jshell/UserExecutionControlTest.java | 18 +-- test/langtools/jdk/jshell/UserInputTest.java | 12 +- .../jdk/jshell/UserJdiUserRemoteTest.java | 22 +-- test/langtools/jdk/jshell/VariablesTest.java | 71 +++++++-- test/langtools/jdk/jshell/WrapperTest.java | 72 +++++---- 123 files changed, 1553 insertions(+), 1029 deletions(-) diff --git a/test/langtools/jdk/jshell/AbstractStopExecutionTest.java b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java index c38549b5128..7fca7d75d5e 100644 --- a/test/langtools/jdk/jshell/AbstractStopExecutionTest.java +++ b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java @@ -26,7 +26,7 @@ import java.io.StringWriter; import jdk.jshell.JShell; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; public abstract class AbstractStopExecutionTest extends KullaTesting { diff --git a/test/langtools/jdk/jshell/AnalysisTest.java b/test/langtools/jdk/jshell/AnalysisTest.java index f6cd5bf9efb..478301f3fd5 100644 --- a/test/langtools/jdk/jshell/AnalysisTest.java +++ b/test/langtools/jdk/jshell/AnalysisTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,14 +25,14 @@ * @test * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream - * @run testng AnalysisTest + * @run junit AnalysisTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class AnalysisTest extends KullaTesting { + @Test public void testSource() { assertAnalyze("int x=3//test", "int x=3;//test", "", true); assertAnalyze("int x=3 ;//test", "int x=3 ;//test", "", true); @@ -41,6 +41,7 @@ public class AnalysisTest extends KullaTesting { assertAnalyze("int ff; int v // hi", "int ff;", " int v // hi", true); } + @Test public void testSourceSlashStar() { assertAnalyze("/*zoo*/int x=3 /*test*/", "/*zoo*/int x=3; /*test*/", "", true); assertAnalyze("/*zoo*/int x=3 ;/*test*/", "/*zoo*/int x=3 ;/*test*/", "", true); @@ -49,11 +50,13 @@ public class AnalysisTest extends KullaTesting { assertAnalyze("int ff; int v /*hgjghj*/", "int ff;", " int v /*hgjghj*/", true); } + @Test public void testIncomplete() { assertAnalyze("void m() { //erer", null, "void m() { //erer\n", false); assertAnalyze("int m=//", null, "int m=//\n", false); } + @Test public void testExpression() { assertAnalyze("45//test", "45//test", "", true); assertAnalyze("45;//test", "45;//test", "", true); diff --git a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java index a9b0315e960..3b93e68f03d 100644 --- a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java +++ b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8182270 8341176 * @summary test non-eval Snippet analysis * @build KullaTesting TestingInputStream - * @run testng AnalyzeSnippetTest + * @run junit AnalyzeSnippetTest */ import java.io.ByteArrayOutputStream; @@ -36,15 +36,12 @@ import java.util.stream.Stream; import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; import jdk.jshell.Diag; -import org.testng.annotations.Test; import jdk.jshell.JShell; import jdk.jshell.MethodSnippet; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import jdk.jshell.ErroneousSnippet; import jdk.jshell.ExpressionSnippet; import jdk.jshell.ImportSnippet; @@ -55,14 +52,16 @@ import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.SubKind.*; import jdk.jshell.SourceCodeAnalysis.SnippetWrapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class AnalyzeSnippetTest { JShell state; SourceCodeAnalysis sca; - @BeforeMethod + @BeforeEach public void setUp() { state = JShell.builder() .out(new PrintStream(new ByteArrayOutputStream())) @@ -72,7 +71,7 @@ public class AnalyzeSnippetTest { sca = state.sourceCodeAnalysis(); } - @AfterMethod + @AfterEach public void tearDown() { if (state != null) { state.close(); @@ -81,55 +80,61 @@ public class AnalyzeSnippetTest { sca = null; } + @Test public void testImport() { ImportSnippet sn = (ImportSnippet) assertSnippet("import java.util.List;", SubKind.SINGLE_TYPE_IMPORT_SUBKIND); - assertEquals(sn.name(), "List"); + assertEquals("List", sn.name()); sn = (ImportSnippet) assertSnippet("import static java.nio.file.StandardOpenOption.CREATE;", SubKind.SINGLE_STATIC_IMPORT_SUBKIND); assertTrue(sn.isStatic()); } + @Test public void testClass() { TypeDeclSnippet sn = (TypeDeclSnippet) assertSnippet("class C {}", SubKind.CLASS_SUBKIND); - assertEquals(sn.name(), "C"); + assertEquals("C", sn.name()); sn = (TypeDeclSnippet) assertSnippet("enum EE {A, B , C}", SubKind.ENUM_SUBKIND); } + @Test public void testMethod() { MethodSnippet sn = (MethodSnippet) assertSnippet("int m(int x) { return x + x; }", SubKind.METHOD_SUBKIND); - assertEquals(sn.name(), "m"); - assertEquals(sn.signature(), "(int)int"); + assertEquals("m", sn.name()); + assertEquals("(int)int", sn.signature()); } + @Test public void testVar() { VarSnippet sn = (VarSnippet) assertSnippet("int i;", SubKind.VAR_DECLARATION_SUBKIND); - assertEquals(sn.name(), "i"); - assertEquals(sn.typeName(), "int"); + assertEquals("i", sn.name()); + assertEquals("int", sn.typeName()); sn = (VarSnippet) assertSnippet("int jj = 6;", SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND); sn = (VarSnippet) assertSnippet("2 + 2", SubKind.TEMP_VAR_EXPRESSION_SUBKIND); } + @Test public void testExpression() { state.eval("int aa = 10;"); ExpressionSnippet sn = (ExpressionSnippet) assertSnippet("aa", SubKind.VAR_VALUE_SUBKIND); - assertEquals(sn.name(), "aa"); - assertEquals(sn.typeName(), "int"); + assertEquals("aa", sn.name()); + assertEquals("int", sn.typeName()); sn = (ExpressionSnippet) assertSnippet("aa;", SubKind.VAR_VALUE_SUBKIND); - assertEquals(sn.name(), "aa"); - assertEquals(sn.typeName(), "int"); + assertEquals("aa", sn.name()); + assertEquals("int", sn.typeName()); sn = (ExpressionSnippet) assertSnippet("aa = 99", SubKind.ASSIGNMENT_SUBKIND); } + @Test public void testStatement() { StatementSnippet sn = (StatementSnippet) assertSnippet("System.out.println(33)", SubKind.STATEMENT_SUBKIND); @@ -137,6 +142,7 @@ public class AnalyzeSnippetTest { SubKind.STATEMENT_SUBKIND); } + @Test public void testErroneous() { ErroneousSnippet sn = (ErroneousSnippet) assertSnippet("+++", SubKind.UNKNOWN_SUBKIND); @@ -144,6 +150,7 @@ public class AnalyzeSnippetTest { SubKind.UNKNOWN_SUBKIND); } + @Test public void testDiagnosticsForSourceSnippet() { Snippet sn; sn = assertSnippet("unknown()", UNKNOWN_SUBKIND); @@ -164,6 +171,7 @@ public class AnalyzeSnippetTest { assertDiagnostics(sn, "7-22:compiler.err.doesnt.exist"); } + @Test public void testSnippetWrapper() { SourceCodeAnalysis analysis = state.sourceCodeAnalysis(); Snippet sn; @@ -171,38 +179,39 @@ public class AnalyzeSnippetTest { sn = assertSnippet(code, UNKNOWN_SUBKIND); SnippetWrapper wrapper = analysis.wrapper(sn); String wrapped = wrapper.wrapped(); - assertEquals(wrapped, """ - package REPL; + assertEquals(""" + package REPL; - class $JShell$DOESNOTMATTER { - public static java.lang.Object do_it$() throws java.lang.Throwable { - return unknown(); - } - } - """); + class $JShell$DOESNOTMATTER { + public static java.lang.Object do_it$() throws java.lang.Throwable { + return unknown(); + } + } + """, wrapped); for (int pos = 0; pos < code.length(); pos++) { int wrappedPos = wrapper.sourceToWrappedPosition(pos); - assertEquals(wrapped.charAt(wrappedPos), code.charAt(pos)); - assertEquals(wrapper.wrappedToSourcePosition(wrappedPos), pos); + assertEquals(code.charAt(pos), wrapped.charAt(wrappedPos)); + assertEquals(pos, wrapper.wrappedToSourcePosition(wrappedPos)); } } + @Test public void testNoStateChange() { assertSnippet("int a = 5;", SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND); assertSnippet("a", SubKind.UNKNOWN_SUBKIND); VarSnippet vsn = (VarSnippet) state.eval("int aa = 10;").get(0).snippet(); assertSnippet("++aa;", SubKind.TEMP_VAR_EXPRESSION_SUBKIND); - assertEquals(state.varValue(vsn), "10"); + assertEquals("10", state.varValue(vsn)); assertSnippet("class CC {}", SubKind.CLASS_SUBKIND); assertSnippet("new CC();", SubKind.UNKNOWN_SUBKIND); } private Snippet assertSnippet(String input, SubKind sk) { List sns = sca.sourceToSnippets(input); - assertEquals(sns.size(), 1, "snippet count"); + assertEquals(1, sns.size(), "snippet count"); Snippet sn = sns.get(0); - assertEquals(sn.id(), "*UNASSOCIATED*"); - assertEquals(sn.subKind(), sk); + assertEquals("*UNASSOCIATED*", sn.id()); + assertEquals(sk, sn.subKind()); return sn; } @@ -213,6 +222,6 @@ public class AnalyzeSnippetTest { private void assertDiagnostics(Snippet s, String... expectedDiags) { List actual = state.diagnostics(s).map(this::diagToString).toList(); List expected = List.of(expectedDiags); - assertEquals(actual, expected); + assertEquals(expected, actual); } } diff --git a/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java b/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java index a4f4158a5c7..f7b34a0e194 100644 --- a/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java +++ b/test/langtools/jdk/jshell/BadExecutionControlSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -29,7 +29,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool - * @run testng BadExecutionControlSpecTest + * @run junit BadExecutionControlSpecTest */ import java.io.ByteArrayInputStream; @@ -38,12 +38,11 @@ import java.io.InputStream; import java.io.PrintStream; import java.util.Collections; import java.util.List; -import org.testng.annotations.Test; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionEnv; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class BadExecutionControlSpecTest { private static void assertIllegal(String spec) throws Throwable { try { @@ -80,6 +79,7 @@ public class BadExecutionControlSpecTest { } } + @Test public void syntaxTest() throws Throwable { assertIllegal(":launch(true)"); assertIllegal("jdi:launch(true"); @@ -87,6 +87,7 @@ public class BadExecutionControlSpecTest { assertIllegal("jdi:,"); } + @Test public void notFoundTest() throws Throwable { assertIllegal("fruitbats"); assertIllegal("jdi:baz(true)"); diff --git a/test/langtools/jdk/jshell/ClassMembersTest.java b/test/langtools/jdk/jshell/ClassMembersTest.java index 25360770ab3..6e188e7b8eb 100644 --- a/test/langtools/jdk/jshell/ClassMembersTest.java +++ b/test/langtools/jdk/jshell/ClassMembersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8139829 * @summary Test access to members of user defined class. * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=600 ClassMembersTest + * @run junit/timeout=600 ClassMembersTest */ import java.lang.annotation.RetentionPolicy; @@ -36,22 +36,26 @@ import java.util.List; import javax.tools.Diagnostic; import jdk.jshell.SourceCodeAnalysis; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.TypeDeclSnippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ClassMembersTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } - @Test(dataProvider = "memberTestCase") + @ParameterizedTest + @MethodSource("memberTestCaseGenerator") public void memberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) { MemberTestCase testCase = new MemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference); assertEval(testCase.generateSource()); @@ -78,7 +82,8 @@ public class ClassMembersTest extends KullaTesting { return list; } - @Test(dataProvider = "memberTestCase") + @ParameterizedTest + @MethodSource("memberTestCaseGenerator") public void extendsMemberTest(AccessModifier accessModifier, CodeChunk codeChunk, Static isStaticMember, Static isStaticReference) { MemberTestCase testCase = new ExtendsMemberTestCase(accessModifier, codeChunk, isStaticMember, isStaticReference); String input = testCase.generateSource(); @@ -151,7 +156,8 @@ public class ClassMembersTest extends KullaTesting { new ExpectedDiagnostic("compiler.err.non-static.cant.be.ref", 0, 8, 1, -1, -1, Diagnostic.Kind.ERROR)); } - @Test(dataProvider = "retentionPolicyTestCase") + @ParameterizedTest + @MethodSource("retentionPolicyTestCaseGenerator") public void annotationTest(RetentionPolicy policy) { assertEval("import java.lang.annotation.*;"); String annotationSource = @@ -174,7 +180,6 @@ public class ClassMembersTest extends KullaTesting { assertEval("C.Inner.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); } - @DataProvider(name = "retentionPolicyTestCase") public Object[][] retentionPolicyTestCaseGenerator() { List list = new ArrayList<>(); for (RetentionPolicy policy : RetentionPolicy.values()) { @@ -183,7 +188,6 @@ public class ClassMembersTest extends KullaTesting { return list.toArray(new Object[list.size()][]); } - @DataProvider(name = "memberTestCase") public Object[][] memberTestCaseGenerator() { List list = new ArrayList<>(); for (AccessModifier accessModifier : AccessModifier.values()) { diff --git a/test/langtools/jdk/jshell/ClassPathTest.java b/test/langtools/jdk/jshell/ClassPathTest.java index b9c86274389..6c2320ffac2 100644 --- a/test/langtools/jdk/jshell/ClassPathTest.java +++ b/test/langtools/jdk/jshell/ClassPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -30,20 +30,20 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ClassPathTest + * @run junit ClassPathTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ClassPathTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("class_path_test"); + @Test public void testDirectory() { compiler.compile(outDir, "package pkg; public class TestDirectory { }"); assertDeclareFail("import pkg.TestDirectory;", "compiler.err.doesnt.exist"); @@ -52,6 +52,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new pkg.TestDirectory();"); } + @Test public void testJar() { compiler.compile(outDir, "package pkg; public class TestJar { }"); String jarName = "test.jar"; @@ -62,6 +63,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new pkg.TestJar();"); } + @Test public void testAmbiguousDirectory() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, @@ -82,6 +84,7 @@ public class ClassPathTest extends KullaTesting { assertEval("new p.TestAmbiguous();", "first"); } + @Test public void testAmbiguousJar() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, @@ -104,11 +107,13 @@ public class ClassPathTest extends KullaTesting { assertEval("new p.TestAmbiguous();", "first"); } + @Test public void testEmptyClassPath() { addToClasspath(""); assertEval("new java.util.ArrayList();"); } + @Test public void testUnknown() { addToClasspath(compiler.getPath(outDir.resolve("UNKNOWN"))); assertDeclareFail("new Unknown();", "compiler.err.cant.resolve.location"); diff --git a/test/langtools/jdk/jshell/ClassesTest.java b/test/langtools/jdk/jshell/ClassesTest.java index 3da389e5059..85f85e69c94 100644 --- a/test/langtools/jdk/jshell/ClassesTest.java +++ b/test/langtools/jdk/jshell/ClassesTest.java @@ -26,7 +26,7 @@ * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 8282160 8292755 8319532 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=480 ClassesTest + * @run junit/timeout=480 ClassesTest */ import java.util.ArrayList; @@ -37,8 +37,6 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import jdk.jshell.Diag; import jdk.jshell.Snippet.Status; @@ -51,16 +49,22 @@ import static jdk.jshell.Snippet.Status.REJECTED; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ClassesTest extends KullaTesting { + @Test public void noClasses() { assertNumberOfActiveClasses(0); } + @Test public void testSignature1() { TypeDeclSnippet c1 = classKey(assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED))); assertTypeDeclSnippet(c1, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); @@ -82,6 +86,7 @@ public class ClassesTest extends KullaTesting { assertTypeDeclSnippet(c5, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); } + @Test public void testSignature2() { TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req"); assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2); @@ -92,27 +97,32 @@ public class ClassesTest extends KullaTesting { ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null)); } + @Test public void classDeclaration() { assertEval("class A { }"); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); } + @Test public void interfaceDeclaration() { assertEval("interface A { }"); assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A")); } + @Test public void annotationDeclaration() { assertEval("@interface A { }"); assertClasses(clazz(KullaTesting.ClassType.ANNOTATION, "A")); } + @Test public void enumDeclaration() { assertEval("enum A { }"); assertClasses(clazz(KullaTesting.ClassType.ENUM, "A")); } + @Test public void classesDeclaration() { assertEval("interface A { }"); assertEval("class B implements A { }"); @@ -128,6 +138,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesRedeclaration1() { Snippet a = classKey(assertEval("class A { }")); Snippet b = classKey(assertEval("interface B { }")); @@ -149,6 +160,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesRedeclaration2() { assertEval("class A { }"); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); @@ -180,6 +192,7 @@ public class ClassesTest extends KullaTesting { } //8154496: test3 update: sig change should false + @Test public void classesRedeclaration3() { Snippet a = classKey(assertEval("class A { }")); assertClasses(clazz(KullaTesting.ClassType.CLASS, "A")); @@ -201,6 +214,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesCyclic1() { Snippet b = classKey(assertEval("class B extends A { }", added(RECOVERABLE_NOT_DEFINED))); @@ -221,11 +235,12 @@ public class ClassesTest extends KullaTesting { diags = diagsA; assertTrue(diagsB.isEmpty()); } - assertEquals(diags.size(), 1, "Expected one error"); - assertEquals(diags.get(0).getCode(), "compiler.err.cyclic.inheritance", "Expected cyclic inheritance error"); + assertEquals(1, diags.size(), "Expected one error"); + assertEquals("compiler.err.cyclic.inheritance", diags.get(0).getCode(), "Expected cyclic inheritance error"); assertActiveKeys(); } + @Test public void classesCyclic2() { Snippet d = classKey(assertEval("class D extends E { }", added(RECOVERABLE_NOT_DEFINED))); assertEval("class E { D d; }", @@ -234,6 +249,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesCyclic3() { Snippet outer = classKey(assertEval("class Outer { class Inner extends Foo { } }", added(RECOVERABLE_NOT_DEFINED))); @@ -247,6 +263,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiers() { assertEval("public interface A { }"); assertEval("static class B implements A { }"); @@ -254,6 +271,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiersAnnotation() { assertEval("public @interface X { }"); assertEval("@X public interface A { }"); @@ -262,6 +280,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void classesIgnoredModifiersOtherModifiers() { assertEval("strictfp public interface A { }"); assertEval("strictfp static class B implements A { }"); @@ -269,6 +288,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void ignoreModifierSpaceIssue() { assertEval("interface I { void f(); } "); // there should not be a space between 'I' and '{' to reproduce the failure @@ -277,7 +297,6 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } - @DataProvider(name = "innerClasses") public Object[][] innerClasses() { List list = new ArrayList<>(); for (ClassType outerClassType : ClassType.values()) { @@ -288,7 +307,8 @@ public class ClassesTest extends KullaTesting { return list.toArray(new Object[list.size()][]); } - @Test(dataProvider = "innerClasses") + @ParameterizedTest + @MethodSource("innerClasses") public void innerClasses(ClassType outerClassType, ClassType innerClassType) { String source = outerClassType + " A {" + (outerClassType == ClassType.ENUM ? ";" : "") + @@ -299,6 +319,7 @@ public class ClassesTest extends KullaTesting { assertActiveKeys(); } + @Test public void testInnerClassesCrash() { Snippet a = classKey(assertEval("class A { class B extends A {} }")); Snippet a2 = classKey(assertEval("class A { interface I1 extends I2 {} interface I2 {} }", @@ -309,20 +330,23 @@ public class ClassesTest extends KullaTesting { ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); } + @Test public void testInnerClassesCrash1() { assertEval("class A { class B extends A {} B getB() { return new B();} }"); - assertEquals(varKey(assertEval("A a = new A();")).name(), "a"); + assertEquals("a", varKey(assertEval("A a = new A();")).name()); VarSnippet variableKey = varKey(assertEval("a.getB();")); - assertEquals(variableKey.typeName(), "A.B"); + assertEquals("A.B", variableKey.typeName()); } + @Test public void testInnerClassesCrash2() { assertEval("class A { interface I1 extends I2 {} interface I2 {} I1 x; }"); - assertEquals(varKey(assertEval("A a = new A();")).name(), "a"); + assertEquals("a", varKey(assertEval("A a = new A();")).name()); VarSnippet variableKey = varKey(assertEval("a.x;")); - assertEquals(variableKey.typeName(), "A.I1"); + assertEquals("A.I1", variableKey.typeName()); } + @Test public void testCircular() { assertEval("import java.util.function.Supplier;"); TypeDeclSnippet aClass = @@ -342,6 +366,7 @@ public class ClassesTest extends KullaTesting { assertEval("new A()"); } + @Test public void testCircular8282160() { TypeDeclSnippet classKey = classKey(assertEval(""" class B { @@ -360,6 +385,7 @@ public class ClassesTest extends KullaTesting { ste(classKey, Status.RECOVERABLE_NOT_DEFINED, Status.VALID, true, null)); } + @Test public void testDefaultMethodInInterface() { assertEvalFail(""" interface C { @@ -374,6 +400,7 @@ public class ClassesTest extends KullaTesting { """); } + @Test public void testNonSealed() { assertAnalyze("non-sealed class C extends B {}int i;", "non-sealed class C extends B {}", diff --git a/test/langtools/jdk/jshell/CommandCompletionTest.java b/test/langtools/jdk/jshell/CommandCompletionTest.java index 3a818a74e1e..ef02e135973 100644 --- a/test/langtools/jdk/jshell/CommandCompletionTest.java +++ b/test/langtools/jdk/jshell/CommandCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build ReplToolTesting TestingInputStream Compiler - * @run testng CommandCompletionTest + * @run junit CommandCompletionTest */ import java.io.IOException; @@ -46,16 +46,16 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.SkipException; -import org.testng.annotations.Test; import jdk.internal.jshell.tool.JShellTool; import jdk.internal.jshell.tool.JShellToolBuilder; import jdk.jshell.SourceCodeAnalysis.Suggestion; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; public class CommandCompletionTest extends ReplToolTesting { @@ -94,7 +94,7 @@ public class CommandCompletionTest extends ReplToolTesting { public void assertCompletion(String code, boolean isSmart, String... expected) { List completions = computeCompletions(code, isSmart); List expectedL = Arrays.asList(expected); - assertEquals(completions, expectedL, "Command: " + code + ", output: " + + assertEquals(expectedL, completions, "Command: " + code + ", output: " + completions.toString() + ", expected: " + expectedL.toString()); } @@ -356,9 +356,7 @@ public class CommandCompletionTest extends ReplToolTesting { .map(file -> file.getFileName().toString().replace(" ", "\\ ")) .orElse(null); } - if (selectedFile == null) { - throw new SkipException("No suitable file(s) found for this test in " + home); - } + Assumptions.assumeFalse(selectedFile == null, "No suitable file(s) found for this test in " + home); try (Stream content = Files.list(home)) { completions = content.filter(CLASSPATH_FILTER) .filter(file -> file.getFileName().toString().startsWith(selectedFile.replace("\\ ", " "))) diff --git a/test/langtools/jdk/jshell/CompilerOptionsTest.java b/test/langtools/jdk/jshell/CompilerOptionsTest.java index 1b4f5a8002d..e4c9332d5aa 100644 --- a/test/langtools/jdk/jshell/CompilerOptionsTest.java +++ b/test/langtools/jdk/jshell/CompilerOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,28 +26,29 @@ * @bug 8159635 * @summary Test setting compiler options * @build KullaTesting TestingInputStream - * @run testng CompilerOptionsTest + * @run junit CompilerOptionsTest */ import javax.tools.Diagnostic; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class CompilerOptionsTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.compilerOptions("-source", "8", "-Xlint:cast,-options")); } + @Test public void testLint() { assertDeclareWarn1("String s = (String)\"hello\";", new ExpectedDiagnostic("compiler.warn.redundant.cast", 11, 26, 11, -1, -1, Diagnostic.Kind.WARNING)); } + @Test public void testSourceVersion() { assertEval("import java.util.ArrayList;", added(VALID)); // Diamond with anonymous classes allowed in 9 diff --git a/test/langtools/jdk/jshell/CompletenessStressTest.java b/test/langtools/jdk/jshell/CompletenessStressTest.java index 167ba716b10..4b20ae93d46 100644 --- a/test/langtools/jdk/jshell/CompletenessStressTest.java +++ b/test/langtools/jdk/jshell/CompletenessStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -64,12 +64,12 @@ import com.sun.tools.javac.api.JavacTaskImpl; import jdk.jshell.SourceCodeAnalysis; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.Integer.max; import static java.lang.Integer.min; import static jdk.jshell.SourceCodeAnalysis.Completeness.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CompletenessStressTest extends KullaTesting { public final static String JDK_ROOT_SRC_PROP = "jdk.root.src"; @@ -99,7 +99,6 @@ public class CompletenessStressTest extends KullaTesting { }; } - @DataProvider(name = "crawler") public Object[][] dataProvider() throws IOException { File[] srcDirs = getDirectoriesToTest(); List list = new ArrayList<>(); @@ -121,7 +120,8 @@ public class CompletenessStressTest extends KullaTesting { return list.toArray(new String[list.size()][]); } - @Test(dataProvider = "crawler") + @ParameterizedTest + @MethodSource("dataProvider") public void testFile(String fileName) throws IOException { File file = getSourceFile(fileName); final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); diff --git a/test/langtools/jdk/jshell/CompletenessTest.java b/test/langtools/jdk/jshell/CompletenessTest.java index c9fc5dc08c3..1d57aef8210 100644 --- a/test/langtools/jdk/jshell/CompletenessTest.java +++ b/test/langtools/jdk/jshell/CompletenessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 8223782 8235474 8246774 8276149 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream - * @run testng CompletenessTest + * @run junit CompletenessTest */ import java.util.Map; @@ -35,13 +35,11 @@ import java.util.function.Consumer; import javax.lang.model.SourceVersion; import jdk.jshell.JShell; -import org.testng.annotations.Test; import jdk.jshell.SourceCodeAnalysis.Completeness; import static jdk.jshell.SourceCodeAnalysis.Completeness.*; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.Test; -@Test public class CompletenessTest extends KullaTesting { // Add complete units that end with semicolon to complete_with_semi (without @@ -278,30 +276,37 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void test_complete() { assertStatus(complete, COMPLETE); } + @Test public void test_expression() { assertStatus(expression, COMPLETE); } + @Test public void test_complete_with_semi() { assertStatus(complete_with_semi, COMPLETE_WITH_SEMI); } + @Test public void test_considered_incomplete() { assertStatus(considered_incomplete, CONSIDERED_INCOMPLETE); } + @Test public void test_definitely_incomplete() { assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); } + @Test public void test_unknown() { assertStatus(definitely_incomplete, DEFINITELY_INCOMPLETE); } + @Test public void testCompleted_complete_with_semi() { for (String in : complete_with_semi) { String input = in + ";"; @@ -309,6 +314,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleted_expression_with_semi() { for (String in : expression) { String input = in + ";"; @@ -316,6 +322,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleted_considered_incomplete() { for (String in : considered_incomplete) { String input = in + ";"; @@ -332,12 +339,14 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_complete() { for (String input : complete) { assertSourceByStatus(input); } } + @Test public void testCompleteSource_complete_with_semi() { for (String in : complete_with_semi) { String input = in + ";"; @@ -345,6 +354,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_expression() { for (String in : expression) { String input = in + ";"; @@ -352,6 +362,7 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testCompleteSource_considered_incomplete() { for (String in : considered_incomplete) { String input = in + ";"; @@ -359,15 +370,18 @@ public class CompletenessTest extends KullaTesting { } } + @Test public void testTrailingSlash() { assertStatus("\"abc\\", UNKNOWN, "\"abc\\"); } + @Test public void testOpenComment() { assertStatus("int xx; /* hello", DEFINITELY_INCOMPLETE, null); assertStatus("/** test", DEFINITELY_INCOMPLETE, null); } + @Test public void testTextBlocks() { assertStatus("\"\"\"", DEFINITELY_INCOMPLETE, null); assertStatus("\"\"\"broken", DEFINITELY_INCOMPLETE, null); @@ -382,6 +396,7 @@ public class CompletenessTest extends KullaTesting { assertStatus("\"\"\"\n\\", DEFINITELY_INCOMPLETE, null); } + @Test public void testMiscSource() { assertStatus("if (t) if ", DEFINITELY_INCOMPLETE, "if (t) if"); //Bug assertStatus("int m() {} dfd", COMPLETE, "int m() {}"); @@ -390,6 +405,7 @@ public class CompletenessTest extends KullaTesting { "int[] m = {1, 2}, n = new int[0];"); } + @Test public void testInstanceOf() { assertStatus("i instanceof Integer", COMPLETE, "i instanceof Integer"); assertStatus("i instanceof int", COMPLETE, "i instanceof int"); diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index cfbe874e6f2..a710f60aec4 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng/timeout=480 CompletionSuggestionTest + * @run junit/timeout=480 CompletionSuggestionTest */ import java.io.IOException; @@ -51,20 +51,21 @@ import java.util.jar.JarOutputStream; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class CompletionSuggestionTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("completion_suggestion_test"); + @Test public void testMemberExpr() { assertEval("class Test { static void test() { } }"); assertCompletion("Test.t|", "test()"); @@ -114,16 +115,19 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("\"\"\"\n\"\"\".leng|", "length()"); } + @Test public void testStartOfExpression() { assertEval("int ccTest = 0;"); assertCompletion("System.err.println(cc|", "ccTest"); assertCompletion("for (int i = cc|", "ccTest"); } + @Test public void testParameter() { assertCompletion("class C{void method(int num){num|", "num"); } + @Test public void testPrimitive() { Set primitives = new HashSet<>(Arrays.asList("boolean", "char", "byte", "short", "int", "long", "float", "double")); Set onlyVoid = new HashSet<>(Collections.singletonList("void")); @@ -157,6 +161,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("class A(Arrays.asList("Object", "Void")), @@ -169,6 +174,7 @@ public class CompletionSuggestionTest extends KullaTesting { new HashSet<>(Arrays.asList("$REPL00DOESNOTMATTER"))); } + @Test public void testSmartCompletion() { assertEval("int ccTest1 = 0;"); assertEval("int ccTest2 = 0;"); @@ -201,6 +207,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new Klass(|", true, "ccTest1", "ccTest2"); } + @Test public void testSmartCompletionInOverriddenMethodInvocation() { assertEval("int ccTest1 = 0;"); assertEval("int ccTest2 = 0;"); @@ -211,6 +218,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new Extend().method(|", true, "ccTest1", "ccTest2"); } + @Test public void testSmartCompletionForBoxedType() { assertEval("int ccTest1 = 0;"); assertEval("Integer ccTest2 = 0;"); @@ -226,6 +234,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("method3(|", true, "ccTest1", "ccTest2", "ccTest3", "method1(", "method2(", "method3("); } + @Test public void testNewClass() { assertCompletion("String str = new Strin|", "String(", "StringBuffer(", "StringBuilder(", "StringIndexOutOfBoundsException("); assertCompletion("String str = new java.lang.Strin|", "String(", "StringBuffer(", "StringBuilder(", "StringIndexOutOfBoundsException("); @@ -246,6 +255,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("new String(I.A|", "A"); } + @Test public void testFullyQualified() { assertCompletion("Optional opt = java.u|", "util."); assertCompletionIncludesExcludes("Optional opt = java.util.O|", new HashSet<>(Collections.singletonList("Optional")), Collections.emptySet()); @@ -274,15 +284,18 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("p1.p3.|", "Test"); } + @Test public void testCheckAccessibility() { assertCompletion("java.util.regex.Pattern.co|", "compile("); } + @Test public void testCompletePackages() { assertCompletion("java.u|", "util."); assertCompletionIncludesExcludes("jav|", new HashSet<>(Arrays.asList("java.", "javax.")), Collections.emptySet()); } + @Test public void testImports() { assertCompletion("import java.u|", "util."); assertCompletionIncludesExcludes("import jav|", new HashSet<>(Arrays.asList("java.", "javax.")), Collections.emptySet()); @@ -301,10 +314,12 @@ public class CompletionSuggestionTest extends KullaTesting { new HashSet<>(Arrays.asList("class"))); } + @Test public void testImportStart() { assertCompletionIncludesExcludes("import c|", Set.of("com."), Set.of()); } + @Test public void testBrokenClassFile() throws Exception { Compiler compiler = new Compiler(); Path testOutDir = Paths.get("CompletionTestBrokenClassFile"); @@ -314,6 +329,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("import inner.|"); } + @Test public void testDocumentation() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("System.getProperty(|", @@ -342,6 +358,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("field.FieldTest.R|", "field.FieldTest.R(java.lang.String s, E e)"); } + @Test public void testMethodsWithNoArguments() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("System.out.println(|", @@ -357,11 +374,13 @@ public class CompletionSuggestionTest extends KullaTesting { "void java.io.PrintStream.println(Object)"); } + @Test public void testErroneous() { assertCompletion("Undefined.|"); assertSignature("does.not.exist|"); } + @Test public void testClinit() { assertEval("enum E{;}"); assertEval("class C{static{}}"); @@ -369,6 +388,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletionIncludesExcludes("C.|", Collections.emptySet(), new HashSet<>(Collections.singletonList(""))); } + @Test public void testMethodHeaderContext() { assertCompletion("private void f(Runn|", "Runnable"); assertCompletion("void f(Runn|", "Runnable"); @@ -380,6 +400,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("void f(Object o1) throws HogeHoge.|", true, "HogeHogeException"); } + @Test public void testTypeVariables() { assertCompletion("class A { public void test() { TY|", "TYPE"); assertCompletion("class A { public static void test() { TY|"); @@ -387,6 +408,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("class A { public static void test() { TY|", "TYPE"); } + @Test public void testGeneric() { assertEval("import java.util.concurrent.*;"); assertCompletion("java.util.Listf(T... ts)", "void f(A a)"); } + @Test public void testClass() { assertSignature("String|", "java.lang.String"); } + @Test public void testDocumentationOfUserDefinedConstructors() { Snippet a = classKey(assertEval("class A {}")); assertSignature("new A(|", "A()"); @@ -522,6 +550,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new A(|", "A(T a)", "A(int i)", " A(T t, U u)"); } + @Test public void testDocumentationOfOverriddenMethods() throws Exception { dontReadParameterNamesFromClassFile(); assertSignature("\"\".wait(|", @@ -537,6 +566,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new Extend().method(|", "void Extend.method()"); } + @Test public void testDocumentationOfInvisibleMethods() { assertSignature("Object.wait(|"); assertSignature("\"\".indexOfSupplementary(|"); @@ -548,12 +578,14 @@ public class CompletionSuggestionTest extends KullaTesting { assertSignature("new A().method(|"); } + @Test public void testDocumentationOfInvisibleConstructors() { assertSignature("new Compiler(|"); assertEval("class A { private A() {} }"); assertSignature("new A(|"); } + @Test public void testDocumentationWithBoxing() { assertEval("int primitive = 0;"); assertEval("Integer boxed = 0;"); @@ -570,6 +602,7 @@ public class CompletionSuggestionTest extends KullaTesting { "void method(Object n, int o)"); } + @Test public void testDocumentationWithGenerics() { class TestDocumentationWithGenerics { private final Function codeFacotry; @@ -624,6 +657,7 @@ public class CompletionSuggestionTest extends KullaTesting { }); } + @Test public void testVarArgs() { assertEval("int i = 0;"); assertEval("class Foo1 { static void m(int... i) { } } "); @@ -649,6 +683,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Foo4.m(ia, |", true, "str"); } + @Test public void testConstructorAsMemberOf() { assertEval("class Baz { Baz(X x) { } } "); assertEval("String str = null;"); @@ -660,6 +695,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Foo.m(new Baz<>(|", true, "str"); } + @Test public void testIntersection() { assertEval(" Z get() { return null; }"); assertEval("var v = get();"); @@ -669,6 +705,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Number r = |", true); } + @Test public void testAnonymous() { assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };"); assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of()); @@ -676,10 +713,12 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("CharSequence r = |", true); } + @Test public void testCompletionInAnonymous() { assertCompletionIncludesExcludes("new Undefined() { int i = \"\".l|", Set.of("length()"), Set.of()); } + @Test public void testMemberReferences() { assertEval("class C {" + " public static String stat() { return null; }" + @@ -703,6 +742,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("FI2 fi = C::|", true, "statConvert1", "statConvert3"); } + @Test public void testBrokenLambdaCompletion() { assertEval("interface Consumer { public void consume(T t); }"); assertEval("interface Function { public R convert(T t); }"); @@ -724,7 +764,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("String s = m8(x -> {x.tri|", "trim()"); } - @BeforeMethod + @BeforeEach public void setUp() { setUp(builder -> builder.executionEngine("local")); @@ -756,7 +796,8 @@ public class CompletionSuggestionTest extends KullaTesting { keepParameterNames.set(getAnalysis(), new String[0]); } - @Test(enabled = false) //TODO 8171829 + @Test //TODO 8171829 + @Disabled public void testBrokenClassFile2() throws IOException { Path broken = outDir.resolve("broken"); compiler.compile(broken, @@ -779,6 +820,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("Broke|", "BrokenA", "BrokenC"); } + @Test public void testStatements() { assertEval("String s = \"\";"); assertCompletion("if (s.conta|", (Boolean) null, "contains("); @@ -791,17 +833,20 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("for (var v : s.conta|", (Boolean) null, "contains("); } + @Test public void testRecord() { assertCompletion("record R() implements Ru|", true, "Runnable"); } //JDK-8296789 + @Test public void testParentMembers() { assertEval("var sb=new StringBuilder();"); assertCompletionIncludesExcludes("sb.|", true, Set.of("capacity()", "setLength("), Set.of("maybeLatin1")); } //JDK-8314662 + @Test public void testDuplicateImport() { MethodSnippet m1 = methodKey(assertEval("void test(String s) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); MethodSnippet m2 = methodKey(assertEval("void test(Integer i) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); @@ -813,6 +858,7 @@ public class CompletionSuggestionTest extends KullaTesting { //JDK-8326333: verify completion returns sensible output for arrays: //JDK-8326333: jshell completion on arrays is incomplete + @Test public void testArray() { assertEval("String[] strs = null;"); assertCompletion("strs.to|", "toString()"); @@ -826,6 +872,7 @@ public class CompletionSuggestionTest extends KullaTesting { } //JDK-8353581: completion for module imports: + @Test public void testModuleImport() { assertCompletionIncludesExcludes("import |", Set.of("module "), Set.of()); assertCompletionIncludesExcludes("import module |", Set.of("java.base"), Set.of("java.", "module")); @@ -835,6 +882,7 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("import module java/*c*/./*c*/ba|", "java.base"); } + @Test public void testCustomClassPathIndexing() { Path p1 = outDir.resolve("dir1"); compiler.compile(p1, diff --git a/test/langtools/jdk/jshell/ComputeFQNsTest.java b/test/langtools/jdk/jshell/ComputeFQNsTest.java index 68bb530f311..8e7f5a1d889 100644 --- a/test/langtools/jdk/jshell/ComputeFQNsTest.java +++ b/test/langtools/jdk/jshell/ComputeFQNsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ComputeFQNsTest + * @run junit ComputeFQNsTest */ import java.io.Writer; @@ -41,15 +41,16 @@ import java.nio.file.Paths; import java.util.Arrays; import jdk.jshell.SourceCodeAnalysis.QualifiedNames; -import static org.testng.Assert.*; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ComputeFQNsTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("ComputeFQNsTest"); + @Test public void testAddImport() throws Exception { compiler.compile(outDir, "package test1; public class FQNTestClass { }", "package test2; public class FQNTestClass { }"); String jarName = "test.jar"; @@ -77,7 +78,8 @@ public class ComputeFQNsTest extends KullaTesting { assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList"); } - @Test(enabled = false) //TODO 8161165 + @Test //TODO 8161165 + @Disabled public void testSuspendIndexing() throws Throwable { compiler.compile(outDir, "package test; public class FQNTest { }"); String jarName = "test.jar"; @@ -127,8 +129,8 @@ public class ComputeFQNsTest extends KullaTesting { QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList(), "Input: " + code + ", candidates=" + candidates.getNames()); - assertEquals(candidates.isUpToDate(), false, "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); + assertEquals(Arrays.asList(), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(false, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); Files.delete(continueMarkFile); @@ -136,7 +138,7 @@ public class ComputeFQNsTest extends KullaTesting { candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList("test.FQNTest"), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(Arrays.asList("test.FQNTest"), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); assertEquals(true, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate()); } diff --git a/test/langtools/jdk/jshell/ConsoleTest.java b/test/langtools/jdk/jshell/ConsoleTest.java index a82e0753b56..a5eead1abe0 100644 --- a/test/langtools/jdk/jshell/ConsoleTest.java +++ b/test/langtools/jdk/jshell/ConsoleTest.java @@ -26,7 +26,7 @@ * @bug 8298425 8344706 * @summary Verify behavior of System.console() * @build KullaTesting TestingInputStream - * @run testng ConsoleTest + * @run junit ConsoleTest */ import java.io.IOError; @@ -45,8 +45,8 @@ import jdk.jshell.JShell; import jdk.jshell.JShellConsole; import jdk.jshell.Snippet.Status; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ConsoleTest extends KullaTesting { @@ -62,7 +62,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public String readLine(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB"; } }; @@ -70,7 +70,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public char[] readPassword(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB".toCharArray(); } }; @@ -118,7 +118,7 @@ public class ConsoleTest extends KullaTesting { console = new ThrowingJShellConsole() { @Override public String readLine(String prompt) throws IOError { - assertEquals(prompt, "expected"); + assertEquals("expected", prompt); return "AB"; } }; @@ -146,7 +146,7 @@ public class ConsoleTest extends KullaTesting { int count = 1_000; assertEval("for (int i = 0; i < " + count + "; i++) System.console().writer().write(\"A\");"); String expected = "A".repeat(count); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test @@ -171,7 +171,7 @@ public class ConsoleTest extends KullaTesting { String testStr = "\u30A2"; // Japanese katakana (A2 >= 80) (JDK-8354910) assertEval("System.console().writer().write(\"" + testStr + "\".repeat(" + count + "))"); String expected = testStr.repeat(count); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test @@ -207,7 +207,7 @@ public class ConsoleTest extends KullaTesting { """.replace("${repeats}", "" + repeats) .replace("${output}", "" + output)); String expected = "A".repeat(repeats * output); - assertEquals(sb.toString(), expected); + assertEquals(expected, sb.toString()); } @Test diff --git a/test/langtools/jdk/jshell/ConsoleToolTest.java b/test/langtools/jdk/jshell/ConsoleToolTest.java index a1d9a612ae5..eccd58c878d 100644 --- a/test/langtools/jdk/jshell/ConsoleToolTest.java +++ b/test/langtools/jdk/jshell/ConsoleToolTest.java @@ -28,11 +28,11 @@ * @modules jdk.internal.le/jdk.internal.org.jline.reader * jdk.jshell/jdk.internal.jshell.tool:+open * @build ConsoleToolTest ReplToolTesting - * @run testng ConsoleToolTest + * @run junit ConsoleToolTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ConsoleToolTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/CustomInputToolBuilder.java b/test/langtools/jdk/jshell/CustomInputToolBuilder.java index 523981b3d91..f6fdf97ae1e 100644 --- a/test/langtools/jdk/jshell/CustomInputToolBuilder.java +++ b/test/langtools/jdk/jshell/CustomInputToolBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary Verify JavaShellToolBuilder uses provided inputs * @modules jdk.jshell * @build KullaTesting TestingInputStream - * @run testng CustomInputToolBuilder + * @run junit CustomInputToolBuilder */ import java.io.ByteArrayInputStream; @@ -38,15 +38,14 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import jdk.jshell.tool.JavaShellToolBuilder; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertTrue; - -@Test public class CustomInputToolBuilder extends KullaTesting { private static final String TEST_JDK = "test.jdk"; + @Test public void checkCustomInput() throws Exception { String testJdk = System.getProperty(TEST_JDK); try { @@ -102,6 +101,7 @@ public class CustomInputToolBuilder extends KullaTesting { } } + @Test public void checkInteractiveTerminal() throws Exception { String testJdk = System.getProperty(TEST_JDK); try { diff --git a/test/langtools/jdk/jshell/DropTest.java b/test/langtools/jdk/jshell/DropTest.java index e277d1cbeea..1501d391a4d 100644 --- a/test/langtools/jdk/jshell/DropTest.java +++ b/test/langtools/jdk/jshell/DropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,20 +26,20 @@ * @bug 8081431 8080069 8167128 8199623 * @summary Test of JShell#drop(). * @build KullaTesting TestingInputStream - * @run testng DropTest + * @run junit DropTest */ import jdk.jshell.DeclarationSnippet; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; +import org.junit.jupiter.api.Test; -@Test public class DropTest extends KullaTesting { + @Test public void testDrop() { Snippet var = varKey(assertEval("int x;")); Snippet method = methodKey(assertEval("int mu() { return x * 4; }")); @@ -88,6 +88,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropImport() { Snippet imp = importKey(assertEval("import java.util.*;")); Snippet decl = varKey( @@ -101,11 +102,13 @@ public class DropTest extends KullaTesting { assertDeclareFail("list;", "compiler.err.cant.resolve.location"); } + @Test public void testDropStatement() { Snippet x = key(assertEval("if (true);")); assertDrop(x, ste(x, VALID, DROPPED, true, null)); } + @Test public void testDropVarToMethod() { Snippet x = varKey(assertEval("int x;")); DeclarationSnippet method = methodKey(assertEval("double mu() { return x * 4; }")); @@ -123,6 +126,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropMethodToMethod() { Snippet a = methodKey(assertEval("double a() { return 2; }")); DeclarationSnippet b = methodKey(assertEval("double b() { return a() * 10; }")); @@ -139,6 +143,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropClassToMethod() { Snippet c = classKey(assertEval("class C { int f() { return 7; } }")); DeclarationSnippet m = methodKey(assertEval("int m() { return new C().f(); }")); @@ -150,6 +155,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropVarToClass() { Snippet x = varKey(assertEval("int x;")); DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x; }")); @@ -165,6 +171,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropMethodToClass() { Snippet x = methodKey(assertEval("int x() { return 0; }")); DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x(); }")); @@ -179,6 +186,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropClassToClass() { Snippet a = classKey(assertEval("class A {}")); Snippet b = classKey(assertEval("class B extends A {}")); @@ -204,6 +212,7 @@ public class DropTest extends KullaTesting { assertActiveKeys(); } + @Test public void testDropNoUpdate() { String as1 = "class A {}"; String as2 = "class A extends java.util.ArrayList {}"; @@ -228,6 +237,7 @@ public class DropTest extends KullaTesting { } // 8199623 + @Test public void testTwoForkedDrop() { MethodSnippet p = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }")); MethodSnippet n = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new RuntimeException(\"bar\", ex); }}")); diff --git a/test/langtools/jdk/jshell/EditorTestBase.java b/test/langtools/jdk/jshell/EditorTestBase.java index 422d07ba1c8..a384c09fcb1 100644 --- a/test/langtools/jdk/jshell/EditorTestBase.java +++ b/test/langtools/jdk/jshell/EditorTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,10 +25,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; public abstract class EditorTestBase extends ReplToolTesting { @@ -61,11 +61,11 @@ public abstract class EditorTestBase extends ReplToolTesting { } void assertEditInput(boolean after, String cmd, String input, Action action) { - assertEditInput(after, cmd, s -> assertEquals(s, input, "Input"), action); + assertEditInput(after, cmd, s -> assertEquals(input, s, "Input"), action); } void assertEditOutput(boolean after, String cmd, String output, Action action) { - assertEditOutput(after, cmd, s -> assertEquals(s.trim(), output.trim(), "command"), action); + assertEditOutput(after, cmd, s -> assertEquals(output.trim(), s.trim(), "command"), action); } @Test @@ -219,16 +219,15 @@ public abstract class EditorTestBase extends ReplToolTesting { @Test public void testNoArguments() { - testEditor( - a -> assertVariable(a, "int", "a"), + testEditor(a -> assertVariable(a, "int", "a"), a -> assertMethod(a, "void f() {}", "()void", "f"), a -> assertClass(a, "class A {}", "class", "A"), a -> assertEditInput(a, "/ed", s -> { String[] ss = s.split("\n"); - assertEquals(ss.length, 3, "Expected 3 lines: " + s); - assertEquals(ss[0], "int a;"); - assertEquals(ss[1], "void f() {}"); - assertEquals(ss[2], "class A {}"); + assertEquals(3, ss.length, "Expected 3 lines: " + s); + assertEquals("int a;", ss[0]); + assertEquals("void f() {}", ss[1]); + assertEquals("class A {}", ss[2]); }, this::exit) ); } @@ -263,7 +262,8 @@ public abstract class EditorTestBase extends ReplToolTesting { ); } - @Test(enabled = false) // TODO JDK-8191875 + @Test // TODO JDK-8191875 + @Disabled public void testStatementMush() { testEditor( a -> assertCommand(a, "System.out.println(\"Hello\")", diff --git a/test/langtools/jdk/jshell/EmptyTest.java b/test/langtools/jdk/jshell/EmptyTest.java index 6e838432220..937ab04cb2d 100644 --- a/test/langtools/jdk/jshell/EmptyTest.java +++ b/test/langtools/jdk/jshell/EmptyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -25,34 +25,39 @@ * @test * @summary null test * @build KullaTesting TestingInputStream - * @run testng EmptyTest + * @run junit EmptyTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class EmptyTest extends KullaTesting { + @Test public void testEmpty() { assertEvalEmpty(""); } + @Test public void testSpace() { assertEvalEmpty(" "); } + @Test public void testSemicolon() { assertEval(";", ""); } + @Test public void testSlashStarComment() { assertEvalEmpty("/*test*/"); } + @Test public void testSlashStarCommentSemicolon() { assertEval("/*test*/;", ""); } + @Test public void testSlashComment() { assertEvalEmpty("// test"); } diff --git a/test/langtools/jdk/jshell/ErrorRecoveryTest.java b/test/langtools/jdk/jshell/ErrorRecoveryTest.java index 22d6a495f41..deaa71cb739 100644 --- a/test/langtools/jdk/jshell/ErrorRecoveryTest.java +++ b/test/langtools/jdk/jshell/ErrorRecoveryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -31,17 +31,17 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream ExpectedDiagnostic toolbox.ToolBox Compiler - * @run testng ErrorRecoveryTest + * @run junit ErrorRecoveryTest */ -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; import static jdk.jshell.Snippet.Status.REJECTED; +import org.junit.jupiter.api.Test; -@Test public class ErrorRecoveryTest extends KullaTesting { + @Test public void testExceptionErrors() { assertEval("import java.lang.annotation.Repeatable;"); assertEval(""" @@ -51,6 +51,7 @@ public class ErrorRecoveryTest extends KullaTesting { ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null)); } + @Test public void testBrokenName() { assertEval("int strictfp = 0;", DiagCheck.DIAG_ERROR, @@ -58,6 +59,7 @@ public class ErrorRecoveryTest extends KullaTesting { ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null)); } + @Test public void testBooleanPatternExpression() { assertEval("Number n = 0;"); assertEval("if (!n instanceof Integer i) {}", @@ -67,6 +69,7 @@ public class ErrorRecoveryTest extends KullaTesting { } //JDK-8332230: + @Test public void testAnnotationsd() { assertEval("k=aa:a.@a", DiagCheck.DIAG_ERROR, diff --git a/test/langtools/jdk/jshell/ErrorTranslationTest.java b/test/langtools/jdk/jshell/ErrorTranslationTest.java index 4db2ff65469..1aa1b2c41dd 100644 --- a/test/langtools/jdk/jshell/ErrorTranslationTest.java +++ b/test/langtools/jdk/jshell/ErrorTranslationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream ExpectedDiagnostic toolbox.ToolBox Compiler - * @run testng ErrorTranslationTest + * @run junit ErrorTranslationTest */ import java.nio.file.Path; @@ -41,15 +41,15 @@ import java.util.function.Consumer; import javax.tools.Diagnostic; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -@Test public class ErrorTranslationTest extends ReplToolTesting { - @Test(enabled = false) // TODO 8080353 + @Test // TODO 8080353 + @Disabled public void testErrors() { test( a -> assertDiagnostic(a, "abstract void f();", newExpectedDiagnostic(0, 8, 0, -1, -1, Diagnostic.Kind.ERROR)), @@ -60,6 +60,7 @@ public class ErrorTranslationTest extends ReplToolTesting { ); } + @Test public void testlvtiErrors() { test( a -> assertDiagnostic(a, "var broken = () -> {};", newExpectedDiagnostic(0, 22, 0, -1, -1, Diagnostic.Kind.ERROR)), @@ -67,13 +68,15 @@ public class ErrorTranslationTest extends ReplToolTesting { ); } + @Test public void testExceptionErrors() { test( a -> assertDiagnostic(a, "try { } catch (IllegalStateException | java.io.IOException ex) { }", newExpectedDiagnostic(39, 58, -1, -1, -1, Diagnostic.Kind.ERROR)) ); } - @Test(enabled = false) // TODO 8132147 + @Test // TODO 8132147 + @Disabled public void stressTest() { Compiler compiler = new Compiler(); Path oome = compiler.getPath("OOME.repl"); @@ -115,11 +118,11 @@ public class ErrorTranslationTest extends ReplToolTesting { throw new AssertionError("Not enough lines: " + s); } String kind = getKind(expectedDiagnostic.getKind()); - assertEquals(lines[0], kind); + assertEquals(kind, lines[0]); boolean found = false; for (int i = 0; i < lines.length; i++) { if (lines[i].endsWith(expectedSource)) { - assertEquals(lines[i + 1], expectedMarkingLine, "Input: " + expectedSource + ", marking line: "); + assertEquals(expectedMarkingLine, lines[i + 1], "Input: " + expectedSource + ", marking line: "); found = true; } } @@ -146,6 +149,7 @@ public class ErrorTranslationTest extends ReplToolTesting { return sb.toString(); } + @Test public String getKind(Diagnostic.Kind kind) { switch (kind) { case WARNING: diff --git a/test/langtools/jdk/jshell/ExceptionMessageTest.java b/test/langtools/jdk/jshell/ExceptionMessageTest.java index 39cca56c612..c329afeb35e 100644 --- a/test/langtools/jdk/jshell/ExceptionMessageTest.java +++ b/test/langtools/jdk/jshell/ExceptionMessageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 8185108 * @summary Test exception().getMessage() in events returned by eval() - * @run testng ExceptionMessageTest + * @run junit ExceptionMessageTest * @key intermittent */ @@ -42,22 +42,23 @@ import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControlProvider; import jdk.jshell.spi.ExecutionEnv; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ExceptionMessageTest { + @Test public void testDefaultEC() { doTestCases(new JdiExecutionControlProvider(), "default"); } + @Test public void testLocalEC() { doTestCases(new LocalExecutionControlProvider(), "local"); } + @Test public void testDirectEC() { doTestCases(new ExecutionControlProvider() { public ExecutionControl generate(ExecutionEnv env, Map param) throws Throwable { @@ -85,11 +86,11 @@ public class ExceptionMessageTest { private void doTest(JShell jshell, String label, String code, String expected) { List result = jshell.eval(code); - assertEquals(result.size(), 1, "Expected only one event"); + assertEquals(1, result.size(), "Expected only one event"); SnippetEvent evt = result.get(0); Exception exc = evt.exception(); String out = exc.getMessage(); - assertEquals(out, expected, "Exception message not as expected: " + + assertEquals(expected, out, "Exception message not as expected: " + label + " -- " + code); } } diff --git a/test/langtools/jdk/jshell/ExceptionsTest.java b/test/langtools/jdk/jshell/ExceptionsTest.java index 765c3696f07..f7273b2a6fc 100644 --- a/test/langtools/jdk/jshell/ExceptionsTest.java +++ b/test/langtools/jdk/jshell/ExceptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng ExceptionsTest + * @run junit ExceptionsTest */ import java.io.IOException; @@ -46,16 +46,16 @@ import jdk.jshell.UnresolvedReferenceException; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.*; - -@Test public class ExceptionsTest extends KullaTesting { private final Compiler compiler = new Compiler(); private final Path outDir = Paths.get("test_class_path"); + @Test public void throwUncheckedException() { String message = "error_message"; SnippetEvent cr = assertEvalException("throw new RuntimeException(\"" + message + "\");"); @@ -64,6 +64,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr.snippet(), 1))); } + @Test public void throwCheckedException() { String message = "error_message"; SnippetEvent cr = assertEvalException("throw new Exception(\"" + message + "\");"); @@ -72,6 +73,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr.snippet(), 1))); } + @Test public void throwFromStaticMethodOfClass() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -84,6 +86,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromStaticMethodOfInterface() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -96,6 +99,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwChained() { String message1 = "error_message1"; String message2 = "error_message2"; @@ -122,6 +126,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr4.snippet(), 1))); } + @Test public void throwChainedUnresolved() { String message1 = "error_message1"; String message2 = "error_message2"; @@ -144,6 +149,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr4.snippet(), 1))); } + @Test public void throwFromConstructor() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -156,6 +162,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromDefaultMethodOfInterface() { String message = "error_message"; Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); @@ -168,6 +175,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr3.snippet(), 1))); } + @Test public void throwFromLambda() { String message = "lambda"; Snippet s1 = varKey(assertEval( @@ -182,6 +190,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr2.snippet(), 1))); } + @Test public void throwFromAnonymousClass() { String message = "anonymous"; Snippet s1 = varKey(assertEval( @@ -198,6 +207,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", cr2.snippet(), 1))); } + @Test public void throwFromLocalClass() { String message = "local"; Snippet s1 = methodKey(assertEval( @@ -219,6 +229,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8210527 + @Test public void throwFromWithoutSource() { String message = "show this"; SnippetEvent se = assertEvalException("java.lang.reflect.Proxy.newProxyInstance(" + @@ -232,6 +243,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8210527 + @Test public void throwFromNoSource() { Path path = outDir.resolve("fail"); compiler.compile(path, @@ -250,6 +262,7 @@ public class ExceptionsTest extends KullaTesting { } // test 8212167 + @Test public void throwLineFormat1() { SnippetEvent se = assertEvalException( "if (true) { \n" + @@ -261,6 +274,7 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", se.snippet(), 3))); } + @Test public void throwLineFormat3() { Snippet sp = methodKey(assertEval( "int p() \n" + @@ -292,13 +306,15 @@ public class ExceptionsTest extends KullaTesting { newStackTraceElement("", "", se.snippet(), 1))); } - @Test(enabled = false) // TODO 8129427 + @Test // TODO 8129427 + @Disabled public void outOfMemory() { assertEval("import java.util.*;"); assertEval("List list = new ArrayList<>();"); assertExecuteException("while (true) { list.add(new byte[10000]); }", OutOfMemoryError.class); } + @Test public void stackOverflow() { assertEval("void f() { f(); }"); assertExecuteException("f();", StackOverflowError.class); @@ -361,11 +377,11 @@ public class ExceptionsTest extends KullaTesting { EvalException ex = (EvalException) exception; String actualException = ex.getExceptionClassName(); String expectedException = exceptionInfo.exception.getCanonicalName(); - assertEquals(actualException, expectedException, + assertEquals(expectedException, actualException, String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s", source, expectedException, actualException, getStackTrace(ex))); if (exceptionInfo.message != null) { - assertEquals(ex.getMessage(), exceptionInfo.message, + assertEquals(exceptionInfo.message, ex.getMessage(), String.format("Given \"%s\" expected message: %s, got: %s", source, exceptionInfo.message, ex.getMessage())); } @@ -395,7 +411,7 @@ public class ExceptionsTest extends KullaTesting { "Expected UnresolvedReferenceException: " + exception); UnresolvedExceptionInfo uei = (UnresolvedExceptionInfo) exceptionInfo; UnresolvedReferenceException ure = (UnresolvedReferenceException) exception; - assertEquals(ure.getSnippet(), uei.sn); + assertEquals(uei.sn, ure.getSnippet()); assertStackMatch(ure, "", exceptionInfo); } } @@ -405,20 +421,20 @@ public class ExceptionsTest extends KullaTesting { if (actual == null || expected == null) { fail(message); } else { - assertEquals(actual.length, expected.length, message + " : arrays do not have the same size"); + assertEquals(expected.length, actual.length, message + " : arrays do not have the same size"); for (int i = 0; i < actual.length; ++i) { StackTraceElement actualElement = actual[i]; StackTraceElement expectedElement = expected[i]; - assertEquals(actualElement.getClassName(), expectedElement.getClassName(), message + " : class names [" + i + "]"); + assertEquals(expectedElement.getClassName(), actualElement.getClassName(), message + " : class names [" + i + "]"); String expectedMethodName = expectedElement.getMethodName(); if (expectedMethodName.startsWith("lambda$")) { assertTrue(actualElement.getMethodName().startsWith("lambda$"), message + " : method names"); } else { - assertEquals(actualElement.getMethodName(), expectedElement.getMethodName(), message + " : method names [" + i + "]"); + assertEquals(expectedElement.getMethodName(), actualElement.getMethodName(), message + " : method names [" + i + "]"); } - assertEquals(actualElement.getFileName(), expectedElement.getFileName(), message + " : file names [" + i + "]"); + assertEquals(expectedElement.getFileName(), actualElement.getFileName(), message + " : file names [" + i + "]"); if (expectedElement.getLineNumber() >= 0) { - assertEquals(actualElement.getLineNumber(), expectedElement.getLineNumber(), message + " : line numbers [" + i + "]" + assertEquals(expectedElement.getLineNumber(), actualElement.getLineNumber(), message + " : line numbers [" + i + "]" + " -- actual: " + actualElement.getLineNumber() + ", expected: " + expectedElement.getLineNumber() + " -- in: " + actualElement.getClassName()); } diff --git a/test/langtools/jdk/jshell/ExecutionControlSpecTest.java b/test/langtools/jdk/jshell/ExecutionControlSpecTest.java index 920310bb1e5..14661030cf0 100644 --- a/test/langtools/jdk/jshell/ExecutionControlSpecTest.java +++ b/test/langtools/jdk/jshell/ExecutionControlSpecTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -34,20 +34,20 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting Compiler - * @run testng ExecutionControlSpecTest + * @run junit ExecutionControlSpecTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class ExecutionControlSpecTest extends KullaTesting { ClassLoader ccl; - @BeforeMethod + @BeforeEach @Override public void setUp() { String mod = "my.ec"; @@ -86,7 +86,7 @@ public class ExecutionControlSpecTest extends KullaTesting { setUp(builder -> builder.executionEngine("prefixing")); } - @AfterMethod + @AfterEach @Override public void tearDown() { super.tearDown(); diff --git a/test/langtools/jdk/jshell/ExecutionControlTestBase.java b/test/langtools/jdk/jshell/ExecutionControlTestBase.java index 20336c902cf..a63e1b16569 100644 --- a/test/langtools/jdk/jshell/ExecutionControlTestBase.java +++ b/test/langtools/jdk/jshell/ExecutionControlTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -23,11 +23,11 @@ import javax.tools.Diagnostic; -import org.testng.annotations.Test; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; public class ExecutionControlTestBase extends KullaTesting { diff --git a/test/langtools/jdk/jshell/ExpectedDiagnostic.java b/test/langtools/jdk/jshell/ExpectedDiagnostic.java index 2416c9875b8..1fe96200e3c 100644 --- a/test/langtools/jdk/jshell/ExpectedDiagnostic.java +++ b/test/langtools/jdk/jshell/ExpectedDiagnostic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ import javax.tools.Diagnostic; import jdk.jshell.Diag; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ExpectedDiagnostic { @@ -79,16 +79,16 @@ public class ExpectedDiagnostic { public void assertDiagnostic(Diag diagnostic) { String code = diagnostic.getCode(); - assertEquals(code, this.code, "Expected error: " + this.code + ", got: " + code); - assertEquals(diagnostic.isError(), kind == Diagnostic.Kind.ERROR); + assertEquals(this.code, code, "Expected error: " + this.code + ", got: " + code); + assertEquals(kind == Diagnostic.Kind.ERROR, diagnostic.isError()); if (startPosition != -1) { - assertEquals(diagnostic.getStartPosition(), startPosition, "Start position"); + assertEquals(startPosition, diagnostic.getStartPosition(), "Start position"); } if (endPosition != -1) { - assertEquals(diagnostic.getEndPosition(), endPosition, "End position"); + assertEquals(endPosition, diagnostic.getEndPosition(), "End position"); } if (position != -1) { - assertEquals(diagnostic.getPosition(), position, "Position"); + assertEquals(position, diagnostic.getPosition(), "Position"); } } } diff --git a/test/langtools/jdk/jshell/ExternalEditorTest.java b/test/langtools/jdk/jshell/ExternalEditorTest.java index 607637e207c..cf1ae4f1ae2 100644 --- a/test/langtools/jdk/jshell/ExternalEditorTest.java +++ b/test/langtools/jdk/jshell/ExternalEditorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @bug 8143955 8080843 8163816 8143006 8169828 8171130 8162989 8210808 * @modules jdk.jshell/jdk.internal.jshell.tool * @build ReplToolTesting CustomEditor EditorTestBase - * @run testng ExternalEditorTest + * @run junit ExternalEditorTest * @key intermittent */ @@ -47,15 +47,17 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ExternalEditorTest extends EditorTestBase { private static Path executionScript; @@ -133,21 +135,19 @@ public class ExternalEditorTest extends EditorTestBase { @Test public void testStatementSemicolonAddition() { - testEditor( - a -> assertCommand(a, "if (true) {}", ""), + testEditor(a -> assertCommand(a, "if (true) {}", ""), a -> assertCommand(a, "if (true) {} else {}", ""), a -> assertCommand(a, "Object o", "o ==> null"), a -> assertCommand(a, "if (true) o = new Object() { int x; }", ""), a -> assertCommand(a, "if (true) o = new Object() { int y; }", ""), a -> assertCommand(a, "System.err.flush()", ""), // test still ; for expression statement a -> assertEditOutput(a, "/ed", "", () -> { - assertEquals(getSource(), - "if (true) {}\n" + + assertEquals( "if (true) {}\n" + "if (true) {} else {}\n" + "Object o;\n" + "if (true) o = new Object() { int x; };\n" + "if (true) o = new Object() { int y; };\n" + - "System.err.flush();\n"); + "System.err.flush();\n", getSource()); exit(); }) ); @@ -173,7 +173,7 @@ public class ExternalEditorTest extends EditorTestBase { return System.getProperty("os.name").startsWith("Windows"); } - @BeforeClass + @BeforeAll public static void setUpExternalEditorTest() throws IOException { listener = new ServerSocket(0); listener.setSoTimeout(30000); @@ -250,7 +250,8 @@ public class ExternalEditorTest extends EditorTestBase { ); } - @Test(enabled = false) // TODO 8159229 + @Test // TODO 8159229 + @Disabled public void testRemoveTempFile() { test(new String[]{"--no-startup"}, a -> assertCommandCheckOutput(a, "/set editor " + executionScript, @@ -264,7 +265,7 @@ public class ExternalEditorTest extends EditorTestBase { ); } - @AfterClass + @AfterAll public static void shutdown() throws IOException { executorShutdown(); if (listener != null) { diff --git a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java index 99457ea2ce6..c43ec747ffa 100644 --- a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting ExecutionControlTestBase Compiler - * @run testng FailOverDirectExecutionControlTest + * @run junit FailOverDirectExecutionControlTest * @key intermittent */ @@ -48,16 +48,15 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.execution.FailOverExecutionControlProvider; import jdk.jshell.spi.ExecutionControlProvider; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase { ClassLoader ccl; @@ -93,7 +92,7 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase } - @BeforeMethod + @BeforeEach @Override public void setUp() { logger = Logger.getLogger("jdk.jshell.execution"); @@ -134,7 +133,7 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase setUp(builder -> builder.executionEngine(provider, pm)); } - @AfterMethod + @AfterEach @Override public void tearDown() { super.tearDown(); @@ -144,11 +143,12 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase } @Override + @Test public void variables() { super.variables(); - assertEquals(logged.get(Level.FINEST).size(), 1); - assertEquals(logged.get(Level.FINE).size(), 2); - assertEquals(logged.get(Level.WARNING).size(), 2); + assertEquals(1, logged.get(Level.FINEST).size()); + assertEquals(2, logged.get(Level.FINE).size()); + assertEquals(2, logged.get(Level.WARNING).size()); assertNull(logged.get(Level.SEVERE)); String log = logged.get(Level.WARNING).get(0); assertTrue(log.contains("Failure failover -- 0 = alwaysFailing"), log); diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java index 31011960880..2e53b11b95a 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -28,17 +28,15 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase DyingRemoteAgent - * @run testng FailOverExecutionControlDyingLaunchTest + * @run junit FailOverExecutionControlDyingLaunchTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine( diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java index 9958b7a3284..0de985b7a28 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -28,16 +28,14 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlHangingLaunchTest + * @run junit FailOverExecutionControlHangingLaunchTest */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine( diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java index 4f29bfe9c7a..6d61bcb0322 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -28,18 +28,16 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlHangingListenTest + * @run junit FailOverExecutionControlHangingListenTest * @key intermittent */ import java.net.InetAddress; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlHangingListenTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { String loopback = InetAddress.getLoopbackAddress().getHostAddress(); diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java index 80dc56d72c4..579029af4c0 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -28,16 +28,14 @@ * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi * @build KullaTesting ExecutionControlTestBase - * @run testng FailOverExecutionControlTest + * @run junit FailOverExecutionControlTest */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class FailOverExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("failover:0(expectedFailureNonExistent1), 1(expectedFailureNonExistent2), " diff --git a/test/langtools/jdk/jshell/FileManagerTest.java b/test/langtools/jdk/jshell/FileManagerTest.java index 9e4f063da9d..c8c6a7dded7 100644 --- a/test/langtools/jdk/jshell/FileManagerTest.java +++ b/test/langtools/jdk/jshell/FileManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8173845 * @summary test custom file managers * @build KullaTesting TestingInputStream - * @run testng FileManagerTest + * @run junit FileManagerTest */ @@ -37,12 +37,10 @@ import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.StandardJavaFileManager; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertTrue; - -@Test public class FileManagerTest extends KullaTesting { boolean encountered; @@ -100,12 +98,13 @@ public class FileManagerTest extends KullaTesting { } - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.fileManager(fm -> new MyFileManager(fm))); } + @Test public void testSnippetMemberAssignment() { assertEval("java.lang.reflect.Array.get(new String[1], 0) == null"); assertTrue(encountered, "java.lang.reflect not encountered"); diff --git a/test/langtools/jdk/jshell/ForwardReferenceImportTest.java b/test/langtools/jdk/jshell/ForwardReferenceImportTest.java index 4e66eaa2196..4459a424092 100644 --- a/test/langtools/jdk/jshell/ForwardReferenceImportTest.java +++ b/test/langtools/jdk/jshell/ForwardReferenceImportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -25,18 +25,18 @@ * @test 8173232 * @summary Test of forward referencing of snippets (related to import). * @build KullaTesting TestingInputStream - * @run testng ForwardReferenceImportTest + * @run junit ForwardReferenceImportTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; +import org.junit.jupiter.api.Test; -@Test public class ForwardReferenceImportTest extends KullaTesting { + @Test public void testImportDeclare() { Snippet singleImport = importKey(assertEval("import java.util.List;", added(VALID))); Snippet importOnDemand = importKey(assertEval("import java.util.*;", added(VALID))); @@ -57,6 +57,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportMethodToMethod() { DeclarationSnippet string = methodKey(assertEval("String string() { return format(\"string\"); }", added(RECOVERABLE_DEFINED))); @@ -76,6 +77,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardImportMethodOnDemandToMethod() { DeclarationSnippet string = methodKey(assertEval("String string() { return format(\"string\"); }", added(RECOVERABLE_DEFINED))); @@ -95,6 +97,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportFieldToMethod() { DeclarationSnippet pi = methodKey(assertEval("double pi() { return PI; }", added(RECOVERABLE_DEFINED))); @@ -114,6 +117,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardImportFieldOnDemandToMethod() { DeclarationSnippet pi = methodKey(assertEval("double pi() { return PI; }", added(RECOVERABLE_DEFINED))); @@ -133,6 +137,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardSingleImportMethodToClass1() { Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", added(RECOVERABLE_DEFINED))); @@ -153,6 +158,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardSingleImportMethodToClass2() { Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", added(RECOVERABLE_DEFINED))); @@ -173,6 +179,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardSingleImportClassToClass1() { Snippet a = classKey(assertEval("class A { static List list; }", added(RECOVERABLE_NOT_DEFINED))); @@ -195,6 +202,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); } + @Test public void testForwardSingleImportClassToClass2() { Snippet clsA = classKey(assertEval("class A extends ArrayList { }", added(RECOVERABLE_NOT_DEFINED))); @@ -219,6 +227,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(clsA, RECOVERABLE_NOT_DEFINED, VALID, true, arraylist)); } + @Test public void testForwardImportOnDemandMethodToClass1() { Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", added(RECOVERABLE_DEFINED))); @@ -241,6 +250,7 @@ public class ForwardReferenceImportTest extends KullaTesting { assertEval("x.s;", "\"10\""); } + @Test public void testForwardImportOnDemandMethodToClass2() { Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", added(RECOVERABLE_DEFINED))); @@ -261,6 +271,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } + @Test public void testForwardImportOnDemandClassToClass1() { Snippet a = classKey(assertEval("class A { static List list; }", added(RECOVERABLE_NOT_DEFINED))); @@ -282,6 +293,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); } + @Test public void testForwardImportOnDemandClassToClass2() { Snippet clsA = classKey(assertEval("class A extends ArrayList { }", added(RECOVERABLE_NOT_DEFINED))); @@ -305,6 +317,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(vara, RECOVERABLE_NOT_DEFINED, VALID, true, clsA)); } + @Test public void testForwardSingleImportFieldToClass1() { Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }", added(RECOVERABLE_DEFINED))); @@ -326,6 +339,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } + @Test public void testForwardSingleImportFieldToClass2() { Snippet a = classKey(assertEval("class A { static double pi = PI; }", added(RECOVERABLE_DEFINED))); @@ -347,6 +361,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, true, list)); } + @Test public void testForwardImportOnDemandFieldToClass1() { Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }", added(RECOVERABLE_DEFINED))); @@ -368,6 +383,7 @@ public class ForwardReferenceImportTest extends KullaTesting { ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } + @Test public void testForwardImportOnDemandFieldToClass2() { Snippet a = classKey(assertEval("class A { static double pi = PI; }", added(RECOVERABLE_DEFINED))); diff --git a/test/langtools/jdk/jshell/ForwardReferenceTest.java b/test/langtools/jdk/jshell/ForwardReferenceTest.java index a010e9ed31a..841b1f60a8e 100644 --- a/test/langtools/jdk/jshell/ForwardReferenceTest.java +++ b/test/langtools/jdk/jshell/ForwardReferenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8173232 8010319 * @summary Test of forward referencing of snippets. * @build KullaTesting TestingInputStream - * @run testng ForwardReferenceTest + * @run junit ForwardReferenceTest */ import java.util.List; @@ -33,17 +33,17 @@ import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.VarSnippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.SnippetEvent; import jdk.jshell.UnresolvedReferenceException; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ForwardReferenceTest extends KullaTesting { + @Test public void testOverwriteMethodForwardReferenceClass() { Snippet k1 = methodKey(assertEval("int q(Boo b) { return b.x; }", added(RECOVERABLE_NOT_DEFINED))); @@ -56,6 +56,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testOverwriteMethodForwardReferenceClassImport() { MethodSnippet k1 = methodKey(assertEval("int ff(List lis) { return lis.size(); }", added(RECOVERABLE_NOT_DEFINED))); @@ -68,6 +69,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToMethod() { DeclarationSnippet t = methodKey(assertEval("int t() { return x; }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(t, RECOVERABLE_DEFINED, "variable x"); @@ -87,6 +89,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardMethodToMethod() { Snippet t = methodKey(assertEval("int t() { return f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("int f() { return g(); }", @@ -109,6 +112,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToMethod() { DeclarationSnippet t = methodKey(assertEval("int t() { return new A().f(); }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(t, RECOVERABLE_DEFINED, "class A"); @@ -133,6 +137,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClass() { DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); @@ -150,6 +155,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClassGeneric() { DeclarationSnippet a = classKey(assertEval("class A { final T x; A(T v) { this.x = v; } ; T get() { return x; } int core() { return g; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); @@ -159,9 +165,9 @@ public class ForwardReferenceTest extends KullaTesting { SnippetEvent ste = events.get(0); Snippet assn = ste.snippet(); DeclarationSnippet unsn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); - assertEquals(unsn.name(), "A", "Wrong with unresolved"); - assertEquals(getState().unresolvedDependencies(unsn).count(), 1, "Wrong size unresolved"); - assertEquals(getState().diagnostics(unsn).count(), 0L, "Expected no diagnostics"); + assertEquals("A", unsn.name(), "Wrong with unresolved"); + assertEquals(1, getState().unresolvedDependencies(unsn).count(), "Wrong size unresolved"); + assertEquals(0L, getState().diagnostics(unsn).count(), "Expected no diagnostics"); Snippet g = varKey(assertEval("int g = 10;", "10", added(VALID), @@ -174,6 +180,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToClassExtendsImplements() { DeclarationSnippet ik = classKey(assertEval("interface I { default int ii() { return 1; } }", added(VALID))); DeclarationSnippet jk = classKey(assertEval("interface J { default int jj() { return 2; } }", added(VALID))); @@ -200,6 +207,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToInterface() { DeclarationSnippet i = classKey(assertEval("interface I { default int f() { return x; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(i, RECOVERABLE_DEFINED, "variable x"); @@ -215,6 +223,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVarToEnum() { DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable fff"); @@ -232,6 +241,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardMethodToClass() { DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_DEFINED))); assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method g()"); @@ -251,6 +261,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass1() { Snippet a = classKey(assertEval("class A { B b = new B(); }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("new A().b;", "compiler.err.cant.resolve.location"); @@ -269,6 +280,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass2() { Snippet a = classKey(assertEval("class A extends B { }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); @@ -287,6 +299,7 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardClassToClass3() { Snippet a = classKey(assertEval("interface A extends B { static int f() { return 10; } }", added(RECOVERABLE_NOT_DEFINED))); assertDeclareFail("A.f();", "compiler.err.cant.resolve.location"); @@ -305,12 +318,14 @@ public class ForwardReferenceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testForwardVariable() { assertEval("int f() { return x; }", added(RECOVERABLE_DEFINED)); assertEvalUnresolvedException("f();", "f", 1, 0); assertActiveKeys(); } + @Test public void testLocalClassInUnresolved() { Snippet f = methodKey(assertEval("void f() { class A {} g(); }", added(RECOVERABLE_DEFINED))); assertEval("void g() {}", diff --git a/test/langtools/jdk/jshell/GetResourceTest.java b/test/langtools/jdk/jshell/GetResourceTest.java index f8b2b1af227..dfba8ed588b 100644 --- a/test/langtools/jdk/jshell/GetResourceTest.java +++ b/test/langtools/jdk/jshell/GetResourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,18 +27,18 @@ * @summary Check that ClassLoader.getResource works as expected in the JShell agent. * @modules jdk.jshell * @build KullaTesting TestingInputStream - * @run testng GetResourceTest + * @run junit GetResourceTest */ import jdk.jshell.Snippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class GetResourceTest extends KullaTesting { + @Test public void checkGetResource() { assertEval("import java.util.Arrays;"); assertEval("boolean match(byte[] data, byte[] snippet) {\n" + @@ -57,6 +57,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkRedefine() { assertEval("import java.util.Arrays;"); assertEval("boolean match(byte[] data, byte[] snippet) {\n" + @@ -85,6 +86,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkResourceSize() { assertEval("import java.net.*;"); assertEval("boolean test() throws Exception {\n" + @@ -97,6 +99,7 @@ public class GetResourceTest extends KullaTesting { assertEval("test()", "true"); } + @Test public void checkTimestampCheck() { assertEval("import java.net.*;"); assertEval("import java.time.*;"); @@ -138,6 +141,7 @@ public class GetResourceTest extends KullaTesting { assertEval("nue[0] == nue[2]", "true"); } + @Test public void checkFieldAccess() { assertEval("import java.net.*;"); assertEval("Class c = new Object() {}.getClass().getEnclosingClass();"); @@ -154,6 +158,7 @@ public class GetResourceTest extends KullaTesting { assertEval("connection.getHeaderField(3) == null", "true"); } + @Test public void checkGetResources() { assertEval("import java.net.*;"); assertEval("Class c = new Object() {}.getClass().getEnclosingClass();"); diff --git a/test/langtools/jdk/jshell/HighlightUITest.java b/test/langtools/jdk/jshell/HighlightUITest.java index 954cb33117a..22403d5ae7e 100644 --- a/test/langtools/jdk/jshell/HighlightUITest.java +++ b/test/langtools/jdk/jshell/HighlightUITest.java @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile HighlightUITest.java - * @run testng HighlightUITest + * @run junit HighlightUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class HighlightUITest extends UITesting { public HighlightUITest() { super(true); } + @Test public void testHighlight() throws Exception { System.setProperty("test.enable.highlighter", "true"); doRunTest((inputSink, out) -> { diff --git a/test/langtools/jdk/jshell/HistoryTest.java b/test/langtools/jdk/jshell/HistoryTest.java index a07523d54cb..923d064c18a 100644 --- a/test/langtools/jdk/jshell/HistoryTest.java +++ b/test/langtools/jdk/jshell/HistoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -28,7 +28,7 @@ * @modules jdk.internal.le/jdk.internal.org.jline.reader * jdk.jshell/jdk.internal.jshell.tool:+open * @build HistoryTest - * @run testng HistoryTest + * @run junit HistoryTest */ import java.lang.reflect.Field; @@ -37,12 +37,12 @@ import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.internal.jshell.tool.JShellTool; import jdk.internal.jshell.tool.JShellToolBuilder; import jdk.internal.org.jline.reader.History; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class HistoryTest extends ReplToolTesting { @@ -180,16 +180,16 @@ public class HistoryTest extends ReplToolTesting { } assertCommand(a, "/exit", ""); }); - assertEquals(prefsMap.get("HISTORY_LINE_00"), "/debug 0"); - assertEquals(prefsMap.get("HISTORY_LINE_01"), "void test() {\\"); - assertEquals(prefsMap.get("HISTORY_LINE_02"), " System.err.println(1);\\"); - assertEquals(prefsMap.get("HISTORY_LINE_03"), " System.err.println(`\\\\\\\\\\"); - assertEquals(prefsMap.get("HISTORY_LINE_04"), " \\\\\\"); - assertEquals(prefsMap.get("HISTORY_LINE_05"), "`);\\"); - assertEquals(prefsMap.get("HISTORY_LINE_06"), "} //test"); - assertEquals(prefsMap.get("HISTORY_LINE_07"), "/debug 0"); - assertEquals(prefsMap.get("HISTORY_LINE_08"), "int i"); - assertEquals(prefsMap.get("HISTORY_LINE_09"), "/exit"); + assertEquals("/debug 0", prefsMap.get("HISTORY_LINE_00")); + assertEquals("void test() {\\", prefsMap.get("HISTORY_LINE_01")); + assertEquals(" System.err.println(1);\\", prefsMap.get("HISTORY_LINE_02")); + assertEquals(" System.err.println(`\\\\\\\\\\", prefsMap.get("HISTORY_LINE_03")); + assertEquals(" \\\\\\", prefsMap.get("HISTORY_LINE_04")); + assertEquals("`);\\", prefsMap.get("HISTORY_LINE_05")); + assertEquals("} //test", prefsMap.get("HISTORY_LINE_06")); + assertEquals("/debug 0", prefsMap.get("HISTORY_LINE_07")); + assertEquals("int i", prefsMap.get("HISTORY_LINE_08")); + assertEquals("/exit", prefsMap.get("HISTORY_LINE_09")); System.err.println("prefsMap: " + prefsMap); } @@ -204,10 +204,10 @@ public class HistoryTest extends ReplToolTesting { private void previousAndAssert(History history, String expected) { assertTrue(history.previous()); - assertEquals(history.current().toString(), expected); + assertEquals(expected, history.current().toString()); } - @BeforeMethod + @BeforeEach public void setUp() { super.setUp(); System.setProperty("jshell.test.allow.incomplete.inputs", "false"); diff --git a/test/langtools/jdk/jshell/HistoryUITest.java b/test/langtools/jdk/jshell/HistoryUITest.java index 3083fe46688..aa10010e270 100644 --- a/test/langtools/jdk/jshell/HistoryUITest.java +++ b/test/langtools/jdk/jshell/HistoryUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile HistoryUITest.java - * @run testng HistoryUITest + * @run junit HistoryUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class HistoryUITest extends UITesting { public HistoryUITest() { super(true); } + @Test public void testPrevNextSnippet() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("void test1() {\nSystem.err.println(1);\n}\n"); @@ -78,6 +78,7 @@ public class HistoryUITest extends UITesting { }); } + @Test public void testReRun() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("System.err.println(\"RAN\");\n"); diff --git a/test/langtools/jdk/jshell/IOTest.java b/test/langtools/jdk/jshell/IOTest.java index 112b956fec3..988b73ec071 100644 --- a/test/langtools/jdk/jshell/IOTest.java +++ b/test/langtools/jdk/jshell/IOTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,28 +25,29 @@ * @test * @summary Test input/output * @build KullaTesting TestingInputStream - * @run testng IOTest + * @run junit IOTest */ -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class IOTest extends KullaTesting { String LINE_SEPARATOR = System.getProperty("line.separator"); + @Test public void testOutput() { assertEval("System.out.println(\"Test\");"); - assertEquals(getOutput(), "Test" + LINE_SEPARATOR); + assertEquals("Test" + LINE_SEPARATOR, getOutput()); } + @Test public void testErrorOutput() { assertEval("System.err.println(\"Oops\");"); - assertEquals(getErrorOutput(), "Oops" + LINE_SEPARATOR); + assertEquals("Oops" + LINE_SEPARATOR, getErrorOutput()); } + @Test public void testInput() { setInput("x"); assertEval("(char)System.in.read();", "'x'"); diff --git a/test/langtools/jdk/jshell/IdGeneratorTest.java b/test/langtools/jdk/jshell/IdGeneratorTest.java index e8a38dfe7f0..6c7f6177e03 100644 --- a/test/langtools/jdk/jshell/IdGeneratorTest.java +++ b/test/langtools/jdk/jshell/IdGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @summary Test custom id generators * @build KullaTesting TestingInputStream - * @run testng IdGeneratorTest + * @run junit IdGeneratorTest */ import java.io.ByteArrayOutputStream; @@ -38,14 +38,13 @@ import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.UnresolvedReferenceException; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -@Test public class IdGeneratorTest { + @Test public JShell.Builder getBuilder() { TestingInputStream inStream = new TestingInputStream(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -57,6 +56,7 @@ public class IdGeneratorTest { .executionEngine(Presets.TEST_DEFAULT_EXECUTION); } + @Test public void testTempNameGenerator() { JShell.Builder builder = getBuilder().tempVariableNameGenerator(new Supplier() { int count = 0; @@ -69,11 +69,12 @@ public class IdGeneratorTest { try (JShell jShell = builder.build()) { for (int i = 0; i < 3; ++i) { VarSnippet v = (VarSnippet) jShell.eval("2 + " + (i + 1)).get(0).snippet(); - assertEquals("temp" + (i + 1), v.name(), "Custom id: "); + assertEquals(v.name(), "temp" + (i + 1), "Custom id: "); } } } + @Test public void testResetTempNameGenerator() { JShell.Builder builder = getBuilder().tempVariableNameGenerator(() -> { throw new AssertionError("Should not be called"); @@ -83,6 +84,7 @@ public class IdGeneratorTest { } } + @Test public void testIdGenerator() { JShell.Builder builder = getBuilder().idGenerator(((snippet, id) -> "custom" + id)); try (JShell jShell = builder.build()) { @@ -99,6 +101,7 @@ public class IdGeneratorTest { } } + @Test public void testIdInException() { JShell.Builder builder = getBuilder().idGenerator(((snippet, id) -> "custom" + id)); try (JShell jShell = builder.build()) { @@ -116,6 +119,7 @@ public class IdGeneratorTest { } } + @Test public void testResetIdGenerator() { JShell.Builder builder = getBuilder().idGenerator((sn, id) -> { throw new AssertionError("Should not be called"); diff --git a/test/langtools/jdk/jshell/IgnoreTest.java b/test/langtools/jdk/jshell/IgnoreTest.java index 023b5c99ac8..4350ce0cac3 100644 --- a/test/langtools/jdk/jshell/IgnoreTest.java +++ b/test/langtools/jdk/jshell/IgnoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,20 +26,20 @@ * @bug 8129559 8246353 8247456 * @summary Test the ignoring of comments and certain modifiers * @build KullaTesting TestingInputStream - * @run testng IgnoreTest + * @run junit IgnoreTest */ -import org.testng.annotations.Test; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; -@Test public class IgnoreTest extends KullaTesting { + @Test public void testComment() { assertVarKeyMatch("//t1\n int//t2\n x//t3\n =//t4\n 12//t5\n ;//t6\n", true, "x", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "int", added(VALID)); @@ -58,6 +58,7 @@ public class IgnoreTest extends KullaTesting { false, "f", METHOD_SUBKIND, added(VALID)); } + @Test public void testVarModifier() { VarSnippet x1 = varKey(assertEval("public int x1;")); assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); @@ -71,6 +72,7 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testVarModifierAnnotation() { assertEval("@interface A { int value() default 0; }"); VarSnippet x1 = varKey(assertEval("@A public int x1;")); @@ -85,6 +87,7 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testVarModifierOtherModifier() { VarSnippet x1 = varKey(assertEval("volatile public int x1;")); assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); @@ -98,12 +101,14 @@ public class IgnoreTest extends KullaTesting { assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); } + @Test public void testMisplacedIgnoredModifier() { assertEvalFail("int public y;"); assertEvalFail("String private x;"); assertEvalFail("(protected 34);"); } + @Test public void testMethodModifier() { MethodSnippet m4 = methodKey(assertEval("static void m4() {}")); assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 0); @@ -111,6 +116,7 @@ public class IgnoreTest extends KullaTesting { assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0); } + @Test public void testMethodModifierAnnotation() { assertEval("@interface A { int value() default 0; }"); MethodSnippet m4 = methodKey(assertEval("@A static void m4() {}")); @@ -119,6 +125,7 @@ public class IgnoreTest extends KullaTesting { assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0); } + @Test public void testClassModifier() { TypeDeclSnippet c4 = classKey(assertEval("static class C4 {}")); assertTypeDeclSnippet(c4, "C4", VALID, CLASS_SUBKIND, 0, 0); @@ -126,6 +133,7 @@ public class IgnoreTest extends KullaTesting { assertTypeDeclSnippet(c5, "C5", VALID, CLASS_SUBKIND, 0, 0); } + @Test public void testInsideModifier() { assertEval("import static java.lang.reflect.Modifier.*;"); assertEval("class C {" diff --git a/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java b/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java index 3ba5910e8b5..f43778bb465 100644 --- a/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java +++ b/test/langtools/jdk/jshell/IllegalArgumentExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @summary Testing IllegalArgumentException. * @build KullaTesting TestingInputStream IllegalArgumentExceptionTest - * @run testng IllegalArgumentExceptionTest + * @run junit IllegalArgumentExceptionTest */ import java.util.function.Consumer; @@ -33,12 +33,10 @@ import java.util.function.Consumer; import jdk.jshell.DeclarationSnippet; import jdk.jshell.Snippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; - -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class IllegalArgumentExceptionTest extends KullaTesting { private void testIllegalArgumentException(Consumer action) { @@ -54,22 +52,27 @@ public class IllegalArgumentExceptionTest extends KullaTesting { } } + @Test public void testVarValue() { testIllegalArgumentException((key) -> getState().varValue((VarSnippet) key)); } + @Test public void testStatus() { testIllegalArgumentException((key) -> getState().status(key)); } + @Test public void testDrop() { testIllegalArgumentException((key) -> getState().drop(key)); } + @Test public void testUnresolved() { testIllegalArgumentException((key) -> getState().unresolvedDependencies((DeclarationSnippet) key)); } + @Test public void testDiagnostics() { testIllegalArgumentException((key) -> getState().diagnostics(key)); } diff --git a/test/langtools/jdk/jshell/ImportTest.java b/test/langtools/jdk/jshell/ImportTest.java index 0e1dbfead96..916df3a2b77 100644 --- a/test/langtools/jdk/jshell/ImportTest.java +++ b/test/langtools/jdk/jshell/ImportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * jdk.jdeps/com.sun.tools.javap * @library /tools/lib * @build KullaTesting TestingInputStream toolbox.Task.ExpectedDiagnostic - * @run testng ImportTest + * @run junit ImportTest */ import java.lang.reflect.Method; @@ -42,7 +42,6 @@ import javax.tools.Diagnostic; import jdk.jshell.JShell; import jdk.jshell.Snippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.OVERWRITTEN; @@ -51,10 +50,13 @@ import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND; import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND; import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; -@Test public class ImportTest extends KullaTesting { + @Test public void testImport() { assertImportKeyMatch("import java.util.List;", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertImportKeyMatch("import java.util.ArrayList;", "ArrayList", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); @@ -63,6 +65,7 @@ public class ImportTest extends KullaTesting { assertEval("list.size();", "1"); } + @Test public void testImportOnDemand() { assertImportKeyMatch("import java.util.*;", "java.util.*", TYPE_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertEval("List list = new ArrayList<>();"); @@ -70,16 +73,19 @@ public class ImportTest extends KullaTesting { assertEval("list.size();", "1"); } + @Test public void testImportStatic() { assertImportKeyMatch("import static java.lang.Math.PI;", "PI", SINGLE_STATIC_IMPORT_SUBKIND, added(VALID)); assertEval("Double.valueOf(PI).toString().substring(0, 16).equals(\"3.14159265358979\");", "true"); } + @Test public void testImportStaticOnDemand() { assertImportKeyMatch("import static java.lang.Math.*;", "java.lang.Math.*", STATIC_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertEval("abs(cos(PI / 2)) < 0.00001;", "true"); } + @Test public void testUnknownPackage() { assertDeclareFail("import unknown.qqq;", new ExpectedDiagnostic("compiler.err.doesnt.exist", 7, 18, 14, -1, -1, Diagnostic.Kind.ERROR)); @@ -87,22 +93,26 @@ public class ImportTest extends KullaTesting { new ExpectedDiagnostic("compiler.err.doesnt.exist", 7, 14, 7, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testBogusImportIgnoredInFuture() { assertDeclareFail("import unknown.qqq;", "compiler.err.doesnt.exist"); assertDeclareFail("import unknown.*;", "compiler.err.doesnt.exist"); assertEval("2 + 2;"); } + @Test public void testBadImport() { assertDeclareFail("import static java.lang.reflect.Modifier;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 14, 31, 23, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testBadSyntaxImport() { assertDeclareFail("import not found.*;", new ExpectedDiagnostic("compiler.err.expected", 10, 10, 10, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testImportRedefinition() { Compiler compiler = new Compiler(); Path path = Paths.get("testImport"); @@ -143,6 +153,7 @@ public class ImportTest extends KullaTesting { assertEval("new ArrayList();", "MyInnerList"); } + @Test public void testImportMemberRedefinition() { Compiler compiler = new Compiler(); Path path = Paths.get("testImport"); @@ -167,19 +178,21 @@ public class ImportTest extends KullaTesting { assertEval("method();", "\"A\""); } + @Test public void testImportWithComment() { assertImportKeyMatch("import java.util.List;//comment", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertEval("List l = null;"); } + @Test public void testImportModule() { assertImportKeyMatch("import module java.base;", "java.base", MODULE_IMPORT_SUBKIND, added(VALID)); assertEval("MethodHandle m;"); } - @org.testng.annotations.BeforeMethod - public void setUp(Method m) { - switch (m.getName()) { + @BeforeEach + public void setUp(TestInfo testInfo) { + switch (testInfo.getTestMethod().orElseThrow().getName()) { case "testImportModule" -> super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); default -> diff --git a/test/langtools/jdk/jshell/InaccessibleExpressionTest.java b/test/langtools/jdk/jshell/InaccessibleExpressionTest.java index 9e6c95fd3f7..db82067d3de 100644 --- a/test/langtools/jdk/jshell/InaccessibleExpressionTest.java +++ b/test/langtools/jdk/jshell/InaccessibleExpressionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -29,23 +29,21 @@ * jdk.jdeps/com.sun.tools.javap * @library /tools/lib * @build KullaTesting Compiler - * @run testng InaccessibleExpressionTest + * @run junit InaccessibleExpressionTest */ import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.BeforeMethod; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class InaccessibleExpressionTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { Path path = Paths.get("eit"); @@ -76,20 +74,22 @@ public class InaccessibleExpressionTest extends KullaTesting { .compilerOptions("--class-path", tpath)); } + @Test public void testExternal() { assertEval("import static priv.GetPriv.*;"); VarSnippet down = varKey(assertEval("down()", "Packp")); - assertEquals(down.typeName(), "priv.Packp"); + assertEquals("priv.Packp", down.typeName()); assertEval(down.name() + ".get()", "5"); VarSnippet list = varKey(assertEval("list()", "[]")); - assertEquals(list.typeName(), "priv.MyList"); + assertEquals("priv.MyList", list.typeName()); assertEval(list.name() + ".size()", "0"); VarSnippet one = varKey(assertEval("priv()", "One")); - assertEquals(one.typeName(), "priv.GetPriv.Count"); + assertEquals("priv.GetPriv.Count", one.typeName()); assertEval("var v = down();", "Packp"); assertDeclareFail("v.toString()", "compiler.err.not.def.access.class.intf.cant.access"); } + @Test public void testInternal() { assertEval( "class Top {" + @@ -98,7 +98,7 @@ public class InaccessibleExpressionTest extends KullaTesting { " }" + " Inner n = new Inner(); }"); VarSnippet n = varKey(assertEval("new Top().n", "Inner")); - assertEquals(n.typeName(), "Top.Inner"); + assertEquals("Top.Inner", n.typeName()); } } diff --git a/test/langtools/jdk/jshell/IndentUITest.java b/test/langtools/jdk/jshell/IndentUITest.java index d7534b3e6b9..a771b9b1031 100644 --- a/test/langtools/jdk/jshell/IndentUITest.java +++ b/test/langtools/jdk/jshell/IndentUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile IndentUITest.java - * @run testng IndentUITest + * @run junit IndentUITest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class IndentUITest extends UITesting { public IndentUITest() { super(true); } + @Test public void testIdent() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("void test1() {\nSystem.err.println(1);\n}\n"); diff --git a/test/langtools/jdk/jshell/InferTypeTest.java b/test/langtools/jdk/jshell/InferTypeTest.java index 080697666a2..a1455306f45 100644 --- a/test/langtools/jdk/jshell/InferTypeTest.java +++ b/test/langtools/jdk/jshell/InferTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -30,14 +30,14 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng InferTypeTest + * @run junit InferTypeTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class InferTypeTest extends KullaTesting { + @Test public void testTypeInference() { assertInferredType("1", "int"); assertEval("import java.util.*;"); diff --git a/test/langtools/jdk/jshell/InputUITest.java b/test/langtools/jdk/jshell/InputUITest.java index 9df0597390c..1a420d2c345 100644 --- a/test/langtools/jdk/jshell/InputUITest.java +++ b/test/langtools/jdk/jshell/InputUITest.java @@ -35,14 +35,13 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @compile InputUITest.java - * @run testng/othervm -Dstderr.encoding=UTF-8 -Dstdin.encoding=UTF-8 -Dstdout.encoding=UTF-8 InputUITest + * @run junit/othervm -Dstderr.encoding=UTF-8 -Dstdin.encoding=UTF-8 -Dstdout.encoding=UTF-8 InputUITest */ import java.util.Map; import java.util.function.Function; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class InputUITest extends UITesting { static final String LINE_SEPARATOR = System.getProperty("line.separator"); @@ -53,6 +52,7 @@ public class InputUITest extends UITesting { super(true); } + @Test public void testUserInputWithSurrogates() throws Exception { Function genSnippet = realCharsToRead -> "new String(System.in.readNBytes(" + @@ -68,6 +68,7 @@ public class InputUITest extends UITesting { }, false); } + @Test public void testCloseInputSinkWhileReadingUserInputSimulatingCtrlD() throws Exception { var snippets = Map.of( "System.in.read()", " ==> -1", @@ -85,6 +86,7 @@ public class InputUITest extends UITesting { } } + @Test public void testUserInputWithCtrlDAndMultipleSnippets() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("IO.readln()\n" + CTRL_D); diff --git a/test/langtools/jdk/jshell/JLCollisionTest.java b/test/langtools/jdk/jshell/JLCollisionTest.java index 2859c1a49f7..88651e9311e 100644 --- a/test/langtools/jdk/jshell/JLCollisionTest.java +++ b/test/langtools/jdk/jshell/JLCollisionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -28,14 +28,14 @@ * the same simple names * @modules jdk.jshell/jdk.jshell * @build KullaTesting - * @run testng JLCollisionTest + * @run junit JLCollisionTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JLCollisionTest extends KullaTesting { + @Test public void testObject() { assertEval("class Object {}"); assertEval("1"); @@ -43,6 +43,7 @@ public class JLCollisionTest extends KullaTesting { assertEval("$2 = \"\""); } + @Test public void testThrowable() { assertEval("class Throwable {}"); assertEval("1"); @@ -50,6 +51,7 @@ public class JLCollisionTest extends KullaTesting { assertEval("var _ = new Object() {};"); } + @Test public void testSuppressWarnings() { assertEval("class SuppressWarnings {}"); //var with an "enhanced" (non-denotable) type: diff --git a/test/langtools/jdk/jshell/JShellQueryTest.java b/test/langtools/jdk/jshell/JShellQueryTest.java index 352e639a29c..e487c294f3b 100644 --- a/test/langtools/jdk/jshell/JShellQueryTest.java +++ b/test/langtools/jdk/jshell/JShellQueryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,21 +26,21 @@ * @bug 8143964 * @summary test queries to the JShell that return Streams * @build KullaTesting - * @run testng JShellQueryTest + * @run junit JShellQueryTest */ import jdk.jshell.Snippet; -import org.testng.annotations.Test; import jdk.jshell.ImportSnippet; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import static java.util.stream.Collectors.joining; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class JShellQueryTest extends KullaTesting { + @Test public void testSnippets() { assertStreamMatch(getState().snippets()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -54,6 +54,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().snippets(), sx, sfoo, smm, svv, sc, si, simp); } + @Test public void testVars() { assertStreamMatch(getState().variables()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -67,6 +68,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().variables(), sx, sfoo); } + @Test public void testMethods() { assertStreamMatch(getState().methods()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -79,6 +81,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().methods(), smm, svv); } + @Test public void testTypes() { assertStreamMatch(getState().types()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -91,6 +94,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().types(), sc, si); } + @Test public void testImports() { assertStreamMatch(getState().imports()); VarSnippet sx = varKey(assertEval("int x = 5;")); @@ -103,6 +107,7 @@ public class JShellQueryTest extends KullaTesting { assertStreamMatch(getState().imports(), simp); } + @Test public void testDiagnostics() { Snippet sx = varKey(assertEval("int x = 5;")); assertStreamMatch(getState().diagnostics(sx)); @@ -110,9 +115,10 @@ public class JShellQueryTest extends KullaTesting { String res = getState().diagnostics(broken) .map(d -> d.getCode()) .collect(joining("+")); - assertEquals(res, "compiler.err.cant.resolve.location.args+compiler.err.prob.found.req"); + assertEquals("compiler.err.cant.resolve.location.args+compiler.err.prob.found.req", res); } + @Test public void testUnresolvedDependencies() { VarSnippet sx = varKey(assertEval("int x = 5;")); assertStreamMatch(getState().unresolvedDependencies(sx)); diff --git a/test/langtools/jdk/jshell/JShellStateClosedTest.java b/test/langtools/jdk/jshell/JShellStateClosedTest.java index 2f8d1215667..62044dc1f2f 100644 --- a/test/langtools/jdk/jshell/JShellStateClosedTest.java +++ b/test/langtools/jdk/jshell/JShellStateClosedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8164277 * @summary Testing IllegalStateException. * @build KullaTesting TestingInputStream JShellStateClosedTest - * @run testng JShellStateClosedTest + * @run junit JShellStateClosedTest */ import java.util.function.Consumer; @@ -36,11 +36,9 @@ import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.fail; - -@Test public class JShellStateClosedTest extends KullaTesting { private void testStateClosedException(Runnable action) { @@ -53,6 +51,7 @@ public class JShellStateClosedTest extends KullaTesting { } } + @Test public void testClasses() { TypeDeclSnippet sc = classKey(assertEval("class C { }")); TypeDeclSnippet si = classKey(assertEval("interface I { }")); @@ -60,6 +59,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().types(), sc, si); } + @Test public void testVariables() { VarSnippet sx = varKey(assertEval("int x = 5;")); VarSnippet sfoo = varKey(assertEval("String foo;")); @@ -67,6 +67,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().variables(), sx, sfoo); } + @Test public void testMethods() { MethodSnippet smm = methodKey(assertEval("int mm() { return 6; }")); MethodSnippet svv = methodKey(assertEval("void vv() { }")); @@ -74,12 +75,14 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().methods(), smm, svv); } + @Test public void testImports() { ImportSnippet simp = importKey(assertEval("import java.lang.reflect.*;")); getState().close(); assertStreamMatch(getState().imports(), simp); } + @Test public void testSnippets() { VarSnippet sx = varKey(assertEval("int x = 5;")); VarSnippet sfoo = varKey(assertEval("String foo;")); @@ -92,6 +95,7 @@ public class JShellStateClosedTest extends KullaTesting { assertStreamMatch(getState().snippets(), sx, sfoo, smm, svv, sc, si, simp); } + @Test public void testEval() { testStateClosedException(() -> getState().eval("int a;")); } @@ -117,22 +121,27 @@ public class JShellStateClosedTest extends KullaTesting { } } + @Test public void testStatus() { testStateClosedWithoutException((key) -> getState().status(key)); } + @Test public void testVarValue() { testStateClosedException((key) -> getState().varValue((VarSnippet) key)); } + @Test public void testDrop() { testStateClosedException((key) -> getState().drop(key)); } + @Test public void testUnresolved() { testStateClosedWithoutException((key) -> getState().unresolvedDependencies((DeclarationSnippet) key)); } + @Test public void testDiagnostics() { testStateClosedWithoutException((key) -> getState().diagnostics(key)); } diff --git a/test/langtools/jdk/jshell/JavadocTest.java b/test/langtools/jdk/jshell/JavadocTest.java index 184921adf9a..463c23a4f31 100644 --- a/test/langtools/jdk/jshell/JavadocTest.java +++ b/test/langtools/jdk/jshell/JavadocTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -31,7 +31,7 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng JavadocTest + * @run junit JavadocTest */ import java.io.IOException; @@ -43,13 +43,13 @@ import java.util.Arrays; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JavadocTest extends KullaTesting { private final Compiler compiler = new Compiler(); + @Test public void testJavadoc() { prepareZip(); assertJavadoc("test.Clazz|", "test.Clazz\n" + @@ -65,6 +65,7 @@ public class JavadocTest extends KullaTesting { assertJavadoc("clz.undef|"); } + @Test public void testVariableInRepl() { assertEval("Object o;"); assertSignature("o|", "o:java.lang.Object"); @@ -107,6 +108,7 @@ public class JavadocTest extends KullaTesting { addToClasspath(compiler.getClassDir()); } + @Test public void testCollectionsMin() { prepareJavaUtilZip(); assertJavadoc("java.util.Collections.min(|", diff --git a/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java index 199964abb0b..c45370c1a54 100644 --- a/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBadOptionLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,22 +26,22 @@ * @bug 8169519 8166581 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBadOptionLaunchExecutionControlTest + * @run junit JdiBadOptionLaunchExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBadOptionLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Failed remote launch: java.util.concurrent.ExecutionException: com.sun.jdi.connect.VMStartException: VM initialization failed"; + @Test public void badOptionLaunchTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java index bdf05c7bd7f..422c6c18b75 100644 --- a/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBadOptionListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,22 +26,22 @@ * @bug 8169519 8166581 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBadOptionListenExecutionControlTest + * @run junit JdiBadOptionListenExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBadOptionListenExecutionControlTest { private static final String EXPECTED_ERROR = "Unrecognized option: -BadBadOption"; + @Test public void badOptionListenTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java index 03659952279..7f0924229b7 100644 --- a/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiBogusHostListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,17 +26,16 @@ * @bug 8169519 8168615 8176474 * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiBogusHostListenExecutionControlTest + * @run junit JdiBogusHostListenExecutionControlTest */ import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiBogusHostListenExecutionControlTest { private static final String EXPECTED_ERROR = @@ -44,6 +43,7 @@ public class JdiBogusHostListenExecutionControlTest { private static final String EXPECTED_LOCATION = "@ com.sun.jdi.SocketListen"; + @Test public void badOptionListenTest() { try { // turn on logging of launch failures diff --git a/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java index 288983a05e5..6ce9df1ccf4 100644 --- a/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiFailingLaunchExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,19 +27,19 @@ * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build DyingRemoteAgent - * @run testng JdiFailingLaunchExecutionControlTest + * @run junit JdiFailingLaunchExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiFailingLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void failLaunchTest() { try { System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;")); diff --git a/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java index aaa3357a754..d8b52458551 100644 --- a/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiFailingListenExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,19 +27,19 @@ * @summary Tests for JDI connector failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build DyingRemoteAgent - * @run testng JdiFailingListenExecutionControlTest + * @run junit JdiFailingListenExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiFailingListenExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void failListenTest() { try { System.err.printf("Unexpected return value: %s\n", DyingRemoteAgent.state(true, null).eval("33;")); diff --git a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java index cb8fc2ea408..950bf0370ca 100644 --- a/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingLaunchExecutionControlTest.java @@ -27,19 +27,19 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng/timeout=480 JdiHangingLaunchExecutionControlTest + * @run junit/timeout=480 JdiHangingLaunchExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiHangingLaunchExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void hangLaunchTimeoutTest() { try { System.err.printf("Unexpected return value: %s\n", diff --git a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java index d43c3f170bd..78cfe66220a 100644 --- a/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiHangingListenExecutionControlTest.java @@ -27,20 +27,20 @@ * @summary Tests for JDI connector timeout failure * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution * @build HangingRemoteAgent - * @run testng/timeout=480 JdiHangingListenExecutionControlTest + * @run junit/timeout=480 JdiHangingListenExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; -@Test public class JdiHangingListenExecutionControlTest { private static final String EXPECTED_ERROR = "Launching JShell execution engine threw: Accept timed out"; + @Test public void hangListenTimeoutTest() { try { System.err.printf("Unexpected return value: %s\n", diff --git a/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java b/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java index af9dce89bcf..35261ff6fa1 100644 --- a/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiLaunchingExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,18 +27,16 @@ * @summary Tests for standard JDI connector (without failover) -- launching * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiLaunchingExecutionControlTest + * @run junit JdiLaunchingExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi:launch(true)")); diff --git a/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java b/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java index 700ec077e34..3cc2a9785a3 100644 --- a/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiListeningExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,18 +27,16 @@ * @summary Tests for alternate JDI connector -- listening * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiListeningExecutionControlTest + * @run junit JdiListeningExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiListeningExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi")); diff --git a/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java b/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java index 241774d639e..2e38e9f9aae 100644 --- a/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java +++ b/test/langtools/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,18 +27,16 @@ * @summary Tests for alternate JDI connector -- listening to "localhost" * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JdiListeningLocalhostExecutionControlTest + * @run junit JdiListeningLocalhostExecutionControlTest * @key intermittent */ -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; -@Test public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("jdi:hostname(localhost)")); diff --git a/test/langtools/jdk/jshell/JdiStarterTest.java b/test/langtools/jdk/jshell/JdiStarterTest.java index 0beee9ceda1..d584f2e1ec5 100644 --- a/test/langtools/jdk/jshell/JdiStarterTest.java +++ b/test/langtools/jdk/jshell/JdiStarterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8319311 * @summary Tests JdiStarter * @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution - * @run testng JdiStarterTest + * @run junit JdiStarterTest */ import java.util.Collections; @@ -34,26 +34,26 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import org.testng.annotations.Test; import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.execution.JdiDefaultExecutionControl.JdiStarter; import jdk.jshell.execution.JdiDefaultExecutionControl.JdiStarter.TargetDescription; import jdk.jshell.execution.JdiExecutionControlProvider; import jdk.jshell.execution.JdiInitiator; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class JdiStarterTest { + @Test public void jdiStarter() { // turn on logging of launch failures Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL); JdiStarter starter = (env, parameters, port) -> { - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_HOST_NAME), ""); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_LAUNCH), "false"); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_REMOTE_AGENT), "jdk.jshell.execution.RemoteExecutionControl"); - assertEquals(parameters.get(JdiExecutionControlProvider.PARAM_TIMEOUT), "5000"); + assertEquals("", parameters.get(JdiExecutionControlProvider.PARAM_HOST_NAME)); + assertEquals("false", parameters.get(JdiExecutionControlProvider.PARAM_LAUNCH)); + assertEquals("jdk.jshell.execution.RemoteExecutionControl", parameters.get(JdiExecutionControlProvider.PARAM_REMOTE_AGENT)); + assertEquals("5000", parameters.get(JdiExecutionControlProvider.PARAM_TIMEOUT)); JdiInitiator jdii = new JdiInitiator(port, env.extraRemoteVMOptions(), diff --git a/test/langtools/jdk/jshell/KullaCompletenessStressTest.java b/test/langtools/jdk/jshell/KullaCompletenessStressTest.java index e79e043dd10..69830880dcb 100644 --- a/test/langtools/jdk/jshell/KullaCompletenessStressTest.java +++ b/test/langtools/jdk/jshell/KullaCompletenessStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,16 +26,19 @@ * @summary Test SourceCodeAnalysis * @modules jdk.compiler/com.sun.tools.javac.api * @build KullaTesting TestingInputStream KullaCompletenessStressTest CompletenessStressTest - * @run testng KullaCompletenessStressTest + * @run junit KullaCompletenessStressTest */ import java.io.File; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class KullaCompletenessStressTest extends CompletenessStressTest { @Override + @Test public File[] getDirectoriesToTest() { String src = System.getProperty("test.src"); File file; @@ -44,11 +47,10 @@ public class KullaCompletenessStressTest extends CompletenessStressTest { } else { file = new File(src, "../../../src/jdk.jshell/share/classes"); } - if (!file.exists()) { - System.out.println("jdk.jshell sources are not exist. Test has been skipped. Path: " + file.toString()); - return new File[]{}; - }else { - return new File[]{file}; - } + + Assumptions.assumeTrue(file.exists(), + "jdk.jshell sources are not exist. Test has been skipped. Path: " + file.toString()); + + return new File[]{file}; } } diff --git a/test/langtools/jdk/jshell/KullaTesting.java b/test/langtools/jdk/jshell/KullaTesting.java index e3eb6ef2823..fd9348507c4 100644 --- a/test/langtools/jdk/jshell/KullaTesting.java +++ b/test/langtools/jdk/jshell/KullaTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -71,8 +71,6 @@ import jdk.jshell.SourceCodeAnalysis.Completeness; import jdk.jshell.SourceCodeAnalysis.QualifiedNames; import jdk.jshell.SourceCodeAnalysis.Suggestion; import jdk.jshell.UnresolvedReferenceException; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; import jdk.jshell.Diag; @@ -80,9 +78,11 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND; import jdk.jshell.SourceCodeAnalysis.Documentation; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; public class KullaTesting { @@ -166,7 +166,7 @@ public class KullaTesting { addToClasspath(path.toString()); } - @BeforeMethod + @BeforeEach public void setUp() { setUp(b -> {}); } @@ -202,7 +202,7 @@ public class KullaTesting { idToSnippet = new LinkedHashMap<>(); } - @AfterMethod + @AfterEach public void tearDown() { if (state != null) state.close(); state = null; @@ -226,16 +226,16 @@ public class KullaTesting { public List assertUnresolvedDependencies(DeclarationSnippet key, int unresolvedSize) { List unresolved = getState().unresolvedDependencies(key).collect(toList()); - assertEquals(unresolved.size(), unresolvedSize, "Input: " + key.source() + ", checking unresolved: "); + assertEquals(unresolvedSize, unresolved.size(), "Input: " + key.source() + ", checking unresolved: "); return unresolved; } public DeclarationSnippet assertUnresolvedDependencies1(DeclarationSnippet key, Status status, String name) { List unresolved = assertUnresolvedDependencies(key, 1); String input = key.source(); - assertEquals(unresolved.size(), 1, "Given input: " + input + ", checking unresolved"); - assertEquals(unresolved.get(0), name, "Given input: " + input + ", checking unresolved: "); - assertEquals(getState().status(key), status, "Given input: " + input + ", checking status: "); + assertEquals(1, unresolved.size(), "Given input: " + input + ", checking unresolved"); + assertEquals(name, unresolved.get(0), "Given input: " + input + ", checking unresolved: "); + assertEquals(status, getState().status(key), "Given input: " + input + ", checking status: "); return key; } @@ -243,24 +243,24 @@ public class KullaTesting { List events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); SnippetEvent ste = events.get(0); DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); - assertEquals(sn.name(), name, "Given input: " + input + ", checking name"); - assertEquals(getState().unresolvedDependencies(sn).count(), unresolvedSize, "Given input: " + input + ", checking unresolved"); - assertEquals(getState().diagnostics(sn).count(), (long) diagnosticsSize, "Given input: " + input + ", checking diagnostics"); + assertEquals(name, sn.name(), "Given input: " + input + ", checking name"); + assertEquals(unresolvedSize, getState().unresolvedDependencies(sn).count(), "Given input: " + input + ", checking unresolved"); + assertEquals((long) diagnosticsSize, getState().diagnostics(sn).count(), "Given input: " + input + ", checking diagnostics"); return sn; } public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) { Snippet key = key(assertEval(input, IGNORE_VALUE, mainInfo, updates)); String source = key.source(); - assertEquals(source, input, "Key \"" + input + "\" source mismatch, got: " + source + ", expected: " + input); + assertEquals(input, source, "Key \"" + input + "\" source mismatch, got: " + source + ", expected: " + input); SubKind subkind = key.subKind(); - assertEquals(subkind, expectedSubKind, "Key \"" + input + "\" subkind mismatch, got: " + assertEquals(expectedSubKind, subkind, "Key \"" + input + "\" subkind mismatch, got: " + subkind + ", expected: " + expectedSubKind); - assertEquals(subkind.isExecutable(), isExecutable, "Key \"" + input + "\", expected isExecutable: " + assertEquals(isExecutable, subkind.isExecutable(), "Key \"" + input + "\", expected isExecutable: " + isExecutable + ", got: " + subkind.isExecutable()); Snippet.Kind expectedKind = getKind(key); - assertEquals(key.kind(), expectedKind, "Checking kind: "); - assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); + assertEquals(expectedKind, key.kind(), "Checking kind: "); + assertEquals(expectedKind, expectedSubKind.kind(), "Checking kind: "); return key; } @@ -310,9 +310,9 @@ public class KullaTesting { assertTrue(key instanceof ImportSnippet, "Expected an ImportKey, got: " + key.getClass().getName()); ImportSnippet importKey = (ImportSnippet) key; - assertEquals(importKey.name(), name, "Input \"" + input + + assertEquals(name, importKey.name(), "Input \"" + input + "\" name mismatch, got: " + importKey.name() + ", expected: " + name); - assertEquals(importKey.kind(), Kind.IMPORT, "Checking kind: "); + assertEquals(Kind.IMPORT, importKey.kind(), "Checking kind: "); return importKey; } @@ -321,7 +321,7 @@ public class KullaTesting { assertTrue(key instanceof DeclarationSnippet, "Expected a DeclarationKey, got: " + key.getClass().getName()); DeclarationSnippet declKey = (DeclarationSnippet) key; - assertEquals(declKey.name(), name, "Input \"" + input + + assertEquals(name, declKey.name(), "Input \"" + input + "\" name mismatch, got: " + declKey.name() + ", expected: " + name); return declKey; } @@ -331,9 +331,9 @@ public class KullaTesting { assertTrue(sn instanceof VarSnippet, "Expected a VarKey, got: " + sn.getClass().getName()); VarSnippet variableKey = (VarSnippet) sn; String signature = variableKey.typeName(); - assertEquals(signature, typeName, "Key \"" + input + + assertEquals(typeName, signature, "Key \"" + input + "\" typeName mismatch, got: " + signature + ", expected: " + typeName); - assertEquals(variableKey.kind(), Kind.VAR, "Checking kind: "); + assertEquals(Kind.VAR, variableKey.kind(), "Checking kind: "); return variableKey; } @@ -341,11 +341,11 @@ public class KullaTesting { Snippet key = assertKeyMatch(input, true, kind, added(VALID)); assertTrue(key instanceof ExpressionSnippet, "Expected a ExpressionKey, got: " + key.getClass().getName()); ExpressionSnippet exprKey = (ExpressionSnippet) key; - assertEquals(exprKey.name(), name, "Input \"" + input + + assertEquals(name, exprKey.name(), "Input \"" + input + "\" name mismatch, got: " + exprKey.name() + ", expected: " + name); - assertEquals(exprKey.typeName(), typeName, "Key \"" + input + + assertEquals(typeName, exprKey.typeName(), "Key \"" + input + "\" typeName mismatch, got: " + exprKey.typeName() + ", expected: " + typeName); - assertEquals(exprKey.kind(), Kind.EXPRESSION, "Checking kind: "); + assertEquals(Kind.EXPRESSION, exprKey.kind(), "Checking kind: "); } // For expressions throwing an EvalException @@ -403,7 +403,7 @@ public class KullaTesting { void assertStreamMatch(Stream result, T... expected) { Set sns = result.collect(toSet()); Set exp = Stream.of(expected).collect(toSet()); - assertEquals(sns, exp); + assertEquals(exp, sns); } private Map closure(List events) { @@ -484,9 +484,9 @@ public class KullaTesting { }); List events = toTest.get(); getState().unsubscribe(token); - assertEquals(dispatched.size(), events.size(), "dispatched event size not the same as event size"); + assertEquals(events.size(), dispatched.size(), "dispatched event size not the same as event size"); for (int i = events.size() - 1; i >= 0; --i) { - assertEquals(dispatched.get(i), events.get(i), "Event element " + i + " does not match"); + assertEquals(events.get(i), dispatched.get(i), "Event element " + i + " does not match"); } dispatched.add(null); // mark end of dispatchs @@ -500,11 +500,11 @@ public class KullaTesting { if (old != null) { switch (evt.status()) { case DROPPED: - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Drop: Old snippet must be what is dropped -- input: " + descriptor); break; case OVERWRITTEN: - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Overwrite: Old snippet (" + old + ") must be what is overwritten -- input: " + descriptor + " -- " + evt); @@ -512,12 +512,12 @@ public class KullaTesting { default: if (evt.causeSnippet() == null) { // New source - assertNotEquals(old, evt.snippet(), + assertNotEquals(evt.snippet(), old, "New source: Old snippet must be different from the replacing -- input: " + descriptor); } else { // An update (key Overwrite??) - assertEquals(old, evt.snippet(), + assertEquals(evt.snippet(), old, "Update: Old snippet must be equal to the replacing -- input: " + descriptor); } @@ -557,7 +557,7 @@ public class KullaTesting { int impactId = 0; Map> groupedEvents = groupByCauseSnippet(events); - assertEquals(groupedEvents.size(), eventChains.length, "Number of main events"); + assertEquals(eventChains.length, groupedEvents.size(), "Number of main events"); for (Map.Entry> entry : groupedEvents.entrySet()) { EventChain eventChain = eventChains[impactId++]; SnippetEvent main = entry.getValue().get(0); @@ -580,12 +580,12 @@ public class KullaTesting { } } if (((Object) eventChain.value) != IGNORE_VALUE) { - assertEquals(main.value(), eventChain.value, "Expected execution value of: " + eventChain.value + + assertEquals(eventChain.value, main.value(), "Expected execution value of: " + eventChain.value + ", but got: " + main.value()); } if (eventChain.exceptionClass != IGNORE_EXCEPTION) { if (main.exception() == null) { - assertEquals(eventChain.exceptionClass, null, "Expected an exception of class " + assertEquals(null, eventChain.exceptionClass, "Expected an exception of class " + eventChain.exceptionClass + " got no exception"); } else if (eventChain.exceptionClass == null) { fail("Expected no exception but got " + main.exception().toString()); @@ -598,7 +598,7 @@ public class KullaTesting { List diagnostics = getState().diagnostics(mainKey).collect(toList()); switch (diagMain) { case DIAG_OK: - assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); + assertEquals(0, diagnostics.size(), "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); break; case DIAG_WARNING: assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); @@ -612,7 +612,7 @@ public class KullaTesting { diagnostics = getState().diagnostics(ste.snippet()).collect(toList()); switch (diagUpdates) { case DIAG_OK: - assertEquals(diagnostics.size(), 0, "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); + assertEquals(0, diagnostics.size(), "Expected no diagnostics, got: " + diagnosticsToString(diagnostics)); break; case DIAG_WARNING: assertFalse(hasFatalError(diagnostics), "Expected no errors, got: " + diagnosticsToString(diagnostics)); @@ -627,7 +627,7 @@ public class KullaTesting { // Use this for all EMPTY calls to eval() public void assertEvalEmpty(String input) { List events = getState().eval(input); - assertEquals(events.size(), 0, "Expected no events, got: " + events.size()); + assertEquals(0, events.size(), "Expected no events, got: " + events.size()); } public VarSnippet varKey(List events) { @@ -661,7 +661,7 @@ public class KullaTesting { public void assertVarValue(Snippet key, String expected) { String value = state.varValue((VarSnippet) key); - assertEquals(value, expected, "Expected var value of: " + expected + ", but got: " + value); + assertEquals(expected, value, "Expected var value of: " + expected + ", but got: " + value); } public Snippet assertDeclareFail(String input, String expectedErrorCode) { @@ -685,7 +685,7 @@ public class KullaTesting { DiagCheck.DIAG_ERROR, DiagCheck.DIAG_IGNORE, mainInfo, updates); SnippetEvent e = events.get(0); Snippet key = e.snippet(); - assertEquals(getState().status(key), REJECTED); + assertEquals(REJECTED, getState().status(key)); List diagnostics = getState().diagnostics(e.snippet()).collect(toList()); assertTrue(diagnostics.size() > 0, "Expected diagnostics, got none"); assertDiagnostic(input, diagnostics.get(0), expectedDiagnostic); @@ -728,7 +728,7 @@ public class KullaTesting { assertDeclarationSnippet(method, expectedName, expectedStatus, METHOD_SUBKIND, unressz, othersz); String signature = method.signature(); - assertEquals(signature, expectedSignature, + assertEquals(expectedSignature, signature, "Expected " + method.source() + " to have the name: " + expectedSignature + ", got: " + signature); } @@ -740,7 +740,7 @@ public class KullaTesting { assertDeclarationSnippet(var, expectedName, expectedStatus, expectedSubKind, unressz, othersz); String signature = var.typeName(); - assertEquals(signature, expectedTypeName, + assertEquals(expectedTypeName, signature, "Expected " + var.source() + " to have the type name: " + expectedTypeName + ", got: " + signature); } @@ -751,27 +751,27 @@ public class KullaTesting { int unressz, int othersz) { assertKey(declarationKey, expectedStatus, expectedSubKind); String source = declarationKey.source(); - assertEquals(declarationKey.name(), expectedName, + assertEquals(expectedName, declarationKey.name(), "Expected " + source + " to have the name: " + expectedName + ", got: " + declarationKey.name()); long unresolved = getState().unresolvedDependencies(declarationKey).count(); - assertEquals(unresolved, unressz, "Expected " + source + " to have " + unressz + assertEquals(unressz, unresolved, "Expected " + source + " to have " + unressz + " unresolved symbols, got: " + unresolved); long otherCorralledErrorsCount = getState().diagnostics(declarationKey).count(); - assertEquals(otherCorralledErrorsCount, othersz, "Expected " + source + " to have " + othersz + assertEquals(othersz, otherCorralledErrorsCount, "Expected " + source + " to have " + othersz + " other errors, got: " + otherCorralledErrorsCount); } public void assertKey(Snippet key, Status expectedStatus, SubKind expectedSubKind) { String source = key.source(); SubKind actualSubKind = key.subKind(); - assertEquals(actualSubKind, expectedSubKind, + assertEquals(expectedSubKind, actualSubKind, "Expected " + source + " to have the subkind: " + expectedSubKind + ", got: " + actualSubKind); Status status = getState().status(key); - assertEquals(status, expectedStatus, "Expected " + source + " to be " + assertEquals(expectedStatus, status, "Expected " + source + " to be " + expectedStatus + ", but it is " + status); Snippet.Kind expectedKind = getKind(key); - assertEquals(key.kind(), expectedKind, "Checking kind: "); - assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: "); + assertEquals(expectedKind, key.kind(), "Checking kind: "); + assertEquals(expectedKind, expectedSubKind.kind(), "Checking kind: "); } public void assertDrop(Snippet key, STEInfo mainInfo, STEInfo... updates) { @@ -796,36 +796,36 @@ public class KullaTesting { public void assertAnalyze(String input, Completeness status, String source, String remaining, Boolean isComplete) { CompletionInfo ci = getAnalysis().analyzeCompletion(input); - if (status != null) assertEquals(ci.completeness(), status, "Input : " + input + ", status: "); - assertEquals(ci.source(), source, "Input : " + input + ", source: "); - if (remaining != null) assertEquals(ci.remaining(), remaining, "Input : " + input + ", remaining: "); + if (status != null) assertEquals(status, ci.completeness(), "Input : " + input + ", status: "); + assertEquals(source, ci.source(), "Input : " + input + ", source: "); + if (remaining != null) assertEquals(remaining, ci.remaining(), "Input : " + input + ", remaining: "); if (isComplete != null) { boolean isExpectedComplete = isComplete; - assertEquals(ci.completeness().isComplete(), isExpectedComplete, "Input : " + input + ", isComplete: "); + assertEquals(isExpectedComplete, ci.completeness().isComplete(), "Input : " + input + ", isComplete: "); } } public void assertNumberOfActiveVariables(int cnt) { - assertEquals(getState().variables().count(), cnt, "Variables : " + getState().variables().collect(toList())); + assertEquals(cnt, getState().variables().count(), "Variables : " + getState().variables().collect(toList())); } public void assertNumberOfActiveMethods(int cnt) { - assertEquals(getState().methods().count(), cnt, "Methods : " + getState().methods().collect(toList())); + assertEquals(cnt, getState().methods().count(), "Methods : " + getState().methods().collect(toList())); } public void assertNumberOfActiveClasses(int cnt) { - assertEquals(getState().types().count(), cnt, "Types : " + getState().types().collect(toList())); + assertEquals(cnt, getState().types().count(), "Types : " + getState().types().collect(toList())); } public void assertKeys(MemberInfo... expected) { int index = 0; List snippets = getState().snippets().collect(toList()); - assertEquals(allSnippets.size(), snippets.size()); + assertEquals(snippets.size(), allSnippets.size()); for (Snippet sn : snippets) { if (sn.kind().isPersistent() && getState().status(sn).isActive()) { MemberInfo actual = getMemberInfo(sn); MemberInfo exp = expected[index]; - assertEquals(actual, exp, String.format("Difference in #%d. Expected: %s, actual: %s", + assertEquals(exp, actual, String.format("Difference in #%d. Expected: %s, actual: %s", index, exp, actual)); ++index; } @@ -841,7 +841,7 @@ public class KullaTesting { int index = 0; for (Snippet key : getState().snippets().collect(toList())) { if (state.status(key).isActive()) { - assertEquals(expected[index], key, String.format("Difference in #%d. Expected: %s, actual: %s", index, key, expected[index])); + assertEquals(key, expected[index], String.format("Difference in #%d. Expected: %s, actual: %s", index, key, expected[index])); ++index; } } @@ -853,7 +853,7 @@ public class KullaTesting { .collect(Collectors.toSet()); Set got = snippets .collect(Collectors.toSet()); - assertEquals(active, got, label); + assertEquals(got, active, label); } public void assertVariables() { @@ -873,8 +873,8 @@ public class KullaTesting { Set got = members .map(this::getMemberInfo) .collect(Collectors.toSet()); - assertEquals(got.size(), expected.size(), "Expected : " + expected + ", actual : " + members); - assertEquals(got, expected); + assertEquals(expected.size(), got.size(), "Expected : " + expected + ", actual : " + members); + assertEquals(expected, got); } public void assertVariables(MemberInfo...expected) { @@ -892,7 +892,7 @@ public class KullaTesting { } assertNotNull(expectedInfo, "Not found method: " + methodKey.name()); int lastIndexOf = expectedInfo.type.lastIndexOf(')'); - assertEquals(methodKey.parameterTypes(), expectedInfo.type.substring(1, lastIndexOf), "Parameter types"); + assertEquals(expectedInfo.type.substring(1, lastIndexOf), methodKey.parameterTypes(), "Parameter types"); }); } @@ -906,7 +906,7 @@ public class KullaTesting { public void assertCompletion(String code, Boolean isSmart, String... expected) { List completions = computeCompletions(code, isSmart); - assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString()); + assertEquals(Arrays.asList(expected), completions, "Input: " + code + ", " + completions.toString()); } public void assertCompletionIncludesExcludes(String code, Set expected, Set notExpected) { @@ -940,7 +940,7 @@ public class KullaTesting { public void assertInferredType(String code, String expectedType) { String inferredType = getAnalysis().analyzeType(code, code.length()); - assertEquals(inferredType, expectedType, "Input: " + code + ", " + inferredType); + assertEquals(expectedType, inferredType, "Input: " + code + ", " + inferredType); } public void assertInferredFQNs(String code, String... fqns) { @@ -952,9 +952,9 @@ public class KullaTesting { QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length()); - assertEquals(candidates.getNames(), Arrays.asList(fqns), "Input: " + code + ", candidates=" + candidates.getNames()); - assertEquals(candidates.getSimpleNameLength(), simpleNameLen, "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength()); - assertEquals(candidates.isResolvable(), resolvable, "Input: " + code + ", resolvable=" + candidates.isResolvable()); + assertEquals(Arrays.asList(fqns), candidates.getNames(), "Input: " + code + ", candidates=" + candidates.getNames()); + assertEquals(simpleNameLen, candidates.getSimpleNameLength(), "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength()); + assertEquals(resolvable, candidates.isResolvable(), "Input: " + code + ", resolvable=" + candidates.isResolvable()); } protected void waitIndexingFinished() { @@ -975,7 +975,7 @@ public class KullaTesting { List documentation = getAnalysis().documentation(code, cursor, false); Set docSet = documentation.stream().map(doc -> doc.signature()).collect(Collectors.toSet()); Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); - assertEquals(docSet, expectedSet, "Input: " + code); + assertEquals(expectedSet, docSet, "Input: " + code); } public void assertJavadoc(String code, String... expected) { @@ -987,7 +987,7 @@ public class KullaTesting { .map(doc -> doc.signature() + "\n" + doc.javadoc()) .collect(Collectors.toSet()); Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); - assertEquals(docSet, expectedSet, "Input: " + code); + assertEquals(expectedSet, docSet, "Input: " + code); } public enum ClassType { @@ -1183,7 +1183,7 @@ public class KullaTesting { assertStatusMatch(ste, ste.previousStatus(), previousStatus()); assertStatusMatch(ste, ste.status(), status()); if (checkIsSignatureChange) { - assertEquals(ste.isSignatureChange(), isSignatureChange(), + assertEquals(isSignatureChange(), ste.isSignatureChange(), "Expected " + (isSignatureChange()? "" : "no ") + "signature-change, got: " + @@ -1206,10 +1206,10 @@ public class KullaTesting { assertTrue(sn != testKey, "Main-event: Expected new snippet to be != : " + testKey + "\n got-event: " + toString(ste)); - assertEquals(sn.id(), testKey.id(), "Expected IDs to match: " + testKey + ", got: " + sn + assertEquals(testKey.id(), sn.id(), "Expected IDs to match: " + testKey + ", got: " + sn + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } else { - assertEquals(sn, testKey, "Expected key to be: " + testKey + ", got: " + sn + assertEquals(testKey, sn, "Expected key to be: " + testKey + ", got: " + sn + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } } @@ -1217,7 +1217,7 @@ public class KullaTesting { private void assertStatusMatch(SnippetEvent ste, Status status, Status expected) { if (expected != null) { - assertEquals(status, expected, "Expected status to be: " + expected + ", got: " + status + + assertEquals(expected, status, "Expected status to be: " + expected + ", got: " + status + "\n expected-event: " + this + "\n got-event: " + toString(ste)); } } diff --git a/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java b/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java index 6511c9a17fb..d53081b698d 100644 --- a/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java +++ b/test/langtools/jdk/jshell/LocalExecutionClassPathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -30,12 +30,14 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JavacTask LocalExecutionTestSupport - * @run testng/othervm LocalExecutionClassPathTest + * @run junit/othervm LocalExecutionClassPathTest */ import java.util.Locale; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocalExecutionClassPathTest extends LocalExecutionTestSupport { @Override diff --git a/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java b/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java index e01ee879a8c..a4150379c75 100644 --- a/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java +++ b/test/langtools/jdk/jshell/LocalExecutionContextLoaderParentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * @build toolbox.ToolBox toolbox.JavacTask LocalExecutionTestSupport - * @run testng/othervm LocalExecutionContextLoaderParentTest + * @run junit/othervm LocalExecutionContextLoaderParentTest */ import java.io.IOException; @@ -49,12 +49,14 @@ import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControlProvider; import jdk.jshell.spi.ExecutionEnv; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeTest; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocalExecutionContextLoaderParentTest extends LocalExecutionTestSupport { - @BeforeTest + @BeforeAll public void installParentTestProvider() throws IOException { Path dir = createSubdir(classesDir, "META-INF/services"); Files.write(dir.resolve(ExecutionControlProvider.class.getName()), diff --git a/test/langtools/jdk/jshell/LocalExecutionTestSupport.java b/test/langtools/jdk/jshell/LocalExecutionTestSupport.java index 6c6e122dfa9..2eceb5a7120 100644 --- a/test/langtools/jdk/jshell/LocalExecutionTestSupport.java +++ b/test/langtools/jdk/jshell/LocalExecutionTestSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import org.testng.annotations.BeforeTest; +import org.junit.jupiter.api.BeforeAll; import toolbox.JavacTask; import toolbox.TestRunner; @@ -49,7 +49,7 @@ public class LocalExecutionTestSupport extends ReplToolTesting { protected Path classesDir; // classes directory // Install file "test/MyClass.class" in some temporary directory somewhere - @BeforeTest + @BeforeAll public void installMyClass() throws IOException { // Create directories diff --git a/test/langtools/jdk/jshell/LocalStopExecutionTest.java b/test/langtools/jdk/jshell/LocalStopExecutionTest.java index 501c5cf7df9..981fec13f04 100644 --- a/test/langtools/jdk/jshell/LocalStopExecutionTest.java +++ b/test/langtools/jdk/jshell/LocalStopExecutionTest.java @@ -27,7 +27,7 @@ * @summary Verify local execution can stop execution when there are no backward branches * @modules jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng LocalStopExecutionTest + * @run junit LocalStopExecutionTest */ import java.io.IOException; @@ -40,15 +40,13 @@ import jdk.internal.jshell.tool.StopDetectingInputStream; import jdk.internal.jshell.tool.StopDetectingInputStream.State; import jdk.jshell.JShell; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class LocalStopExecutionTest extends AbstractStopExecutionTest { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(b -> b.executionEngine("local")); diff --git a/test/langtools/jdk/jshell/MethodsTest.java b/test/langtools/jdk/jshell/MethodsTest.java index 85f63f82f77..9577f943c51 100644 --- a/test/langtools/jdk/jshell/MethodsTest.java +++ b/test/langtools/jdk/jshell/MethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456 8267221 8272135 * @summary Tests for EvaluationState.methods * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng MethodsTest + * @run junit MethodsTest */ import javax.tools.Diagnostic; @@ -34,21 +34,23 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet.Status; -import org.testng.annotations.Test; import java.util.List; import java.util.stream.Collectors; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class MethodsTest extends KullaTesting { + @Test public void noMethods() { assertNumberOfActiveMethods(0); } + @Test public void testSignature1() { MethodSnippet m1 = methodKey(assertEval("void f() { g(); }", added(RECOVERABLE_DEFINED))); assertMethodDeclSnippet(m1, "f", "()void", RECOVERABLE_DEFINED, 1, 0); @@ -58,6 +60,7 @@ public class MethodsTest extends KullaTesting { assertMethodDeclSnippet(m2, "g", "()void", VALID, 0, 0); } + @Test public void testSignature2() { MethodSnippet m1 = (MethodSnippet) assertDeclareFail("void f() { return g(); }", "compiler.err.prob.found.req"); assertMethodDeclSnippet(m1, "f", "()void", REJECTED, 0, 2); @@ -67,7 +70,8 @@ public class MethodsTest extends KullaTesting { assertMethodDeclSnippet(m2, "f", "()int", RECOVERABLE_DEFINED, 1, 0); } - @Test(enabled = false) // TODO 8081690 + @Test // TODO 8081690 + @Disabled public void testSignature3() { MethodSnippet m1 = methodKey(assertEval("void f(Bar b) { }", added(RECOVERABLE_NOT_DEFINED))); assertMethodDeclSnippet(m1, "f", "(Bar)void", RECOVERABLE_NOT_DEFINED, 1, 0); @@ -79,6 +83,7 @@ public class MethodsTest extends KullaTesting { } // 8080357 + @Test public void testNonReplUnresolved() { // internal case assertEval("class CCC {}", added(VALID)); @@ -87,6 +92,7 @@ public class MethodsTest extends KullaTesting { assertDeclareFail("void f2() { System.xxxx(); }", "compiler.err.cant.resolve.location.args"); } + @Test public void methods() { assertEval("int x() { return 10; }"); assertEval("String y() { return null; }"); @@ -95,6 +101,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodOverload() { assertEval("int m() { return 1; }"); assertEval("int m(int x) { return 2; }"); @@ -139,6 +146,7 @@ public class MethodsTest extends KullaTesting { } ***/ + @Test public void methodsRedeclaration1() { Snippet x = methodKey(assertEval("int x() { return 10; }")); Snippet y = methodKey(assertEval("String y() { return \"\"; }")); @@ -158,6 +166,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsRedeclaration2() { assertEval("int a() { return 1; }"); assertMethods(method("()int", "a")); @@ -179,6 +188,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsRedeclaration3() { Snippet x = methodKey(assertEval("int x(Object...a) { return 10; }")); assertMethods(method("(Object...)int", "x")); @@ -192,6 +202,7 @@ public class MethodsTest extends KullaTesting { } + @Test public void methodsRedeclaration4() { Snippet a = methodKey(assertEval("int foo(int a) { return a; }")); assertEval("int x = foo(10);"); @@ -204,6 +215,7 @@ public class MethodsTest extends KullaTesting { } // 8199762 + @Test public void methodsRedeclaration5() { Snippet m1 = methodKey(assertEval("int m(Object o) { return 10; }")); assertMethods(method("(Object)int", "m")); @@ -220,22 +232,23 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsAbstract() { MethodSnippet m1 = methodKey(assertEval("abstract String f();", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); - assertEquals(getState().unresolvedDependencies(m1).collect(Collectors.toList()), - List.of("method f()")); + assertEquals( List.of("method f()"), getState().unresolvedDependencies(m1).collect(Collectors.toList())); MethodSnippet m2 = methodKey(assertEval("abstract int mm(Blah b);", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null))); List unr = getState().unresolvedDependencies(m2).collect(Collectors.toList()); - assertEquals(unr.size(), 2); + assertEquals(2, unr.size()); unr.remove("class Blah"); unr.remove("method mm(Blah)"); - assertEquals(unr.size(), 0, "unexpected entry: " + unr); + assertEquals(0, unr.size(), "unexpected entry: " + unr); assertNumberOfActiveMethods(2); assertActiveKeys(); } + @Test public void methodsErrors() { assertDeclareFail("String f();", new ExpectedDiagnostic("compiler.err.missing.meth.body.or.decl.abstract", 0, 11, 7, -1, -1, Diagnostic.Kind.ERROR)); @@ -267,6 +280,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void objectMethodNamedMethodsErrors() { assertDeclareFail("boolean equals(double d1, double d2) { return d1 == d2; }", new ExpectedDiagnostic("jdk.eval.error.object.method", 8, 14, 8, -1, -1, Diagnostic.Kind.ERROR)); @@ -286,6 +300,7 @@ public class MethodsTest extends KullaTesting { } + @Test public void methodsAccessModifierIgnored() { Snippet f = methodKey(assertEval("public String f() {return null;}", added(VALID))); @@ -305,6 +320,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodsIgnoredModifiers() { Snippet f = methodKey(assertEval("static String f() {return null;}")); assertNumberOfActiveMethods(1); @@ -318,6 +334,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void methodSignatureUnresolved() { MethodSnippet key = (MethodSnippet) methodKey(assertEval("und m() { return new und(); }", added(RECOVERABLE_NOT_DEFINED))); assertMethodDeclSnippet(key, "m", "()und", RECOVERABLE_NOT_DEFINED, 1, 0); @@ -330,7 +347,8 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void classMethodsAreNotVisible() { assertEval( "class A {" + @@ -351,6 +369,7 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + @Test public void lambdas() { assertEval("class Inner1 implements Runnable {" + "public Runnable lambda1 = () -> {};" + @@ -376,15 +395,17 @@ public class MethodsTest extends KullaTesting { } //JDK-8267221: + @Test public void testMethodArrayParameters() { MethodSnippet m1 = methodKey(assertEval("void m1(int... p) { }", added(VALID))); - assertEquals(m1.parameterTypes(), "int..."); + assertEquals("int...", m1.parameterTypes()); MethodSnippet m2 = methodKey(assertEval("void m2(int[]... p) { }", added(VALID))); - assertEquals(m2.parameterTypes(), "int[]..."); + assertEquals("int[]...", m2.parameterTypes()); MethodSnippet m3 = methodKey(assertEval("void m3(int[][] p) { }", added(VALID))); - assertEquals(m3.parameterTypes(), "int[][]"); + assertEquals("int[][]", m3.parameterTypes()); } + @Test public void testOverloadCalls() { MethodSnippet orig = methodKey(assertEval("int m(String s) { return 0; }")); MethodSnippet overload = methodKey(assertEval("int m(int i) { return 1; }")); diff --git a/test/langtools/jdk/jshell/ModifiersTest.java b/test/langtools/jdk/jshell/ModifiersTest.java index 2cbebc8b5b8..2cdb5ce28b6 100644 --- a/test/langtools/jdk/jshell/ModifiersTest.java +++ b/test/langtools/jdk/jshell/ModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8167643 8129559 8247456 * @summary Tests for modifiers * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng ModifiersTest + * @run junit ModifiersTest */ import java.util.ArrayList; @@ -34,13 +34,14 @@ import java.util.List; import java.util.function.Consumer; import javax.tools.Diagnostic; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ModifiersTest extends KullaTesting { - @DataProvider(name = "ignoredModifiers") public Object[][] getTestCases() { List testCases = new ArrayList<>(); String[] ignoredModifiers = new String[] { @@ -77,7 +78,8 @@ public class ModifiersTest extends KullaTesting { return testCases.toArray(new Object[testCases.size()][]); } - @Test(dataProvider = "ignoredModifiers") + @ParameterizedTest + @MethodSource("getTestCases") public void ignoredModifiers(String modifier, ClassType classType, Consumer eval, String preface, String context) { if (context != null) { @@ -95,6 +97,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticFieldsOfClass() { assertEval("class A {" + "int x = 14;" + @@ -108,6 +111,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticMethodsOfClass() { assertEval("class A {" + "void x() {}" + @@ -119,6 +123,7 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticFieldsOfInterface() { assertEval("interface A {" + "int x = 14;" + @@ -134,12 +139,14 @@ public class ModifiersTest extends KullaTesting { assertActiveKeys(); } + @Test public void accessToStaticMethodsOfInterface() { assertEval("interface A { static void x() {} }"); assertEval("A.x();"); assertActiveKeys(); } + @Test public void finalMethod() { assertEval("class A { final void f() {} }"); assertDeclareFail("class B extends A { void f() {} }", @@ -148,6 +155,7 @@ public class ModifiersTest extends KullaTesting { } //TODO: is this the right semantics? + @Test public void finalConstructor() { assertDeclareFail("class A { final A() {} }", new ExpectedDiagnostic("compiler.err.mod.not.allowed.here", 10, 22, 16, -1, -1, Diagnostic.Kind.ERROR)); @@ -155,6 +163,7 @@ public class ModifiersTest extends KullaTesting { } //TODO: is this the right semantics? + @Test public void finalDefaultMethod() { assertDeclareFail("interface A { final default void a() {} }", new ExpectedDiagnostic("compiler.err.mod.not.allowed.here", 14, 39, 33, -1, -1, Diagnostic.Kind.ERROR)); diff --git a/test/langtools/jdk/jshell/MultipleDocumentationTest.java b/test/langtools/jdk/jshell/MultipleDocumentationTest.java index 8037381ccc8..d7894212016 100644 --- a/test/langtools/jdk/jshell/MultipleDocumentationTest.java +++ b/test/langtools/jdk/jshell/MultipleDocumentationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -26,8 +26,8 @@ import java.io.PrintStream; import java.util.List; import java.util.stream.Collectors; import jdk.jshell.JShell; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /* * @test @@ -39,11 +39,11 @@ import static org.testng.Assert.assertEquals; * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build Compiler toolbox.ToolBox - * @run testng MultipleDocumentationTest + * @run junit MultipleDocumentationTest */ -@Test public class MultipleDocumentationTest { + @Test public void testMultipleDocumentation() { String input = "java.lang.String"; @@ -68,7 +68,7 @@ public class MultipleDocumentationTest { .map(d -> d.javadoc()) .collect(Collectors.toList()); - assertEquals(javadocs2, javadocs1); + assertEquals(javadocs1, javadocs2); } } } diff --git a/test/langtools/jdk/jshell/MyExecutionControl.java b/test/langtools/jdk/jshell/MyExecutionControl.java index 8493638db57..12a0ac6986d 100644 --- a/test/langtools/jdk/jshell/MyExecutionControl.java +++ b/test/langtools/jdk/jshell/MyExecutionControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -42,7 +42,7 @@ import jdk.jshell.execution.Util; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl.EngineTerminationException; import jdk.jshell.spi.ExecutionEnv; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import static jdk.jshell.execution.Util.remoteInputOutput; class MyExecutionControl extends JdiExecutionControl { diff --git a/test/langtools/jdk/jshell/NullTest.java b/test/langtools/jdk/jshell/NullTest.java index b365b5155f8..c4759aca87f 100644 --- a/test/langtools/jdk/jshell/NullTest.java +++ b/test/langtools/jdk/jshell/NullTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -25,14 +25,14 @@ * @test * @summary null test * @build KullaTesting TestingInputStream - * @run testng NullTest + * @run junit NullTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class NullTest extends KullaTesting { + @Test public void testNull() { assertEval("null;", "null"); assertEval("(Object)null;", "null"); diff --git a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java index 8ec8ded1741..350a6659c52 100644 --- a/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java +++ b/test/langtools/jdk/jshell/PasteAndMeasurementsUITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -38,7 +38,7 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build PasteAndMeasurementsUITest - * @run testng/othervm PasteAndMeasurementsUITest + * @run junit/othervm PasteAndMeasurementsUITest */ import java.io.Console; @@ -46,15 +46,15 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import jdk.internal.org.jline.reader.impl.LineReaderImpl; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class PasteAndMeasurementsUITest extends UITesting { public PasteAndMeasurementsUITest() { super(true); } + @Test public void testPrevNextSnippet() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); @@ -77,6 +77,7 @@ public class PasteAndMeasurementsUITest extends UITesting { } private static final String LOC = "\033[12;1R"; + @Test public void testBracketedPaste() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); @@ -91,6 +92,7 @@ public class PasteAndMeasurementsUITest extends UITesting { }); } + @Test public void testBracketedPasteNonAscii() throws Exception { Field cons = System.class.getDeclaredField("cons"); cons.setAccessible(true); diff --git a/test/langtools/jdk/jshell/PipeInputStreamTest.java b/test/langtools/jdk/jshell/PipeInputStreamTest.java index 867a1f254a4..0062c6006e1 100644 --- a/test/langtools/jdk/jshell/PipeInputStreamTest.java +++ b/test/langtools/jdk/jshell/PipeInputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @summary Verify PipeInputStream works. * @modules jdk.compiler/com.sun.tools.javac.util * jdk.jshell/jdk.jshell.execution.impl:open - * @run testng PipeInputStreamTest + * @run junit PipeInputStreamTest */ import java.io.InputStream; @@ -34,28 +34,28 @@ import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import org.testng.annotations.Test; import com.sun.tools.javac.util.Pair; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class PipeInputStreamTest { + @Test public void testReadArrayNotBlocking() throws Exception { Pair streams = createPipeStream(); InputStream in = streams.fst; OutputStream out = streams.snd; out.write('a'); byte[] data = new byte[12]; - assertEquals(in.read(data), 1); - assertEquals(data[0], 'a'); + assertEquals(1, in.read(data)); + assertEquals('a', data[0]); out.write('a'); out.write('b'); out.write('c'); - assertEquals(in.read(data), 3); - assertEquals(data[0], 'a'); - assertEquals(data[1], 'b'); - assertEquals(data[2], 'c'); + assertEquals(3, in.read(data)); + assertEquals('a', data[0]); + assertEquals('b', data[1]); + assertEquals('c', data[2]); } private Pair createPipeStream() throws Exception { diff --git a/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java b/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java index f967b14d280..4d59e11e38b 100644 --- a/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java +++ b/test/langtools/jdk/jshell/PrimitiveInstanceOfTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -25,42 +25,46 @@ * @bug 8304487 8325257 * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) * @build KullaTesting TestingInputStream - * @run testng PrimitiveInstanceOfTest + * @run junit PrimitiveInstanceOfTest */ import jdk.jshell.JShell; -import org.testng.annotations.Test; import java.util.function.Consumer; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class PrimitiveInstanceOfTest extends KullaTesting { + @Test public void testInstanceOf() { assertEval("int i = 42;"); assertEval("i instanceof Integer"); assertEval("i instanceof int"); } + @Test public void testInstanceOfRef() { assertEval("Integer i = 42;"); assertEval("i instanceof Integer"); assertEval("i instanceof Number"); } + @Test public void testInstanceOfObjectToPrimitive() { assertEval("Object o = 1L;"); assertEval("o instanceof long"); assertEval("o instanceof Long"); } + @Test public void testInstanceOfPrimitiveToPrimitiveInvokingExactnessMethod() { assertEval("int b = 1024;"); assertEval("b instanceof byte"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/RecordsTest.java b/test/langtools/jdk/jshell/RecordsTest.java index 69aaae8e46f..fdf75aed3ab 100644 --- a/test/langtools/jdk/jshell/RecordsTest.java +++ b/test/langtools/jdk/jshell/RecordsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -27,27 +27,27 @@ * @summary Tests for evalution of records * @modules jdk.jshell * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng RecordsTest + * @run junit RecordsTest */ -import org.testng.annotations.Test; import javax.lang.model.SourceVersion; import jdk.jshell.Snippet.Status; import jdk.jshell.UnresolvedReferenceException; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -@Test public class RecordsTest extends KullaTesting { + @Test public void testRecordClass() { assertEval("record R(String s, int i) { }"); - assertEquals(varKey(assertEval("R r = new R(\"r\", 42);")).name(), "r"); + assertEquals("r", varKey(assertEval("R r = new R(\"r\", 42);")).name()); assertEval("r.s()", "\"r\""); assertEval("r.i()", "42"); } + @Test public void testRecordCorralling() { //simple record with a mistake that can be fixed by corralling: assertEval("record R1(int i) { int g() { return j; } }", ste(MAIN_SNIPPET, Status.NONEXISTENT, Status.RECOVERABLE_DEFINED, true, null)); @@ -66,13 +66,15 @@ public class RecordsTest extends KullaTesting { assertEval("R5 r5 = new R5(1);", null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, added(Status.VALID)); } + @Test public void testRecordField() { - assertEquals(varKey(assertEval("String record = \"\";")).name(), "record"); + assertEquals("record", varKey(assertEval("String record = \"\";")).name()); assertEval("record.length()", "0"); } + @Test public void testRecordMethod() { - assertEquals(methodKey(assertEval("String record(String record) { return record + record; }")).name(), "record"); + assertEquals("record", methodKey(assertEval("String record(String record) { return record + record; }")).name()); assertEval("record(\"r\")", "\"rr\""); assertEval("record(\"r\").length()", "2"); } diff --git a/test/langtools/jdk/jshell/RejectedFailedTest.java b/test/langtools/jdk/jshell/RejectedFailedTest.java index 5411d5d8aee..5e97a03d399 100644 --- a/test/langtools/jdk/jshell/RejectedFailedTest.java +++ b/test/langtools/jdk/jshell/RejectedFailedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,13 +25,12 @@ * @test 8080352 * @summary Tests for hard errors, like syntax errors * @build KullaTesting - * @run testng RejectedFailedTest + * @run junit RejectedFailedTest */ import java.util.List; import jdk.jshell.Snippet.SubKind; -import org.testng.annotations.Test; import jdk.jshell.Diag; import jdk.jshell.Snippet; @@ -40,31 +39,31 @@ import jdk.jshell.Snippet.Status; import jdk.jshell.SnippetEvent; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class RejectedFailedTest extends KullaTesting { private String bad(String input, Kind kind, String prevId) { List events = assertEvalFail(input); - assertEquals(events.size(), 1, "Expected one event, got: " + events.size()); + assertEquals(1, events.size(), "Expected one event, got: " + events.size()); SnippetEvent e = events.get(0); List diagnostics = getState().diagnostics(e.snippet()).collect(toList()); assertTrue(diagnostics.size() > 0, "Expected diagnostics, got none"); - assertEquals(e.exception(), null, "Expected exception to be null."); - assertEquals(e.value(), null, "Expected value to be null."); + assertEquals(null, e.exception(), "Expected exception to be null."); + assertEquals(null, e.value(), "Expected value to be null."); Snippet key = e.snippet(); assertTrue(key != null, "key must be non-null, but was null."); - assertEquals(key.kind(), kind, "Expected kind: " + kind + ", got: " + key.kind()); + assertEquals(kind, key.kind(), "Expected kind: " + kind + ", got: " + key.kind()); SubKind expectedSubKind = kind == Kind.ERRONEOUS ? SubKind.UNKNOWN_SUBKIND : SubKind.METHOD_SUBKIND; - assertEquals(key.subKind(), expectedSubKind, "SubKind: "); + assertEquals(expectedSubKind, key.subKind(), "SubKind: "); assertTrue(key.id().compareTo(prevId) > 0, "Current id: " + key.id() + ", previous: " + prevId); - assertEquals(getState().diagnostics(key).collect(toList()), diagnostics, "Expected retrieved diagnostics to match, but didn't."); - assertEquals(key.source(), input, "Expected retrieved source: " + + assertEquals(diagnostics, getState().diagnostics(key).collect(toList()), "Expected retrieved diagnostics to match, but didn't."); + assertEquals(input, key.source(), "Expected retrieved source: " + key.source() + " to match input: " + input); - assertEquals(getState().status(key), Status.REJECTED, "Expected status of REJECTED, got: " + getState().status(key)); + assertEquals(Status.REJECTED, getState().status(key), "Expected status of REJECTED, got: " + getState().status(key)); return key.id(); } @@ -75,6 +74,7 @@ public class RejectedFailedTest extends KullaTesting { } } + @Test public void testErroneous() { String[] inputsErroneous = { "%&^%&", @@ -86,6 +86,7 @@ public class RejectedFailedTest extends KullaTesting { checkByKind(inputsErroneous, Kind.ERRONEOUS); } + @Test public void testBadMethod() { String[] inputsMethod = { "transient int m() { return x; }", diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index 5ca010af3c2..429a0a7ce02 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -46,14 +46,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.BeforeMethod; import jdk.jshell.tool.JavaShellToolBuilder; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; public class ReplToolTesting { @@ -132,7 +132,7 @@ public class ReplToolTesting { .filter(l -> !l.isEmpty()) .collect(Collectors.toList()); int previousId = Integer.MIN_VALUE; - assertEquals(lines.size(), keys.size(), "Number of keys"); + assertEquals(keys.size(), lines.size(), "Number of keys"); for (int i = 0; i < lines.size(); ++i) { String line = lines.get(i); Matcher matcher = idPattern.matcher(line); @@ -155,7 +155,7 @@ public class ReplToolTesting { .filter(l -> !l.isEmpty()) .filter(l -> !l.startsWith("| ")) // error/unresolved info .collect(Collectors.toList()); - assertEquals(lines.size(), set.size(), message + " : expected: " + set.keySet() + "\ngot:\n" + lines); + assertEquals(set.size(), lines.size(), message + " : expected: " + set.keySet() + "\ngot:\n" + lines); for (String line : lines) { Matcher matcher = extractPattern.matcher(line); assertTrue(matcher.find(), line); @@ -271,7 +271,7 @@ public class ReplToolTesting { } } - @BeforeMethod + @BeforeEach public void setUp() { prefsMap = new HashMap<>(); prefsMap.put("INDENT", "0"); @@ -331,8 +331,7 @@ public class ReplToolTesting { String ueos = getUserErrorOutput(); assertTrue((cos.isEmpty() || cos.startsWith("| Goodbye") || !locale.equals(Locale.ROOT)), "Expected a goodbye, but got: " + cos); - assertEquals(ceos, - expectedErrorOutput, + assertEquals( expectedErrorOutput, ceos, "Expected \"" + expectedErrorOutput + "\" command error output, got: \"" + ceos + "\""); assertTrue(uos.isEmpty(), "Expected empty user output, got: " + uos); @@ -563,7 +562,7 @@ public class ReplToolTesting { public void assertOutput(String got, String expected, String display) { if (expected != null) { - assertEquals(got, expected, display + ".\n"); + assertEquals(expected, got, display + ".\n"); } } diff --git a/test/langtools/jdk/jshell/ReplaceTest.java b/test/langtools/jdk/jshell/ReplaceTest.java index e4c2c8575c0..02ebb27fcb9 100644 --- a/test/langtools/jdk/jshell/ReplaceTest.java +++ b/test/langtools/jdk/jshell/ReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8080069 8152925 * @summary Test of Snippet redefinition and replacement. * @build KullaTesting TestingInputStream - * @run testng ReplaceTest + * @run junit ReplaceTest */ import java.util.Iterator; @@ -34,16 +34,16 @@ import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertFalse; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ReplaceTest extends KullaTesting { + @Test public void testRedefine() { Snippet vx = varKey(assertEval("int x;")); Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); @@ -69,6 +69,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToVar() { Snippet oldA = classKey(assertEval("class A { public String toString() { return \"old\"; } }")); Snippet v = varKey(assertEval("A a = new A();", "old")); @@ -92,6 +93,7 @@ public class ReplaceTest extends KullaTesting { assertFalse(it.hasNext(), "expected exactly one"); } + @Test public void testReplaceVarToMethod() { Snippet x = varKey(assertEval("int x;")); MethodSnippet musn = methodKey(assertEval("double mu() { return x * 4; }")); @@ -106,6 +108,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceMethodToMethod() { Snippet a = methodKey(assertEval("double a() { return 2; }")); Snippet b = methodKey(assertEval("double b() { return a() * 10; }")); @@ -119,6 +122,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToMethod() { Snippet c = classKey(assertEval("class C { int f() { return 7; } }")); Snippet m = methodKey(assertEval("int m() { return new C().f(); }")); @@ -130,6 +134,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceVarToClass() { Snippet x = varKey(assertEval("int x;")); TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x; }")); @@ -144,6 +149,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceMethodToClass() { Snippet x = methodKey(assertEval("int x() { return 0; }")); TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x(); }")); @@ -159,6 +165,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testReplaceClassToClass() { TypeDeclSnippet a = classKey(assertEval("class A {}")); assertTypeDeclSnippet(a, "A", VALID, CLASS_SUBKIND, 0, 0); @@ -178,6 +185,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testOverwriteReplaceMethod() { MethodSnippet k1 = methodKey(assertEval("String m(Integer i) { return i.toString(); }")); MethodSnippet k2 = methodKey(assertEval("String m(java.lang.Integer i) { return \"java.lang.\" + i.toString(); }", @@ -193,6 +201,7 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } + @Test public void testImportDeclare() { Snippet singleImport = importKey(assertEval("import java.util.List;", added(VALID))); Snippet importOnDemand = importKey(assertEval("import java.util.*;", added(VALID))); @@ -213,7 +222,8 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8129420 + @Test // TODO 8129420 + @Disabled public void testLocalClassEvolve() { Snippet j = methodKey(assertEval("Object j() { return null; }", added(VALID))); assertEval("Object j() { class B {}; return null; }", @@ -227,6 +237,7 @@ public class ReplaceTest extends KullaTesting { assertEval("j();", "Yep"); } + @Test public void testReplaceCausesMethodReferenceError() { Snippet l = classKey(assertEval("interface Logger { public void log(String message); }", added(VALID))); Snippet v = varKey(assertEval("Logger l = System.out::println;", added(VALID))); @@ -238,6 +249,7 @@ public class ReplaceTest extends KullaTesting { ste(v, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); } + @Test public void testReplaceCausesClassCompilationError() { Snippet l = classKey(assertEval("interface L { }", added(VALID))); Snippet c = classKey(assertEval("class C implements L { }", added(VALID))); @@ -249,6 +261,7 @@ public class ReplaceTest extends KullaTesting { ste(c, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); } + @Test public void testOverwriteNoUpdate() { String xsi = "int x = 5;"; String xsd = "double x = 3.14159;"; diff --git a/test/langtools/jdk/jshell/SealedClassesTest.java b/test/langtools/jdk/jshell/SealedClassesTest.java index ba4f8c8f008..c45bc767769 100644 --- a/test/langtools/jdk/jshell/SealedClassesTest.java +++ b/test/langtools/jdk/jshell/SealedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -27,7 +27,7 @@ * @summary Test sealed class in jshell * @modules jdk.jshell * @build KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng SealedClassesTest + * @run junit SealedClassesTest */ import javax.lang.model.SourceVersion; @@ -35,14 +35,13 @@ import javax.lang.model.SourceVersion; import jdk.jshell.TypeDeclSnippet; import jdk.jshell.Snippet.Status; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class SealedClassesTest extends KullaTesting { + @Test public void testSealed() { TypeDeclSnippet base = classKey( assertEval("sealed class B permits I {}", @@ -53,6 +52,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new I()"); } + @Test public void testInterface() { TypeDeclSnippet base = classKey( assertEval("sealed interface I permits C {}", @@ -63,6 +63,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new C()"); } + @Test public void testNonSealed() { TypeDeclSnippet base = classKey( assertEval("sealed class B permits I {}", @@ -74,6 +75,7 @@ public class SealedClassesTest extends KullaTesting { assertEval("new I2()"); } + @Test public void testNonSealedInterface() { TypeDeclSnippet base = classKey( assertEval("sealed interface B permits C {}", diff --git a/test/langtools/jdk/jshell/ShutdownTest.java b/test/langtools/jdk/jshell/ShutdownTest.java index d97b83950cc..9b68ab6f46b 100644 --- a/test/langtools/jdk/jshell/ShutdownTest.java +++ b/test/langtools/jdk/jshell/ShutdownTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @summary Shutdown tests * @build KullaTesting TestingInputStream - * @run testng ShutdownTest + * @run junit ShutdownTest */ import java.io.IOException; @@ -37,11 +37,13 @@ import java.util.function.Consumer; import jdk.jshell.JShell; import jdk.jshell.JShell.Subscription; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; public class ShutdownTest extends KullaTesting { @@ -51,12 +53,13 @@ public class ShutdownTest extends KullaTesting { ++shutdownCount; } - @Test(enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testExit() { shutdownCount = 0; getState().onShutdown(this::shutdownCounter); assertEval("System.exit(1);"); - assertEquals(shutdownCount, 1); + assertEquals(1, shutdownCount); } @Test @@ -64,7 +67,7 @@ public class ShutdownTest extends KullaTesting { shutdownCount = 0; getState().onShutdown(this::shutdownCounter); getState().close(); - assertEquals(shutdownCount, 1); + assertEquals(1, shutdownCount); } @Test @@ -73,7 +76,7 @@ public class ShutdownTest extends KullaTesting { Subscription token = getState().onShutdown(this::shutdownCounter); getState().unsubscribe(token); getState().close(); - assertEquals(shutdownCount, 0); + assertEquals(0, shutdownCount); } @Test @@ -85,46 +88,56 @@ public class ShutdownTest extends KullaTesting { getState().unsubscribe(subscription1); getState().close(); - assertEquals(listener1.getEvents(), 0, "Checking got events"); - assertEquals(listener2.getEvents(), 1, "Checking got events"); + assertEquals(0, listener1.getEvents(), "Checking got events"); + assertEquals(1, listener2.getEvents(), "Checking got events"); getState().close(); - assertEquals(listener1.getEvents(), 0, "Checking got events"); - assertEquals(listener2.getEvents(), 1, "Checking got events"); + assertEquals(0, listener1.getEvents(), "Checking got events"); + assertEquals(1, listener2.getEvents(), "Checking got events"); getState().unsubscribe(subscription2); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testCloseException() { - getState().close(); - getState().eval("45"); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().eval("45"); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testShutdownException() { - assertEval("System.exit(0);"); - getState().eval("45"); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().eval("45"); + }); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCallback() { - getState().onShutdown(null); + Assertions.assertThrows(NullPointerException.class, () -> { + getState().onShutdown(null); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testSubscriptionAfterClose() { - getState().close(); - getState().onShutdown(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().onShutdown(e -> {}); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testSubscriptionAfterShutdown() { - assertEval("System.exit(0);"); - getState().onShutdown(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().onShutdown(e -> {}); + }); } @Test @@ -150,13 +163,13 @@ public class ShutdownTest extends KullaTesting { private Method currentTestMethod; - @BeforeMethod - public void setUp(Method testMethod) { - currentTestMethod = testMethod; + @BeforeEach + public void setUp(TestInfo testInfo) { + currentTestMethod = testInfo.getTestMethod().orElseThrow(); super.setUp(); } - @BeforeMethod + @BeforeEach public void setUp() { } diff --git a/test/langtools/jdk/jshell/SimpleRegressionTest.java b/test/langtools/jdk/jshell/SimpleRegressionTest.java index 1e347cfd207..4cd7c8b71eb 100644 --- a/test/langtools/jdk/jshell/SimpleRegressionTest.java +++ b/test/langtools/jdk/jshell/SimpleRegressionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test 8130450 8158906 8154374 8166400 8171892 8173807 8173848 8282434 * @summary simple regression test * @build KullaTesting TestingInputStream - * @run testng SimpleRegressionTest + * @run junit SimpleRegressionTest */ @@ -36,53 +36,56 @@ import javax.tools.Diagnostic; import jdk.jshell.Snippet; import jdk.jshell.VarSnippet; import jdk.jshell.SnippetEvent; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND; import static jdk.jshell.Snippet.Status.VALID; -import org.testng.annotations.BeforeMethod; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class SimpleRegressionTest extends KullaTesting { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } + @Test public void testSnippetMemberAssignment() { assertEval("class C { int y; }"); assertEval("C c = new C();"); assertVarKeyMatch("c.y = 4;", true, "$1", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testUserTakesTempVarName() { assertEval("int $2 = 4;"); assertEval("String $1;"); assertVarKeyMatch("1234;", true, "$3", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testCompileThrow() { assertEvalException("throw new Exception();"); } + @Test public void testMultiSnippetDependencies() { List events = assertEval("int a = 3, b = a+a, c = b *100;", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(VALID)), chain(added(VALID)), chain(added(VALID))); - assertEquals(events.get(0).value(), "3"); - assertEquals(events.get(1).value(), "6"); - assertEquals(events.get(2).value(), "600"); + assertEquals("3", events.get(0).value()); + assertEquals("6", events.get(1).value()); + assertEquals("600", events.get(2).value()); assertEval("c;", "600"); } + @Test public void testLessThanParsing() { assertEval("int x = 3;", "3"); assertEval("int y = 4;", "4"); @@ -92,18 +95,22 @@ public class SimpleRegressionTest extends KullaTesting { assertEval("x < y && y < z", "true"); } + @Test public void testNotStmtCannotResolve() { assertDeclareFail("dfasder;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 7, 0, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testNotStmtIncomparable() { assertDeclareFail("true == 5.0;", new ExpectedDiagnostic("compiler.err.incomparable.types", 0, 11, 5, -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void testStringAdd() { assertEval("String s = \"a\" + \"b\";", "\"ab\""); } + @Test public void testExprSanity() { assertEval("int x = 3;", "3"); assertEval("int y = 4;", "4"); @@ -111,13 +118,15 @@ public class SimpleRegressionTest extends KullaTesting { assertActiveKeys(); } + @Test public void testGenericMethodCrash() { assertDeclareWarn1(" void f(T...a) {}", (ExpectedDiagnostic) null); Snippet sn = methodKey(assertEval(" R n(R x) { return x; }", added(VALID))); VarSnippet sne = varKey(assertEval("n(5)", added(VALID))); - assertEquals(sne.typeName(), "Integer"); + assertEquals("Integer", sne.typeName()); } + @Test public void testLongRemoteStrings() { //8158906 assertEval("String m(int x) { byte[] b = new byte[x]; for (int i = 0; i < x; ++i) b[i] = (byte) 'a'; return new String(b); }"); boolean[] shut = new boolean[1]; @@ -127,12 +136,13 @@ public class SimpleRegressionTest extends KullaTesting { for (String len : new String[]{"12345", "64000", "65535", "65536", "120000"}) { List el = assertEval("m(" + len + ");"); assertFalse(shut[0], "JShell died with long string"); - assertEquals(el.size(), 1, "Excepted one event"); + assertEquals(1, el.size(), "Excepted one event"); assertTrue(el.get(0).value().length() > 10000, "Expected truncated but long String, got: " + el.get(0).value().length()); } } + @Test public void testLongRemoteJapaneseStrings() { //8158906 assertEval("import java.util.stream.*;"); assertEval("String m(int x) { return Stream.generate(() -> \"\u3042\").limit(x).collect(Collectors.joining()); }"); @@ -143,13 +153,14 @@ public class SimpleRegressionTest extends KullaTesting { for (String len : new String[]{"12345", "21843", "21844", "21845", "21846", "64000", "65535", "65536", "120000"}) { List el = assertEval("m(" + len + ");"); assertFalse(shut[0], "JShell died with long string"); - assertEquals(el.size(), 1, "Excepted one event"); + assertEquals(1, el.size(), "Excepted one event"); assertTrue(el.get(0).value().length() > 10000, "Expected truncated but long String, got: " + el.get(0).value().length()); } } // 8130450 + @Test public void testDuplicate() { Snippet snm = methodKey(assertEval("void mm() {}", added(VALID))); assertEval("void mm() {}", @@ -161,11 +172,13 @@ public class SimpleRegressionTest extends KullaTesting { ste(snv, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); } + @Test public void testContextClassLoader() { assertEval("class C {}"); assertEval("C.class.getClassLoader() == Thread.currentThread().getContextClassLoader()", "true"); } + @Test public void testArrayRepresentation() { assertEval("new int[4]", "int[4] { 0, 0, 0, 0 }"); assertEval("new int[0]", "int[0] { }"); @@ -183,6 +196,7 @@ public class SimpleRegressionTest extends KullaTesting { "Object[3] { \"howdy\", int[3] { 33, 44, 55 }, String[2] { \"up\", \"down\" } }"); } + @Test public void testMultiDimArrayRepresentation() { assertEval("new int[3][1]", "int[3][] { int[1] { 0 }, int[1] { 0 }, int[1] { 0 } }"); @@ -199,6 +213,7 @@ public class SimpleRegressionTest extends KullaTesting { "boolean[2][][] { boolean[1][] { boolean[3] { false, false, false } }, boolean[1][] { boolean[3] { false, false, false } } }"); } + @Test public void testStringRepresentation() { assertEval("\"A!\\rB!\"", "\"A!\\rB!\""); @@ -220,6 +235,7 @@ public class SimpleRegressionTest extends KullaTesting { "\"a\u032Ea\""); } + @Test public void testCharRepresentation() { for (String s : new String[]{"'A'", "'Z'", "'0'", "'9'", "'a'", "'z'", "'*'", "'%'", diff --git a/test/langtools/jdk/jshell/SnippetEventToStringTest.java b/test/langtools/jdk/jshell/SnippetEventToStringTest.java index 7d2de387951..7dacafe93d2 100644 --- a/test/langtools/jdk/jshell/SnippetEventToStringTest.java +++ b/test/langtools/jdk/jshell/SnippetEventToStringTest.java @@ -25,7 +25,7 @@ * @test * @bug 8350808 * @summary Check for proper formatting of SnippetEvent.toString() - * @run testng SnippetEventToStringTest + * @run junit SnippetEventToStringTest */ import java.util.Map; @@ -35,13 +35,14 @@ import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.execution.LocalExecutionControlProvider; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SnippetEventToStringTest { - @DataProvider(name = "cases") public String[][] sourceLevels() { return new String[][] { { "*", ",causeSnippet=null" }, @@ -50,11 +51,12 @@ public class SnippetEventToStringTest { }; } - @Test(dataProvider = "cases") - private void verifySnippetEvent(String source, String match) { + @ParameterizedTest + @MethodSource("sourceLevels") + void verifySnippetEvent(String source, String match) { try (JShell jsh = JShell.builder().executionEngine(new LocalExecutionControlProvider(), Map.of()).build()) { List result = jsh.eval(source); - assertEquals(result.size(), 1); + assertEquals(1, result.size()); String string = result.get(0).toString(); if (!string.contains(match)) throw new AssertionError(String.format("\"%s\" not found in \"%s\"", match, string)); diff --git a/test/langtools/jdk/jshell/SnippetHighlightTest.java b/test/langtools/jdk/jshell/SnippetHighlightTest.java index 902d4347f74..dbf3418af83 100644 --- a/test/langtools/jdk/jshell/SnippetHighlightTest.java +++ b/test/langtools/jdk/jshell/SnippetHighlightTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -32,22 +32,22 @@ * jdk.jshell/jdk.jshell:open * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng SnippetHighlightTest + * @run junit SnippetHighlightTest */ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import org.testng.annotations.Test; import jdk.jshell.SourceCodeAnalysis.Highlight; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; -@Test public class SnippetHighlightTest extends KullaTesting { + @Test public void testMemberExpr() { assertEval("@Deprecated class TestClass { }"); assertEval("class TestConstructor { @Deprecated TestConstructor() {} }"); @@ -99,6 +99,7 @@ public class SnippetHighlightTest extends KullaTesting { "Highlight[start=5, end=11, attributes=[DECLARATION]]"); } + @Test public void testClassErrorRecovery() { //JDK-8301580 assertHighlights(""" class C { @@ -114,6 +115,7 @@ public class SnippetHighlightTest extends KullaTesting { "Highlight[start=32, end=38, attributes=[KEYWORD]]"); } + @Test public void testNoCrashOnLexicalErrors() { //JDK-8359497 assertHighlights(""" " @@ -122,7 +124,7 @@ public class SnippetHighlightTest extends KullaTesting { private void assertHighlights(String code, String... expected) { List completions = computeHighlights(code); - assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString()); + assertEquals(Arrays.asList(expected), completions, "Input: " + code + ", " + completions.toString()); } private List computeHighlights(String code) { diff --git a/test/langtools/jdk/jshell/SnippetStatusListenerTest.java b/test/langtools/jdk/jshell/SnippetStatusListenerTest.java index 14ea0b956a7..205749af277 100644 --- a/test/langtools/jdk/jshell/SnippetStatusListenerTest.java +++ b/test/langtools/jdk/jshell/SnippetStatusListenerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @summary Subscribe tests * @build KullaTesting TestingInputStream - * @run testng SnippetStatusListenerTest + * @run junit SnippetStatusListenerTest */ import java.util.ArrayList; @@ -37,14 +37,16 @@ import jdk.jshell.DeclarationSnippet; import jdk.jshell.JShell.Subscription; import jdk.jshell.SnippetEvent; import jdk.jshell.TypeDeclSnippet; -import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class SnippetStatusListenerTest extends KullaTesting { + @Test public void testTwoSnippetEventListeners() { SnippetListener listener1 = new SnippetListener(); SnippetListener listener2 = new SnippetListener(); @@ -61,45 +63,52 @@ public class SnippetStatusListenerTest extends KullaTesting { assertEval("int a = 0;"); List events1 = Collections.unmodifiableList(listener1.getEvents()); - assertEquals(events1, listener2.getEvents(), "Checking got events"); + assertEquals(listener2.getEvents(), events1, "Checking got events"); getState().unsubscribe(subscription1); assertDrop(f, DiagCheck.DIAG_IGNORE, DiagCheck.DIAG_IGNORE, ste(f, REJECTED, DROPPED, false, null)); assertEval("void f() { }", added(VALID)); assertEvalException("throw new RuntimeException();"); - assertEquals(listener1.getEvents(), events1, "Checking that unsubscribed listener does not get events"); + assertEquals(events1, listener1.getEvents(), "Checking that unsubscribed listener does not get events"); List events2 = new ArrayList<>(listener2.getEvents()); events2.removeAll(events1); - assertEquals(events2.size(), 3, "The second listener got events"); + assertEquals(3, events2.size(), "The second listener got events"); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void testNullCallback() { - getState().onSnippetEvent(null); + Assertions.assertThrows(NullPointerException.class, () -> { + getState().onSnippetEvent(null); + }); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testSubscriptionAfterClose() { - getState().close(); - getState().onSnippetEvent(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + getState().close(); + getState().onSnippetEvent(e -> {}); + }); } - @Test(expectedExceptions = IllegalStateException.class, - enabled = false) //TODO 8139873 + @Test //TODO 8139873 + @Disabled public void testSubscriptionAfterShutdown() { - assertEval("System.exit(0);"); - getState().onSnippetEvent(e -> {}); + Assertions.assertThrows(IllegalStateException.class, () -> { + assertEval("System.exit(0);"); + getState().onSnippetEvent(e -> {}); + }); } + @Test public void testSubscriptionToAnotherState() { SnippetListener listener = new SnippetListener(); Subscription subscription = getState().onSnippetEvent(listener); tearDown(); setUp(); assertEval("int x;"); - assertEquals(Collections.emptyList(), listener.getEvents(), "No events"); + assertEquals(listener.getEvents(), Collections.emptyList(), "No events"); getState().unsubscribe(subscription); } diff --git a/test/langtools/jdk/jshell/SnippetTest.java b/test/langtools/jdk/jshell/SnippetTest.java index 3ccd0e42f4b..3e5bdbbf324 100644 --- a/test/langtools/jdk/jshell/SnippetTest.java +++ b/test/langtools/jdk/jshell/SnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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 @@ -26,74 +26,86 @@ * @bug 8139829 * @summary test accessors of Snippet * @build KullaTesting TestingInputStream - * @run testng SnippetTest + * @run junit SnippetTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet.Status; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class SnippetTest extends KullaTesting { + @Test public void testImportKey() { assertImportKeyMatch("import java.util.List;", "List", SINGLE_TYPE_IMPORT_SUBKIND, added(VALID)); assertImportKeyMatch("import java.util.*;", "java.util.*", TYPE_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertImportKeyMatch("import static java.lang.String.*;", "java.lang.String.*", STATIC_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); } + @Test public void testClassKey() { assertDeclarationKeyMatch("class X {}", false, "X", CLASS_SUBKIND, added(VALID)); } + @Test public void testInterfaceKey() { assertDeclarationKeyMatch("interface I {}", false, "I", INTERFACE_SUBKIND, added(VALID)); } + @Test public void testEnumKey() { assertDeclarationKeyMatch("enum E {}", false, "E", ENUM_SUBKIND, added(VALID)); } + @Test public void testAnnotationKey() { assertDeclarationKeyMatch("@interface A {}", false, "A", ANNOTATION_TYPE_SUBKIND, added(VALID)); } + @Test public void testMethodKey() { assertDeclarationKeyMatch("void m() {}", false, "m", METHOD_SUBKIND, added(VALID)); } + @Test public void testVarDeclarationKey() { assertVarKeyMatch("int a;", true, "a", VAR_DECLARATION_SUBKIND, "int", added(VALID)); } + @Test public void testVarDeclarationWithInitializerKey() { assertVarKeyMatch("double b = 9.0;", true, "b", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "double", added(VALID)); } + @Test public void testTempVarExpressionKey() { assertVarKeyMatch("47;", true, "$1", TEMP_VAR_EXPRESSION_SUBKIND, "int", added(VALID)); } + @Test public void testVarValueKey() { assertEval("double x = 4;", "4.0"); assertExpressionKeyMatch("x;", "x", VAR_VALUE_SUBKIND, "double"); } + @Test public void testAssignmentKey() { assertEval("int y;"); assertExpressionKeyMatch("y = 4;", "y", ASSIGNMENT_SUBKIND, "int"); } + @Test public void testStatementKey() { assertKeyMatch("if (true) {}", true, STATEMENT_SUBKIND, added(VALID)); assertKeyMatch("while (true) { break; }", true, STATEMENT_SUBKIND, added(VALID)); @@ -101,10 +113,12 @@ public class SnippetTest extends KullaTesting { assertKeyMatch("for (;;) { break; }", true, STATEMENT_SUBKIND, added(VALID)); } + @Test public void noKeys() { assertActiveKeys(new DeclarationSnippet[0]); } + @Test public void testKeyId1() { Snippet a = classKey(assertEval("class A { }")); assertEval("void f() { }"); @@ -116,7 +130,8 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void testKeyId2() { Snippet g = methodKey(assertEval("void g() { f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("void f() { }", @@ -136,6 +151,7 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } + @Test public void testKeyId3() { Snippet g = methodKey(assertEval("void g() { f(); }", added(RECOVERABLE_DEFINED))); Snippet f = methodKey(assertEval("void f() { }", @@ -154,6 +170,7 @@ public class SnippetTest extends KullaTesting { assertActiveKeys(); } + @Test public void testBooleanSnippetQueries() { Snippet nd = varKey(assertEval("blort x;", added(RECOVERABLE_NOT_DEFINED))); assertTrue(nd.kind().isPersistent(), "nd.isPersistent"); diff --git a/test/langtools/jdk/jshell/SourceLevelTest.java b/test/langtools/jdk/jshell/SourceLevelTest.java index ce5572e6f71..f1092a5d2e8 100644 --- a/test/langtools/jdk/jshell/SourceLevelTest.java +++ b/test/langtools/jdk/jshell/SourceLevelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -26,15 +26,16 @@ * @bug 8259820 * @summary Check JShell can handle -source 8 * @modules jdk.jshell - * @run testng SourceLevelTest + * @run junit SourceLevelTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SourceLevelTest extends ReplToolTesting { - @DataProvider(name="sourceLevels") public Object[][] sourceLevels() { return new Object[][] { new Object[] {"8"}, @@ -42,7 +43,8 @@ public class SourceLevelTest extends ReplToolTesting { }; } - @Test(dataProvider="sourceLevels") + @ParameterizedTest + @MethodSource("sourceLevels") public void testSourceLevel(String sourceLevel) { test(new String[] {"-C", "-source", "-C", sourceLevel}, (a) -> assertCommand(a, "1 + 1", "$1 ==> 2"), diff --git a/test/langtools/jdk/jshell/StartOptionTest.java b/test/langtools/jdk/jshell/StartOptionTest.java index 0d6a9d0d65f..0271d7df57b 100644 --- a/test/langtools/jdk/jshell/StartOptionTest.java +++ b/test/langtools/jdk/jshell/StartOptionTest.java @@ -32,7 +32,7 @@ * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch StartOptionTest + * @run junit/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch StartOptionTest */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -52,16 +52,15 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import jdk.jshell.JShell; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import jdk.jshell.tool.JavaShellToolBuilder; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class StartOptionTest { protected ByteArrayOutputStream cmdout; @@ -116,7 +115,7 @@ public class StartOptionTest { if (checkOut != null) { checkOut.accept(out); } else { - assertEquals(out, "", label + ": Expected empty -- "); + assertEquals("", out, label + ": Expected empty -- "); } } catch (Throwable t) { logOutput("cmdout", cmdout); @@ -139,7 +138,7 @@ public class StartOptionTest { if (checkCode != null) { checkCode.accept(ec); } else { - assertEquals(ec, 0, "Expected standard exit code (0), but found: " + ec); + assertEquals(0, ec, "Expected standard exit code (0), but found: " + ec); } } @@ -188,8 +187,7 @@ public class StartOptionTest { // Start with an exit code and command error check protected void startExCe(int eec, Consumer checkError, String... args) { - StartOptionTest.this.startExCoUoCeCn( - (Integer ec) -> assertEquals((int) ec, eec, + StartOptionTest.this.startExCoUoCeCn((Integer ec) -> assertEquals(eec, (int) ec, "Expected error exit code (" + eec + "), but found: " + ec), null, null, checkError, null, args); } @@ -202,7 +200,7 @@ public class StartOptionTest { private Consumer assertOrNull(String expected, String label) { return expected == null ? null - : s -> assertEquals(s.replaceAll("\\r\\n?", "\n").trim(), expected.trim(), label); + : s -> assertEquals(expected.trim(), s.replaceAll("\\r\\n?", "\n").trim(), label); } // Start and check the resultant: exit code (Ex), command output (Co), @@ -213,10 +211,9 @@ public class StartOptionTest { String expectedError, String expectedConsole, String... args) { - startExCoUoCeCn( - expectedExitCode == 0 + startExCoUoCeCn(expectedExitCode == 0 ? null - : (Integer i) -> assertEquals((int) i, expectedExitCode, + : (Integer i) -> assertEquals(expectedExitCode, (int) i, "Expected exit code (" + expectedExitCode + "), but found: " + i), assertOrNull(expectedCmdOutput, "cmdout: "), assertOrNull(expectedUserOutput, "userout: "), @@ -240,7 +237,7 @@ public class StartOptionTest { startExCoUoCeCn(0, null, expectedUserOutput, null, null, args); } - @BeforeMethod + @BeforeEach public void setUp() { cmdout = new ByteArrayOutputStream(); cmderr = new ByteArrayOutputStream(); @@ -267,6 +264,7 @@ public class StartOptionTest { } // Test load files + @Test public void testCommandFile() { String fn = writeToFile("String str = \"Hello \"\n" + "/list\n" + @@ -281,6 +279,7 @@ public class StartOptionTest { } // Test that the usage message is printed + @Test public void testUsage() { for (String opt : new String[]{"-?", "-h", "--help"}) { startCo(s -> { @@ -293,6 +292,7 @@ public class StartOptionTest { } // Test the --help-extra message + @Test public void testHelpExtra() { for (String opt : new String[]{"-X", "--help-extra"}) { startCo(s -> { @@ -305,12 +305,14 @@ public class StartOptionTest { } // Test handling of bogus options + @Test public void testUnknown() { startExCe(1, "Unknown option: u", "-unknown"); startExCe(1, "Unknown option: unknown", "--unknown"); } // Test that input is read with "-" and there is no extra output. + @Test public void testHypenFile() { setIn("System.out.print(\"Hello\");\n"); startUo("Hello", "-"); @@ -327,6 +329,7 @@ public class StartOptionTest { } // Test that user specified exit codes are propagated + @Test public void testExitCode() { setIn("/exit 57\n"); startExCoUoCeCn(57, null, null, null, "-> /exit 57", "-s"); @@ -341,11 +344,13 @@ public class StartOptionTest { } // Test that non-existent load file sends output to stderr and does not startExCe (no welcome). + @Test public void testUnknownLoadFile() { startExCe(1, "File 'UNKNOWN' for 'jshell' is not found.", "UNKNOWN"); } // Test bad usage of the --startup option + @Test public void testStartup() { String fn = writeToFile(""); startExCe(1, "Argument to startup missing.", "--startup"); @@ -355,18 +360,21 @@ public class StartOptionTest { } // Test an option that causes the back-end to fail is propagated + @Test public void testStartupFailedOption() { startExCe(1, s -> assertTrue(s.contains("Unrecognized option: -hoge-foo-bar"), "cmderr: " + s), "-R-hoge-foo-bar"); } // Test the use of non-existant files with the --startup option + @Test public void testStartupUnknown() { startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "UNKNOWN"); startExCe(1, "File 'UNKNOWN' for '--startup' is not found.", "--startup", "DEFAULT", "--startup", "UNKNOWN"); } // Test bad usage of --class-path option + @Test public void testClasspath() { for (String cp : new String[]{"--class-path"}) { startExCe(1, "Only one --class-path option may be used.", cp, ".", "--class-path", "."); @@ -375,12 +383,14 @@ public class StartOptionTest { } // Test bogus module on --add-modules option + @Test public void testUnknownModule() { startExCe(1, s -> assertTrue(s.contains("rror") && s.contains("unKnown"), "cmderr: " + s), "--add-modules", "unKnown"); } // Test that muliple feedback options fail + @Test public void testFeedbackOptionConflict() { startExCe(1, "Only one feedback option (--feedback, -q, -s, or -v) may be used.", "--feedback", "concise", "--feedback", "verbose"); @@ -395,12 +405,14 @@ public class StartOptionTest { } // Test bogus arguments to the --feedback option + @Test public void testNegFeedbackOption() { startExCe(1, "Argument to feedback missing.", "--feedback"); startExCe(1, "Does not match any current feedback mode: blorp -- --feedback blorp", "--feedback", "blorp"); } // Test --version + @Test public void testVersion() { startCo(s -> { assertTrue(s.startsWith("jshell"), "unexpected version: " + s); @@ -410,6 +422,7 @@ public class StartOptionTest { } // Test --show-version + @Test public void testShowVersion() { startExCoUoCeCn(null, s -> { @@ -422,6 +435,7 @@ public class StartOptionTest { "--show-version"); } + @Test public void testPreviewEnabled() { String fn = writeToFile( """ @@ -430,18 +444,18 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), fn); String fn24 = writeToFile( """ System.out.println(\"test\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--release", "-C24", fn24); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--source", "-C24", fn24); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C-source", "-C24", fn24); //JDK-8341631: String fn2 = writeToFile( @@ -451,7 +465,7 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\ntest\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\ntest\nsuffix\n", s), fn2); //verify the correct resource is selected when --enable-preview, relies on //--patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch @@ -462,7 +476,7 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\nHello!\nsuffix\n"), + startCheckUserOutput(s -> assertEquals("prefix\nHello!\nsuffix\n", s), "--enable-preview", fn2Preview, "-"); @@ -482,7 +496,7 @@ public class StartOptionTest { """ /exit """); - startCheckUserOutput(s -> assertEquals(s, "Custom start script\n"), + startCheckUserOutput(s -> assertEquals("Custom start script\n", s), exit); String clearStartup = writeToFile( """ @@ -498,16 +512,16 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), - s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), - s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckCommandUserOutput(s -> assertEquals("/set start -retain -default\n", s), + s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), + s -> assertEquals("/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), retainTest); String retainTest24 = writeToFile( """ System.out.println(\"test\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "test\n"), + startCheckUserOutput(s -> assertEquals("test\n", s), "-C--release", "-C24", retainTest24); String set24DefaultTest = writeToFile( @@ -526,12 +540,13 @@ public class StartOptionTest { System.out.println(\"suffix\"); /exit """); - startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), - s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), - s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + startCheckCommandUserOutput(s -> assertEquals("/set start -retain -default\n", s), + s -> assertEquals("prefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), + s -> assertEquals("/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n", s), checkDefaultAfterSet24Test); } + @Test public void testInput() { //readLine(String): String readLinePrompt = writeToFile( @@ -540,7 +555,7 @@ public class StartOptionTest { System.out.println(v); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prompt: null\n"), + startCheckUserOutput(s -> assertEquals("prompt: null\n", s), readLinePrompt); //readPassword(String): String readPasswordPrompt = writeToFile( @@ -549,10 +564,11 @@ public class StartOptionTest { System.out.println(java.util.Arrays.toString(v)); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prompt: null\n"), + startCheckUserOutput(s -> assertEquals("prompt: null\n", s), readPasswordPrompt); } + @Test public void testErroneousFile() { String code = """ var v = ( @@ -567,12 +583,12 @@ public class StartOptionTest { .getString("jshell.err.incomplete.input"); String expectedError = new MessageFormat(expectedErrorFormat).format(new Object[] {code}); - startCheckError(s -> assertEquals(s, expectedError), + startCheckError(s -> assertEquals(expectedError, s), readLinePrompt); } - @AfterMethod + @AfterEach public void tearDown() { cmdout = null; cmderr = null; diff --git a/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java b/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java index b0695ae8636..918e8f7984d 100644 --- a/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java +++ b/test/langtools/jdk/jshell/StartupWithFormatSpecifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -31,16 +31,16 @@ * @library /tools/lib * @build toolbox.ToolBox * @build KullaTesting Compiler - * @run testng StartupWithFormatSpecifierTest + * @run junit StartupWithFormatSpecifierTest */ import java.nio.file.Path; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class StartupWithFormatSpecifierTest extends ReplToolTesting { + @Test public void testStartupWithFormatSpecifier() { Compiler compiler = new Compiler(); String startupScript = "String.format(\"This is a %s.\", \"test\");"; diff --git a/test/langtools/jdk/jshell/StopExecutionTest.java b/test/langtools/jdk/jshell/StopExecutionTest.java index b1584c0eb89..eae515da6e5 100644 --- a/test/langtools/jdk/jshell/StopExecutionTest.java +++ b/test/langtools/jdk/jshell/StopExecutionTest.java @@ -27,7 +27,7 @@ * @summary Test JShell#stop * @modules jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng StopExecutionTest + * @run junit StopExecutionTest */ import java.io.IOException; @@ -39,28 +39,31 @@ import java.util.function.Consumer; import jdk.internal.jshell.tool.StopDetectingInputStream; import jdk.internal.jshell.tool.StopDetectingInputStream.State; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class StopExecutionTest extends AbstractStopExecutionTest { - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testStopLoop() throws InterruptedException { scheduleStop("while (true) ;"); } - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testStopASleep() throws InterruptedException { scheduleStop("while (true) { try { Thread.sleep(100); } catch (InterruptedException ex) { } }"); } - @Test(enabled = false) // TODO 8129546 + @Test // TODO 8129546 + @Disabled public void testScriptCatchesStop() throws Exception { scheduleStop("for (int i = 0; i < 30; i++) { try { Thread.sleep(100); } catch (Throwable ex) { } }"); } + @Test public void testStopDetectingInputRandom() throws IOException { long seed = System.nanoTime(); Random r = new Random(seed); @@ -86,10 +89,11 @@ public class StopExecutionTest extends AbstractStopExecutionTest { for (int c = 0; c < chunkSize; c++) { int read = buffer.read(); - assertEquals(read, c); + assertEquals(c, read); } } + @Test public void testStopDetectingInputBufferWaitStop() throws Exception { Runnable shouldNotHappenRun = () -> { throw new AssertionError("Should not happen."); }; diff --git a/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java b/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java index 8cf92545bb5..21cb37e65b3 100644 --- a/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java +++ b/test/langtools/jdk/jshell/T8146368/JShellTest8146368.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -27,14 +27,14 @@ * @summary Test Smashing Error when user language is Japanese * @library /tools/lib /jdk/jshell * @build KullaTesting - * @run testng/othervm -Duser.language=ja JShellTest8146368 + * @run junit/othervm -Duser.language=ja JShellTest8146368 */ import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JShellTest8146368 extends KullaTesting { + @Test public void test() { assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED)); assertEval("und m() { return new und(); }", added(RECOVERABLE_NOT_DEFINED)); diff --git a/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java b/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java index 101083c0e27..3a7db71be71 100644 --- a/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java +++ b/test/langtools/jdk/jshell/T8146368/JShellToolTest8146368.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -28,13 +28,13 @@ * @modules jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib /jdk/jshell * @build ReplToolTesting - * @run testng/othervm -Duser.language=ja JShellToolTest8146368 + * @run junit/othervm -Duser.language=ja JShellToolTest8146368 */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class JShellToolTest8146368 extends ReplToolTesting { + @Test public void test() { test( a -> assertCommand(a, "class A extends B {}", "| created class A, however, it cannot be referenced until class B is declared\n"), diff --git a/test/langtools/jdk/jshell/Test8294583.java b/test/langtools/jdk/jshell/Test8294583.java index 3d2ce2e3638..281911b7113 100644 --- a/test/langtools/jdk/jshell/Test8294583.java +++ b/test/langtools/jdk/jshell/Test8294583.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -26,22 +26,23 @@ * @bug 8294583 * @summary JShell: NPE in switch with non existing record pattern * @build KullaTesting TestingInputStream - * @run testng Test8294583 + * @run junit Test8294583 */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class Test8294583 extends KullaTesting { + @Test public void test() { assertEvalFail("switch (new Object()) {\n" + " case Foo() -> {}\n" + "};"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/Test8296012.java b/test/langtools/jdk/jshell/Test8296012.java index 73e5cc06ae0..4f08861b952 100644 --- a/test/langtools/jdk/jshell/Test8296012.java +++ b/test/langtools/jdk/jshell/Test8296012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -26,21 +26,22 @@ * @bug 8296012 * @summary jshell crashes on mismatched record pattern * @build KullaTesting TestingInputStream - * @run testng Test8296012 + * @run junit Test8296012 */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class Test8296012 extends KullaTesting { + @Test public void test() { assertEval("record Foo(int x, int y) {}"); assertEvalFail("switch (new Foo(1, 2)) { case Foo(int z) -> z; }"); } - @org.testng.annotations.BeforeMethod + @BeforeEach public void setUp() { super.setUp(bc -> bc.compilerOptions("--source", System.getProperty("java.specification.version"), "--enable-preview").remoteVMOptions("--enable-preview")); } diff --git a/test/langtools/jdk/jshell/ToolBasicTest.java b/test/langtools/jdk/jshell/ToolBasicTest.java index b5128de738a..5015d1f64b1 100644 --- a/test/langtools/jdk/jshell/ToolBasicTest.java +++ b/test/langtools/jdk/jshell/ToolBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -32,7 +32,7 @@ * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler - * @run testng/timeout=600 ToolBasicTest + * @run junit/timeout=600 ToolBasicTest * @key intermittent */ @@ -57,19 +57,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.sun.net.httpserver.HttpServer; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.fail; - -@Test public class ToolBasicTest extends ReplToolTesting { + @Test public void elideStartUpFromList() { - test( - (a) -> assertCommandOutputContains(a, "123", "==> 123"), + test((a) -> assertCommandOutputContains(a, "123", "==> 123"), (a) -> assertCommandCheckOutput(a, "/list", (s) -> { int cnt; try (Scanner scanner = new Scanner(s)) { @@ -81,11 +80,12 @@ public class ToolBasicTest extends ReplToolTesting { } } } - assertEquals(cnt, 1, "Expected only one listed line"); + assertEquals(1, cnt, "Expected only one listed line"); }) ); } + @Test public void elideStartUpFromSave() throws IOException { Compiler compiler = new Compiler(); Path path = compiler.getPath("myfile"); @@ -94,10 +94,11 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommand(a, "/save " + path.toString(), "") ); try (Stream lines = Files.lines(path)) { - assertEquals(lines.count(), 1, "Expected only one saved line"); + assertEquals(1, lines.count(), "Expected only one saved line"); } } + @Test public void testInterrupt() { ReplTest interrupt = (a) -> assertCommand(a, "\u0003", ""); for (String s : new String[] { "", "\u0003" }) { @@ -132,6 +133,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testCtrlD() { test(false, new String[]{"--no-startup"}, a -> { @@ -193,6 +195,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testStop() { test( (a) -> assertStop(a, "while (true) {}", ""), @@ -200,6 +203,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRerun() { test(false, new String[] {"--no-startup"}, (a) -> assertCommand(a, "/0", "| No snippet with ID: 0"), @@ -221,7 +225,7 @@ public class ToolBasicTest extends ReplToolTesting { final int finalI = i; Consumer check = (s) -> { String[] ss = s.split("\n"); - assertEquals(ss[0], codes[finalI]); + assertEquals(codes[finalI], ss[0]); assertTrue(ss.length > 1, s); }; tests.add((a) -> assertCommandCheckOutput(a, "/" + (finalI + 1), check)); @@ -231,7 +235,7 @@ public class ToolBasicTest extends ReplToolTesting { final int finalI = i; Consumer check = (s) -> { String[] ss = s.split("\n"); - assertEquals(ss[0], codes[codes.length - finalI - 1]); + assertEquals(codes[codes.length - finalI - 1], ss[0]); assertTrue(ss.length > 1, s); }; tests.add((a) -> assertCommandCheckOutput(a, "/-" + (2 * finalI + 1), check)); @@ -241,11 +245,12 @@ public class ToolBasicTest extends ReplToolTesting { tests.toArray(new ReplTest[tests.size()])); } + @Test public void test8142447() { Function> assertRerun = cmd -> (code, assertionCount) -> (a) -> assertCommandCheckOutput(a, cmd, s -> { String[] ss = s.split("\n"); - assertEquals(ss[0], code); + assertEquals(code, ss[0]); loadVariable(a, "int", "assertionCount", Integer.toString(assertionCount), Integer.toString(assertionCount)); }); ReplTest assertVariables = (a) -> assertCommandCheckOutput(a, "/v", assertVariables()); @@ -256,7 +261,7 @@ public class ToolBasicTest extends ReplToolTesting { "void add(int n) { assertionCount += n; }"); test(new String[]{"--startup", startup.toString()}, (a) -> assertCommand(a, "add(1)", ""), // id: 1 - (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals(s.split("\n")[0], "| Error:")), // id: e1 + (a) -> assertCommandCheckOutput(a, "add(ONE)", s -> assertEquals("| Error:", s.split("\n")[0])), // id: e1 (a) -> assertVariable(a, "int", "ONE", "1", "1"), assertRerun.apply("/1").apply("add(1)", 2), assertVariables, assertRerun.apply("/e1").apply("add(ONE)", 3), assertVariables, @@ -270,6 +275,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testClasspathDirectory() { Compiler compiler = new Compiler(); Path outDir = Paths.get("testClasspathDirectory"); @@ -285,6 +291,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testEnvInStartUp() { Compiler compiler = new Compiler(); Path outDir = Paths.get("testClasspathDirectory"); @@ -320,6 +327,7 @@ public class ToolBasicTest extends ReplToolTesting { return compiler.getPath(outDir).resolve(jarName).toString(); } + @Test public void testClasspathJar() { String jarPath = makeSimpleJar(); test( @@ -332,6 +340,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testClasspathUserHomeExpansion() { String jarPath = makeSimpleJar(); String tilde = "~" + File.separator; @@ -346,6 +355,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testBadClasspath() { String jarPath = makeSimpleJar(); Compiler compiler = new Compiler(); @@ -373,6 +383,7 @@ public class ToolBasicTest extends ReplToolTesting { return compiler.getPath(outDir).resolve(jarName).toString(); } + @Test public void testBadSourceJarClasspath() { String jarPath = makeBadSourceJar(); test( @@ -391,6 +402,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testModulePath() { Compiler compiler = new Compiler(); Path modsDir = Paths.get("mods"); @@ -406,6 +418,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testModulePathUserHomeExpansion() { String tilde = "~" + File.separatorChar; test( @@ -415,6 +428,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testBadModulePath() { Compiler compiler = new Compiler(); Path t1 = compiler.getPath("whatever/thing.zip"); @@ -425,6 +439,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testStartupFileOption() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartupFileOption/startup.txt"); @@ -440,6 +455,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testLoadingFromArgs() { Compiler compiler = new Compiler(); Path path = compiler.getPath("loading.repl"); @@ -450,6 +466,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testReset() { test( (a) -> assertReset(a, "/res"), @@ -470,6 +487,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testOpen() { Compiler compiler = new Compiler(); Path path = compiler.getPath("testOpen.repl"); @@ -504,6 +522,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenLocalFileUrl() { Compiler compiler = new Compiler(); Path path = compiler.getPath("testOpen.repl"); @@ -518,6 +537,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenFileOverHttp() throws IOException { var script = "int a = 10;int b = 20;int c = a + b;"; @@ -549,6 +569,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testOpenResource() { test(new String[]{"-R", "-Duser.language=en", "-R", "-Duser.country=US"}, (a) -> assertCommand(a, "/open PRINTING", ""), @@ -559,6 +580,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testSave() throws IOException { Compiler compiler = new Compiler(); Path path = compiler.getPath("testSave.repl"); @@ -573,7 +595,7 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertClass(a, "class A { public String toString() { return \"A\"; } }", "class", "A"), (a) -> assertCommand(a, "/save " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), list); + assertEquals(list, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -589,7 +611,7 @@ public class ToolBasicTest extends ReplToolTesting { .collect(Collectors.toList()))), (a) -> assertCommand(a, "/save -all " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -606,7 +628,7 @@ public class ToolBasicTest extends ReplToolTesting { .collect(Collectors.toList()))), (a) -> assertCommand(a, "/save 2-3 1 4 " + path.toString(), "") ); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } { List output = new ArrayList<>(); @@ -621,10 +643,11 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertCommand(a, "/save -history " + path.toString(), "") ); output.add("/save -history " + path.toString()); - assertEquals(Files.readAllLines(path), output); + assertEquals(output, Files.readAllLines(path)); } } + @Test public void testStartRetain() { Compiler compiler = new Compiler(); Path startUpFile = compiler.getPath("startUp.txt"); @@ -655,6 +678,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testStartSave() throws IOException { Compiler compiler = new Compiler(); Path startSave = compiler.getPath("startSave.txt"); @@ -662,9 +686,10 @@ public class ToolBasicTest extends ReplToolTesting { List lines = Files.lines(startSave) .filter(s -> !s.isEmpty()) .collect(Collectors.toList()); - assertEquals(lines, START_UP); + assertEquals(START_UP, lines); } + @Test public void testConstrainedUpdates() { test( a -> assertClass(a, "class XYZZY { }", "class", "XYZZY"), @@ -674,6 +699,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRemoteExit() { test( a -> assertVariable(a, "int", "x"), @@ -686,11 +712,13 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testFeedbackNegative() { test(a -> assertCommandCheckOutput(a, "/set feedback aaaa", assertStartsWith("| Does not match any current feedback mode"))); } + @Test public void testFeedbackSilent() { for (String off : new String[]{"s", "silent"}) { test( @@ -702,6 +730,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testFeedbackNormal() { Compiler compiler = new Compiler(); Path testNormalFile = compiler.getPath("testConciseNormal"); @@ -728,6 +757,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testVarsWithNotActive() { test( a -> assertVariable(a, "Blath", "x"), @@ -735,6 +765,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testHistoryReference() { test(false, new String[]{"--no-startup"}, a -> assertCommand(a, "System.err.println(99)", "", "", null, "", "99\n"), @@ -767,6 +798,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRerunIdRange() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("rangeStartup"); @@ -825,7 +857,8 @@ public class ToolBasicTest extends ReplToolTesting { ); } - @Test(enabled = false) // TODO 8158197 + @Test // TODO 8158197 + @Disabled public void testHeadlessEditPad() { String prevHeadless = System.getProperty("java.awt.headless"); try { @@ -838,6 +871,7 @@ public class ToolBasicTest extends ReplToolTesting { } } + @Test public void testAddExports() { test(false, new String[]{"--no-startup"}, a -> assertCommandOutputStartsWith(a, "import jdk.internal.misc.VM;", "| Error:") @@ -854,6 +888,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testRedeclareVariableNoInit() { test( a -> assertCommand(a, "Integer a;", "a ==> null"), @@ -865,6 +900,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testWarningUnchecked() { //8223688 test(false, new String[]{"--no-startup"}, a -> assertCommand(a, "abstract class A { A(T t){} }", "| created class A"), @@ -876,6 +912,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testIndent() { //8223688 prefsMap.remove("INDENT"); test(false, new String[]{"--no-startup"}, @@ -887,6 +924,7 @@ public class ToolBasicTest extends ReplToolTesting { ); } + @Test public void testSystemExitStartUp() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("SystemExitStartUp/startup.txt"); diff --git a/test/langtools/jdk/jshell/ToolCommandOptionTest.java b/test/langtools/jdk/jshell/ToolCommandOptionTest.java index affeabacb7a..aea2fd93f17 100644 --- a/test/langtools/jdk/jshell/ToolCommandOptionTest.java +++ b/test/langtools/jdk/jshell/ToolCommandOptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -30,16 +30,16 @@ * jdk.compiler/com.sun.tools.javac.main * @library /tools/lib * @build ToolCommandOptionTest ReplToolTesting - * @run testng ToolCommandOptionTest + * @run junit ToolCommandOptionTest */ import java.nio.file.Path; -import org.testng.annotations.Test; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolCommandOptionTest extends ReplToolTesting { + @Test public void listTest() { test( (a) -> assertCommand(a, "int x;", @@ -67,6 +67,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void typesTest() { test( (a) -> assertCommand(a, "int x", @@ -92,6 +93,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void dropTest() { test(false, new String[]{"--no-startup"}, (a) -> assertCommand(a, "int x = 5;", @@ -120,6 +122,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setEditorTest() { test( (a) -> assertCommand(a, "/set editor -furball", @@ -157,6 +160,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainEditorTest() { test( (a) -> assertCommand(a, "/set editor -retain -furball", @@ -211,6 +215,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setEditorEnvTest() { setEnvVar("EDITOR", "best one"); setEditorEnvSubtest(); @@ -244,6 +249,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setStartTest() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartTest/startup.txt"); @@ -288,6 +294,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainStartTest() { Compiler compiler = new Compiler(); Path startup = compiler.getPath("StartTest/startup.txt"); @@ -337,6 +344,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setModeTest() { test( (a) -> assertCommandOutputContains(a, "/set mode", @@ -399,6 +407,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void setModeSmashTest() { test( (a) -> assertCommand(a, "/set mode mymode -command", @@ -428,6 +437,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainModeTest() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode -retain", @@ -531,6 +541,7 @@ public class ToolCommandOptionTest extends ReplToolTesting { ); } + @Test public void retainModeDeleteLocalTest() { test( (a) -> assertCommand(a, "/set mode rmdlt normal -command", diff --git a/test/langtools/jdk/jshell/ToolCompletionTest.java b/test/langtools/jdk/jshell/ToolCompletionTest.java index 9997db45c4d..9cd07e0684b 100644 --- a/test/langtools/jdk/jshell/ToolCompletionTest.java +++ b/test/langtools/jdk/jshell/ToolCompletionTest.java @@ -34,14 +34,14 @@ * java.desktop * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build ReplToolTesting TestingInputStream Compiler - * @run testng ToolCompletionTest + * @run junit ToolCompletionTest */ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ToolCompletionTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java index 212301c0fd8..54cae875d89 100644 --- a/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java +++ b/test/langtools/jdk/jshell/ToolEnableNativeAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -26,12 +26,11 @@ * @bug 8268725 * @summary Tests for the --enable-native-access option * @modules jdk.jshell - * @run testng ToolEnableNativeAccessTest + * @run junit ToolEnableNativeAccessTest */ -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolEnableNativeAccessTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java index 1825e7b39ad..d6d01389ac0 100644 --- a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java +++ b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -25,7 +25,7 @@ * @test * @bug 8199193 * @summary Tests for the --enable-preview option - * @run testng ToolEnablePreviewTest + * @run junit ToolEnablePreviewTest */ import java.io.IOException; @@ -33,9 +33,8 @@ import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolEnablePreviewTest extends ReplToolTesting { diff --git a/test/langtools/jdk/jshell/ToolFormatTest.java b/test/langtools/jdk/jshell/ToolFormatTest.java index 3aaf5e79ea5..5d25fb99928 100644 --- a/test/langtools/jdk/jshell/ToolFormatTest.java +++ b/test/langtools/jdk/jshell/ToolFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -31,21 +31,22 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolFormatTest + * @run junit ToolFormatTest */ import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class ToolFormatTest extends ReplToolTesting { + @Test public void testSetFormat() { try { test( @@ -86,6 +87,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetFormatOverride() { test( (a) -> assertCommand(a, "/set mode tm -c", "| Created new feedback mode: tm"), @@ -138,6 +140,7 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testSetFormatSelectorSample() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode ate -quiet", @@ -197,7 +200,8 @@ public class ToolFormatTest extends ReplToolTesting { // A sampling of these has been added (above: testSetFormatSelectorSample). // See 8173007 // Save for possible future deep testing or debugging - @Test(enabled = false) + @Test + @Disabled public void testSetFormatSelector() { List tests = new ArrayList<>(); tests.add((a) -> assertCommandOutputStartsWith(a, "/set mode ate -quiet", @@ -278,6 +282,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetTruncation() { try { test( @@ -309,6 +314,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testDefaultTruncation() { test( (a) -> assertCommand(a, "char[] cs = new char[2000];", null), @@ -331,9 +337,9 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testPrompt() { - test( - (a) -> assertCommand(a, "/set mode tp -quiet", "| Created new feedback mode: tp"), + test((a) -> assertCommand(a, "/set mode tp -quiet", "| Created new feedback mode: tp"), (a) -> assertCommand(a, "/set prompt tp 'aaa' 'bbb'", ""), (a) -> assertCommand(a, "/set prompt tp", "| /set prompt tp \"aaa\" \"bbb\""), @@ -347,21 +353,21 @@ public class ToolFormatTest extends ReplToolTesting { (s) -> { try { BufferedReader rdr = new BufferedReader(new StringReader(s)); - assertEquals(rdr.readLine(), "| /set mode tp -quiet", + assertEquals("| /set mode tp -quiet", rdr.readLine(), "| /set mode tp -quiet"); - assertEquals(rdr.readLine(), "| /set prompt tp \"aaa\" \"bbb\"", + assertEquals("| /set prompt tp \"aaa\" \"bbb\"", rdr.readLine(), "| /set prompt tp \"aaa\" \"bbb\""); String l = rdr.readLine(); while (l.startsWith("| /set format tp ")) { l = rdr.readLine(); } - assertEquals(l, "| /set mode -retain tp", + assertEquals("| /set mode -retain tp", l, "| /set mode -retain tp"); - assertEquals(rdr.readLine(), "| ", + assertEquals("| ", rdr.readLine(), "| "); - assertEquals(rdr.readLine(), "| /set mode tp -quiet", + assertEquals("| /set mode tp -quiet", rdr.readLine(), "| /set mode tp -quiet"); - assertEquals(rdr.readLine(), "| /set prompt tp \"ccc\" \"ddd\"", + assertEquals("| /set prompt tp \"ccc\" \"ddd\"", rdr.readLine(), "| /set prompt tp \"ccc\" \"ddd\""); } catch (IOException ex) { fail("threw " + ex); @@ -370,12 +376,14 @@ public class ToolFormatTest extends ReplToolTesting { ); } + @Test public void testShowFeedbackModes() { test( (a) -> assertCommandOutputContains(a, "/set feedback", "normal") ); } + @Test public void testSetNewModeQuiet() { try { test( @@ -396,6 +404,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetError() { try { test( @@ -473,6 +482,7 @@ public class ToolFormatTest extends ReplToolTesting { } } + @Test public void testSetHelp() { try { test( diff --git a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java index 6af4b82dbb9..a1122c0ddfa 100644 --- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java @@ -30,12 +30,12 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream ToolSimpleTest - * @run testng/othervm/timeout=480 ToolLocalSimpleTest + * @run junit/othervm/timeout=480 ToolLocalSimpleTest */ import java.util.Locale; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; public class ToolLocalSimpleTest extends ToolSimpleTest { @@ -51,12 +51,12 @@ public class ToolLocalSimpleTest extends ToolSimpleTest { @Test public void verifyLocal() { System.setProperty("LOCAL_CHECK", "Here"); - assertEquals(System.getProperty("LOCAL_CHECK"), "Here"); + assertEquals("Here", System.getProperty("LOCAL_CHECK")); test(new String[]{"--no-startup"}, a -> assertCommand(a, "System.getProperty(\"LOCAL_CHECK\")", "$1 ==> \"Here\""), a -> assertCommand(a, "System.setProperty(\"LOCAL_CHECK\", \"After\")", "$2 ==> \"Here\"") ); - assertEquals(System.getProperty("LOCAL_CHECK"), "After"); + assertEquals("After", System.getProperty("LOCAL_CHECK")); } @Override diff --git a/test/langtools/jdk/jshell/ToolLocaleMessageTest.java b/test/langtools/jdk/jshell/ToolLocaleMessageTest.java index 6111320f1af..c3e4a421143 100644 --- a/test/langtools/jdk/jshell/ToolLocaleMessageTest.java +++ b/test/langtools/jdk/jshell/ToolLocaleMessageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -31,16 +31,15 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolLocaleMessageTest + * @run junit ToolLocaleMessageTest * @key intermittent */ import java.util.Locale; -import org.testng.annotations.Test; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolLocaleMessageTest extends ReplToolTesting { void testLocale(ReplTest... tests) { @@ -67,12 +66,14 @@ public class ToolLocaleMessageTest extends ReplToolTesting { }); } + @Test public void testTerminate() { testLocale( (a) -> assertCommandOK(a, "System.exit(1)", "/reload") ); } + @Test public void testSample() { try { testLocale( @@ -98,6 +99,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { } } + @Test public void testCommand() { try { testLocale( @@ -132,6 +134,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { } } + @Test public void testHelp() { testLocale( (a) -> assertCommandOK(a, "/help", "/list", "/save", "/set", "[-restore]"), @@ -153,6 +156,7 @@ public class ToolLocaleMessageTest extends ReplToolTesting { ); } + @Test public void testFeedbackError() { try { testLocale( diff --git a/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java b/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java index 1850f6c3639..e3cbba3f20d 100644 --- a/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java +++ b/test/langtools/jdk/jshell/ToolMultilineSnippetHistoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,18 +31,18 @@ * jdk.jshell/jdk.jshell:open * @build UITesting * @build ToolMultilineSnippetHistoryTest - * @run testng ToolMultilineSnippetHistoryTest + * @run junit ToolMultilineSnippetHistoryTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolMultilineSnippetHistoryTest extends UITesting { public ToolMultilineSnippetHistoryTest() { super(true); } + @Test public void testUpArrow() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("int x=\n44\n"); diff --git a/test/langtools/jdk/jshell/ToolProviderTest.java b/test/langtools/jdk/jshell/ToolProviderTest.java index 1a600efe737..8312ec49ab6 100644 --- a/test/langtools/jdk/jshell/ToolProviderTest.java +++ b/test/langtools/jdk/jshell/ToolProviderTest.java @@ -29,8 +29,8 @@ import java.util.function.Function; import javax.tools.Tool; import jdk.internal.jshell.tool.JShellToolProvider; import jdk.jshell.tool.JavaShellToolBuilder; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /* * @test @@ -43,9 +43,8 @@ import static org.testng.Assert.assertTrue; * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch ToolProviderTest + * @run junit/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch ToolProviderTest */ -@Test public class ToolProviderTest extends StartOptionTest { // Through the provider, the console and console go to command out (we assume, @@ -102,6 +101,7 @@ public class ToolProviderTest extends StartOptionTest { // Test --show-version @Override + @Test public void testShowVersion() { startCo(s -> { assertTrue(s.startsWith("jshell "), "unexpected version: " + s); diff --git a/test/langtools/jdk/jshell/ToolReloadTest.java b/test/langtools/jdk/jshell/ToolReloadTest.java index 4709584cd12..c4193f602be 100644 --- a/test/langtools/jdk/jshell/ToolReloadTest.java +++ b/test/langtools/jdk/jshell/ToolReloadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -32,20 +32,20 @@ * jdk.jshell/jdk.internal.jshell.tool * @library /tools/lib * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler - * @run testng ToolReloadTest + * @run junit ToolReloadTest */ import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.Function; -import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; -@Test public class ToolReloadTest extends ReplToolTesting { + @Test public void testReloadSnippets() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -63,6 +63,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadClasspath() { Function prog = (s) -> String.format( "package pkg; public class A { public String toString() { return \"%s\"; } }\n", s); @@ -89,6 +90,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadDrop() { test(false, new String[]{"--no-startup"}, a -> assertVariable(a, "int", "a"), @@ -112,6 +114,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadQuiet() { test(false, new String[]{"--no-startup"}, a -> assertVariable(a, "int", "a"), @@ -129,6 +132,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadRepeat() { test(false, new String[]{"--no-startup"}, (a) -> assertVariable(a, "int", "c", "7", "7"), @@ -149,6 +153,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadIgnore() { test(false, new String[]{"--no-startup"}, (a) -> assertCommand(a, "(-)", null), @@ -162,6 +167,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadResetRestore() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -180,6 +186,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadCrashRestore() { test( (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -200,6 +207,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testEnvBadModule() { test(new String[] {"--execution", Presets.TEST_STANDARD_EXECUTION}, (a) -> assertVariable(a, "int", "x", "5", "5"), @@ -221,6 +229,7 @@ public class ToolReloadTest extends ReplToolTesting { ); } + @Test public void testReloadExitRestore() { test(false, new String[]{"--no-startup"}, (a) -> assertVariable(a, "int", "x", "5", "5"), diff --git a/test/langtools/jdk/jshell/ToolRetainTest.java b/test/langtools/jdk/jshell/ToolRetainTest.java index 452a3d8dac2..adf3dd0343e 100644 --- a/test/langtools/jdk/jshell/ToolRetainTest.java +++ b/test/langtools/jdk/jshell/ToolRetainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,15 +27,15 @@ * @summary Tests of what information is retained across jshell tool runs * @modules jdk.jshell/jdk.internal.jshell.tool * @build ToolRetainTest ReplToolTesting - * @run testng ToolRetainTest + * @run junit ToolRetainTest */ import java.util.Locale; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolRetainTest extends ReplToolTesting { + @Test public void testRetainMode() { test( (a) -> assertCommand(a, "/set mode trm -quiet", "| Created new feedback mode: trm"), @@ -53,6 +53,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetain2Mode() { test( (a) -> assertCommand(a, "/set mode trm1 -quiet", "| Created new feedback mode: trm1"), @@ -81,6 +82,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedback() { test( (a) -> assertCommand(a, "/set feedback -retain verbose", "| Feedback mode: verbose"), @@ -95,6 +97,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedbackBlank() { String feedbackOut = "| /set feedback -retain verbose\n" + @@ -116,6 +119,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainEditor() { test( (a) -> assertCommand(a, "/set editor -retain nonexistent", @@ -130,6 +134,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainEditorBlank() { test( (a) -> assertCommand(a, "/set editor nonexistent", "| Editor set to: nonexistent"), @@ -142,6 +147,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainModeNeg() { test( (a) -> assertCommandOutputStartsWith(a, "/set mode -retain verbose", @@ -151,6 +157,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testRetainFeedbackNeg() { test( (a) -> assertCommandOutputStartsWith(a, "/set feedback -retain babble1", @@ -167,6 +174,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testNoRetainMode() { test( (a) -> assertCommand(a, "/set mode trm -quiet", "| Created new feedback mode: trm"), @@ -182,6 +190,7 @@ public class ToolRetainTest extends ReplToolTesting { ); } + @Test public void testNoRetainFeedback() { test( (a) -> assertCommand(a, "/set feedback verbose", "| Feedback mode: verbose"), diff --git a/test/langtools/jdk/jshell/ToolShiftTabTest.java b/test/langtools/jdk/jshell/ToolShiftTabTest.java index 87f616678cb..84f1a65c67b 100644 --- a/test/langtools/jdk/jshell/ToolShiftTabTest.java +++ b/test/langtools/jdk/jshell/ToolShiftTabTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -31,18 +31,18 @@ * jdk.jshell/jdk.jshell:open * @build UITesting * @build ToolShiftTabTest - * @run testng/timeout=300 ToolShiftTabTest + * @run junit/timeout=300 ToolShiftTabTest */ import java.util.regex.Pattern; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolShiftTabTest extends UITesting { // Shift-tab as escape sequence private String FIX = "\033\133\132"; + @Test public void testFixVariable() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("3+4"); @@ -54,6 +54,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethod() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("5.5 >= 3.1415926535"); @@ -68,6 +69,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethodVoid() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("System.out.println(\"Testing\")"); @@ -81,6 +83,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixMethodNoLeaks() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("4"); @@ -106,6 +109,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixImport() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("Frame"); @@ -126,6 +130,7 @@ public class ToolShiftTabTest extends UITesting { }); } + @Test public void testFixBad() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("123"); diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 4ed0e741d49..39ce248a521 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -35,7 +35,7 @@ * jdk.jshell/jdk.internal.jshell.tool * java.desktop * @build KullaTesting TestingInputStream - * @run testng/timeout=480 ToolSimpleTest + * @run junit/timeout=480 ToolSimpleTest */ import java.util.ArrayList; @@ -47,10 +47,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; public class ToolSimpleTest extends ReplToolTesting { @@ -543,7 +542,7 @@ public class ToolSimpleTest extends ReplToolTesting { String[] res = trimmed.isEmpty() ? new String[0] : trimmed.split("\n"); - assertEquals(res.length, match.size(), "Got: " + Arrays.asList(res)); + assertEquals(match.size(), res.length, "Got: " + Arrays.asList(res)); for (int i = 0; i < match.size(); ++i) { assertTrue(res[i].contains(match.get(i))); } @@ -619,7 +618,7 @@ public class ToolSimpleTest extends ReplToolTesting { a -> assertCommandCheckOutput(a, "/methods print println printf", s -> checkLineToList(s, printingMethodList)), a -> assertCommandCheckOutput(a, "/methods println", - s -> assertEquals(s.trim().split("\n").length, 10)), + s -> assertEquals(10, s.trim().split("\n").length)), a -> assertCommandCheckOutput(a, "/methods", s -> checkLineToList(s, printingMethodList)), a -> assertCommandOutputStartsWith(a, "/methods " + arg, diff --git a/test/langtools/jdk/jshell/ToolTabCommandTest.java b/test/langtools/jdk/jshell/ToolTabCommandTest.java index f2f3111c4fa..3dcc81e77be 100644 --- a/test/langtools/jdk/jshell/ToolTabCommandTest.java +++ b/test/langtools/jdk/jshell/ToolTabCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -34,18 +34,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build ToolTabCommandTest - * @run testng ToolTabCommandTest + * @run junit ToolTabCommandTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolTabCommandTest extends UITesting { public ToolTabCommandTest() { super(true); } + @Test public void testCommand() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); @@ -133,6 +133,7 @@ public class ToolTabCommandTest extends UITesting { }); } + @Test public void testRerunCommands() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); @@ -170,6 +171,7 @@ public class ToolTabCommandTest extends UITesting { }); } + @Test public void testHelp() throws Exception { // set terminal height so that help output won't hit page breaks System.setProperty("test.terminal.height", "1000000"); diff --git a/test/langtools/jdk/jshell/ToolTabSnippetTest.java b/test/langtools/jdk/jshell/ToolTabSnippetTest.java index 252d57f4a6f..39189da8686 100644 --- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java +++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. 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 @@ -34,7 +34,7 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build ToolTabSnippetTest - * @run testng/timeout=300 ToolTabSnippetTest + * @run junit/timeout=300 ToolTabSnippetTest */ import java.io.IOException; @@ -48,15 +48,15 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import jdk.internal.jshell.tool.ConsoleIOContextTestSupport; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class ToolTabSnippetTest extends UITesting { public ToolTabSnippetTest() { super(true); } + @Test public void testExpression() throws Exception { Path classes = prepareZip(); doRunTest((inputSink, out) -> { @@ -208,6 +208,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testCleaningCompletionTODO() throws Exception { doRunTest((inputSink, out) -> { CountDownLatch testCompleteComputationStarted = new CountDownLatch(1); @@ -241,6 +242,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testNoRepeat() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("String xyzAA;\n"); @@ -266,6 +268,7 @@ public class ToolTabSnippetTest extends UITesting { }); } + @Test public void testCrash8221759() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("java.io.File.path" + TAB); @@ -331,6 +334,7 @@ public class ToolTabSnippetTest extends UITesting { //where: private final Compiler compiler = new Compiler(); + @Test public void testDocumentationAfterInsert() throws Exception { doRunTest((inputSink, out) -> { inputSink.write("import java.time.*\n"); diff --git a/test/langtools/jdk/jshell/ToolingTest.java b/test/langtools/jdk/jshell/ToolingTest.java index f0d0e3f68eb..6f1c899c884 100644 --- a/test/langtools/jdk/jshell/ToolingTest.java +++ b/test/langtools/jdk/jshell/ToolingTest.java @@ -30,11 +30,10 @@ * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng ToolingTest + * @run junit ToolingTest */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class ToolingTest extends ReplToolTesting { @Test diff --git a/test/langtools/jdk/jshell/TypeNameTest.java b/test/langtools/jdk/jshell/TypeNameTest.java index dc2b2152ca8..cbcde20a541 100644 --- a/test/langtools/jdk/jshell/TypeNameTest.java +++ b/test/langtools/jdk/jshell/TypeNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -26,14 +26,12 @@ * @bug 8144903 8171981 8191802 8191842 * @summary Tests for determining the type from the expression * @build KullaTesting TestingInputStream - * @run testng TypeNameTest + * @run junit TypeNameTest */ -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; -import static org.testng.Assert.assertEquals; - -@Test public class TypeNameTest extends KullaTesting { @@ -42,10 +40,11 @@ public class TypeNameTest extends KullaTesting { } private void assertType(String expr, String type, String inferType) { - assertEquals(varKey(assertEval(expr)).typeName(), type); + assertEquals(type, varKey(assertEval(expr)).typeName()); assertInferredType(expr, inferType); } + @Test public void testTypeInference() { assertEval("import java.util.List;"); assertEval("import java.util.ArrayList;"); @@ -75,6 +74,7 @@ public class TypeNameTest extends KullaTesting { assertType("(P) null", "P"); } + @Test public void testConditionals() { assertEval("import java.util.List;"); assertEval("import java.util.ArrayList;"); @@ -95,6 +95,7 @@ public class TypeNameTest extends KullaTesting { assertType("b? new B() : new C()", "X"); } + @Test public void testJEP286NonDenotable() { assertEval("import java.util.List;"); assertEval("import java.util.Arrays;"); @@ -144,6 +145,7 @@ public class TypeNameTest extends KullaTesting { assertType("unbStringIter().iterator().next().get(0)", "Object"); } + @Test public void testJEP286NonDenotable2() { assertEval("import java.util.List;"); assertEval("import java.util.Arrays;"); @@ -197,6 +199,7 @@ public class TypeNameTest extends KullaTesting { "Number"); } + @Test public void testVariableTypeName() { assertType("\"x\"", "String"); @@ -213,30 +216,36 @@ public class TypeNameTest extends KullaTesting { assertType("java.util.Locale.Category.FORMAT", "Category"); } + @Test public void testReplNestedClassName() { assertEval("class D { static class E {} }"); assertType("new D.E();", "D.E"); } + @Test public void testAnonymousClassName() { assertEval("class C {}"); assertType("new C();", "C"); assertType("new C() { int x; };", "", "C"); } + @Test public void testCapturedTypeName() { assertType("\"\".getClass();", "Class"); assertType("\"\".getClass().getEnumConstants();", "String[]"); } + @Test public void testJavaLang() { assertType("\"\";", "String"); } + @Test public void testNotOverEagerPackageEating() { assertType("\"\".getClass().getDeclaredMethod(\"hashCode\");", "java.lang.reflect.Method"); } + @Test public void testBounds() { assertEval("java.util.List list1 = java.util.Arrays.asList(\"\");"); assertType("list1.iterator().next()", "String"); diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index e7daa4df8e6..a1bd8f35dee 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -63,11 +63,11 @@ public class UITesting { this.laxLineEndings = laxLineEndings; } - protected void doRunTest(Test test) throws Exception { + protected void doRunTest(UITest test) throws Exception { doRunTest(test, true); } - protected void doRunTest(Test test, boolean setUserInput) throws Exception { + protected void doRunTest(UITest test, boolean setUserInput) throws Exception { // turn on logging of launch failures Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL); @@ -141,7 +141,7 @@ public class UITesting { } } - protected interface Test { + protected interface UITest { public void test(Writer inputSink, StringBuilder out) throws Exception; } diff --git a/test/langtools/jdk/jshell/UndefinedClassTest.java b/test/langtools/jdk/jshell/UndefinedClassTest.java index eb0cf3699cf..3891aa7b4cd 100644 --- a/test/langtools/jdk/jshell/UndefinedClassTest.java +++ b/test/langtools/jdk/jshell/UndefinedClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -35,18 +35,18 @@ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build Compiler UITesting * @build UndefinedClassTest - * @run testng UndefinedClassTest + * @run junit UndefinedClassTest */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class UndefinedClassTest extends UITesting { public UndefinedClassTest() { super(true); } + @Test public void testUndefinedClassWithStaticAccess() throws Exception{ String code = "@FunctionalInterface\n" + "interface RunnableWithThrowable {\n" + @@ -62,6 +62,7 @@ public class UndefinedClassTest extends UITesting { }); } + @Test public void testUndefinedClassWithDefaultAccess() throws Exception{ String code = "@FunctionalInterface\n" + "interface RunnableWithThrowable {\n" + diff --git a/test/langtools/jdk/jshell/UnicodeTest.java b/test/langtools/jdk/jshell/UnicodeTest.java index 6812dcf1a50..13dd30f0975 100644 --- a/test/langtools/jdk/jshell/UnicodeTest.java +++ b/test/langtools/jdk/jshell/UnicodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. 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 @@ -26,27 +26,28 @@ * @bug 8248157 * @summary test Unicode characters in Snippets * @build KullaTesting TestingInputStream - * @run testng UnicodeTest + * @run junit UnicodeTest */ import jdk.jshell.Snippet; import jdk.jshell.DeclarationSnippet; -import org.testng.annotations.Test; import jdk.jshell.Snippet.Status; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; +import org.junit.jupiter.api.Test; -@Test public class UnicodeTest extends KullaTesting { + @Test public void testVarDeclarationKey() { assertVarKeyMatch("int \\u00aa;", true, "\u00aa", VAR_DECLARATION_SUBKIND, "int", added(VALID)); assertEval("\\u00aa", "0"); } + @Test public void testVarDeclarationWithInitializerKey() { assertVarKeyMatch("double \\u00ba\\u0044\\u0577 = 9.4;", true, "\u00ba\u0044\u0577", VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, "double", added(VALID)); diff --git a/test/langtools/jdk/jshell/UnnamedTest.java b/test/langtools/jdk/jshell/UnnamedTest.java index 9c7bb6ba5a2..65d2b83c856 100644 --- a/test/langtools/jdk/jshell/UnnamedTest.java +++ b/test/langtools/jdk/jshell/UnnamedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -30,20 +30,20 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng UnnamedTest + * @run junit UnnamedTest */ import java.util.function.Consumer; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.VarSnippet; -import org.testng.Assert; -import org.testng.annotations.Test; import jdk.jshell.JShell; import static jdk.jshell.SourceCodeAnalysis.Completeness.COMPLETE; import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class UnnamedTest extends KullaTesting { @@ -51,8 +51,8 @@ public class UnnamedTest extends KullaTesting { public void unnamed() { VarSnippet sn1 = varKey(assertEval("int _ = 0;")); VarSnippet sn2 = varKey(assertEval("String _ = \"x\";")); - Assert.assertEquals(getState().varValue(sn1), "0"); - Assert.assertEquals(getState().varValue(sn2), "\"x\""); + Assertions.assertEquals("0", getState().varValue(sn1)); + Assertions.assertEquals("\"x\"", getState().varValue(sn2)); } static final String[] definitely_incomplete = new String[]{ diff --git a/test/langtools/jdk/jshell/UserExecutionControlTest.java b/test/langtools/jdk/jshell/UserExecutionControlTest.java index 90c99db4a8f..41719f9ff2a 100644 --- a/test/langtools/jdk/jshell/UserExecutionControlTest.java +++ b/test/langtools/jdk/jshell/UserExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,29 +26,29 @@ * @bug 8156101 8159935 8159122 8168615 * @summary Tests for ExecutionControl SPI * @build KullaTesting ExecutionControlTestBase - * @run testng UserExecutionControlTest + * @run junit UserExecutionControlTest */ -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeMethod; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class UserExecutionControlTest extends ExecutionControlTestBase { - @BeforeMethod + @BeforeEach @Override public void setUp() { setUp(builder -> builder.executionEngine("local")); } + @Test public void verifyLocal() throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { System.setProperty("LOCAL_CHECK", "TBD"); - assertEquals(System.getProperty("LOCAL_CHECK"), "TBD"); + assertEquals("TBD", System.getProperty("LOCAL_CHECK")); assertEval("System.getProperty(\"LOCAL_CHECK\")", "\"TBD\""); assertEval("System.setProperty(\"LOCAL_CHECK\", \"local\")"); - assertEquals(System.getProperty("LOCAL_CHECK"), "local"); + assertEquals("local", System.getProperty("LOCAL_CHECK")); } } diff --git a/test/langtools/jdk/jshell/UserInputTest.java b/test/langtools/jdk/jshell/UserInputTest.java index 392278abef1..c0246acdf63 100644 --- a/test/langtools/jdk/jshell/UserInputTest.java +++ b/test/langtools/jdk/jshell/UserInputTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,18 +26,18 @@ * @bug 8131023 8167461 * @summary Verify that the user's code can read System.in * @build KullaTesting TestingInputStream - * @run testng UserInputTest + * @run junit UserInputTest * @key intermittent */ import java.io.IOException; import java.io.InputStream; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -@Test public class UserInputTest extends KullaTesting { + @Test public void testReadInput() { setInput("AB\n"); assertEval("System.in.read()", "65"); @@ -45,6 +45,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read()", "67"); } + @Test public void testScanner() { assertEval("import java.util.Scanner;"); assertEval("Scanner s = new Scanner(System.in);"); @@ -52,6 +53,7 @@ public class UserInputTest extends KullaTesting { assertEval("s.nextInt();", "12"); } + @Test public void testClose() { setInput(new InputStream() { private final byte[] data = new byte[] {0, 1, 2}; @@ -73,6 +75,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read();", "-1"); } + @Test public void testException() { setInput(new InputStream() { private final int[] data = new int[] {0, 1, -2, 2}; @@ -99,6 +102,7 @@ public class UserInputTest extends KullaTesting { assertEval("System.in.read();", "-1"); } + @Test public void testNoConsole() { assertEval("System.console()", "null"); } diff --git a/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java b/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java index 02c725cffa4..094c705bce6 100644 --- a/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java +++ b/test/langtools/jdk/jshell/UserJdiUserRemoteTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -26,46 +26,48 @@ * @bug 8160128 8159935 8168615 * @summary Tests for Aux channel, custom remote agents, custom JDI implementations. * @build KullaTesting ExecutionControlTestBase MyExecutionControl MyRemoteExecutionControl MyExecutionControlProvider - * @run testng UserJdiUserRemoteTest + * @run junit UserJdiUserRemoteTest * @key intermittent */ import java.io.ByteArrayOutputStream; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; import jdk.jshell.Snippet; import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.Status.VALID; import jdk.jshell.VarSnippet; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl.ExecutionControlException; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@Test public class UserJdiUserRemoteTest extends ExecutionControlTestBase { ExecutionControl currentEC; ByteArrayOutputStream auxStream; - @BeforeMethod + @BeforeEach @Override public void setUp() { auxStream = new ByteArrayOutputStream(); setUp(builder -> builder.executionEngine(new MyExecutionControlProvider(this), null)); } + @Test public void testVarValue() { VarSnippet dv = varKey(assertEval("double aDouble = 1.5;")); String vd = getState().varValue(dv); - assertEquals(vd, "1.5"); - assertEquals(auxStream.toString(), "aDouble"); + assertEquals("1.5", vd); + assertEquals("aDouble", auxStream.toString()); } + @Test public void testExtension() throws ExecutionControlException { assertEval("42;"); Object res = currentEC.extensionCommand("FROG", "test"); - assertEquals(res, "ribbit"); + assertEquals("ribbit", res); } + @Test public void testRedefine() { Snippet vx = varKey(assertEval("int x;")); Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 64d25e8a63c..94dcbbf7c8d 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jshell * @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic - * @run testng/timeout=480 VariablesTest + * @run junit/timeout=480 VariablesTest */ import java.nio.file.Path; @@ -44,18 +44,19 @@ import jdk.jshell.TypeDeclSnippet; import jdk.jshell.VarSnippet; import jdk.jshell.Snippet.SubKind; import jdk.jshell.SnippetEvent; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import static java.util.stream.Collectors.toList; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.VAR_DECLARATION_SUBKIND; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -@Test public class VariablesTest extends KullaTesting { + @Test public void noVariables() { assertNumberOfActiveVariables(0); } @@ -69,6 +70,7 @@ public class VariablesTest extends KullaTesting { } } + @Test public void testVarValue1() { VarSnippet v1 = varKey(assertEval("und1 a;", added(RECOVERABLE_NOT_DEFINED))); badVarValue(v1); @@ -89,6 +91,7 @@ public class VariablesTest extends KullaTesting { badVarValue(v2); } + @Test public void testVarValue2() { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); badVarValue(v1); @@ -97,6 +100,7 @@ public class VariablesTest extends KullaTesting { badVarValue(v2); } + @Test public void testSignature1() { VarSnippet v1 = varKey(assertEval("und1 a;", added(RECOVERABLE_NOT_DEFINED))); assertVariableDeclSnippet(v1, "a", "und1", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); @@ -116,6 +120,7 @@ public class VariablesTest extends KullaTesting { assertVariableDeclSnippet(v2, "a", "und2", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); } + @Test public void testSignature2() { VarSnippet v1 = (VarSnippet) assertDeclareFail("int a = 0.0;", "compiler.err.prob.found.req"); assertVariableDeclSnippet(v1, "a", "int", REJECTED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 1); @@ -126,6 +131,7 @@ public class VariablesTest extends KullaTesting { assertVariableDeclSnippet(v2, "a", "int", DROPPED, SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND, 0, 0); } + @Test public void variables() { VarSnippet snx = varKey(assertEval("int x = 10;")); VarSnippet sny = varKey(assertEval("String y = \"hi\";")); @@ -137,22 +143,25 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesArray() { VarSnippet sn = varKey(assertEval("int[] a = new int[12];")); - assertEquals(sn.typeName(), "int[]"); + assertEquals("int[]", sn.typeName()); assertEval("int len = a.length;", "12"); assertVariables(variable("int[]", "a"), variable("int", "len")); assertActiveKeys(); } + @Test public void variablesArrayOld() { VarSnippet sn = varKey(assertEval("int a[] = new int[12];")); - assertEquals(sn.typeName(), "int[]"); + assertEquals("int[]", sn.typeName()); assertEval("int len = a.length;", "12"); assertVariables(variable("int[]", "a"), variable("int", "len")); assertActiveKeys(); } + @Test public void variablesRedefinition() { Snippet x = varKey(assertEval("int x = 10;")); Snippet y = varKey(assertEval("String y = \"\";", added(VALID))); @@ -170,6 +179,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporary() { assertEval("int $1 = 10;", added(VALID)); assertEval("2 * $1;", added(VALID)); @@ -180,6 +190,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporaryNull() { assertEval("null;", added(VALID)); assertVariables(variable("Object", "$1")); @@ -194,6 +205,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesTemporaryArrayOfCapturedType() { assertEval("class Test { T[][] get() { return null; } }", added(VALID)); assertEval("Test test() { return new Test<>(); }", added(VALID)); @@ -204,6 +216,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesClassReplace() { assertEval("import java.util.*;", added(VALID)); Snippet var = varKey(assertEval("List list = new ArrayList<>();", "[]", @@ -223,12 +236,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesErrors() { assertDeclareFail("String;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 6, 0, -1, -1, Diagnostic.Kind.ERROR)); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void variablesUnresolvedActiveFailed() { VarSnippet key = varKey(assertEval("und x;", added(RECOVERABLE_NOT_DEFINED))); assertVariableDeclSnippet(key, "x", "und", RECOVERABLE_NOT_DEFINED, VAR_DECLARATION_SUBKIND, 1, 0); @@ -237,12 +252,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void variablesUnresolvedError() { assertDeclareFail("und y = null;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 3, 0, -1, -1, Diagnostic.Kind.ERROR)); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void variablesMultiByteCharacterType() { assertEval("class \u3042 {}"); assertEval("\u3042 \u3042 = null;", added(VALID)); @@ -261,7 +278,8 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void methodVariablesAreNotVisible() { Snippet foo = varKey(assertEval("int foo() {" + "int x = 10;" + @@ -283,7 +301,8 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } - @Test(enabled = false) // TODO 8081689 + @Test // TODO 8081689 + @Disabled public void classFieldsAreNotVisible() { Snippet key = classKey(assertEval("class clazz {" + "int x = 10;" + @@ -303,6 +322,7 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void multiVariables() { List abc = assertEval("int a, b, c = 10;", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, @@ -324,12 +344,14 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + @Test public void syntheticVariables() { assertEval("assert false;"); assertNumberOfActiveVariables(0); assertActiveKeys(); } + @Test public void undefinedReplaceVariable() { Snippet key = varKey(assertEval("int d = 234;", "234")); assertVariables(variable("int", "d")); @@ -339,13 +361,14 @@ public class VariablesTest extends KullaTesting { ste(key, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); //assertEquals(getState().source(snippet), src); //assertEquals(snippet, undefKey); - assertEquals(getState().status(undefKey), RECOVERABLE_NOT_DEFINED); + assertEquals(RECOVERABLE_NOT_DEFINED, getState().status(undefKey)); List unr = getState().unresolvedDependencies((VarSnippet) undefKey).collect(toList()); - assertEquals(unr.size(), 1); - assertEquals(unr.get(0), "class undefined"); + assertEquals(1, unr.size()); + assertEquals("class undefined", unr.get(0)); assertVariables(variable("undefined", "d")); } + @Test public void lvti() { assertEval("var d = 234;", "234"); assertEval("class Test { T[][] get() { return null; } }", added(VALID)); @@ -410,12 +433,14 @@ public class VariablesTest extends KullaTesting { assertEval("var r16d = r16d();"); } + @Test public void test8191842() { assertEval("import java.util.stream.*;"); assertEval("var list = Stream.of(1, 2, 3).map(j -> new Object() { int i = j; }).collect(Collectors.toList());"); assertEval("list.stream().map(a -> String.valueOf(a.i)).collect(Collectors.joining(\", \"));", "\"1, 2, 3\""); } + @Test public void lvtiRecompileDependentsWithIntersectionTypes() { assertEval(" Z get1() { return null; }", added(VALID)); assertEval("var i1 = get1();", added(VALID)); @@ -428,27 +453,32 @@ public class VariablesTest extends KullaTesting { assertEval("void t2() { i2.run(); i2.count(); }", added(VALID)); } + @Test public void arrayInit() { assertEval("int[] d = {1, 2, 3};"); } + @Test public void testAnonymousVar() { assertEval("new Object() { public String get() { return \"a\"; } }"); assertEval("$1.get()", "\"a\""); } + @Test public void testIntersectionVar() { assertEval(" Z get() { return null; }", added(VALID)); assertEval("get();", added(VALID)); assertEval("void t1() { $1.run(); $1.length(); }", added(VALID)); } + @Test public void multipleCaptures() { assertEval("class D { D(int foo, String bar) { this.foo = foo; this.bar = bar; } int foo; String bar; } "); assertEval("var d = new D(34, \"hi\") { String z = foo + bar; };"); assertEval("d.z", "\"34hi\""); } + @Test public void multipleAnonymous() { VarSnippet v1 = varKey(assertEval("new Object() { public int i = 42; public int i1 = i; public int m1() { return i1; } };")); VarSnippet v2 = varKey(assertEval("new Object() { public int i = 42; public int i2 = i; public int m2() { return i2; } };")); @@ -466,6 +496,7 @@ public class VariablesTest extends KullaTesting { -1, -1, Diagnostic.Kind.ERROR)); } + @Test public void displayName() { assertVarDisplayName("var v1 = 234;", "int"); assertVarDisplayName("var v2 = new int[] {234};", "int[]"); @@ -478,6 +509,7 @@ public class VariablesTest extends KullaTesting { assertVarDisplayName("var v6 = new Runnable() { public void run() { } };", ""); } + @Test public void varType() { assertEval("import java.util.*;"); var firstVar = varKey(assertEval("var v1 = List.of(1);", added(VALID))); @@ -487,6 +519,7 @@ public class VariablesTest extends KullaTesting { assertEval("v2", "[1]"); } + @Test public void varDeclNoInit() { assertVarDeclNoInit("byte", "b", "0"); assertVarDeclNoInit("short", "h", "0"); @@ -500,6 +533,7 @@ public class VariablesTest extends KullaTesting { assertVarDeclNoInit("String", "s", "null"); } + @Test public void varDeclRedefNoInit() { assertVarDeclRedefNoInit("byte", "b", "1", "0"); assertVarDeclRedefNoInit("short", "h", "2", "0"); @@ -513,6 +547,7 @@ public class VariablesTest extends KullaTesting { assertVarDeclRedefNoInit("String", "s", "\"hi\"", "null"); } + @Test public void badPkgVarDecl() { Compiler compiler = new Compiler(); Path nopkgdirpath = Paths.get("cp", "xyz"); @@ -545,16 +580,16 @@ public class VariablesTest extends KullaTesting { private VarSnippet assertVarDeclNoInit(String typeName, String name, String dvalue, STEInfo mainInfo, STEInfo... updates) { VarSnippet vs = varKey(assertEval(typeName + " " + name + ";", dvalue, mainInfo, updates)); - assertEquals(vs.typeName(), typeName); + assertEquals(typeName, vs.typeName()); assertEval(name, dvalue, added(VALID)); return vs; } private void assertVarDisplayName(String var, String typeName) { - assertEquals(varKey(assertEval(var)).typeName(), typeName); + assertEquals(typeName, varKey(assertEval(var)).typeName()); } - @BeforeMethod + @BeforeEach @Override public void setUp() { Path path = Paths.get("cp"); @@ -611,22 +646,26 @@ public class VariablesTest extends KullaTesting { .compilerOptions("--class-path", tpath)); } + @Test public void varIntersection() { assertEval("interface Marker {}"); assertEval("var v = (Marker & Runnable) () -> {};", added(VALID)); assertEval("v.run()"); } + @Test public void varAnonymousClassAndStaticField() { //JDK-8294431 assertEval("var obj = new Object() { public static final String msg = \"hello\"; };"); } + @Test public void underscoreAsLambdaParameter() { //JDK-8322532 assertAnalyze("Func f = _ -> 0; int i;", "Func f = _ -> 0;", " int i;", true); } + @Test public void intersectionTypeAsTypeArgument() { //JDK-8322003 assertEval("interface Shape {}"); assertEval("record Square(int edge) implements Shape {}"); diff --git a/test/langtools/jdk/jshell/WrapperTest.java b/test/langtools/jdk/jshell/WrapperTest.java index 8986c99b4b3..9903f04676f 100644 --- a/test/langtools/jdk/jshell/WrapperTest.java +++ b/test/langtools/jdk/jshell/WrapperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -27,28 +27,28 @@ * @summary test wrappers and dependencies * @modules jdk.jshell/jdk.jshell * @build KullaTesting - * @run testng WrapperTest + * @run junit WrapperTest */ import java.util.Collection; import java.util.List; -import org.testng.annotations.Test; import jdk.jshell.ErroneousSnippet; import jdk.jshell.Snippet; import jdk.jshell.Snippet.Kind; import jdk.jshell.SourceCodeAnalysis.SnippetWrapper; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.VALID; +import org.junit.jupiter.api.Test; -@Test public class WrapperTest extends KullaTesting { + @Test public void testMethod() { String src = "void glib() { System.out.println(\"hello\"); }"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.METHOD, "void", "glib", "println"); assertPosition(swl.get(0), src, 0, 4); assertPosition(swl.get(0), src, 5, 4); @@ -63,6 +63,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testMethodCorralled() { String src = "void glib() { f(); }"; // _123456789_123456789 @@ -75,6 +76,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassCorralled0() { String src = "class AAA { float mmm(double d1234) { return (float) (f0 * d1234); } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -91,6 +93,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassCorralled() { String src = "class AAA { int xxx = x0 + 4; float mmm(float ffff) { return f0 * ffff; } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -109,6 +112,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testClassWithConstructorCorralled() { String src = "public class AAA { AAA(String b) {} int xxx = x0 + 4; float mmm(float ffff) { return f0 * ffff; } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -130,6 +134,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testInterfaceCorralled() { String src = "interface AAA { default float mmm(double d1234) { return (float) (f0 * d1234); } }"; // _123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 @@ -147,6 +152,7 @@ public class WrapperTest extends KullaTesting { } // test 8159740 + @Test public void testEnumCorralled() { String src = "public enum Planet {\n" + @@ -182,25 +188,27 @@ public class WrapperTest extends KullaTesting { "radius", "surfaceGravity", "surfaceWeight"); } + @Test public void testMethodBad() { String src = "void flob() { ?????; }"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.METHOD, "void", "flob", "?????"); assertPosition(swl.get(0), src, 9, 2); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.METHOD); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.METHOD, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.METHOD, "void", "flob", "?????"); assertPosition(swl.get(0), src, 14, 5); } + @Test public void testVar() { String src = "int gx = 1234;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.VAR, "int", "gx", "1234"); assertPosition(swl.get(0), src, 4, 2); @@ -210,25 +218,27 @@ public class WrapperTest extends KullaTesting { assertPosition(swg, src, 0, 3); } + @Test public void testVarBad() { String src = "double dd = ?????;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.VAR, "double", "dd", "?????"); assertPosition(swl.get(0), src, 9, 2); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.VAR); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.VAR, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.VAR, "double", "dd", "?????"); assertPosition(swl.get(0), src, 12, 5); } + @Test public void testImport() { String src = "import java.lang.*;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.IMPORT, "import", "java.lang"); assertPosition(swl.get(0), src, 7, 4); @@ -238,61 +248,65 @@ public class WrapperTest extends KullaTesting { assertPosition(swg, src, 0, 6); } + @Test public void testImportBad() { String src = "import java.?????;"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.IMPORT, "import", "?????"); assertPosition(swl.get(0), src, 7, 4); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.IMPORT); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.IMPORT, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.IMPORT, "import", "?????"); assertPosition(swl.get(0), src, 0, 6); } + @Test public void testErroneous() { String src = "@@@@@@@@@@"; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 1, "unexpected list length"); + assertEquals(1, swl.size(), "unexpected list length"); assertWrapperHas(swl.get(0), src, Kind.ERRONEOUS, "@@@@@@@@@@"); assertPosition(swl.get(0), src, 0, 10); Snippet f = key(assertEvalFail(src)); - assertEquals(f.kind(), Kind.ERRONEOUS); - assertEquals(((ErroneousSnippet)f).probableKind(), Kind.ERRONEOUS); + assertEquals(Kind.ERRONEOUS, f.kind()); + assertEquals(Kind.ERRONEOUS, ((ErroneousSnippet)f).probableKind()); SnippetWrapper sw = getState().sourceCodeAnalysis().wrapper(f); assertWrapperHas(sw, src, Kind.ERRONEOUS, "@@@@@@@@@@"); assertPosition(swl.get(0), src, 0, 10); } + @Test public void testEmpty() { String src = ""; List swl = getState().sourceCodeAnalysis().wrappers(src); - assertEquals(swl.size(), 0, "expected empty list"); + assertEquals(0, swl.size(), "expected empty list"); } + @Test public void testDependencies() { Snippet a = key(assertEval("int aaa = 6;", added(VALID))); Snippet b = key(assertEval("class B { B(int x) { aaa = x; } }", added(VALID))); Snippet c = key(assertEval("B ccc() { return new B(aaa); }", added(VALID))); Collection dep; dep = getState().sourceCodeAnalysis().dependents(c); - assertEquals(dep.size(), 0); + assertEquals(0, dep.size()); dep = getState().sourceCodeAnalysis().dependents(b); - assertEquals(dep.size(), 1); + assertEquals(1, dep.size()); assertTrue(dep.contains(c)); dep = getState().sourceCodeAnalysis().dependents(a); - assertEquals(dep.size(), 2); + assertEquals(2, dep.size()); assertTrue(dep.contains(c)); assertTrue(dep.contains(b)); } private void assertWrapperHas(SnippetWrapper sw, String source, Kind kind, String... has) { - assertEquals(sw.source(), source); - assertEquals(sw.kind(), kind); + assertEquals(source, sw.source()); + assertEquals(kind, sw.kind()); String s = sw.wrapped(); if (kind == Kind.IMPORT) { assertHas(s, "import"); @@ -322,8 +336,8 @@ public class WrapperTest extends KullaTesting { //System.err.printf("# wrapped @ wrappedPos: %s\n", wrappedPart); //System.err.printf("# source @ start: %s\n", sourcePart); - assertEquals(wrappedPart, sourcePart, + assertEquals(sourcePart, wrappedPart, "position " + wpg + " in " + sw.wrapped()); - assertEquals(sw.wrappedToSourcePosition(wpg), start); + assertEquals(start, sw.wrappedToSourcePosition(wpg)); } } From f9dc640ef07ea5569b3581360041db2bb7e30c40 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 06:33:30 +0000 Subject: [PATCH 398/471] 8351260: java.lang.AssertionError: Unexpected type tree: (ERROR) = (ERROR) Reviewed-by: vromero --- .../sun/tools/javac/parser/JavacParser.java | 9 +++ .../tools/javac/parser/JavacParserTest.java | 65 ++++++++++++++++++- .../tools/javac/recovery/AttrRecovery.java | 20 +++++- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index fb8d3aaeecd..dacf2daf4db 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1104,6 +1104,11 @@ public class JavacParser implements Parser { syntaxError(result.pos, Errors.RestrictedTypeNotAllowedHere(restrictedTypeName)); } + if ((lastmode & TYPE) == 0) { + //if the mode was switched to expression while expecting type, wrap with Erroneous: + result = F.Erroneous(List.of(result)); + } + return result; } @@ -1431,6 +1436,7 @@ public class JavacParser implements Parser { protected JCExpression term3() { int pos = token.pos; JCExpression t; + int startMode = mode; List typeArgs = typeArgumentsOpt(EXPR); switch (token.kind) { case QUES: @@ -1760,6 +1766,9 @@ public class JavacParser implements Parser { } // Not reachable. default: + if (typeArgs != null && (startMode & TYPE) != 0) { + return F.at(pos).TypeApply(F.Erroneous(), typeArgs); + } return illegal(); } return term3Rest(t, typeArgs); diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 9c6ad617132..7d34a14f1d7 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 8344706 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 8344706 8351260 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -3013,6 +3013,69 @@ public class JavacParserTest extends TestCase { }"""); } + @Test //JDK-8351260 + void testVeryBrokenTypeWithAnnotations() throws IOException { + String code = """ + package tests; + class ListUtilsTest { + void test(List<@AlphaChars <@StringLength(int value = 5)String> s){ + } + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testVeryBrokenTypeWithAnnotations: " + codes, + List.of("3:32:compiler.err.illegal.start.of.type", + "3:51:compiler.err.dot.class.expected", + "3:57:compiler.err.expected2", + "3:60:compiler.err.expected2", + "3:61:compiler.err.expected2", + "3:67:compiler.err.not.stmt", + "3:70:compiler.err.expected", + "5:2:compiler.err.premature.eof"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + class ListUtilsTest { + \n\ + void test(List<@AlphaChars (ERROR: (ERROR)<@StringLength(int) value, (ERROR)> = 5), (ERROR: )> ) { + (ERROR: String > s); + { + } + } + }"""); + } + + @Test //JDK-8351260 + void testVeryBrokenTypeWithAnnotationsMinimal() throws IOException { + String code = """ + B<@C<@D(e f= + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + //no exceptions: + ct.parse().iterator().next(); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index c5d393a23b3..a5370884f62 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -322,4 +322,22 @@ public class AttrRecovery extends TestRunner { } } + @Test //JDK-8351260 + public void testVeryBrokenAnnotation() throws Exception { + String code = """ + class ListUtilsTest { + void test(List<@AlphaChars <@StringLength(int value = 5)String> s){ + } + } + """; + Path curPath = Path.of("."); + //should not fail with an exception: + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .writeAll(); + } } From fb1924d2e34f77dc834094485dccb1751bc5b3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 8 Sep 2025 06:33:49 +0000 Subject: [PATCH 399/471] 8366874: Test gc/arguments/TestParallelGCErgo.java fails with UseTransparentHugePages Reviewed-by: ayang, shade, stefank, tschatzl --- test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java index 63c51c25149..b9e5629d875 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java @@ -27,7 +27,7 @@ package gc.arguments; * @test TestParallelGCErgo * @bug 8272364 * @requires vm.gc.Parallel - * @requires vm.opt.UseLargePages == null | !vm.opt.UseLargePages + * @requires !vm.opt.final.UseLargePages * @summary Verify ParallelGC minimum young and old ergonomics are setup correctly * @modules java.base/jdk.internal.misc * @library /test/lib From 051f39e12ce8845d13c7d4813dabc556a834892d Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 8 Sep 2025 07:10:12 +0000 Subject: [PATCH 400/471] 8366864: Sort os/linux includes Reviewed-by: ayang, dholmes --- .../os/linux/cgroupSubsystem_linux.cpp | 11 ++-- .../os/linux/cgroupSubsystem_linux.hpp | 6 +-- src/hotspot/os/linux/cgroupUtil_linux.cpp | 2 +- src/hotspot/os/linux/cgroupUtil_linux.hpp | 2 +- .../os/linux/cgroupV1Subsystem_linux.cpp | 11 ++-- .../os/linux/cgroupV1Subsystem_linux.hpp | 4 +- .../os/linux/cgroupV2Subsystem_linux.cpp | 2 +- src/hotspot/os/linux/osContainer_linux.cpp | 13 ++--- src/hotspot/os/linux/osContainer_linux.hpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 51 +++++++++---------- src/hotspot/os/linux/os_linux.inline.hpp | 2 +- src/hotspot/os/linux/os_perf_linux.cpp | 22 ++++---- src/hotspot/os/linux/waitBarrier_linux.cpp | 3 +- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 14 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 3186d97ec61..f935e2cbb9c 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -22,14 +22,10 @@ * */ -#include -#include -#include -#include #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" -#include "cgroupUtil_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "os_linux.hpp" @@ -37,6 +33,11 @@ #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include +#include +#include +#include + // Inlined from for portability. #ifndef CGROUP2_SUPER_MAGIC # define CGROUP2_SUPER_MAGIC 0x63677270 diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index f72d1a7fb1e..22e57d56c93 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -25,12 +25,12 @@ #ifndef CGROUP_SUBSYSTEM_LINUX_HPP #define CGROUP_SUBSYSTEM_LINUX_HPP -#include "memory/allocation.hpp" -#include "runtime/os.hpp" #include "logging/log.hpp" +#include "memory/allocation.hpp" +#include "osContainer_linux.hpp" +#include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -#include "osContainer_linux.hpp" // Shared cgroups code (used by cgroup version 1 and version 2) diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 72dda36504d..de027db812a 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -22,8 +22,8 @@ * */ -#include "os_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "os_linux.hpp" int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { assert(host_cpus > 0, "physical host cpus must be positive"); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index 19220af3177..aa63a7457cc 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -25,8 +25,8 @@ #ifndef CGROUP_UTIL_LINUX_HPP #define CGROUP_UTIL_LINUX_HPP -#include "utilities/globalDefinitions.hpp" #include "cgroupSubsystem_linux.hpp" +#include "utilities/globalDefinitions.hpp" class CgroupUtil: AllStatic { diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index f65da207062..64cb53eda28 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -22,17 +22,18 @@ * */ -#include -#include -#include -#include "cgroupV1Subsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "cgroupV1Subsystem_linux.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" +#include "os_linux.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" -#include "os_linux.hpp" + +#include +#include +#include /* * Set directory to subsystem specific files based diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index a56ad455165..33bf2ed6e55 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -25,10 +25,10 @@ #ifndef CGROUP_V1_SUBSYSTEM_LINUX_HPP #define CGROUP_V1_SUBSYSTEM_LINUX_HPP -#include "runtime/os.hpp" -#include "memory/allocation.hpp" #include "cgroupSubsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "memory/allocation.hpp" +#include "runtime/os.hpp" // Cgroups version 1 specific implementation diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 6472fdfccc5..661f7e909b5 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -23,8 +23,8 @@ * */ -#include "cgroupV2Subsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +#include "cgroupV2Subsystem_linux.hpp" // Constructor CgroupV2Controller::CgroupV2Controller(char* mount_path, diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index 2ba4c252659..899e7535fde 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -22,15 +22,16 @@ * */ -#include -#include -#include -#include "runtime/globals.hpp" -#include "runtime/os.hpp" +#include "cgroupSubsystem_linux.hpp" #include "logging/log.hpp" #include "os_linux.hpp" #include "osContainer_linux.hpp" -#include "cgroupSubsystem_linux.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" + +#include +#include +#include bool OSContainer::_is_initialized = false; diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index 3c270e8ea50..d9b024dbbb5 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -25,10 +25,10 @@ #ifndef OS_LINUX_OSCONTAINER_LINUX_HPP #define OS_LINUX_OSCONTAINER_LINUX_HPP +#include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -#include "memory/allStatic.hpp" #define OSCONTAINER_ERROR (-2) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index ba026442f7f..d133813feb0 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -36,9 +36,9 @@ #include "memory/allocation.inline.hpp" #include "nmt/memTracker.hpp" #include "oops/oop.inline.hpp" -#include "osContainer_linux.hpp" #include "os_linux.inline.hpp" #include "os_posix.inline.hpp" +#include "osContainer_linux.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" #include "runtime/arguments.hpp" @@ -81,42 +81,39 @@ #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" #endif -// put OS-includes here # include -# include -# include -# include -# include -# include -# include -# include -# include +# include # include # include +# include # include -# include -# include -# include -# include +# include +# include +# include +# include # include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include # include +# include # include # include +# include # include -# include -# include -# include -# include -# include # include -# include -# include -# include -# include -# include -# include -# include -# include +# include #ifdef __GLIBC__ # include #endif diff --git a/src/hotspot/os/linux/os_linux.inline.hpp b/src/hotspot/os/linux/os_linux.inline.hpp index f9d798404b5..4b5592d2f62 100644 --- a/src/hotspot/os/linux/os_linux.inline.hpp +++ b/src/hotspot/os/linux/os_linux.inline.hpp @@ -27,8 +27,8 @@ #include "os_linux.hpp" -#include "runtime/os.hpp" #include "os_posix.inline.hpp" +#include "runtime/os.hpp" inline bool os::zero_page_read_protected() { return true; diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 9151049dd1c..7caf8f98a00 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -31,21 +31,21 @@ #include "runtime/vm_version.hpp" #include "utilities/globalDefinitions.hpp" -#include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include /** /proc/[number]/stat diff --git a/src/hotspot/os/linux/waitBarrier_linux.cpp b/src/hotspot/os/linux/waitBarrier_linux.cpp index f1f5be05152..0d5722f0725 100644 --- a/src/hotspot/os/linux/waitBarrier_linux.cpp +++ b/src/hotspot/os/linux/waitBarrier_linux.cpp @@ -26,8 +26,9 @@ #include "runtime/os.hpp" #include "utilities/debug.hpp" #include "waitBarrier_linux.hpp" -#include + #include +#include // 32-bit RISC-V has no SYS_futex syscall. #ifdef RISCV32 diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 19aaeed69a2..119f32ffe2e 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -43,6 +43,7 @@ public class TestIncludesAreSorted { * can be checked). */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { + "os/linux", "share" }; From bea2b029a77e126171d17c3a44baec6d5cafed4a Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Mon, 8 Sep 2025 08:30:03 +0000 Subject: [PATCH 401/471] 8360219: [AIX] assert(locals_base >= l2) failed: bad placement Reviewed-by: dlong, mdoerr --- src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp index beadce33637..9c74e6f53e7 100644 --- a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp +++ b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp @@ -100,7 +100,7 @@ int AbstractInterpreter::size_activation(int max_stack, // It is also guaranteed to be walkable even though it is in a skeletal state // // is_top_frame == true: -// We're processing the *oldest* interpreter frame! +// We're processing the *youngest* interpreter frame on top of stack! // // pop_frame_extra_args: // If this is != 0 we are returning to a deoptimized frame by popping @@ -131,8 +131,9 @@ void AbstractInterpreter::layout_activation(Method* method, #ifdef ASSERT if (caller->is_interpreted_frame()) { assert(locals_base <= caller->interpreter_frame_expression_stack(), "bad placement"); - const int caller_abi_bytesize = (is_bottom_frame ? frame::top_ijava_frame_abi_size : frame::parent_ijava_frame_abi_size); - intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (caller_abi_bytesize / Interpreter::stackElementSize); + // If the bottom frame's caller was thawed then it has frame::java_abi (aka parent_ijava_frame_abi). + // With an ordinary i2c call it would keep the larger frame::top_ijava_frame_abi + intptr_t* l2 = caller->sp() + method->max_locals() - 1 + (frame::parent_ijava_frame_abi_size / Interpreter::stackElementSize); assert(locals_base >= l2, "bad placement"); } #endif From 5e423e034f1f077ce9c17cfe9b0d838a4cf9365e Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Mon, 8 Sep 2025 09:37:36 +0000 Subject: [PATCH 402/471] 8367025: zIndexDistributor.hpp uses angle-bracket inclusion of globalDefinitions.hpp Reviewed-by: aboldtch, tschatzl, jwaters --- src/hotspot/share/gc/z/zIndexDistributor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/z/zIndexDistributor.hpp b/src/hotspot/share/gc/z/zIndexDistributor.hpp index d4b9edcb5b4..2b46ddafdb2 100644 --- a/src/hotspot/share/gc/z/zIndexDistributor.hpp +++ b/src/hotspot/share/gc/z/zIndexDistributor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ #ifndef SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP #define SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP -#include +#include "utilities/globalDefinitions.hpp" class ZIndexDistributor { private: From a272696813f2e5e896ac9de9985246aaeb9d476c Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 8 Sep 2025 10:28:18 +0000 Subject: [PATCH 403/471] 8365190: Remove LockingMode related code from share Reviewed-by: aboldtch, dholmes, ayang, coleenp, lmesnik, rcastanedalo --- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 42 +- src/hotspot/share/c1/c1_LIRGenerator.cpp | 2 +- src/hotspot/share/c1/c1_Runtime1.cpp | 3 - .../share/gc/g1/g1BarrierSet.inline.hpp | 4 +- .../share/gc/g1/g1BarrierSetRuntime.cpp | 2 +- .../share/gc/g1/g1HeapRegion.inline.hpp | 6 +- .../share/gc/g1/g1SATBMarkQueueSet.cpp | 2 +- .../share/gc/shared/cardTableBarrierSet.cpp | 2 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 6 - .../interpreter/zero/bytecodeInterpreter.cpp | 127 +--- src/hotspot/share/jvmci/jvmciRuntime.cpp | 4 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 5 - .../share/oops/instanceStackChunkKlass.cpp | 4 - src/hotspot/share/oops/markWord.cpp | 33 +- src/hotspot/share/oops/markWord.hpp | 20 +- src/hotspot/share/oops/oop.cpp | 22 +- src/hotspot/share/oops/oop.hpp | 4 +- .../share/oops/stackChunkOop.inline.hpp | 3 +- src/hotspot/share/opto/library_call.cpp | 16 +- src/hotspot/share/opto/phaseX.cpp | 1 + src/hotspot/share/prims/jvmtiEnv.cpp | 10 - src/hotspot/share/runtime/arguments.cpp | 18 - src/hotspot/share/runtime/basicLock.cpp | 25 +- src/hotspot/share/runtime/basicLock.hpp | 11 - .../share/runtime/basicLock.inline.hpp | 10 - src/hotspot/share/runtime/continuation.cpp | 4 - .../share/runtime/continuationFreezeThaw.cpp | 31 +- src/hotspot/share/runtime/deoptimization.cpp | 52 +- src/hotspot/share/runtime/globals.hpp | 4 - src/hotspot/share/runtime/javaCalls.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 52 +- src/hotspot/share/runtime/javaThread.hpp | 3 - .../share/runtime/lightweightSynchronizer.cpp | 34 +- src/hotspot/share/runtime/lockStack.cpp | 1 - src/hotspot/share/runtime/objectMonitor.cpp | 3 +- src/hotspot/share/runtime/objectMonitor.hpp | 13 +- .../share/runtime/objectMonitor.inline.hpp | 14 +- src/hotspot/share/runtime/sharedRuntime.cpp | 13 +- src/hotspot/share/runtime/synchronizer.cpp | 684 +----------------- src/hotspot/share/runtime/synchronizer.hpp | 30 +- .../share/runtime/synchronizer.inline.hpp | 18 +- src/hotspot/share/runtime/threads.cpp | 21 +- src/hotspot/share/runtime/threads.hpp | 5 +- src/hotspot/share/runtime/vmStructs.cpp | 9 - .../share/utilities/globalDefinitions.cpp | 2 - .../share/utilities/globalDefinitions.hpp | 11 - src/hotspot/share/utilities/vmError.cpp | 2 +- .../jvm/hotspot/runtime/ObjectMonitor.java | 6 +- test/hotspot/gtest/runtime/test_lockStack.cpp | 12 +- .../locking/TestRecursiveMonitorChurn.java | 3 - 50 files changed, 141 insertions(+), 1270 deletions(-) diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 029ccbded13..28c2364315e 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -331,26 +331,9 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { monitor = nullptr; if (method->is_synchronized()) { monitor = (BasicObjectLock*) istate->stack_base(); - oop lockee = monitor->obj(); - bool success = false; - if (LockingMode == LM_LEGACY) { - markWord disp = lockee->mark().set_unlocked(); - monitor->lock()->set_displaced_header(disp); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { - // Is it simple recursive case? - if (thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { - monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); - if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; - } + CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; } // Get the signature handler @@ -481,24 +464,7 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // Unlock if necessary if (monitor) { - bool success = false; - if (LockingMode == LM_LEGACY) { - BasicLock* lock = monitor->lock(); - oop rcvr = monitor->obj(); - monitor->set_obj(nullptr); - success = true; - markWord header = lock->displaced_header(); - if (header.to_pointer() != nullptr) { // Check for recursive lock - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - monitor->set_obj(rcvr); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(monitor); - } + InterpreterRuntime::monitorexit(monitor); } unwind_and_return: diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index cbd84b3a11e..b30667dcac3 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -635,7 +635,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L // setup registers LIR_Opr hdr = lock; lock = new_hdr; - CodeStub* slow_path = new MonitorExitStub(lock, LockingMode != LM_MONITOR, monitor_no); + CodeStub* slow_path = new MonitorExitStub(lock, true, monitor_no); __ load_stack_address_monitor(monitor_no, lock); __ unlock_object(hdr, object, lock, scratch, slow_path); } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 4a1969788f3..fbf2bfb0f53 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -778,9 +778,6 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj, _monitorenter_slowcase_cnt++; } #endif - if (LockingMode == LM_MONITOR) { - lock->set_obj(obj); - } assert(obj == lock->obj(), "must match"); SharedRuntime::monitor_enter_helper(obj, lock->lock(), current); JRT_END diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp index 33c153e9e5d..9678da190af 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -37,7 +37,7 @@ inline void G1BarrierSet::enqueue_preloaded(oop pre_val) { // Nulls should have been already filtered. - assert(oopDesc::is_oop(pre_val, true), "Error"); + assert(oopDesc::is_oop(pre_val), "Error"); G1SATBMarkQueueSet& queue_set = G1BarrierSet::satb_mark_queue_set(); if (!queue_set.is_active()) return; diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp index ce0d53e4891..205829bba1a 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp @@ -47,7 +47,7 @@ void G1BarrierSetRuntime::write_ref_array_post_entry(HeapWord* dst, size_t lengt JRT_LEAF(void, G1BarrierSetRuntime::write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread)) assert(thread == JavaThread::current(), "pre-condition"); assert(orig != nullptr, "should be optimized out"); - assert(oopDesc::is_oop(orig, true /* ignore mark word */), "Error"); + assert(oopDesc::is_oop(orig), "Error"); // store the original value that was in the field reference SATBMarkQueue& queue = G1ThreadLocalData::satb_mark_queue(thread); G1BarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index c2e5c5df4b1..236e72aeb91 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -350,7 +350,7 @@ inline HeapWord* G1HeapRegion::oops_on_memregion_iterate_in_unparsable(MemRegion assert(bitmap->is_marked(cur), "inv"); oop obj = cast_to_oop(cur); - assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); + assert(oopDesc::is_oop(obj), "Not an oop at " PTR_FORMAT, p2i(cur)); cur += obj->size(); bool is_precise; @@ -418,7 +418,7 @@ inline HeapWord* G1HeapRegion::oops_on_memregion_iterate(MemRegion mr, Closure* // All objects >= pb are parsable. So we can just take object sizes directly. while (true) { oop obj = cast_to_oop(cur); - assert(oopDesc::is_oop(obj, true), "Not an oop at " PTR_FORMAT, p2i(cur)); + assert(oopDesc::is_oop(obj), "Not an oop at " PTR_FORMAT, p2i(cur)); bool is_precise = false; diff --git a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp index f0b29a5bbab..7d197c37158 100644 --- a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp +++ b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp @@ -89,7 +89,7 @@ static inline bool requires_marking(const void* entry, G1CollectedHeap* g1h) { return false; } - assert(oopDesc::is_oop(cast_to_oop(entry), true /* ignore mark word */), + assert(oopDesc::is_oop(cast_to_oop(entry)), "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry)); return true; diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index 84bf3eac130..dfa00636dec 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -162,7 +162,7 @@ void CardTableBarrierSet::flush_deferred_card_mark_barrier(JavaThread* thread) { DEBUG_ONLY(oop old_obj = cast_to_oop(deferred.start());) assert(!_card_table->is_in_young(old_obj), "Else should have been filtered in on_slowpath_allocation_exit()"); - assert(oopDesc::is_oop(old_obj, true), "Not an oop"); + assert(oopDesc::is_oop(old_obj), "Not an oop"); assert(deferred.word_size() == old_obj->size(), "Mismatch: multiple objects?"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index cf9d808f7ce..4de6ccead51 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -312,11 +312,6 @@ void ShenandoahHeap::increase_object_age(oop obj, uint additional_age) { // For all these reasons, we take the conservative approach and not attempt // to increase the age when the header is displaced. markWord w = obj->mark(); - // The mark-word has been copied from the original object. It can not be - // inflating, because inflation can not be interrupted by a safepoint, - // and after a safepoint, a Java thread would first have to successfully - // evacuate the object before it could inflate the monitor. - assert(!w.is_being_inflated() || LockingMode == LM_LIGHTWEIGHT, "must not inflate monitor before evacuation of object succeeds"); // It is possible that we have copied the object after another thread has // already successfully completed evacuation. While harmless (we would never // publish our copy), don't even attempt to modify the age when that @@ -334,7 +329,6 @@ uint ShenandoahHeap::get_object_age(oop obj) { markWord w = obj->mark(); assert(!w.is_marked(), "must not be forwarded"); if (UseObjectMonitorTable) { - assert(LockingMode == LM_LIGHTWEIGHT, "Must use LW locking, too"); assert(w.age() <= markWord::max_age, "Impossible!"); return w.age(); } diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index bfed16f2769..e9adfce6372 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -624,26 +624,7 @@ void BytecodeInterpreter::run(interpreterState istate) { // The initial monitor is ours for the taking. BasicObjectLock* mon = &istate->monitor_base()[-1]; mon->set_obj(rcvr); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = rcvr->mark().set_unlocked(); - mon->lock()->set_displaced_header(displaced); - success = true; - if (rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } THREAD->set_do_not_unlock_if_synchronized(false); @@ -725,26 +706,7 @@ void BytecodeInterpreter::run(interpreterState istate) { BasicObjectLock* entry = (BasicObjectLock*) istate->stack_base(); assert(entry->obj() == nullptr, "Frame manager didn't allocate the monitor"); entry->set_obj(lockee); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); UPDATE_PC_AND_TOS(1, -1); goto run; } @@ -1657,26 +1619,7 @@ run: } if (entry != nullptr) { entry->set_obj(lockee); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // Traditional fast locking. - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - success = true; - if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - success = false; - } - } - } - if (!success) { - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); - } - + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); @@ -1694,25 +1637,7 @@ run: while (most_recent != limit ) { if ((most_recent)->obj() == lockee) { BasicLock* lock = most_recent->lock(); - - bool success = false; - if (LockingMode == LM_LEGACY) { - // If it isn't recursive we either must swap old header or call the runtime - most_recent->set_obj(nullptr); - success = true; - markWord header = lock->displaced_header(); - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - most_recent->set_obj(lockee); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(most_recent); - } + InterpreterRuntime::monitorexit(most_recent); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } most_recent++; @@ -3137,27 +3062,7 @@ run: while (end < base) { oop lockee = end->obj(); if (lockee != nullptr) { - BasicLock* lock = end->lock(); - - bool success = false; - if (LockingMode == LM_LEGACY) { - markWord header = lock->displaced_header(); - end->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - success = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - end->set_obj(lockee); - success = false; - } - } - } - if (!success) { - InterpreterRuntime::monitorexit(end); - } + InterpreterRuntime::monitorexit(end); // One error is plenty if (illegal_state_oop() == nullptr && !suppress_error) { @@ -3204,32 +3109,12 @@ run: illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else if (LockingMode != LM_LEGACY) { + } else { InterpreterRuntime::monitorexit(base); if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else { - BasicLock* lock = base->lock(); - markWord header = lock->displaced_header(); - base->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - base->set_obj(rcvr); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(base); - if (THREAD->has_pending_exception()) { - if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); - THREAD->clear_pending_exception(); - } - } - } } } } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c0335e7c67e..33aa40acbc2 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -565,8 +565,8 @@ JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, bool a if (obj == nullptr) { tty->print("null"); - } else if (oopDesc::is_oop_or_null(obj, true) && (!as_string || !java_lang_String::is_instance(obj))) { - if (oopDesc::is_oop_or_null(obj, true)) { + } else if (oopDesc::is_oop_or_null(obj) && (!as_string || !java_lang_String::is_instance(obj))) { + if (oopDesc::is_oop_or_null(obj)) { char buf[O_BUFLEN]; tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); } else { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 737718096c5..47ebe5aa7a7 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -341,7 +341,6 @@ volatile_nonstatic_field(ObjectMonitor, _recursions, intptr_t) \ volatile_nonstatic_field(ObjectMonitor, _entry_list, ObjectWaiter*) \ volatile_nonstatic_field(ObjectMonitor, _succ, int64_t) \ - volatile_nonstatic_field(ObjectMonitor, _stack_locker, BasicLock*) \ \ volatile_nonstatic_field(oopDesc, _mark, markWord) \ volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ @@ -780,10 +779,6 @@ declare_constant(InstanceKlass::being_initialized) \ declare_constant(InstanceKlass::fully_initialized) \ \ - declare_constant(LockingMode::LM_MONITOR) \ - declare_constant(LockingMode::LM_LEGACY) \ - declare_constant(LockingMode::LM_LIGHTWEIGHT) \ - \ /*********************************/ \ /* InstanceKlass _misc_flags */ \ /*********************************/ \ diff --git a/src/hotspot/share/oops/instanceStackChunkKlass.cpp b/src/hotspot/share/oops/instanceStackChunkKlass.cpp index bf08cfd25ab..db60e74013f 100644 --- a/src/hotspot/share/oops/instanceStackChunkKlass.cpp +++ b/src/hotspot/share/oops/instanceStackChunkKlass.cpp @@ -164,10 +164,6 @@ void InstanceStackChunkKlass::oop_oop_iterate_stack_slow(stackChunkOop chunk, Oo template void InstanceStackChunkKlass::oop_oop_iterate_lockstack(stackChunkOop chunk, OopIterateClosure* closure, MemRegion mr) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - StackChunkOopIterateFilterClosure cl(closure, mr); if (chunk->has_bitmap()) { chunk->iterate_lockstack(&cl); diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 2ba57cddc67..001666b0439 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -36,35 +36,18 @@ STATIC_ASSERT(markWord::klass_shift == markWord::hash_bits + markWord::hash_shif markWord markWord::displaced_mark_helper() const { assert(has_displaced_mark_helper(), "check"); - if (has_monitor()) { - // Has an inflated monitor. Must be checked before has_locker(). - ObjectMonitor* monitor = this->monitor(); - return monitor->header(); - } - if (has_locker()) { // has a stack lock - BasicLock* locker = this->locker(); - return locker->displaced_header(); - } - // This should never happen: - fatal("bad header=" INTPTR_FORMAT, value()); - return markWord(value()); + // Make sure we have an inflated monitor. + guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); + ObjectMonitor* monitor = this->monitor(); + return monitor->header(); } void markWord::set_displaced_mark_helper(markWord m) const { assert(has_displaced_mark_helper(), "check"); - if (has_monitor()) { - // Has an inflated monitor. Must be checked before has_locker(). - ObjectMonitor* monitor = this->monitor(); - monitor->set_header(m); - return; - } - if (has_locker()) { // has a stack lock - BasicLock* locker = this->locker(); - locker->set_displaced_header(m); - return; - } - // This should never happen: - fatal("bad header=" INTPTR_FORMAT, value()); + // Make sure we have an inflated monitor. + guarantee(has_monitor(), "bad header=" INTPTR_FORMAT, value()); + ObjectMonitor* monitor = this->monitor(); + monitor->set_header(m); } void markWord::print_on(outputStream* st, bool print_monitor_info) const { diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 9cb46f4697d..08234709c97 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -198,17 +198,8 @@ class markWord { markWord set_unlocked() const { return markWord(value() | unlocked_value); } - bool has_locker() const { - assert(LockingMode == LM_LEGACY, "should only be called with legacy stack locking"); - return (value() & lock_mask_in_place) == locked_value; - } - BasicLock* locker() const { - assert(has_locker(), "check"); - return (BasicLock*) value(); - } bool is_fast_locked() const { - assert(LockingMode == LM_LIGHTWEIGHT, "should only be called with new lightweight locking"); return (value() & lock_mask_in_place) == locked_value; } markWord set_fast_locked() const { @@ -227,11 +218,7 @@ class markWord { } bool has_displaced_mark_helper() const { intptr_t lockbits = value() & lock_mask_in_place; - if (LockingMode == LM_LIGHTWEIGHT) { - return !UseObjectMonitorTable && lockbits == monitor_value; - } - // monitor (0b10) | stack-locked (0b00)? - return (lockbits & unlocked_value) == 0; + return !UseObjectMonitorTable && lockbits == monitor_value; } markWord displaced_mark_helper() const; void set_displaced_mark_helper(markWord m) const; @@ -304,17 +291,14 @@ class markWord { inline void* decode_pointer() const { return (void*)clear_lock_bits().value(); } inline bool is_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return mask_bits(value(), self_fwd_mask_in_place) != 0; } inline markWord set_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return markWord(value() | self_fwd_mask_in_place); } inline markWord unset_self_forwarded() const { - NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");) return markWord(value() & ~self_fwd_mask_in_place); } diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 7f0068f7473..be6e16855bd 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -110,27 +110,13 @@ intptr_t oopDesc::slow_identity_hash() { } // used only for asserts and guarantees -bool oopDesc::is_oop(oop obj, bool ignore_mark_word) { - if (!Universe::heap()->is_oop(obj)) { - return false; - } - - // Header verification: the mark is typically non-zero. If we're - // at a safepoint, it must not be zero, except when using the new lightweight locking. - // Outside of a safepoint, the header could be changing (for example, - // another thread could be inflating a lock on this object). - if (ignore_mark_word) { - return true; - } - if (obj->mark().value() != 0) { - return true; - } - return LockingMode == LM_LIGHTWEIGHT || !SafepointSynchronize::is_at_safepoint(); +bool oopDesc::is_oop(oop obj) { + return Universe::heap()->is_oop(obj); } // used only for asserts and guarantees -bool oopDesc::is_oop_or_null(oop obj, bool ignore_mark_word) { - return obj == nullptr ? true : is_oop(obj, ignore_mark_word); +bool oopDesc::is_oop_or_null(oop obj) { + return obj == nullptr ? true : is_oop(obj); } VerifyOopClosure VerifyOopClosure::verify_oop; diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 3ec0ce5764a..a1c1a64b050 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -261,8 +261,8 @@ class oopDesc { inline bool is_unlocked() const; // asserts and guarantees - static bool is_oop(oop obj, bool ignore_mark_word = false); - static bool is_oop_or_null(oop obj, bool ignore_mark_word = false); + static bool is_oop(oop obj); + static bool is_oop_or_null(oop obj); // garbage collection inline bool is_gc_marked() const; diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index 384dbefc10b..9c91e934328 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -195,7 +195,6 @@ void stackChunkOopDesc::do_barriers(const StackChunkFrameStream& f, template inline void stackChunkOopDesc::iterate_lockstack(StackChunkLockStackClosureType* closure) { - assert(LockingMode == LM_LIGHTWEIGHT, ""); int cnt = lockstack_size(); intptr_t* lockstart_addr = start_address(); for (int i = 0; i < cnt; i++) { diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index da04d6b01ac..433dacc0ee1 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4788,19 +4788,11 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { // Test the header to see if it is safe to read w.r.t. locking. Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - if (LockingMode == LM_LIGHTWEIGHT) { - Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); - Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); - Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); - generate_slow_guard(test_monitor, slow_region); - } else { - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); - Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); - - generate_slow_guard(test_not_unlocked, slow_region); - } + generate_slow_guard(test_monitor, slow_region); } // Get the hash value and check to see that it has been properly assigned. diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1df2cdb179e..a4248cb2b91 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1670,6 +1670,7 @@ bool PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { // Found (linux x64 only?) with: // serviceability/sa/ClhsdbThreadContext.java // -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 + // Note: The -XX:LockingMode option is not available anymore. case Op_StrEquals: return false; diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index bc4013a7cab..30dd1f77d23 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1367,11 +1367,6 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job return err; } - if (LockingMode == LM_LEGACY && java_thread == nullptr) { - *owned_monitor_count_ptr = 0; - return JVMTI_ERROR_NONE; - } - // growable array of jvmti monitors info on the C-heap GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); @@ -1427,11 +1422,6 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count return err; } - if (LockingMode == LM_LEGACY && java_thread == nullptr) { - *monitor_info_count_ptr = 0; - return JVMTI_ERROR_NONE; - } - // growable array of jvmti monitors info on the C-heap GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2ebc15d0e1a..21706eb7726 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1854,24 +1854,6 @@ bool Arguments::check_vm_args_consistency() { } #endif - if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { - // ObjectMonitorTable requires lightweight locking. - FLAG_SET_CMDLINE(UseObjectMonitorTable, false); - warning("UseObjectMonitorTable requires LM_LIGHTWEIGHT"); - } - -#if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) && !defined(S390) - if (LockingMode == LM_MONITOR) { - jio_fprintf(defaultStream::error_stream(), - "LockingMode == 0 (LM_MONITOR) is not fully implemented on this architecture\n"); - return false; - } -#endif - if (VerifyHeavyMonitors && LockingMode != LM_MONITOR) { - jio_fprintf(defaultStream::error_stream(), - "-XX:+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)\n"); - return false; - } return status; } diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 384fc493e0b..71082e24bb9 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -34,13 +34,6 @@ void BasicLock::print_on(outputStream* st, oop owner) const { if (mon != nullptr) { mon->print_on(st); } - } else if (LockingMode == LM_LEGACY) { - markWord mark_word = displaced_header(); - if (mark_word.value() != 0) { - // Print monitor info if there's an owning oop and it refers to this BasicLock. - bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); - mark_word.print_on(st, print_monitor_info); - } } } @@ -73,23 +66,7 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { // small (given the support for inflated fast-path locking in the fast_lock, etc) // we'll leave that optimization for another time. - if (LockingMode == LM_LEGACY) { - if (displaced_header().is_neutral()) { - // The object is locked and the resulting ObjectMonitor* will also be - // locked so it can't be async deflated until ownership is dropped. - ObjectSynchronizer::inflate_helper(obj); - // WARNING: We cannot put a check here, because the inflation - // will not update the displaced header. Once BasicLock is inflated, - // no one should ever look at its content. - } else { - // Typically the displaced header will be 0 (recursive stack lock) or - // unused_mark. Naively we'd like to assert that the displaced mark - // value is either 0, neutral, or 3. But with the advent of the - // store-before-CAS avoidance in fast_lock/compiler_lock_object - // we can find any flavor mark in the displaced mark. - } - dest->set_displaced_header(displaced_header()); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { // Preserve the ObjectMonitor*, the cache is cleared when a box is reused // and only read while the lock is held, so no stale ObjectMonitor* is // encountered. diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index 50de8db6bc6..8ed38747c74 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -35,12 +35,6 @@ class BasicLock { friend class VMStructs; friend class JVMCIVMStructs; private: - // * For LM_MONITOR - // Unused. - // * For LM_LEGACY - // This is either the actual displaced header from a locked object, or - // a sentinel zero value indicating a recursive stack-lock. - // * For LM_LIGHTWEIGHT // Used as a cache of the ObjectMonitor* used when locking. Must either // be nullptr or the ObjectMonitor* used when locking. volatile uintptr_t _metadata; @@ -52,15 +46,10 @@ class BasicLock { public: BasicLock() : _metadata(0) {} - // LM_MONITOR void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - // LM_LEGACY - inline markWord displaced_header() const; - inline void set_displaced_header(markWord header); static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } - // LM_LIGHTWEIGHT inline ObjectMonitor* object_monitor_cache() const; inline void clear_object_monitor_cache(); inline void set_object_monitor_cache(ObjectMonitor* mon); diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 773d8a1c848..2ea1fe2371c 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -29,16 +29,6 @@ #include "runtime/objectMonitor.inline.hpp" -inline markWord BasicLock::displaced_header() const { - assert(LockingMode == LM_LEGACY, "must be"); - return markWord(get_metadata()); -} - -inline void BasicLock::set_displaced_header(markWord header) { - assert(LockingMode == LM_LEGACY, "must be"); - Atomic::store(&_metadata, header.value()); -} - inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); #if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 727dcf8fc26..8f1cbe39640 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -146,10 +146,6 @@ static void verify_preempt_preconditions(JavaThread* current, oop continuation) freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { verify_preempt_preconditions(current, continuation); - if (LockingMode == LM_LEGACY) { - return freeze_unsupported; - } - if (!is_vthread_safe_to_preempt(current, current->vthread())) { return freeze_pinned_native; } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 40a8987e139..64f9d2b9994 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -533,11 +533,7 @@ FreezeBase::FreezeBase(JavaThread* thread, ContinuationWrapper& cont, intptr_t* cont_size(), _cont.argsize(), p2i(_cont_stack_top), p2i(_cont_stack_bottom)); assert(cont_size() > 0, ""); - if (LockingMode != LM_LIGHTWEIGHT) { - _monitors_in_lockstack = 0; - } else { - _monitors_in_lockstack = _thread->lock_stack().monitor_count(); - } + _monitors_in_lockstack = _thread->lock_stack().monitor_count(); } void FreezeBase::init_rest() { // we want to postpone some initialization after chunk handling @@ -587,33 +583,12 @@ static void assert_frames_in_continuation_are_safe(JavaThread* thread) { #endif // ASSERT } -#ifdef ASSERT -static bool monitors_on_stack(JavaThread* thread) { - assert_frames_in_continuation_are_safe(thread); - ContinuationEntry* ce = thread->last_continuation(); - RegisterMap map(thread, - RegisterMap::UpdateMap::include, - RegisterMap::ProcessFrames::skip, - RegisterMap::WalkContinuation::skip); - map.set_include_argument_oops(false); - for (frame f = thread->last_frame(); Continuation::is_frame_in_continuation(ce, f); f = f.sender(&map)) { - if ((f.is_interpreted_frame() && ContinuationHelper::InterpretedFrame::is_owning_locks(f)) || - (f.is_compiled_frame() && ContinuationHelper::CompiledFrame::is_owning_locks(map.thread(), &map, f)) || - (f.is_native_frame() && ContinuationHelper::NativeFrame::is_owning_locks(map.thread(), f))) { - return true; - } - } - return false; -} -#endif // ASSERT - // Called _after_ the last possible safepoint during the freeze operation (chunk allocation) void FreezeBase::unwind_frames() { ContinuationEntry* entry = _cont.entry(); entry->flush_stack_processing(_thread); assert_frames_in_continuation_are_safe(_thread); JFR_ONLY(Jfr::check_and_process_sample_request(_thread);) - assert(LockingMode != LM_LEGACY || !monitors_on_stack(_thread), "unexpected monitors on stack"); set_anchor_to_entry(_thread, entry); } @@ -1762,8 +1737,8 @@ static inline freeze_result freeze_internal(JavaThread* current, intptr_t* const assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), ""); - assert(LockingMode == LM_LEGACY || (current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), - "Held monitor count should only be used for LM_LEGACY: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); + assert((current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), + "Held monitor count should not be used for lightweight locking: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); if (entry->is_pinned() || current->held_monitor_count() > 0) { log_develop_debug(continuations)("PINNED due to critical section/hold monitor"); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index da9a4e9cd9a..693815c6fc4 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1645,26 +1645,17 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArrayowner()); markWord mark = obj->mark(); if (exec_mode == Unpack_none) { - if (LockingMode == LM_LEGACY && mark.has_locker() && fr.sp() > (intptr_t*)mark.locker()) { - // With exec_mode == Unpack_none obj may be thread local and locked in - // a callee frame. Make the lock in the callee a recursive lock and restore the displaced header. - markWord dmw = mark.displaced_mark_helper(); - mark.locker()->set_displaced_header(markWord::encode((BasicLock*) nullptr)); - obj->set_mark(dmw); - } if (mark.has_monitor()) { // defer relocking if the deoptee thread is currently waiting for obj ObjectMonitor* waiting_monitor = deoptee_thread->current_waiting_monitor(); if (waiting_monitor != nullptr && waiting_monitor->object() == obj()) { assert(fr.is_deoptimized_frame(), "frame must be scheduled for deoptimization"); - if (LockingMode == LM_LEGACY) { - mon_info->lock()->set_displaced_header(markWord::unused_mark()); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { mon_info->lock()->clear_object_monitor_cache(); } #ifdef ASSERT else { - assert(LockingMode == LM_MONITOR || !UseObjectMonitorTable, "must be"); + assert(!UseObjectMonitorTable, "must be"); mon_info->lock()->set_bad_metadata_deopt(); } #endif @@ -1674,29 +1665,24 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraylock(); - if (LockingMode == LM_LIGHTWEIGHT) { - // We have lost information about the correct state of the lock stack. - // Entering may create an invalid lock stack. Inflate the lock if it - // was fast_locked to restore the valid lock stack. - if (UseObjectMonitorTable) { - // UseObjectMonitorTable expects the BasicLock cache to be either a - // valid ObjectMonitor* or nullptr. Right now it is garbage, set it - // to nullptr. - lock->clear_object_monitor_cache(); - } - ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); - if (deoptee_thread->lock_stack().contains(obj())) { - LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, - deoptee_thread, thread); - } - assert(mon_info->owner()->is_locked(), "object must be locked now"); - assert(obj->mark().has_monitor(), "must be"); - assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); - assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->has_owner(deoptee_thread), "must be"); - } else { - ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); - assert(mon_info->owner()->is_locked(), "object must be locked now"); + // We have lost information about the correct state of the lock stack. + // Entering may create an invalid lock stack. Inflate the lock if it + // was fast_locked to restore the valid lock stack. + if (UseObjectMonitorTable) { + // UseObjectMonitorTable expects the BasicLock cache to be either a + // valid ObjectMonitor* or nullptr. Right now it is garbage, set it + // to nullptr. + lock->clear_object_monitor_cache(); } + ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); + if (deoptee_thread->lock_stack().contains(obj())) { + LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, + deoptee_thread, thread); + } + assert(mon_info->owner()->is_locked(), "object must be locked now"); + assert(obj->mark().has_monitor(), "must be"); + assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); + assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->has_owner(deoptee_thread), "must be"); } } } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 9149e389e21..e76b7474891 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1048,10 +1048,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, ErrorFileToStdout, false, \ "If true, error data is printed to stdout instead of a file") \ \ - develop(bool, VerifyHeavyMonitors, false, \ - "Checks that no stack locking happens when using " \ - "-XX:LockingMode=0 (LM_MONITOR)") \ - \ product(bool, PrintStringTableStatistics, false, \ "print statistics about the StringTable and SymbolTable") \ \ diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index f237886c128..ec3132220d9 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -553,7 +553,7 @@ class SignatureChekker : public SignatureIterator { "Bad JNI oop argument %d: " PTR_FORMAT, _pos, v); // Verify the pointee. oop vv = resolve_indirect_oop(v, _value_state[_pos]); - guarantee(oopDesc::is_oop_or_null(vv, true), + guarantee(oopDesc::is_oop_or_null(vv), "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT, _pos, v, p2i(vv)); } diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 89d742e0ea8..ba98f5928aa 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1063,11 +1063,6 @@ JavaThread* JavaThread::active() { } } -bool JavaThread::is_lock_owned(address adr) const { - assert(LockingMode != LM_LIGHTWEIGHT, "should not be called with new lightweight locking"); - return is_in_full_stack(adr); -} - oop JavaThread::exception_oop() const { return Atomic::load(&_exception_oop); } @@ -1437,9 +1432,8 @@ void JavaThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { entry = entry->parent(); } - if (LockingMode == LM_LIGHTWEIGHT) { - lock_stack().oops_do(f); - } + // Due to lightweight locking + lock_stack().oops_do(f); } void JavaThread::oops_do_frames(OopClosure* f, NMethodClosure* cf) { @@ -1999,22 +1993,9 @@ void JavaThread::trace_stack() { // this slow-path. void JavaThread::inc_held_monitor_count(intx i, bool jni) { #ifdef SUPPORT_MONITOR_COUNT - - if (LockingMode != LM_LEGACY) { - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); - return; - } - - assert(_held_monitor_count >= 0, "Must always be non-negative: %zd", _held_monitor_count); - _held_monitor_count += i; - if (jni) { - assert(_jni_monitor_count >= 0, "Must always be non-negative: %zd", _jni_monitor_count); - _jni_monitor_count += i; - } - assert(_held_monitor_count >= _jni_monitor_count, "Monitor count discrepancy detected - held count " - "%zd is less than JNI count %zd", _held_monitor_count, _jni_monitor_count); + // Nothing to do. Just do some sanity check. + assert(_held_monitor_count == 0, "counter should not be used"); + assert(_jni_monitor_count == 0, "counter should not be used"); #endif // SUPPORT_MONITOR_COUNT } @@ -2022,26 +2003,9 @@ void JavaThread::inc_held_monitor_count(intx i, bool jni) { // this slow-path. void JavaThread::dec_held_monitor_count(intx i, bool jni) { #ifdef SUPPORT_MONITOR_COUNT - - if (LockingMode != LM_LEGACY) { - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); - return; - } - - _held_monitor_count -= i; - assert(_held_monitor_count >= 0, "Must always be non-negative: %zd", _held_monitor_count); - if (jni) { - _jni_monitor_count -= i; - assert(_jni_monitor_count >= 0, "Must always be non-negative: %zd", _jni_monitor_count); - } - // When a thread is detaching with still owned JNI monitors, the logic that releases - // the monitors doesn't know to set the "jni" flag and so the counts can get out of sync. - // So we skip this assert if the thread is exiting. Once all monitors are unlocked the - // JNI count is directly set to zero. - assert(_held_monitor_count >= _jni_monitor_count || is_exiting(), "Monitor count discrepancy detected - held count " - "%zd is less than JNI count %zd", _held_monitor_count, _jni_monitor_count); + // Nothing to do. Just do some sanity check. + assert(_held_monitor_count == 0, "counter should not be used"); + assert(_jni_monitor_count == 0, "counter should not be used"); #endif // SUPPORT_MONITOR_COUNT } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index bf72fac5737..32003e1962e 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -755,9 +755,6 @@ public: return (_suspend_flags & _obj_deopt) != 0; } - // Stack-locking support (not for LM_LIGHTWEIGHT) - bool is_lock_owned(address adr) const; - // Accessors for vframe array top // The linked list of vframe arrays are sorted on sp. This means when we // unpack the head must contain the vframe array to unpack. diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp index 423ca990abd..6cec5c80982 100644 --- a/src/hotspot/share/runtime/lightweightSynchronizer.cpp +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -333,8 +333,6 @@ size_t ObjectMonitorTable::_table_size = 0; volatile bool ObjectMonitorTable::_resize = false; ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - ObjectMonitor* monitor = get_monitor_from_table(current, object); if (monitor != nullptr) { *inserted = false; @@ -628,7 +626,6 @@ bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stac } void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(!UseObjectMonitorTable || lock->object_monitor_cache() == nullptr, "must be cleared"); JavaThread* current = JavaThread::current(); VerifyThreadState vts(locking_thread, current); @@ -657,7 +654,6 @@ void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* } void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(current == JavaThread::current(), "must be"); if (obj->klass()->is_value_based()) { @@ -718,7 +714,6 @@ void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* cur } void LightweightSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); assert(current == Thread::current(), "must be"); markWord mark = object->mark(); @@ -770,18 +765,14 @@ void LightweightSynchronizer::exit(oop object, BasicLock* lock, JavaThread* curr monitor->exit(current); } -// LightweightSynchronizer::inflate_locked_or_imse is used to to get an inflated -// ObjectMonitor* with LM_LIGHTWEIGHT. It is used from contexts which require -// an inflated ObjectMonitor* for a monitor, and expects to throw a -// java.lang.IllegalMonitorStateException if it is not held by the current -// thread. Such as notify/wait and jni_exit. LM_LIGHTWEIGHT keeps it invariant -// that it only inflates if it is already locked by the current thread or the -// current thread is in the process of entering. To maintain this invariant we -// need to throw a java.lang.IllegalMonitorStateException before inflating if -// the current thread is not the owner. -// LightweightSynchronizer::inflate_locked_or_imse facilitates this. +// LightweightSynchronizer::inflate_locked_or_imse is used to get an +// inflated ObjectMonitor* from contexts which require that, such as +// notify/wait and jni_exit. Lightweight locking keeps the invariant that it +// only inflates if it is already locked by the current thread or the current +// thread is in the process of entering. To maintain this invariant we need to +// throw a java.lang.IllegalMonitorStateException before inflating if the +// current thread is not the owner. ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchronizer::InflateCause cause, TRAPS) { - assert(LockingMode == LM_LIGHTWEIGHT, "must be"); JavaThread* current = THREAD; for (;;) { @@ -826,12 +817,11 @@ ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSy ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, Thread* current) { - // The JavaThread* locking_thread parameter is only used by LM_LIGHTWEIGHT and requires - // that the locking_thread == Thread::current() or is suspended throughout the call by - // some other mechanism. - // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non + // The JavaThread* locking parameter requires that the locking_thread == JavaThread::current, + // or is suspended throughout the call by some other mechanism. + // Even with lightweight locking the thread might be nullptr when called from a non // JavaThread. (As may still be the case from FastHashCode). However it is only - // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread + // important for the correctness of the lightweight locking algorithm that the thread // is set when called from ObjectSynchronizer::enter from the owning thread, // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. EventJavaMonitorInflate event; @@ -943,7 +933,6 @@ ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, O } ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); VerifyThreadState vts(locking_thread, current); assert(locking_thread->lock_stack().contains(object), "locking_thread must have object on its lock stack"); @@ -1000,7 +989,6 @@ ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, O } ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, BasicLock* lock, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); VerifyThreadState vts(locking_thread, current); // Note: In some paths (deoptimization) the 'current' thread inflates and diff --git a/src/hotspot/share/runtime/lockStack.cpp b/src/hotspot/share/runtime/lockStack.cpp index cab54e420a9..a55c5a6451b 100644 --- a/src/hotspot/share/runtime/lockStack.cpp +++ b/src/hotspot/share/runtime/lockStack.cpp @@ -77,7 +77,6 @@ uint32_t LockStack::end_offset() { #ifndef PRODUCT void LockStack::verify(const char* msg) const { - assert(LockingMode == LM_LIGHTWEIGHT, "never use lock-stack when light weight locking is disabled"); assert((_top <= end_offset()), "lockstack overflow: _top %d end_offset %d", _top, end_offset()); assert((_top >= start_offset()), "lockstack underflow: _top %d start_offset %d", _top, start_offset()); if (SafepointSynchronize::is_at_safepoint() || (Thread::current()->is_Java_thread() && is_owning_thread())) { diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 9e3638ddadc..c1febe7a28c 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -296,8 +296,7 @@ ObjectMonitor::ObjectMonitor(oop object) : _contentions(0), _wait_set(nullptr), _waiters(0), - _wait_set_lock(0), - _stack_locker(nullptr) + _wait_set_lock(0) { } ObjectMonitor::~ObjectMonitor() { diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index c8daeb65b50..ab315ba0fc5 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -160,9 +160,9 @@ class ObjectMonitor : public CHeapObj { // Because of frequent access, the metadata field is at offset zero (0). // Enforced by the assert() in metadata_addr(). - // * LM_LIGHTWEIGHT with UseObjectMonitorTable: - // Contains the _object's hashCode. - // * LM_LEGACY, LM_MONITOR, LM_LIGHTWEIGHT without UseObjectMonitorTable: + // * Lightweight locking with UseObjectMonitorTable: + // Contains the _object's hashCode. + // * * Lightweight locking without UseObjectMonitorTable: // Contains the displaced object header word - mark volatile uintptr_t _metadata; // metadata WeakHandle _object; // backward object pointer @@ -204,9 +204,6 @@ class ObjectMonitor : public CHeapObj { volatile int _waiters; // number of waiting threads volatile int _wait_set_lock; // protects wait set queue - simple spinlock - // Used in LM_LEGACY mode to store BasicLock* in case of inflation by contending thread. - BasicLock* volatile _stack_locker; - public: static void Initialize(); @@ -318,10 +315,6 @@ class ObjectMonitor : public CHeapObj { set_owner_from(ANONYMOUS_OWNER, owner); } - // Get and set _stack_locker. - BasicLock* stack_locker() const; - void set_stack_locker(BasicLock* locker); - // Simply get _next_om field. ObjectMonitor* next_om() const; // Simply set _next_om field to new_value. diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 7dabc50fca7..05ad06c9bf3 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -52,11 +52,7 @@ inline int64_t ObjectMonitor::owner_id_from(oop vthread) { inline bool ObjectMonitor::is_entered(JavaThread* current) const { if (has_anonymous_owner()) { - if (LockingMode == LM_LIGHTWEIGHT) { - return current->lock_stack().contains(object()); - } else { - return current->is_lock_owned((address)stack_locker()); - } + return current->lock_stack().contains(object()); } else { return has_owner(current); } @@ -116,14 +112,6 @@ inline int64_t ObjectMonitor::owner_raw() const { return Atomic::load(&_owner); } -inline BasicLock* ObjectMonitor::stack_locker() const { - return Atomic::load(&_stack_locker); -} - -inline void ObjectMonitor::set_stack_locker(BasicLock* locker) { - Atomic::store(&_stack_locker, locker); -} - // Returns true if owner field == DEFLATER_MARKER and false otherwise. inline bool ObjectMonitor::owner_is_DEFLATER_MARKER() const { return owner_raw() == DEFLATER_MARKER; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 4d3f1327d43..60161643315 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3348,18 +3348,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) kptr2 = fr.next_monitor_in_interpreter_frame(kptr2) ) { if (kptr2->obj() != nullptr) { // Avoid 'holes' in the monitor array BasicLock *lock = kptr2->lock(); - if (LockingMode == LM_LEGACY) { - // Inflate so the object's header no longer refers to the BasicLock. - if (lock->displaced_header().is_unlocked()) { - // The object is locked and the resulting ObjectMonitor* will also be - // locked so it can't be async deflated until ownership is dropped. - // See the big comment in basicLock.cpp: BasicLock::move_to(). - ObjectSynchronizer::inflate_helper(kptr2->obj()); - } - // Now the displaced header is free to move because the - // object's header no longer refers to it. - buf[i] = (intptr_t)lock->displaced_header().value(); - } else if (UseObjectMonitorTable) { + if (UseObjectMonitorTable) { buf[i] = (intptr_t)lock->object_monitor_cache(); } #ifdef ASSERT diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index f3e3072978b..ec4e91d8c6f 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -281,9 +281,7 @@ void ObjectSynchronizer::initialize() { // Start the timer for deflations, so it does not trigger immediately. _last_async_deflation_time_ns = os::javaTimeNanos(); - if (LockingMode == LM_LIGHTWEIGHT) { - LightweightSynchronizer::initialize(); - } + LightweightSynchronizer::initialize(); } MonitorList ObjectSynchronizer::_in_use_list; @@ -342,23 +340,15 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al if (obj == nullptr) return false; // slow-path for invalid obj const markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) { - // Degenerate notify - // fast-locked by caller so by definition the implied waitset is empty. - return true; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Degenerate notify - // stack-locked by caller so by definition the implied waitset is empty. - return true; - } + if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) { + // Degenerate notify + // fast-locked by caller so by definition the implied waitset is empty. + return true; } if (mark.has_monitor()) { ObjectMonitor* const mon = read_monitor(current, obj, mark); - if (LockingMode == LM_LIGHTWEIGHT && mon == nullptr) { + if (mon == nullptr) { // Racing with inflation/deflation go slow path return false; } @@ -381,79 +371,6 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al return false; } -static bool useHeavyMonitors() { -#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) - return LockingMode == LM_MONITOR; -#else - return false; -#endif -} - -// The LockNode emitted directly at the synchronization site would have -// been too big if it were to have included support for the cases of inflated -// recursive enter and exit, so they go here instead. -// Note that we can't safely call AsyncPrintJavaStack() from within -// quick_enter() as our thread state remains _in_Java. - -bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) { - assert(current->thread_state() == _thread_in_Java, "invariant"); - - if (useHeavyMonitors()) { - return false; // Slow path - } - - assert(LockingMode == LM_LEGACY, "legacy mode below"); - - const markWord mark = obj->mark(); - - if (mark.has_monitor()) { - - ObjectMonitor* const m = read_monitor(mark); - // An async deflation or GC can race us before we manage to make - // the ObjectMonitor busy by setting the owner below. If we detect - // that race we just bail out to the slow-path here. - if (m->object_peek() == nullptr) { - return false; - } - - // Lock contention and Transactional Lock Elision (TLE) diagnostics - // and observability - // Case: light contention possibly amenable to TLE - // Case: TLE inimical operations such as nested/recursive synchronization - - if (m->has_owner(current)) { - m->increment_recursions(current); - current->inc_held_monitor_count(); - return true; - } - - // This Java Monitor is inflated so obj's header will never be - // displaced to this thread's BasicLock. Make the displaced header - // non-null so this BasicLock is not seen as recursive nor as - // being locked. We do this unconditionally so that this thread's - // BasicLock cannot be mis-interpreted by any stack walkers. For - // performance reasons, stack walkers generally first check for - // stack-locking in the object's header, the second check is for - // recursive stack-locking in the displaced header in the BasicLock, - // and last are the inflated Java Monitor (ObjectMonitor) checks. - lock->set_displaced_header(markWord::unused_mark()); - - if (!m->has_owner() && m->try_set_owner(current)) { - assert(m->recursions() == 0, "invariant"); - current->inc_held_monitor_count(); - return true; - } - } - - // Note that we could inflate in quick_enter. - // This is likely a useful optimization - // Critically, in quick_enter() we must not: - // -- block indefinitely, or - // -- reach a safepoint - - return false; // revert to slow-path -} - // Handle notifications when synchronizing on value based classes void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread* locking_thread) { assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); @@ -512,144 +429,7 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock // the locking_thread with respect to the current thread. Currently only used when // deoptimizing and re-locking locks. See Deoptimization::relock_objects assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); - - if (LockingMode == LM_LIGHTWEIGHT) { - return LightweightSynchronizer::enter_for(obj, lock, locking_thread); - } - - if (!enter_fast_impl(obj, lock, locking_thread)) { - // Inflated ObjectMonitor::enter_for is required - - // An async deflation can race after the inflate_for() call and before - // enter_for() can make the ObjectMonitor busy. enter_for() returns false - // if we have lost the race to async deflation and we simply try again. - while (true) { - ObjectMonitor* monitor = inflate_for(locking_thread, obj(), inflate_cause_monitor_enter); - if (monitor->enter_for(locking_thread)) { - return; - } - assert(monitor->is_being_async_deflated(), "must be"); - } - } -} - -void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) { - if (!enter_fast_impl(obj, lock, current)) { - // Inflated ObjectMonitor::enter is required - - // An async deflation can race after the inflate() call and before - // enter() can make the ObjectMonitor busy. enter() returns false if - // we have lost the race to async deflation and we simply try again. - while (true) { - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_monitor_enter); - if (monitor->enter(current)) { - return; - } - } - } -} - -// The interpreter and compiler assembly code tries to lock using the fast path -// of this algorithm. Make sure to update that code if the following function is -// changed. The implementation is extremely sensitive to race condition. Be careful. -bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) { - assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); - - if (obj->klass()->is_value_based()) { - handle_sync_on_value_based_class(obj, locking_thread); - } - - locking_thread->inc_held_monitor_count(); - - if (!useHeavyMonitors()) { - if (LockingMode == LM_LEGACY) { - markWord mark = obj->mark(); - if (mark.is_unlocked()) { - // Anticipate successful CAS -- the ST of the displaced mark must - // be visible <= the ST performed by the CAS. - lock->set_displaced_header(mark); - if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) { - return true; - } - } else if (mark.has_locker() && - locking_thread->is_lock_owned((address) mark.locker())) { - assert(lock != mark.locker(), "must not re-lock the same lock"); - assert(lock != (BasicLock*) obj->mark().value(), "don't relock with same BasicLock"); - lock->set_displaced_header(markWord::from_pointer(nullptr)); - return true; - } - - // The object header will never be displaced to this lock, - // so it does not matter what the value is, except that it - // must be non-zero to avoid looking like a re-entrant lock, - // and must not look locked either. - lock->set_displaced_header(markWord::unused_mark()); - - // Failed to fast lock. - return false; - } - } else if (VerifyHeavyMonitors) { - guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - - return false; -} - -void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) { - assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); - - if (!useHeavyMonitors()) { - markWord mark = object->mark(); - if (LockingMode == LM_LEGACY) { - markWord dhw = lock->displaced_header(); - if (dhw.value() == 0) { - // If the displaced header is null, then this exit matches up with - // a recursive enter. No real work to do here except for diagnostics. -#ifndef PRODUCT - if (mark != markWord::INFLATING()) { - // Only do diagnostics if we are not racing an inflation. Simply - // exiting a recursive enter of a Java Monitor that is being - // inflated is safe; see the has_monitor() comment below. - assert(!mark.is_unlocked(), "invariant"); - assert(!mark.has_locker() || - current->is_lock_owned((address)mark.locker()), "invariant"); - if (mark.has_monitor()) { - // The BasicLock's displaced_header is marked as a recursive - // enter and we have an inflated Java Monitor (ObjectMonitor). - // This is a special case where the Java Monitor was inflated - // after this thread entered the stack-lock recursively. When a - // Java Monitor is inflated, we cannot safely walk the Java - // Monitor owner's stack and update the BasicLocks because a - // Java Monitor can be asynchronously inflated by a thread that - // does not own the Java Monitor. - ObjectMonitor* m = read_monitor(mark); - assert(m->object()->mark() == mark, "invariant"); - assert(m->is_entered(current), "invariant"); - } - } -#endif - return; - } - - if (mark == markWord::from_pointer(lock)) { - // If the object is stack-locked by the current thread, try to - // swing the displaced header from the BasicLock back to the mark. - assert(dhw.is_neutral(), "invariant"); - if (object->cas_set_mark(dhw, mark) == mark) { - return; - } - } - } - } else if (VerifyHeavyMonitors) { - guarantee((object->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - - // We have to take the slow-path of possible inflation and then exit. - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - ObjectMonitor* monitor = inflate(current, object, inflate_cause_vm_internal); - assert(!monitor->has_anonymous_owner(), "must not be"); - monitor->exit(current); + return LightweightSynchronizer::enter_for(obj, lock, locking_thread); } // ----------------------------------------------------------------------------- @@ -670,17 +450,8 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { // enter() can make the ObjectMonitor busy. enter() returns false if // we have lost the race to async deflation and we simply try again. while (true) { - ObjectMonitor* monitor; - bool entered; - if (LockingMode == LM_LIGHTWEIGHT) { - BasicLock lock; - entered = LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr; - } else { - monitor = inflate(current, obj(), inflate_cause_jni_enter); - entered = monitor->enter(current); - } - - if (entered) { + BasicLock lock; + if (LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr) { current->inc_held_monitor_count(1, true); break; } @@ -693,13 +464,7 @@ void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { JavaThread* current = THREAD; ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - monitor = inflate(current, obj, inflate_cause_jni_exit); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); // If this thread has locked the object, exit the monitor. We // intentionally do not use CHECK on check_owner because we must exit the // monitor even if an exception was already pending. @@ -740,14 +505,7 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { } ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); - } else { - // The ObjectMonitor* can't be async deflated because the _waiters - // field is incremented before ownership is dropped and decremented - // after ownership is regained. - monitor = inflate(current, obj(), inflate_cause_wait); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), current, millis); monitor->wait(millis, true, THREAD); // Not CHECK as we need following code @@ -766,11 +524,7 @@ void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { } ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); - } else { - monitor = inflate(THREAD, obj(), inflate_cause_wait); - } + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); monitor->wait(millis, false, THREAD); } @@ -779,26 +533,11 @@ void ObjectSynchronizer::notify(Handle obj, TRAPS) { JavaThread* current = THREAD; markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { - // Not inflated so there can't be any waiters to notify. - return; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Not inflated so there can't be any waiters to notify. - return; - } - } - - ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - monitor = inflate(current, obj(), inflate_cause_notify); + if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { + // Not inflated so there can't be any waiters to notify. + return; } + ObjectMonitor* monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); monitor->notify(CHECK); } @@ -807,26 +546,12 @@ void ObjectSynchronizer::notifyall(Handle obj, TRAPS) { JavaThread* current = THREAD; markWord mark = obj->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { - // Not inflated so there can't be any waiters to notify. - return; - } - } else if (LockingMode == LM_LEGACY) { - if (mark.has_locker() && current->is_lock_owned((address)mark.locker())) { - // Not inflated so there can't be any waiters to notify. - return; - } + if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) { + // Not inflated so there can't be any waiters to notify. + return; } - ObjectMonitor* monitor; - if (LockingMode == LM_LIGHTWEIGHT) { - monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); - } else { - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - monitor = inflate(current, obj(), inflate_cause_notify); - } + ObjectMonitor* monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); monitor->notifyAll(CHECK); } @@ -846,67 +571,6 @@ struct SharedGlobals { static SharedGlobals GVars; -static markWord read_stable_mark(oop obj) { - markWord mark = obj->mark_acquire(); - if (!mark.is_being_inflated() || LockingMode == LM_LIGHTWEIGHT) { - // New lightweight locking does not use the markWord::INFLATING() protocol. - return mark; // normal fast-path return - } - - int its = 0; - for (;;) { - markWord mark = obj->mark_acquire(); - if (!mark.is_being_inflated()) { - return mark; // normal fast-path return - } - - // The object is being inflated by some other thread. - // The caller of read_stable_mark() must wait for inflation to complete. - // Avoid live-lock. - - ++its; - if (its > 10000 || !os::is_MP()) { - if (its & 1) { - os::naked_yield(); - } else { - // Note that the following code attenuates the livelock problem but is not - // a complete remedy. A more complete solution would require that the inflating - // thread hold the associated inflation lock. The following code simply restricts - // the number of spinners to at most one. We'll have N-2 threads blocked - // on the inflationlock, 1 thread holding the inflation lock and using - // a yield/park strategy, and 1 thread in the midst of inflation. - // A more refined approach would be to change the encoding of INFLATING - // to allow encapsulation of a native thread pointer. Threads waiting for - // inflation to complete would use CAS to push themselves onto a singly linked - // list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag - // and calling park(). When inflation was complete the thread that accomplished inflation - // would detach the list and set the markword to inflated with a single CAS and - // then for each thread on the list, set the flag and unpark() the thread. - - // Index into the lock array based on the current object address. - static_assert(is_power_of_2(inflation_lock_count()), "must be"); - size_t ix = (cast_from_oop(obj) >> 5) & (inflation_lock_count() - 1); - int YieldThenBlock = 0; - assert(ix < inflation_lock_count(), "invariant"); - inflation_lock(ix)->lock(); - while (obj->mark_acquire() == markWord::INFLATING()) { - // Beware: naked_yield() is advisory and has almost no effect on some platforms - // so we periodically call current->_ParkEvent->park(1). - // We use a mixed spin/yield/block mechanism. - if ((YieldThenBlock++) >= 16) { - Thread::current()->_ParkEvent->park(1); - } else { - os::naked_yield(); - } - } - inflation_lock(ix)->unlock(); - } - } else { - SpinPause(); // SMP-polite spinning - } - } -} - // hashCode() generation : // // Possibilities: @@ -965,7 +629,7 @@ static intptr_t get_next_hash(Thread* current, oop obj) { } static intptr_t install_hash_code(Thread* current, oop obj) { - assert(UseObjectMonitorTable && LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(UseObjectMonitorTable, "must be"); markWord mark = obj->mark_acquire(); for (;;) { @@ -996,12 +660,8 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { ObjectMonitor* monitor = nullptr; markWord temp, test; intptr_t hash; - markWord mark = read_stable_mark(obj); - if (VerifyHeavyMonitors) { - assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)"); - guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); - } - if (mark.is_unlocked() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { + markWord mark = obj->mark_acquire(); + if (mark.is_unlocked() || mark.is_fast_locked()) { hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it return hash; @@ -1013,10 +673,9 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { if (test == mark) { // if the hash was installed, return it return hash; } - if (LockingMode == LM_LIGHTWEIGHT) { - // CAS failed, retry - continue; - } + // CAS failed, retry + continue; + // Failed to install the hash. It could be that another thread // installed the hash just before our attempt or inflation has // occurred or... so we fall thru to inflate the monitor for @@ -1048,34 +707,14 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { } // Fall thru so we only have one place that installs the hash in // the ObjectMonitor. - } else if (LockingMode == LM_LEGACY && mark.has_locker() - && current->is_Java_thread() - && JavaThread::cast(current)->is_lock_owned((address)mark.locker())) { - // This is a stack-lock owned by the calling thread so fetch the - // displaced markWord from the BasicLock on the stack. - temp = mark.displaced_mark_helper(); - assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value()); - hash = temp.hash(); - if (hash != 0) { // if it has a hash, just return it - return hash; - } - // WARNING: - // The displaced header in the BasicLock on a thread's stack - // is strictly immutable. It CANNOT be changed in ANY cases. - // So we have to inflate the stack-lock into an ObjectMonitor - // even if the current thread owns the lock. The BasicLock on - // a thread's stack can be asynchronously read by other threads - // during an inflate() call so any change to that stack memory - // may not propagate to other threads correctly. } - // Inflate the monitor to set the hash. - - // There's no need to inflate if the mark has already got a monitor. // NOTE: an async deflation can race after we get the monitor and // before we can update the ObjectMonitor's header with the hash // value below. - monitor = mark.has_monitor() ? mark.monitor() : inflate(current, obj, inflate_cause_hash_code); + assert(mark.has_monitor(), "must be"); + monitor = mark.monitor(); + // Load ObjectMonitor's header/dmw field and see if it has a hash. mark = monitor->header(); assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); @@ -1115,19 +754,14 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, assert(current == JavaThread::current(), "Can only be called on current thread"); oop obj = h_obj(); - markWord mark = read_stable_mark(obj); + markWord mark = obj->mark_acquire(); - if (LockingMode == LM_LEGACY && mark.has_locker()) { - // stack-locked case, header points into owner's stack - return current->is_lock_owned((address)mark.locker()); - } - - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { + if (mark.is_fast_locked()) { // fast-locking case, see if lock is in current's lock stack return current->lock_stack().contains(h_obj()); } - while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + while (mark.has_monitor()) { ObjectMonitor* monitor = read_monitor(current, obj, mark); if (monitor != nullptr) { return monitor->is_entered(current) != 0; @@ -1141,13 +775,6 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, } } - if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { - // Inflated monitor so header points to ObjectMonitor (tagged pointer). - // The first stage of async deflation does not affect any field - // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = read_monitor(mark); - return monitor->is_entered(current) != 0; - } // Unlocked case, header in place assert(mark.is_unlocked(), "sanity check"); return false; @@ -1155,21 +782,15 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_obj) { oop obj = h_obj(); - markWord mark = read_stable_mark(obj); + markWord mark = obj->mark_acquire(); - if (LockingMode == LM_LEGACY && mark.has_locker()) { - // stack-locked so header points into owner's stack. - // owning_thread_from_monitor_owner() may also return null here: - return Threads::owning_thread_from_stacklock(t_list, (address) mark.locker()); - } - - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { + if (mark.is_fast_locked()) { // fast-locked so get owner from the object. // owning_thread_from_object() may also return null here: return Threads::owning_thread_from_object(t_list, h_obj()); } - while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + while (mark.has_monitor()) { ObjectMonitor* monitor = read_monitor(Thread::current(), obj, mark); if (monitor != nullptr) { return Threads::owning_thread_from_monitor(t_list, monitor); @@ -1183,16 +804,6 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob } } - if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { - // Inflated monitor so header points to ObjectMonitor (tagged pointer). - // The first stage of async deflation does not affect any field - // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = read_monitor(mark); - assert(monitor != nullptr, "monitor should be non-null"); - // owning_thread_from_monitor() may also return null here: - return Threads::owning_thread_from_monitor(t_list, monitor); - } - // Unlocked case, header in place // Cannot have assertion since this object may have been // locked by another thread when reaching here. @@ -1415,230 +1026,6 @@ jlong ObjectSynchronizer::time_since_last_async_deflation_ms() { return (os::javaTimeNanos() - last_async_deflation_time_ns()) / (NANOUNITS / MILLIUNITS); } -static void post_monitor_inflate_event(EventJavaMonitorInflate* event, - const oop obj, - ObjectSynchronizer::InflateCause cause) { - assert(event != nullptr, "invariant"); - const Klass* monitor_klass = obj->klass(); - if (ObjectMonitor::is_jfr_excluded(monitor_klass)) { - return; - } - event->set_monitorClass(monitor_klass); - event->set_address((uintptr_t)(void*)obj); - event->set_cause((u1)cause); - event->commit(); -} - -// Fast path code shared by multiple functions -void ObjectSynchronizer::inflate_helper(oop obj) { - assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); - markWord mark = obj->mark_acquire(); - if (mark.has_monitor()) { - ObjectMonitor* monitor = read_monitor(mark); - markWord dmw = monitor->header(); - assert(dmw.is_neutral(), "sanity check: header=" INTPTR_FORMAT, dmw.value()); - return; - } - (void)inflate(Thread::current(), obj, inflate_cause_vm_internal); -} - -ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) { - assert(current == Thread::current(), "must be"); - assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); - return inflate_impl(current->is_Java_thread() ? JavaThread::cast(current) : nullptr, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) { - assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be"); - assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for"); - return inflate_impl(thread, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* locking_thread, oop object, const InflateCause cause) { - // The JavaThread* locking_thread requires that the locking_thread == Thread::current() or - // is suspended throughout the call by some other mechanism. - // The thread might be nullptr when called from a non JavaThread. (As may still be - // the case from FastHashCode). However it is only important for correctness that the - // thread is set when called from ObjectSynchronizer::enter from the owning thread, - // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. - assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl"); - EventJavaMonitorInflate event; - - for (;;) { - const markWord mark = object->mark_acquire(); - - // The mark can be in one of the following states: - // * inflated - If the ObjectMonitor owner is anonymous and the - // locking_thread owns the object lock, then we - // make the locking_thread the ObjectMonitor owner. - // * stack-locked - Coerce it to inflated from stack-locked. - // * INFLATING - Busy wait for conversion from stack-locked to - // inflated. - // * unlocked - Aggressively inflate the object. - - // CASE: inflated - if (mark.has_monitor()) { - ObjectMonitor* inf = mark.monitor(); - markWord dmw = inf->header(); - assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - if (inf->has_anonymous_owner() && locking_thread != nullptr) { - assert(LockingMode == LM_LEGACY, "invariant"); - if (locking_thread->is_lock_owned((address)inf->stack_locker())) { - inf->set_stack_locker(nullptr); - inf->set_owner_from_anonymous(locking_thread); - } - } - return inf; - } - - // CASE: inflation in progress - inflating over a stack-lock. - // Some other thread is converting from stack-locked to inflated. - // Only that thread can complete inflation -- other threads must wait. - // The INFLATING value is transient. - // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. - // We could always eliminate polling by parking the thread on some auxiliary list. - if (mark == markWord::INFLATING()) { - read_stable_mark(object); - continue; - } - - // CASE: stack-locked - // Could be stack-locked either by current or by some other thread. - // - // Note that we allocate the ObjectMonitor speculatively, _before_ attempting - // to install INFLATING into the mark word. We originally installed INFLATING, - // allocated the ObjectMonitor, and then finally STed the address of the - // ObjectMonitor into the mark. This was correct, but artificially lengthened - // the interval in which INFLATING appeared in the mark, thus increasing - // the odds of inflation contention. If we lose the race to set INFLATING, - // then we just delete the ObjectMonitor and loop around again. - // - LogStreamHandle(Trace, monitorinflation) lsh; - if (LockingMode == LM_LEGACY && mark.has_locker()) { - ObjectMonitor* m = new ObjectMonitor(object); - // Optimistically prepare the ObjectMonitor - anticipate successful CAS - // We do this before the CAS in order to minimize the length of time - // in which INFLATING appears in the mark. - - markWord cmp = object->cas_set_mark(markWord::INFLATING(), mark); - if (cmp != mark) { - delete m; - continue; // Interference -- just retry - } - - // We've successfully installed INFLATING (0) into the mark-word. - // This is the only case where 0 will appear in a mark-word. - // Only the singular thread that successfully swings the mark-word - // to 0 can perform (or more precisely, complete) inflation. - // - // Why do we CAS a 0 into the mark-word instead of just CASing the - // mark-word from the stack-locked value directly to the new inflated state? - // Consider what happens when a thread unlocks a stack-locked object. - // It attempts to use CAS to swing the displaced header value from the - // on-stack BasicLock back into the object header. Recall also that the - // header value (hash code, etc) can reside in (a) the object header, or - // (b) a displaced header associated with the stack-lock, or (c) a displaced - // header in an ObjectMonitor. The inflate() routine must copy the header - // value from the BasicLock on the owner's stack to the ObjectMonitor, all - // the while preserving the hashCode stability invariants. If the owner - // decides to release the lock while the value is 0, the unlock will fail - // and control will eventually pass from slow_exit() to inflate. The owner - // will then spin, waiting for the 0 value to disappear. Put another way, - // the 0 causes the owner to stall if the owner happens to try to - // drop the lock (restoring the header from the BasicLock to the object) - // while inflation is in-progress. This protocol avoids races that might - // would otherwise permit hashCode values to change or "flicker" for an object. - // Critically, while object->mark is 0 mark.displaced_mark_helper() is stable. - // 0 serves as a "BUSY" inflate-in-progress indicator. - - - // fetch the displaced mark from the owner's stack. - // The owner can't die or unwind past the lock while our INFLATING - // object is in the mark. Furthermore the owner can't complete - // an unlock on the object, either. - markWord dmw = mark.displaced_mark_helper(); - // Catch if the object's header is not neutral (not locked and - // not marked is what we care about here). - assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - - // Setup monitor fields to proper values -- prepare the monitor - m->set_header(dmw); - - // Note that a thread can inflate an object - // that it has stack-locked -- as might happen in wait() -- directly - // with CAS. That is, we can avoid the xchg-nullptr .... ST idiom. - if (locking_thread != nullptr && locking_thread->is_lock_owned((address)mark.locker())) { - m->set_owner(locking_thread); - } else { - // Use ANONYMOUS_OWNER to indicate that the owner is the BasicLock on the stack, - // and set the stack locker field in the monitor. - m->set_stack_locker(mark.locker()); - m->set_anonymous_owner(); - } - // TODO-FIXME: assert BasicLock->dhw != 0. - - // Must preserve store ordering. The monitor state must - // be stable at the time of publishing the monitor address. - guarantee(object->mark() == markWord::INFLATING(), "invariant"); - // Release semantics so that above set_object() is seen first. - object->release_set_mark(markWord::encode(m)); - - // Once ObjectMonitor is configured and the object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(m); - - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return m; - } - - // CASE: unlocked - // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. - // If we know we're inflating for entry it's better to inflate by swinging a - // pre-locked ObjectMonitor pointer into the object header. A successful - // CAS inflates the object *and* confers ownership to the inflating thread. - // In the current implementation we use a 2-step mechanism where we CAS() - // to inflate and then CAS() again to try to swing _owner from null to current. - // An inflateTry() method that we could call from enter() would be useful. - - assert(mark.is_unlocked(), "invariant: header=" INTPTR_FORMAT, mark.value()); - ObjectMonitor* m = new ObjectMonitor(object); - // prepare m for installation - set monitor to initial state - m->set_header(mark); - - if (object->cas_set_mark(markWord::encode(m), mark) != mark) { - delete m; - m = nullptr; - continue; - // interference - the markword changed - just retry. - // The state-transitions are one-way, so there's no chance of - // live-lock -- "Inflated" is an absorbing state. - } - - // Once the ObjectMonitor is configured and object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(m); - - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(unlocked): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return m; - } -} - // Walk the in-use list and deflate (at most MonitorDeflationMax) idle // ObjectMonitors. Returns the number of deflated ObjectMonitors. // @@ -1914,7 +1301,6 @@ const char* ObjectSynchronizer::inflate_cause_name(const InflateCause cause) { case inflate_cause_monitor_enter: return "Monitor Enter"; case inflate_cause_wait: return "Monitor Wait"; case inflate_cause_notify: return "Monitor Notify"; - case inflate_cause_hash_code: return "Monitor Hash Code"; case inflate_cause_jni_enter: return "JNI Monitor Enter"; case inflate_cause_jni_exit: return "JNI Monitor Exit"; default: diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index e35c3651f5b..419cf2bf5bb 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -73,16 +73,15 @@ class ObjectSynchronizer : AllStatic { friend class ObjectMonitorDeflationLogging; friend class WhiteBox; - public: +public: typedef enum { inflate_cause_vm_internal = 0, inflate_cause_monitor_enter = 1, inflate_cause_wait = 2, inflate_cause_notify = 3, - inflate_cause_hash_code = 4, - inflate_cause_jni_enter = 5, - inflate_cause_jni_exit = 6, - inflate_cause_nof = 7 // Number of causes + inflate_cause_jni_enter = 4, + inflate_cause_jni_exit = 5, + inflate_cause_nof = 6 // Number of causes } InflateCause; typedef enum { @@ -104,15 +103,7 @@ class ObjectSynchronizer : AllStatic { // locked on is either already locked by the locking_thread or cannot // escape the locking_thread. static void enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread); -private: - // Shared implementation for enter and enter_for. Performs all but - // inflated monitor enter. - static bool enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread); - static bool quick_enter_legacy(oop obj, BasicLock* Lock, JavaThread* current); - static void enter_legacy(Handle obj, BasicLock* Lock, JavaThread* current); - static void exit_legacy(oop obj, BasicLock* lock, JavaThread* current); -public: // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. static void jni_enter(Handle obj, JavaThread* current); @@ -131,18 +122,7 @@ public: // throwing unexpected InterruptedExecutionExceptions. static void waitUninterruptibly(Handle obj, jlong Millis, TRAPS); - // Inflate light weight monitor to heavy weight monitor - static ObjectMonitor* inflate(Thread* current, oop obj, const InflateCause cause); - // Used to inflate a monitor as if it was done from the thread JavaThread. - static ObjectMonitor* inflate_for(JavaThread* thread, oop obj, const InflateCause cause); - -private: - // Shared implementation between the different LockingMode. - static ObjectMonitor* inflate_impl(JavaThread* locking_thread, oop obj, const InflateCause cause); - public: - // This version is only for internal use - static void inflate_helper(oop obj); static const char* inflate_cause_name(const InflateCause cause); inline static ObjectMonitor* read_monitor(markWord mark); diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp index ac9116088f7..a44fe817276 100644 --- a/src/hotspot/share/runtime/synchronizer.inline.hpp +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -45,11 +45,7 @@ inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { assert(current == Thread::current(), "must be"); - if (LockingMode == LM_LIGHTWEIGHT) { LightweightSynchronizer::enter(obj, lock, current); - } else { - enter_legacy(obj, lock, current); - } } inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { @@ -61,21 +57,13 @@ inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread return false; } - if (LockingMode == LM_LIGHTWEIGHT) { - return LightweightSynchronizer::quick_enter(obj, lock, current); - } else { - return quick_enter_legacy(obj, lock, current); - } + return LightweightSynchronizer::quick_enter(obj, lock, current); } inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { current->dec_held_monitor_count(); - if (LockingMode == LM_LIGHTWEIGHT) { - LightweightSynchronizer::exit(object, lock, current); - } else { - exit_legacy(object, lock, current); - } + LightweightSynchronizer::exit(object, lock, current); } #endif // SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 3cf1058b6f7..65eea9d5fb2 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1294,21 +1294,7 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, } #endif // INCLUDE_JVMTI -JavaThread *Threads::owning_thread_from_stacklock(ThreadsList * t_list, address basicLock) { - assert(LockingMode == LM_LEGACY, "Not with new lightweight locking"); - - JavaThread* the_owner = nullptr; - for (JavaThread* q : *t_list) { - if (q->is_lock_owned(basicLock)) { - the_owner = q; - break; - } - } - return the_owner; -} - JavaThread* Threads::owning_thread_from_object(ThreadsList * t_list, oop obj) { - assert(LockingMode == LM_LIGHTWEIGHT, "Only with new lightweight locking"); for (JavaThread* q : *t_list) { // Need to start processing before accessing oops in the thread. StackWatermark* watermark = StackWatermarkSet::get(q, StackWatermarkKind::gc); @@ -1325,12 +1311,7 @@ JavaThread* Threads::owning_thread_from_object(ThreadsList * t_list, oop obj) { JavaThread* Threads::owning_thread_from_monitor(ThreadsList* t_list, ObjectMonitor* monitor) { if (monitor->has_anonymous_owner()) { - if (LockingMode == LM_LIGHTWEIGHT) { - return owning_thread_from_object(t_list, monitor->object()); - } else { - assert(LockingMode == LM_LEGACY, "invariant"); - return owning_thread_from_stacklock(t_list, (address)monitor->stack_locker()); - } + return owning_thread_from_object(t_list, monitor->object()); } else { JavaThread* the_owner = nullptr; for (JavaThread* q : *t_list) { diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp index 979b1dffe26..c6428c874f6 100644 --- a/src/hotspot/share/runtime/threads.hpp +++ b/src/hotspot/share/runtime/threads.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -134,9 +134,6 @@ public: static GrowableArray* get_pending_threads(ThreadsList * t_list, int count, address monitor); - // Get owning Java thread from the basicLock address. - static JavaThread *owning_thread_from_stacklock(ThreadsList * t_list, address basicLock); - static JavaThread* owning_thread_from_object(ThreadsList* t_list, oop obj); static JavaThread* owning_thread_from_monitor(ThreadsList* t_list, ObjectMonitor* owner); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 1fba55cde99..bc026887b84 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -673,7 +673,6 @@ volatile_nonstatic_field(ObjectMonitor, _metadata, uintptr_t) \ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _owner, int64_t) \ - volatile_nonstatic_field(ObjectMonitor, _stack_locker, BasicLock*) \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ @@ -1640,14 +1639,6 @@ declare_constant(T_NARROWKLASS_size) \ declare_constant(T_VOID_size) \ \ - /**********************************************/ \ - /* LockingMode enum (globalDefinitions.hpp) */ \ - /**********************************************/ \ - \ - declare_constant(LM_MONITOR) \ - declare_constant(LM_LEGACY) \ - declare_constant(LM_LIGHTWEIGHT) \ - \ /*********************************************/ \ /* MethodCompilation (globalDefinitions.hpp) */ \ /*********************************************/ \ diff --git a/src/hotspot/share/utilities/globalDefinitions.cpp b/src/hotspot/share/utilities/globalDefinitions.cpp index 84a0730212f..8a111a12607 100644 --- a/src/hotspot/share/utilities/globalDefinitions.cpp +++ b/src/hotspot/share/utilities/globalDefinitions.cpp @@ -56,8 +56,6 @@ int LogMinObjAlignmentInBytes = -1; // Oop encoding heap max uint64_t OopEncodingHeapMax = 0; -const int LockingMode = LM_LIGHTWEIGHT; - // Something to help porters sleep at night #ifdef ASSERT diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 64ccae539a3..8217451a5c6 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1004,17 +1004,6 @@ enum JavaThreadState { _thread_max_state = 12 // maximum thread state+1 - used for statistics allocation }; -enum LockingMode { - // Use only heavy monitors for locking - LM_MONITOR = 0, - // Legacy stack-locking, with monitors as 2nd tier - LM_LEGACY = 1, - // New lightweight locking, with monitors as 2nd tier - LM_LIGHTWEIGHT = 2 -}; - -extern const int LockingMode; - //---------------------------------------------------------------------------------------------------- // Special constants for debugging diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index a4d44a96878..81e357f1c4f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1078,7 +1078,7 @@ void VMError::report(outputStream* st, bool _verbose) { print_stack_location(st, _context, continuation); st->cr(); - STEP_IF("printing lock stack", _verbose && _thread != nullptr && _thread->is_Java_thread() && LockingMode == LM_LIGHTWEIGHT); + STEP_IF("printing lock stack", _verbose && _thread != nullptr && _thread->is_Java_thread()); st->print_cr("Lock stack of current Java thread (top to bottom):"); JavaThread::cast(_thread)->lock_stack().print_on(st); st->cr(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index 25c5344506c..1bdbf8ce8a2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. 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 @@ -51,8 +51,6 @@ public class ObjectMonitor extends VMObject { objectFieldOffset = f.getOffset(); f = type.getField("_owner"); ownerFieldOffset = f.getOffset(); - f = type.getField("_stack_locker"); - stackLockerFieldOffset = f.getOffset(); f = type.getField("_next_om"); nextOMFieldOffset = f.getOffset(); contentionsField = new CIntField(type.getCIntegerField("_contentions"), 0); @@ -89,7 +87,6 @@ public class ObjectMonitor extends VMObject { } public Address owner() { return addr.getAddressAt(ownerFieldOffset); } - public Address stackLocker() { return addr.getAddressAt(stackLockerFieldOffset); } // FIXME // void set_owner(void* owner); @@ -120,7 +117,6 @@ public class ObjectMonitor extends VMObject { private static long metadataFieldOffset; private static long objectFieldOffset; private static long ownerFieldOffset; - private static long stackLockerFieldOffset; private static long nextOMFieldOffset; private static CIntField contentionsField; private static CIntField waitersField; diff --git a/test/hotspot/gtest/runtime/test_lockStack.cpp b/test/hotspot/gtest/runtime/test_lockStack.cpp index 3163898e17d..6755541adb0 100644 --- a/test/hotspot/gtest/runtime/test_lockStack.cpp +++ b/test/hotspot/gtest/runtime/test_lockStack.cpp @@ -63,7 +63,7 @@ public: } while (false) TEST_VM_F(LockStackTest, is_recursive) { - if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) { + if (!VM_Version::supports_recursive_lightweight_locking()) { return; } @@ -130,7 +130,7 @@ TEST_VM_F(LockStackTest, is_recursive) { } TEST_VM_F(LockStackTest, try_recursive_enter) { - if (LockingMode != LM_LIGHTWEIGHT || !VM_Version::supports_recursive_lightweight_locking()) { + if (!VM_Version::supports_recursive_lightweight_locking()) { return; } @@ -197,10 +197,6 @@ TEST_VM_F(LockStackTest, try_recursive_enter) { } TEST_VM_F(LockStackTest, contains) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - const bool test_recursive = VM_Version::supports_recursive_lightweight_locking(); JavaThread* THREAD = JavaThread::current(); @@ -263,10 +259,6 @@ TEST_VM_F(LockStackTest, contains) { } TEST_VM_F(LockStackTest, remove) { - if (LockingMode != LM_LIGHTWEIGHT) { - return; - } - const bool test_recursive = VM_Version::supports_recursive_lightweight_locking(); JavaThread* THREAD = JavaThread::current(); diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index e92e947ecfa..505d5cc7df7 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -53,9 +53,6 @@ public class TestRecursiveMonitorChurn { public static volatile Monitor monitor; public static void main(String[] args) { - if (WB.getBooleanVMFlag("VerifyHeavyMonitors")) { - throw new SkippedException("VerifyHeavyMonitors always inflates. Invalid test."); - } final long pre_monitor_count = WB.getInUseMonitorCount(); System.out.println(" Precount = " + pre_monitor_count); for (int i = 0; i < COUNT; i++) { From 03c54d4288dfd70190c3f306a44a8424f268f787 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Sep 2025 12:26:58 +0000 Subject: [PATCH 404/471] 8365689: Elements.getFileObjectOf fails with a NullPointerException when an erroneous Element is passed in Reviewed-by: darcy, vromero --- .../sun/tools/javac/model/JavacElements.java | 3 +- .../model/element/TestFileObjectOf.java | 159 +++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index 73219ca38ae..c9bb6cf4182 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -800,6 +800,7 @@ public class JavacElements implements Elements { yield msym.module_info.classfile; } case TYP -> ((ClassSymbol) sym).classfile; + case ERR -> null; default -> sym.enclClass().classfile; }; } diff --git a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java index ad7c701fa5e..4f9703bc428 100644 --- a/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java +++ b/test/langtools/tools/javac/processing/model/element/TestFileObjectOf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8224922 + * @bug 8224922 8365689 * @summary Verify the behavior of the Elements.getFileObjectOf * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -33,6 +33,8 @@ * @run main TestFileObjectOf */ +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.nio.file.Path; @@ -49,6 +51,7 @@ import javax.lang.model.util.Elements; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import toolbox.JarTask; import toolbox.JavacTask; @@ -592,4 +595,156 @@ public class TestFileObjectOf extends TestRunner { } + @Test //JDK-8365689 + public void testUndefined(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + module m { + requires undefined1; //as module + exports undefined2; //as package + exports test; + } + """, + """ + package test; + public class TestClass { + void t() { + undefined3.call(); + this.undefined4(); + } + } + """); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + //from source, implicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName(), + "-sourcepath", src.toString()) + .outdir(classes) + .classes("java.lang.Object") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + + tb.cleanDirectory(classes); + + //from source, explicit: + { + List log; + + log = new JavacTask(tb) + .options("-XDshould-stop.at=FLOW", + "-classpath", "", + "-processorpath", System.getProperty("test.classes"), + "-processor", UndefinedPrintFiles.class.getName()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + List expected = List.of( + "undefined1: " + "", + "undefined2: " + "", + "undefined3: " + "", + "undefined4: " + "" + ); + + if (!expected.equals(log)) + throw new AssertionError("expected output not found: " + log); + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions("fromClass") + public static final class UndefinedPrintFiles extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) + return false; + + Elements elements = processingEnv.getElementUtils(); + Trees trees = Trees.instance(processingEnv); + + Queue q = new ArrayDeque<>(); + q.add(elements.getModuleElement("m")); + + while (!q.isEmpty()) { + Element currentElement = q.remove(); + + switch (currentElement.getKind()) { + case MODULE -> { + ElementFilter.exportsIn(((ModuleElement) currentElement).getDirectives()) + .stream() + .map(ed -> ed.getPackage()) + .forEach(q::add); + } + case PACKAGE -> { + currentElement.getEnclosedElements() + .stream() + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) + .forEach(q::add); + continue; + } + default -> {} + } + + TreePath tp = trees.getPath(currentElement); + + new TreePathScanner<>() { + @Override + public Object visitIdentifier(IdentifierTree node, Object p) { + if (node.getName().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitIdentifier(node, p); + } + + @Override + public Object visitMemberSelect(MemberSelectTree node, Object p) { + if (node.getIdentifier().toString().startsWith("undefined")) { + Element el = trees.getElement(getCurrentPath()); + handleDeclaration(el); + } + return super.visitMemberSelect(node, p); + } + }.scan(tp, null); + } + + return false; + } + + void handleDeclaration(Element el) { + Elements elements = processingEnv.getElementUtils(); + JavaFileObject fileObjects = elements.getFileObjectOf(el); + System.out.println(el.getSimpleName() + ": " + (fileObjects != null ? fileObjects.toUri().toString() : "")); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + } } From bcff857ba09028cc43e856726b5c839cc6b1b0d9 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Mon, 8 Sep 2025 13:30:45 +0000 Subject: [PATCH 405/471] 8361381: GlyphLayout behavior differs on JDK 11+ compared to JDK 8 Reviewed-by: prr, serb --- .../sun/font/ExtendedTextSourceLabel.java | 10 +- .../GlyphVector/GetGlyphCharIndexTest.java | 19 ++- .../LineBreakMeasurer/KhmerLineBreakTest.java | 115 ++++++++++++++++++ 3 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java index 433d1d5413f..784035f4fe2 100644 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -577,6 +577,7 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La * not all do, and it cannot be relied upon. * - each glyph maps to a single character, when multiple glyphs exist for a character they all map to it, but * no two characters map to the same glyph +* This was only true for the old, ICU layout engine which inserted 0xffff glyphs for ligaturized characters! * - multiple glyphs mapping to the same character need not be in sequence (thai, tamil have split characters) * - glyphs may be arbitrarily reordered (Indic reorders glyphs) * - all glyphs share the same bidi level @@ -712,8 +713,6 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La while (gx != gxlimit) { // start of new cluster - int clusterExtraGlyphs = 0; - minIndex = indices[gx]; maxIndex = minIndex; @@ -730,14 +729,11 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La while (gx != gxlimit && ((glyphinfo[gp + advx] == 0) || - (indices[gx] <= maxIndex) || - (maxIndex - minIndex > clusterExtraGlyphs))) { + (indices[gx] <= maxIndex))) { - ++clusterExtraGlyphs; // have an extra glyph in this cluster if (DEBUG) { System.err.println("gp=" +gp +" adv=" + glyphinfo[gp + advx] + - " gx="+ gx+ " i[gx]="+indices[gx] + - " clusterExtraGlyphs="+clusterExtraGlyphs); + " gx="+ gx+ " i[gx]="+indices[gx]); } // adjust advance only if new glyph has non-zero advance diff --git a/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java b/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java index 6ec6a257ae8..939643c7a45 100644 --- a/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java +++ b/test/jdk/java/awt/font/GlyphVector/GetGlyphCharIndexTest.java @@ -23,7 +23,7 @@ /* @test * @summary Test getGlyphCharIndex() results from layout - * @bug 8152680 + * @bug 8152680 8361381 */ import java.awt.Font; @@ -40,5 +40,22 @@ public class GetGlyphCharIndexTest { if (idx0 != 0) { throw new RuntimeException("Expected 0, got " + idx0); } + + // This is the encoding-independent Khmer string "បានស្នើសុំនៅតែត្រូវបានបដិសេធ" + // We can't check for more details like e.g. correct line breaking because it is font and platform dependent, + // but we can at least chack that the created GlyphVector has monotonically increasing character indices. + // This is guaranteed by HarfBuzz's HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS cluster level which is used + // in the OpenJDK layout implementation. + String khmer = "\u1794\u17b6\u1793\u179f\u17d2\u1793\u17be\u179f\u17bb\u17c6\u1793\u17c5" + + "\u178f\u17c2\u178f\u17d2\u179a\u17bc\u179c\u1794\u17b6\u1793\u1794\u178a\u17b7\u179f\u17c1\u1792"; + font = new Font(Font.DIALOG, Font.PLAIN, 12); + gv = font.layoutGlyphVector(frc, khmer.toCharArray(), 0, khmer.length(), 0); + int[] indices = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + for (int i = 0; i < (indices.length - 1); i++) { + if (indices[i] > indices[i + 1]) { + throw new RuntimeException("Glyph character indices are supposed to be monotonically growing, but character index at position " + + i + " is bigger then the one at position " + (i + 1) + ", i.e. " + indices[i] + " > " + indices[i + 1] + "."); + } + } } } diff --git a/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java b/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java new file mode 100644 index 00000000000..855ad1b320b --- /dev/null +++ b/test/jdk/java/awt/font/LineBreakMeasurer/KhmerLineBreakTest.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8361381 + * @summary GlyphLayout behavior differs on JDK 11+ compared to JDK 8 + */ + +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.text.BreakIterator; +import java.util.Locale; + +public class KhmerLineBreakTest { + static String khmer = "បានស្នើសុំនៅតែត្រូវបានបដិសេធ"; + /* + + This is part of the output we get from `ExtendedTextSourceLabel::createCharinfo()` + when running with `-Dsun.java2d.debugfonts=true`. It's a listing of the 28 code points + of the `khmer` string defined above and displays their x-position during rendering as + well as their advance. Code points with zero advance belong to the glyph cluster which + is started by the first preceding code point with a non-zero advance. There should be no + breaks at characters with zero advance, because this would break a glyph cluster. + + 0 ch: 1794 x: 0.0 xa: 68.115234 + 1 ch: 17b6 x: 68.115234 xa: 0.0 + 2 ch: 1793 x: 68.115234 xa: 45.410156 + 3 ch: 179f x: 113.52539 xa: 90.82031 + 4 ch: 17d2 x: 204.3457 xa: 0.0 + 5 ch: 1793 x: 204.3457 xa: 0.0 + 6 ch: 17be x: 204.3457 xa: 0.0 + 7 ch: 179f x: 204.3457 xa: 68.115234 + 8 ch: 17bb x: 272.46094 xa: 0.0 + 9 ch: 17c6 x: 272.46094 xa: 0.0 + 10 ch: 1793 x: 272.46094 xa: 90.82031 + 11 ch: 17c5 x: 363.28125 xa: 0.0 + 12 ch: 178f x: 363.28125 xa: 68.115234 + 13 ch: 17c2 x: 431.39648 xa: 0.0 + 14 ch: 178f x: 431.39648 xa: 68.115234 + 15 ch: 17d2 x: 499.51172 xa: 0.0 + 16 ch: 179a x: 499.51172 xa: 0.0 + 17 ch: 17bc x: 499.51172 xa: 0.0 + 18 ch: 179c x: 499.51172 xa: 22.705078 + 19 ch: 1794 x: 522.2168 xa: 68.115234 + 20 ch: 17b6 x: 590.33203 xa: 0.0 + 21 ch: 1793 x: 590.33203 xa: 45.410156 + 22 ch: 1794 x: 635.7422 xa: 45.410156 + 23 ch: 178a x: 681.15234 xa: 45.410156 + 24 ch: 17b7 x: 726.5625 xa: 0.0 + 25 ch: 179f x: 726.5625 xa: 90.82031 + 26 ch: 17c1 x: 817.3828 xa: 0.0 + 27 ch: 1792 x: 817.3828 xa: 45.410156 + + */ + static boolean[] possibleBreak = new boolean[] + { true, false, true, true, false, false, false, true, false, false, + true, false, true, false, true, false, false, false, true, true, + false, true, true, true, false, true, false, true, true /* */ }; + static Locale locale = new Locale.Builder().setLanguage("km").setRegion("KH").build(); + static BreakIterator breakIterator = BreakIterator.getLineInstance(locale); + static FontRenderContext frc = new FontRenderContext(null, true, true); + + public static void main(String[] args) { + Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (int i=0; i < allFonts.length; i++) { + if (allFonts[i].canDisplayUpTo(khmer) == -1) { + Font font = allFonts[i].deriveFont(Font.PLAIN, 60f); + System.out.println("Trying font: " + font.getFontName()); + AttributedString attrStr = new AttributedString(khmer); + attrStr.addAttribute(TextAttribute.FONT, font); + AttributedCharacterIterator it = attrStr.getIterator(); + for (int width = 200; width < 400; width += 10) { + LineBreakMeasurer measurer = new LineBreakMeasurer(it, breakIterator, frc); + System.out.print(width + " : "); + while (measurer.getPosition() < it.getEndIndex()) { + int nextOffset = measurer.nextOffset(width); + System.out.print(nextOffset + " "); + if (!possibleBreak[nextOffset]) { + System.out.println(); + throw new RuntimeException("Invalid break at offset " + nextOffset + " (width = " + width + " font = " + font.getFontName() + ")"); + } + measurer.setPosition(nextOffset); + } + System.out.println(); + } + System.out.println("OK"); + } + } + } +} From 166ef5e7b1c6d6a9f0f1f29fedb7f65b94f53119 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Mon, 8 Sep 2025 14:37:25 +0000 Subject: [PATCH 406/471] 8366159: SkippedException is treated as a pass for pkcs11/KeyStore, pkcs11/SecretKeyFactory and pkcs11/SecureRandom Reviewed-by: weijun --- .../pkcs11/KeyStore/CertChainRemoval.java | 11 ++-- .../security/pkcs11/KeyStore/ClientAuth.java | 5 +- .../pkcs11/SecretKeyFactory/TestGeneral.java | 51 ++++++++++++------- .../security/pkcs11/SecureRandom/Basic.java | 7 +-- .../SecureRandom/TestDeserialization.java | 12 ++--- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java b/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java index 0158da0da36..31efbccaeab 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/CertChainRemoval.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -28,15 +28,17 @@ * @run testng/othervm CertChainRemoval */ import jdk.test.lib.SecurityTools; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; import java.nio.file.Path; -import java.util.*; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.Provider; import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Enumeration; import jtreg.SkippedException; import org.testng.SkipException; @@ -125,8 +127,7 @@ public class CertChainRemoval extends PKCS11Test { p11ks.load(null, PKCS11KS.passwd); printKeyStore("Initial PKCS11 KeyStore: ", p11ks); } catch (Exception e) { - System.out.println("Skip test, due to " + e); - return; + throw new SkippedException("Skip test, due to " + e, e); } // get the necessary keys from the temp keystore diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java index 1af1258d173..5d50015880d 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -260,8 +260,7 @@ public class ClientAuth extends PKCS11Test { try { javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding", p); } catch (GeneralSecurityException e) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } this.provider = p; diff --git a/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java index bca594c66bd..e59d0b4a1ca 100644 --- a/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java +++ b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -30,10 +30,14 @@ * @run main/othervm TestGeneral */ +import jtreg.SkippedException; + import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -57,8 +61,11 @@ public class TestGeneral extends PKCS11Test { try { skf = SecretKeyFactory.getInstance(algorithm, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Not supported, skipping: " + e); - return; + throw new SkippedException("[algorithm: " + algorithm + + ", key: " + key.getAlgorithm() + "]" + + ", provider: " + p.getName() + "]" + + ", expectedTestResult: " + expected + "]" + + "Not supported, skipping: " + e); } try { SecretKey key2 = skf.translateKey(key); @@ -99,21 +106,31 @@ public class TestGeneral extends PKCS11Test { SecretKey bf_128Key = new SecretKeySpec(rawBytes, 0, 16, "Blowfish"); SecretKey cc20Key = new SecretKeySpec(rawBytes, 0, 32, "ChaCha20"); - // fixed key length - test("AES", aes_128Key, p, TestResult.PASS); - test("AES", aes_256Key, p, TestResult.PASS); - test("AES", cc20Key, p, TestResult.FAIL); + List skippedList = new ArrayList<>(); + try { + // fixed key length + test("AES", aes_128Key, p, TestResult.PASS); + test("AES", aes_256Key, p, TestResult.PASS); + test("AES", cc20Key, p, TestResult.FAIL); - test("ChaCha20", aes_128Key, p, TestResult.FAIL); - test("ChaCha20", aes_256Key, p, TestResult.FAIL); - test("ChaCha20", cc20Key, p, TestResult.PASS); + test("ChaCha20", aes_128Key, p, TestResult.FAIL); + test("ChaCha20", aes_256Key, p, TestResult.FAIL); + test("ChaCha20", cc20Key, p, TestResult.PASS); - // variable key length - // Different PKCS11 impls may have different ranges - // of supported key sizes for variable-key-length - // algorithms. - test("Blowfish", aes_128Key, p, TestResult.FAIL); - test("Blowfish", cc20Key, p, TestResult.FAIL); - test("Blowfish", bf_128Key, p, TestResult.PASS); + // variable key length + // Different PKCS11 impls may have different ranges + // of supported key sizes for variable-key-length + // algorithms. + test("Blowfish", aes_128Key, p, TestResult.FAIL); + test("Blowfish", cc20Key, p, TestResult.FAIL); + test("Blowfish", bf_128Key, p, TestResult.PASS); + } catch (SkippedException skippedException){ + skippedException.printStackTrace(); + skippedList.add(skippedException.getMessage()); + } + + if (!skippedList.isEmpty()) { + throw new SkippedException("One or more tests skipped " + skippedList); + } } } diff --git a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java index 091b906171c..1b3aed50d7c 100644 --- a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java +++ b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -32,6 +32,8 @@ * @run main/othervm Basic */ +import jtreg.SkippedException; + import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; @@ -44,9 +46,8 @@ public class Basic extends PKCS11Test { try { random = SecureRandom.getInstance("PKCS11"); } catch (NoSuchAlgorithmException e) { - System.out.println("Provider " + p + " does not support SecureRandom, skipping"); e.printStackTrace(); - return; + throw new SkippedException("Provider " + p + " does not support SecureRandom, skipping", e); } byte[] b = new byte[32]; random.nextBytes(b); diff --git a/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java b/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java index f54ae95f36d..b8d37e2a00e 100644 --- a/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java +++ b/test/jdk/sun/security/pkcs11/SecureRandom/TestDeserialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. 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 @@ -29,6 +29,8 @@ * @modules jdk.crypto.cryptoki */ +import jtreg.SkippedException; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -43,18 +45,16 @@ public class TestDeserialization extends PKCS11Test { public void main(Provider p) throws Exception { // Skip this test for providers not found by java.security.Security if (Security.getProvider(p.getName()) != p) { - System.out.println("Skip test for provider " + p.getName()); - return; + throw new SkippedException("Skip test for provider " + p.getName()); } SecureRandom r; try { r = SecureRandom.getInstance("PKCS11", p); System.out.println("SecureRandom instance " + r); } catch (NoSuchAlgorithmException e) { - System.out.println("Provider " + p + - " does not support SecureRandom, skipping"); e.printStackTrace(); - return; + throw new SkippedException("Provider " + p + + " does not support SecureRandom, skipping"); } r.setSeed(System.currentTimeMillis()); byte[] buf = new byte[16]; From 6765a9d775b5bd3d1b36090038060762f976d174 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 8 Sep 2025 15:50:09 +0000 Subject: [PATCH 407/471] 8366908: Use a different class for testing JDK-8351654 Reviewed-by: liach, lmesnik --- test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java index 214751863ea..33cb881e537 100644 --- a/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java +++ b/test/hotspot/jtreg/runtime/verifier/CFLH/TestVerify.java @@ -39,7 +39,6 @@ */ import java.lang.invoke.MethodHandles; -import java.time.Duration; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassTransform; import java.lang.classfile.MethodTransform; @@ -61,7 +60,7 @@ import java.io.FileNotFoundException; public class TestVerify { - private static final String CLASS_TO_BREAK = "java.time.Duration"; + private static final String CLASS_TO_BREAK = "java.util.Date"; private static final String INTERNAL_CLASS_TO_BREAK = CLASS_TO_BREAK.replace('.', '/'); private static final boolean DEBUG = false; @@ -91,7 +90,7 @@ public class TestVerify { } builder.with(element); }); - var classTransform = ClassTransform.transformingMethods(mm -> mm.methodName().stringValue().equals("getSeconds"), methodTransform); + var classTransform = ClassTransform.transformingMethods(mm -> mm.methodName().equalsString("parse"), methodTransform); byte[] bytes; try { @@ -164,7 +163,7 @@ public class TestVerify { } else { // Load the class instrumented with CFLH for the VerifyError. inst.addTransformer(new BadTransformer()); - System.out.println("1 hour is " + Duration.ofHours(1).getSeconds() + " seconds"); + Class cls = Class.forName(CLASS_TO_BREAK); } throw new RuntimeException("Failed: Did not throw VerifyError"); } catch (VerifyError e) { From ab12fbfda2c364bb16ddf03b923989639f437f6a Mon Sep 17 00:00:00 2001 From: Fabio Romano Date: Mon, 8 Sep 2025 16:10:22 +0000 Subject: [PATCH 408/471] 8077587: BigInteger Roots Reviewed-by: rgiulietti --- .../share/classes/java/math/BigInteger.java | 79 +++++++ .../classes/java/math/MutableBigInteger.java | 200 +++++++++++++++++- .../java/math/BigInteger/BigIntegerTest.java | 157 +++++++++++++- 3 files changed, 433 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 51d935f10c1..21f8598266f 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -2742,6 +2742,85 @@ public class BigInteger extends Number implements Comparable { return new BigInteger[] { sqrtRem[0].toBigInteger(), sqrtRem[1].toBigInteger() }; } + /** + * Returns the integer {@code n}th root of this BigInteger. The integer + * {@code n}th root {@code r} of the corresponding mathematical integer {@code x} + * is defined as follows: + *

            + *
          • if {@code x} ≥ 0, then {@code r} ≥ 0 is the largest integer such that + * {@code r}{@code n} ≤ {@code x}; + *
          • if {@code x} < 0, then {@code r} ≤ 0 is the smallest integer such that + * {@code r}{@code n} ≥ {@code x}. + *
          + * If the root is defined, it is equal to the value of + * {@code x.signum()}⋅ ⌊{@code |nthRoot(x, n)|}⌋, + * where {@code nthRoot(x, n)} denotes the real {@code n}th root of {@code x} + * treated as a real. + * Otherwise, the method throws an {@code ArithmeticException}. + * + *

          Note that the magnitude of the integer {@code n}th root will be less than + * the magnitude of the real {@code n}th root if the latter is not representable + * as an integral value. + * + * @param n the root degree + * @return the integer {@code n}th root of {@code this} + * @throws ArithmeticException if {@code n <= 0}. + * @throws ArithmeticException if {@code n} is even and {@code this} is negative. + * @see #sqrt() + * @since 26 + * @apiNote Note that calling {@code nthRoot(2)} is equivalent to calling {@code sqrt()}. + */ + public BigInteger nthRoot(int n) { + if (n == 1) + return this; + + if (n == 2) + return sqrt(); + + checkRootDegree(n); + return new MutableBigInteger(this.mag).nthRootRem(n)[0].toBigInteger(signum); + } + + /** + * Returns an array of two BigIntegers containing the integer {@code n}th root + * {@code r} of {@code this} and its remainder {@code this - r}{@code n}, + * respectively. + * + * @param n the root degree + * @return an array of two BigIntegers with the integer {@code n}th root at + * offset 0 and the remainder at offset 1 + * @throws ArithmeticException if {@code n <= 0}. + * @throws ArithmeticException if {@code n} is even and {@code this} is negative. + * @see #sqrt() + * @see #sqrtAndRemainder() + * @see #nthRoot(int) + * @since 26 + * @apiNote Note that calling {@code nthRootAndRemainder(2)} is equivalent to calling + * {@code sqrtAndRemainder()}. + */ + public BigInteger[] nthRootAndRemainder(int n) { + if (n == 1) + return new BigInteger[] { this, ZERO }; + + if (n == 2) + return sqrtAndRemainder(); + + checkRootDegree(n); + MutableBigInteger[] rootRem = new MutableBigInteger(this.mag).nthRootRem(n); + return new BigInteger[] { + rootRem[0].toBigInteger(signum), + rootRem[1].toBigInteger(signum) + }; + } + + private void checkRootDegree(int n) { + if (n <= 0) + throw new ArithmeticException("Non-positive root degree"); + + if ((n & 1) == 0 && this.signum < 0) + throw new ArithmeticException("Negative radicand with even root degree"); + } + /** * Returns a BigInteger whose value is the greatest common divisor of * {@code abs(this)} and {@code abs(val)}. Returns 0 if diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index 6ff435ba1ed..dd1da29ddd2 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. 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 @@ -1892,6 +1892,204 @@ class MutableBigInteger { return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE); } + /** + * Calculate the integer {@code n}th root {@code floor(nthRoot(this, n))} and the remainder, + * where {@code nthRoot(., n)} denotes the mathematical {@code n}th root. + * The contents of {@code this} are not changed. The value of {@code this} + * is assumed to be non-negative and the root degree {@code n >= 3}. + * Assumes {@code bitLength() <= Integer.MAX_VALUE}. + * + * @implNote The implementation is based on the material in Richard P. Brent + * and Paul Zimmermann, + * Modern Computer Arithmetic, p. 27-28. + * + * @param n the root degree + * @return the integer {@code n}th root of {@code this} and the remainder + */ + MutableBigInteger[] nthRootRem(int n) { + // Special cases. + if (this.isZero() || this.isOne()) + return new MutableBigInteger[] { this, new MutableBigInteger() }; + + final int bitLength = (int) this.bitLength(); + // if this < 2^n, result is unity + if (bitLength <= n) { + MutableBigInteger rem = new MutableBigInteger(this); + rem.subtract(ONE); + return new MutableBigInteger[] { new MutableBigInteger(1), rem }; + } + + MutableBigInteger s; + if (bitLength <= Long.SIZE) { + // Initial estimate is the root of the unsigned long value. + final long x = this.toLong(); + long sLong = (long) nthRootApprox(Math.nextUp(x >= 0 ? x : x + 0x1p64), n) + 1L; + /* The integer-valued recurrence formula in the algorithm of Brent&Zimmermann + * simply discards the fraction part of the real-valued Newton recurrence + * on the function f discussed in the referenced work. + * Indeed, for real x and integer n > 0, the equality ⌊x/n⌋ == ⌊⌊x⌋/n⌋ holds, + * from which the claim follows. + * As a consequence, an initial underestimate (not discussed in BZ) + * will immediately lead to a (weak) overestimate during the 1st iteration, + * thus meeting BZ requirements for termination and correctness. + */ + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { + // Do the 1st iteration outside the loop to ensure an overestimate + long sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); + sLong = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; + + if (BigInteger.bitLengthForLong(sLong) * (n - 1) <= Long.SIZE) { + // Refine the estimate. + long u = sLong; + do { + sLong = u; + sToN1 = BigInteger.unsignedLongPow(sLong, n - 1); + u = ((n - 1) * sLong + Long.divideUnsigned(x, sToN1)) / n; + } while (u < sLong); // Terminate when non-decreasing. + + return new MutableBigInteger[] { + new MutableBigInteger(sLong), new MutableBigInteger(x - sToN1 * sLong) + }; + } + } + // s^(n - 1) could overflow long range, use MutableBigInteger loop instead + s = new MutableBigInteger(sLong); + } else { + final int rootLen = (bitLength - 1) / n + 1; // ⌈bitLength / n⌉ + int rootSh; + double rad = 0.0, approx = 0.0; + if (n < Double.PRECISION) { + // Set up the initial estimate of the iteration. + /* Since the following equality holds: + * nthRoot(x, n) == nthRoot(x/2^sh, n) * 2^(sh/n), + * + * to get an upper bound of the root of x, it suffices to find an integer sh + * and a real s such that s >= nthRoot(x/2^sh, n) and sh % n == 0. + * The upper bound will be s * 2^(sh/n), indeed: + * s * 2^(sh/n) >= nthRoot(x/2^sh, n) * 2^(sh/n) == nthRoot(x, n). + * To achieve this, we right shift the input of sh bits into finite double range, + * rounding up the result. + * + * The value of the shift sh is chosen in order to have the smallest number of + * trailing zeros in the double value of s after the significand (minimizing + * non-significant bits), to avoid losing bits in the significand. + */ + // Determine a right shift that is a multiple of n into finite double range. + rootSh = (bitLength - Double.PRECISION) / n; // rootSh < rootLen + /* Let x = this, P = Double.PRECISION, ME = Double.MAX_EXPONENT, + * bl = bitLength, sh = rootSh * n, ex = (bl - P) % n + * + * We have bl-sh = bl-((bl-P)-ex) = P + ex + * Since ex < n < P, we get P + ex ≤ ME, and so bl-sh ≤ ME. + * + * Recalling x < 2^bl: + * x >> sh < 2^(bl-sh) ≤ 2^ME < Double.MAX_VALUE + * Thus, rad ≤ 2^ME is in the range of finite doubles. + * + * Noting that ex ≥ 0, we get bl-sh = P + ex ≥ P + * which shows that x >> sh has at least P bits of precision, + * since bl-sh is its bit length. + */ + // Shift the value into finite double range + rad = this.toBigInteger().shiftRight(rootSh * n).doubleValue(); + + // Use the root of the shifted value as an estimate. + // rad ≤ 2^ME, so Math.nextUp(rad) < Double.MAX_VALUE + rad = Math.nextUp(rad); + approx = nthRootApprox(rad, n); + } else { // fp arithmetic gives too few correct bits + // Set the root shift to the root's bit length minus 1 + // The initial estimate will be 2^rootLen == 2 << (rootLen - 1) + rootSh = rootLen - 1; + } + + if (rootSh == 0) { + // approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits + s = new MutableBigInteger((int) approx + 1); + } else { + // Allocate ⌈intLen / n⌉ ints to store the final root + s = new MutableBigInteger(new int[(intLen - 1) / n + 1]); + + if (n >= Double.PRECISION) { // fp arithmetic gives too few correct bits + // Set the initial estimate to 2 << (rootLen - 1) + s.value[0] = 2; + s.intLen = 1; + } else { + // Discard wrong integer bits from the initial estimate + // The reduced radicand rad has Math.getExponent(rad)+1 integer bits, but only + // the first Double.PRECISION leftmost bits are correct + // We scale the corresponding wrong bits of approx in the fraction part. + int wrongBits = ((Math.getExponent(rad) + 1) - Double.PRECISION) / n; + // Since rad <= 2^(bitLength - sh), then + // wrongBits <= ((bitLength - sh + 1) - Double.PRECISION) / n, + // so wrongBits is less than ⌈(bitLength - sh) / n⌉, + // the bit length of the exact shifted root, + // hence wrongBits + rootSh < ⌈(bitLength - sh) / n⌉ + rootSh == rootLen + rootSh += wrongBits; + approx = Math.scalb(approx, -wrongBits); + + // now approx has at most ⌈Double.PRECISION / n⌉ + 1 ≤ 19 integer bits + s.value[0] = (int) approx + 1; + s.intLen = 1; + } + + /* The Newton's recurrence roughly doubles the correct bits at each iteration. + * Instead of shifting the approximate root into the original range right now, + * we only double its bit length and then refine it with Newton's recurrence, + * using a suitable shifted radicand, in order to avoid computing and + * carrying trash bits in the approximate root. + * The shifted radicand is determined by the same reasoning used to get the + * initial estimate. + */ + // Refine the estimate to avoid computing non-significant bits + // rootSh is always less than rootLen, so correctBits >= 1 + for (int correctBits = rootLen - rootSh; correctBits < rootSh; correctBits <<= 1) { + s.leftShift(correctBits); + rootSh -= correctBits; + // Remove useless bits from the radicand + MutableBigInteger x = new MutableBigInteger(this); + x.rightShift(rootSh * n); + + newtonRecurrenceNthRoot(x, s, n, s.toBigInteger().pow(n - 1)); + s.add(ONE); // round up to ensure s is an upper bound of the root + } + + // Shift the approximate root back into the original range. + s.leftShift(rootSh); // Here rootSh > 0 always + } + } + + // Do the 1st iteration outside the loop to ensure an overestimate + newtonRecurrenceNthRoot(this, s, n, s.toBigInteger().pow(n - 1)); + // Refine the estimate. + do { + BigInteger sBig = s.toBigInteger(); + BigInteger sToN1 = sBig.pow(n - 1); + MutableBigInteger rem = new MutableBigInteger(sToN1.multiply(sBig).mag); + if (rem.subtract(this) <= 0) + return new MutableBigInteger[] { s, rem }; + + newtonRecurrenceNthRoot(this, s, n, sToN1); + } while (true); + } + + private static double nthRootApprox(double x, int n) { + return Math.nextUp(n == 3 ? Math.cbrt(x) : Math.pow(x, Math.nextUp(1.0 / n))); + } + + /** + * Computes {@code ((n-1)*s + x/sToN1)/n} and places the result in {@code s}. + */ + private static void newtonRecurrenceNthRoot( + MutableBigInteger x, MutableBigInteger s, int n, BigInteger sToN1) { + MutableBigInteger dividend = new MutableBigInteger(); + s.mul(n - 1, dividend); + MutableBigInteger xDivSToN1 = new MutableBigInteger(); + x.divide(new MutableBigInteger(sToN1.mag), xDivSToN1, false); + dividend.add(xDivSToN1); + dividend.divideOneWord(n, s); + } + /** * Calculate the integer square root {@code floor(sqrt(this))} and the remainder * if needed, where {@code sqrt(.)} denotes the mathematical square root. diff --git a/test/jdk/java/math/BigInteger/BigIntegerTest.java b/test/jdk/java/math/BigInteger/BigIntegerTest.java index 7da3fdac618..9018db6bb3c 100644 --- a/test/jdk/java/math/BigInteger/BigIntegerTest.java +++ b/test/jdk/java/math/BigInteger/BigIntegerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -26,7 +26,7 @@ * @library /test/lib * @build jdk.test.lib.RandomFactory * @run main BigIntegerTest - * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 8229845 + * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 8078672 8032027 8229845 8077587 * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed) * @run main/timeout=400 BigIntegerTest * @author madbot @@ -231,6 +231,9 @@ public class BigIntegerTest { if (!y.equals(z)) failCount1++; + + failCount1 += checkResult(x.signum() < 0 && power % 2 == 0 ? x.negate() : x, + y.nthRoot(power), "BigInteger.pow() inconsistent with BigInteger.nthRoot()"); } report("pow for " + order + " bits", failCount1); } @@ -412,6 +415,154 @@ public class BigIntegerTest { BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); } + private static void nthRootSmall() { + int failCount = 0; + + // A non-positive degree should cause an exception. + int n = 0; + BigInteger x = BigInteger.ONE; + BigInteger s; + try { + s = x.nthRoot(n); + // If nthRoot() does not throw an exception that is a failure. + failCount++; + printErr("nthRoot() of non-positive degree did not throw an exception"); + } catch (ArithmeticException expected) { + // Not a failure + } + + // A negative value with even degree should cause an exception. + n = 4; + x = BigInteger.valueOf(-1); + try { + s = x.nthRoot(n); + // If nthRoot() does not throw an exception that is a failure. + failCount++; + printErr("nthRoot() of negative number and even degree did not throw an exception"); + } catch (ArithmeticException expected) { + // Not a failure + } + + // A negative value with odd degree should return -nthRoot(-x, n) + n = 3; + x = BigInteger.valueOf(-8); + failCount += checkResult(x.negate().nthRoot(n).negate(), x.nthRoot(n), + "nthRoot(" + x + ", " + n + ") != -nthRoot(" + x.negate() + ", " + n + ")"); + + // A zero value should return BigInteger.ZERO. + failCount += checkResult(BigInteger.ZERO, BigInteger.ZERO.nthRoot(n), + "nthRoot(0, " + n + ") != 0"); + + // A one degree should return x. + x = BigInteger.TWO; + failCount += checkResult(x, x.nthRoot(1), "nthRoot(" + x + ", 1) != " + x); + + n = 8; + // 1 <= value < 2^n should return BigInteger.ONE. + int end = 1 << n; + for (int i = 1; i < end; i++) { + failCount += checkResult(BigInteger.ONE, + BigInteger.valueOf(i).nthRoot(n), "nthRoot(" + i + ", " + n + ") != 1"); + } + + report("nthRootSmall", failCount); + } + + public static void nthRoot() { + nthRootSmall(); + + ToIntFunction f = (x) -> { + int n = random.nextInt(x.bitLength()) + 2; + int failCount = 0; + + // nth root of x^n -> x + BigInteger xN = x.pow(n); + failCount += checkResult(x, xN.nthRoot(n), "nthRoot() x^n -> x"); + + // nth root of x^n + 1 -> x + BigInteger xNup = xN.add(BigInteger.ONE); + failCount += checkResult(x, xNup.nthRoot(n), "nthRoot() x^n + 1 -> x"); + + // nth root of (x + 1)^n - 1 -> x + BigInteger up = + x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); + failCount += checkResult(x, up.nthRoot(n), "nthRoot() (x + 1)^n - 1 -> x"); + + // nthRoot(x, n)^n <= x + BigInteger r = x.nthRoot(n); + if (r.pow(n).compareTo(x) > 0) { + failCount++; + printErr("nthRoot(x, n)^n > x for x = " + x + ", n = " + n); + } + + // (nthRoot(x, n) + 1)^n > x + if (r.add(BigInteger.ONE).pow(n).compareTo(x) <= 0) { + failCount++; + printErr("(nthRoot(x, n) + 1)^n <= x for x = " + x + ", n = " + n); + } + + return failCount; + }; + + Stream.Builder sb = Stream.builder(); + int maxExponent = 256; + for (int i = 1; i <= maxExponent; i++) { + BigInteger p2 = BigInteger.ONE.shiftLeft(i); + sb.add(p2.subtract(BigInteger.ONE)); + sb.add(p2); + sb.add(p2.add(BigInteger.ONE)); + } + sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger()); + sb.add((new BigDecimal(Double.MAX_VALUE)).toBigInteger().add(BigInteger.ONE)); + report("nthRoot for 2^N, 2^N - 1 and 2^N + 1, 1 <= N <= " + maxExponent, + sb.build().collect(Collectors.summingInt(f))); + + IntStream ints = random.ints(SIZE, 2, Integer.MAX_VALUE); + report("nthRoot for int", ints.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); + + LongStream longs = random.longs(SIZE, Integer.MAX_VALUE + 1L, Long.MAX_VALUE); + report("nthRoot for long", longs.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(f))); + + DoubleStream doubles = random.doubles(SIZE, 0x1p63, Math.scalb(1.0, maxExponent)); + report("nthRoot for double", doubles.mapToObj(x -> + BigDecimal.valueOf(x).toBigInteger()).collect(Collectors.summingInt(f))); + } + + public static void nthRootAndRemainder() { + ToIntFunction g = (x) -> { + int failCount = 0; + int n = random.nextInt(x.bitLength()) + 2; + BigInteger xN = x.pow(n); + + // nth root of x^n -> x + BigInteger[] actual = xN.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + failCount += checkResult(BigInteger.ZERO, actual[1], "nthRootAndRemainder()[1]"); + + // nth root of x^n + 1 -> x + BigInteger xNup = xN.add(BigInteger.ONE); + actual = xNup.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + failCount += checkResult(BigInteger.ONE, actual[1], "nthRootAndRemainder()[1]"); + + // nth root of (x + 1)^n - 1 -> x + BigInteger up = + x.add(BigInteger.ONE).pow(n).subtract(BigInteger.ONE); + actual = up.nthRootAndRemainder(n); + failCount += checkResult(x, actual[0], "nthRootAndRemainder()[0]"); + BigInteger r = up.subtract(xN); + failCount += checkResult(r, actual[1], "nthRootAndRemainder()[1]"); + + return failCount; + }; + + IntStream bits = random.ints(SIZE, 3, Short.MAX_VALUE); + report("nthRootAndRemainder", bits.mapToObj(x -> + BigInteger.valueOf(x)).collect(Collectors.summingInt(g))); + } + public static void arithmetic(int order) { int failCount = 0; @@ -1294,6 +1445,8 @@ public class BigIntegerTest { squareRoot(); squareRootAndRemainder(); + nthRoot(); + nthRootAndRemainder(); bitCount(); bitLength(); From 48831c65b5535fef706b64a4eb23ba28b1567ead Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 8 Sep 2025 16:23:26 +0000 Subject: [PATCH 409/471] 8367021: Regression in LocaleDataTest refactoring Reviewed-by: jlu, joehw --- test/jdk/sun/text/resources/LocaleDataTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 009ba718de5..40182034854 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -41,7 +41,7 @@ * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 * 8251317 8274658 8283277 8283805 8265315 8287868 8295564 8284840 8296715 - * 8301206 8303472 8317979 8306116 8174269 8333582 8357075 8357882 + * 8301206 8303472 8317979 8306116 8174269 8333582 8357075 8357882 8367021 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata @@ -204,7 +204,7 @@ public class LocaleDataTest in = new BufferedReader(new InputStreamReader(new FileInputStream(localeData), StandardCharsets.UTF_8)); } - out = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8)); + out = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8), true); // perform the actual test int errorCount = doTest(in, out, writeNewFile); From 323b02016e7458a0be39d52c9b0a5c61d579347e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:46:30 +0000 Subject: [PATCH 410/471] 8367034: [REDO] Protect ExecuteWithLog from running with redirection without a subshell Reviewed-by: erikj --- make/RunTests.gmk | 34 ++++++++++++++-------------- make/StaticLibs.gmk | 2 +- make/common/MakeBase.gmk | 26 +++++++++++++-------- make/common/ProcessMarkdown.gmk | 2 +- make/hotspot/gensrc/GensrcDtrace.gmk | 5 ++-- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 10f0a2f87ed..7b05a0ba12f 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -509,7 +509,7 @@ define SetupRunGtestTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ $$(CD) $$($1_TEST_SUPPORT_DIR) && \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ -jdk $(JDK_UNDER_TEST) $$($1_GTEST_FILTER) \ @@ -520,7 +520,7 @@ define SetupRunGtestTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt @@ -644,7 +644,7 @@ define SetupRunMicroTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/micro, \ $$(CD) $$(TEST_IMAGE_DIR) && \ $$(FIXPATH) $$($1_MICRO_TEST_JDK)/bin/java $$($1_MICRO_JAVA_OPTIONS) \ -jar $$($1_MICRO_BENCHMARKS_JAR) \ @@ -655,7 +655,7 @@ define SetupRunMicroTestBody > >($(TEE) $$($1_TEST_RESULTS_DIR)/micro.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/micro.txt @@ -758,34 +758,34 @@ define SetupAOTBody ifeq ($$($1_TRAINING), onestep) $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ - -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + -Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) else $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ cd $$($1_AOT_JDK_OUTPUT_DIR); \ $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ - -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ + -Xlog:class+load$$(COMMA)aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) + ) $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), \ $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ - $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + $$($1_VM_OPTIONS) -Xlog:aot$$(COMMA)aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - )) + ) endif @@ -1085,9 +1085,9 @@ define SetupRunJtregTestBody $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ - )) + ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1204,12 +1204,12 @@ define SetupRunSpecialTestBody $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, ( \ + $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \ $$($1_TEST_COMMAND_LINE) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ - )) + ) # We can not parse the various "special" tests. parse-test-$1: run-test-$1 diff --git a/make/StaticLibs.gmk b/make/StaticLibs.gmk index 3cf2a4dd136..80d6b4538c8 100644 --- a/make/StaticLibs.gmk +++ b/make/StaticLibs.gmk @@ -111,7 +111,7 @@ else ifeq ($(call isTargetOs, aix), true) INFO := Generating export list for $(notdir $(lib)), \ DEPS := $(lib), \ OUTPUT_FILE := $(lib).exp, \ - COMMAND := ( $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp ), \ + COMMAND := $(AR) $(ARFLAGS) -w $(lib) | $(GREP) -v '^\.' | $(AWK) '{print $$1}' | $(SORT) -u > $(lib).exp, \ )) \ $(eval STATIC_LIB_EXPORT_FILES += $(lib).exp) \ ) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index d1bb0396943..97ef88932cb 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -284,6 +284,12 @@ else LogCmdlines = endif +# Check if the command line contains redirection, that is <, > or >>, +# and if so, return a value that is interpreted as true in a make $(if) +# construct. +is_redirect = \ + $(if $(filter < > >>, $1), true) + ################################################################################ # ExecuteWithLog will run a command and log the output appropriately. This is # meant to be used by commands that do "real" work, like a compilation. @@ -291,21 +297,23 @@ endif # of the build in case of failure. The command line itself is stored in a file, # and also logged to stdout if the LOG=cmdlines option has been given. # -# NOTE: If the command redirects stdout, the caller needs to wrap it in a -# subshell (by adding parentheses around it), otherwise the redirect to the -# subshell tee process will create a race condition where the target file may -# not be fully written when the make recipe is done. -# # Param 1 - The path to base the name of the log file / command line file on # Param 2 - The command to run ExecuteWithLog = \ - $(call LogCmdlines, Executing: [$(strip $2)]) \ + $(call LogCmdlines, Executing: \ + [$(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN))]) \ $(call MakeDir, $(dir $(strip $1)) $(MAKESUPPORT_OUTPUTDIR)/failure-logs) \ $(call WriteFile, $2, $(strip $1).cmdline) \ - ( $(RM) $(strip $1).log && $(strip $2) > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ + ( $(RM) $(strip $1).log && \ + $(if $(call is_redirect, $2),$(LEFT_PAREN) )$(strip $2)$(if $(call \ + is_redirect, $2), $(RIGHT_PAREN)) \ + > >($(TEE) -a $(strip $1).log) 2> >($(TEE) -a $(strip $1).log >&2) || \ ( exitcode=$(DOLLAR)? && \ - $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ - $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ + $(CP) $(strip $1).log $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).log && \ + $(CP) $(strip $1).cmdline $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(subst \ + /,_,$(patsubst $(OUTPUTDIR)/%,%,$(strip $1))).cmdline && \ exit $(DOLLAR)exitcode ) ) ################################################################################ diff --git a/make/common/ProcessMarkdown.gmk b/make/common/ProcessMarkdown.gmk index 1b4a5b76ea1..c60b49ae85f 100644 --- a/make/common/ProcessMarkdown.gmk +++ b/make/common/ProcessMarkdown.gmk @@ -109,7 +109,7 @@ define ProcessMarkdown $$(call LogInfo, Post-processing markdown file $2) $$(call MakeDir, $$(SUPPORT_OUTPUTDIR)/markdown $$($1_$2_TARGET_DIR)) $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/markdown/$$($1_$2_MARKER)_post, \ - ( $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) ) + $$($1_POST_PROCESS) $$($1_$2_PANDOC_OUTPUT) > $$($1_$2_OUTPUT_FILE) ) endif $1 += $$($1_$2_OUTPUT_FILE) diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index e71c3cb961d..7a80bf47285 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -47,8 +47,9 @@ ifeq ($(call check-jvm-feature, dtrace), true) $(call LogInfo, Generating dtrace header file $(@F)) $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - ($(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) - $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(CPP) $(DTRACE_CPP_FLAGS) $(SYSROOT_CFLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, \ + $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) # Process all .d files in DTRACE_SOURCE_DIR. They are: # hotspot_jni.d hotspot.d hs_private.d From 55af9d83800930966776224bc4c7ff4ab1af9817 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:48:14 +0000 Subject: [PATCH 411/471] 8366837: Clean up gensrc by spp.Spp Reviewed-by: erikj --- make/common/Utils.gmk | 36 ++ .../modules/GensrcStreamPreProcessing.gmk | 228 ++++++++ make/modules/java.base/Gensrc.gmk | 4 +- .../modules/java.base/gensrc/GensrcBuffer.gmk | 535 +++++++----------- .../java.base/gensrc/GensrcCharsetCoder.gmk | 141 ++--- .../gensrc/GensrcScopedMemoryAccess.gmk | 185 ++---- .../java.base/gensrc/GensrcVarHandles.gmk | 339 ++++------- .../nio/charset/Charset-X-Coder.java.template | 18 +- test/make/TestMakeBase.gmk | 57 ++ 9 files changed, 752 insertions(+), 791 deletions(-) create mode 100644 make/common/modules/GensrcStreamPreProcessing.gmk diff --git a/make/common/Utils.gmk b/make/common/Utils.gmk index 03009ec3ca4..c0ebabca3f7 100644 --- a/make/common/Utils.gmk +++ b/make/common/Utils.gmk @@ -55,6 +55,42 @@ uppercase = \ $(uppercase_result) \ ) +lowercase_table := A,a B,b C,c D,d E,e F,f G,g H,h I,i J,j K,k L,l M,m N,n O,o \ + P,p Q,q R,r S,s T,t U,u V,v W,w X,x Y,y Z,z + +lowercase_internal = \ + $(if $(strip $1), $$(subst $(firstword $1), $(call lowercase_internal, \ + $(wordlist 2, $(words $1), $1), $2)), $2) + +# Convert a string to lower case. Works only on a-z. +# $1 - The string to convert +lowercase = \ + $(strip \ + $(eval lowercase_result := $(call lowercase_internal, $(lowercase_table), $1)) \ + $(lowercase_result) \ + ) + +lowercase_letters := a b c d e f g h i j k l m n o p q r s t u v w x y z +uppercase_letters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + +titlecase_internal = \ + $(strip $(or \ + $(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \ + $(if $(filter $l%, $1), \ + $(call uppercase, $l)$(call lowercase, $(patsubst $l%,%,$1))))), \ + $1)) + +# Convert a string to Title Case. Works only on a-z. +# $1 - The string to convert +titlecase = \ + $(strip $(foreach w, $1, $(call titlecase_internal, $w))) + +# Returns the first character of a string. Works only on a-z. +# $1 - The string to extract the first character from +firstchar = \ + $(strip $(foreach l, $(lowercase_letters) $(uppercase_letters), \ + $(if $(filter $l%, $(firstword $1)), $l))) + ################################################################################ # Creates a sequence of increasing numbers (inclusive). # Param 1 - starting number diff --git a/make/common/modules/GensrcStreamPreProcessing.gmk b/make/common/modules/GensrcStreamPreProcessing.gmk new file mode 100644 index 00000000000..a48e3c98d4b --- /dev/null +++ b/make/common/modules/GensrcStreamPreProcessing.gmk @@ -0,0 +1,228 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. 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. Oracle 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. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include MakeIncludeStart.gmk +ifeq ($(INCLUDE), true) + +################################################################################ +# This file defines macros that sets up rules for running the spp.Spp build tool +################################################################################ + +include Execute.gmk +include $(TOPDIR)/make/ToolsJdk.gmk + +NON_BYTE_NUMBER_TYPES := char short int long float double +NUMBER_TYPES := byte $(NON_BYTE_NUMBER_TYPES) +PRIMITIVE_TYPES := boolean $(NUMBER_TYPES) + +################################################################################ +# The Conv function converts a type given as first argument (as a normal Java +# native type name), into one of several corresponding strings, depending on +# the aspect given in the second argument +# +# The implementation dispatches the call to one of several Conv_ macros. +# +# arg $1: the type to convert +# arg $2: the aspect to convert for +# arg $3: byte order (only needed for certain aspects) +# +Conv = \ + $(strip $(call Conv_$(strip $2),$(strip $1),$(strip $3))) + +################################################################################ +# Conv_ implementations + +# Return a single letter representing the type (lowercase first letter) +Conv_x = \ + $(call firstchar, $1) + +# Return capitalized type name +Conv_Type = \ + $(call titlecase, $1) + +# Return the full descriptive name of the type, e.g. int -> integer +Conv_fulltype = \ + $(if $(filter char, $1), \ + character, \ + $(if $(filter int, $1), \ + integer, \ + $1 \ + ) \ + ) + +# Return the capitalized full descriptive name of the type, e.g. int -> Integer +Conv_Fulltype = \ + $(call titlecase, $(call Conv_fulltype, $1)) + +# Return log2 bits per value (0-3) +Conv_LBPV = \ + $(if $(filter byte, $1), \ + 0, \ + $(if $(filter char short, $1), \ + 1, \ + $(if $(filter int float, $1), \ + 2, \ + $(if $(filter long double, $1), \ + 3)))) + +# Return float or int category +Conv_category = \ + $(if $(filter float double, $1), \ + floatingPointType, \ + integralType \ + ) + +# Return stream information for char +Conv_streams = \ + $(if $(filter char, $1), streamableType) + +# Return stream type information for char +Conv_streamtype = \ + $(if $(filter char, $1), int) + +# Return capitalized stream type information for char +Conv_Streamtype = \ + $(if $(filter char, $1), Int) + +# Return article to use for type in English text +Conv_a = \ + $(if $(filter int, $1), an, a) + +# Return capitalized article to use for type in English text +Conv_A = \ + $(if $(filter int, $1), An, A) + +# Return integer type with same size as the type +Conv_memtype = \ + $(if $(filter float, $1), int, $(if $(filter double, $1), long, $1)) + +# Return capitalized integer type with same size as the type +Conv_Memtype = \ + $(call titlecase, $(call Conv, $1, memtype)) + +# Return capitalized full descriptive name for integer type with same size as the type +Conv_FullMemtype = \ + $(call Conv, $(call Conv, $1, memtype), Fulltype) + +# Return Type or Memtype depending on byte order +# arg $2: BYTE_ORDER +Conv_Swaptype = \ + $(if $(filter U, $2), \ + $(call Conv, $1, Type), \ + $(call Conv, $1, Memtype)) + +# Return fromBits method name for floating types, depending on byte order +# arg $2: BYTE_ORDER +Conv_fromBits = \ + $(if $(filter float double, $1), \ + $(if $(filter U, $2), , \ + $(call Conv, $1, Type).$(call Conv, $1, memtype)BitsTo$(call Conv, $1, Type))) + +# Return toBits method name for floating types, depending on byte order +# arg $2: BYTE_ORDER +Conv_toBits = \ + $(if $(filter float double, $1), \ + $(if $(filter U, $2), , \ + $(call Conv, $1, Type).$1ToRaw$(call Conv, $(call Conv, $1, memtype), Type)Bits)) + +# Return swap method name, depending on byte order +# arg $2: BYTE_ORDER +Conv_swap = \ + $(if $(filter S, $2), Bits.swap) + +# Return word describing the number of bytes required by type +Conv_nbytes = \ + $(if $(filter 0, $(call Conv, $1, LBPV)), one, \ + $(if $(filter 1, $(call Conv, $1, LBPV)), two, \ + $(if $(filter 2, $(call Conv, $1, LBPV)), four, \ + $(if $(filter 3, $(call Conv, $1, LBPV)), eight)))) + +# Return word describing the number of bytes required by type, minus one +Conv_nbytesButOne = \ + $(if $(filter 0, $(call Conv, $1, LBPV)), zero, \ + $(if $(filter 1, $(call Conv, $1, LBPV)), one, \ + $(if $(filter 2, $(call Conv, $1, LBPV)), three, \ + $(if $(filter 3, $(call Conv, $1, LBPV)), seven)))) + +################################################################################ +# Setup make rules that runs the spp.Spp build tool on an input file. +# +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. +# +# Remaining parameters are named arguments. These include: +# BEGIN_END Set to true to exclude everything outside #begin/#end (default: false) +# SUBST_EMPTY_LINES Set to false to not generate empty lines for removed lines (default: true) +# SOURCE_FILE The input file to process (required) +# OUTPUT_FILE The output file (required) +# INFO Override default message to print (optional) +# KEYS One or more keys to control the generation (optional) +# REPLACEMENTS one or more text replacement patterns, using the syntax: +# VAR=VALUE [VAR=VALUE] ... +# +SetupStreamPreProcessing = $(NamedParamsMacroTemplate) +define SetupStreamPreProcessingBody + # Verify arguments + ifeq ($$($1_SOURCE_FILE), ) + $$(error Must specify SOURCE_FILE (in $1)) + endif + ifeq ($$($1_OUTPUT_FILE), ) + $$(error Must specify OUTPUT_FILE (in $1)) + endif + + $1_COMMAND_LINE := + ifeq ($$($1_BEGIN_END), true) + $1_COMMAND_LINE += -be + endif + + ifeq ($$($1_SUBST_EMPTY_LINES), false) + $1_COMMAND_LINE += -nel + endif + + $1_COMMAND_LINE += $$(foreach k, $$($1_KEYS), -K$$k) + $1_COMMAND_LINE += $$(subst $$$$(SPACE), ,$$(foreach d, $$($1_REPLACEMENTS), -D$$d)) + + $1_COMMAND_LINE += -i$$($1_SOURCE_FILE) -o$$($1_OUTPUT_FILE).tmp + + ifeq ($$($1_INFO), ) + $1_INFO := Preprocessing $$(notdir $$($1_SOURCE_FILE)) for $(MODULE) + endif + + $$(eval $$(call SetupExecute, RUN_SPP_$1, \ + INFO := $$($1_INFO), \ + DEPS := $$($1_SOURCE_FILE) $$(BUILD_TOOLS_JDK), \ + OUTPUT_FILE := $$($1_OUTPUT_FILE), \ + COMMAND := $$(TOOL_SPP) $$($1_COMMAND_LINE), \ + PRE_COMMAND := $$(RM) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \ + POST_COMMAND := $$(MV) $$($1_OUTPUT_FILE).tmp $$($1_OUTPUT_FILE), \ +)) + + $1 += $$(RUN_SPP_$1) +endef + +################################################################################ + +endif # include guard +include MakeIncludeEnd.gmk diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index e4a019ed584..2750a6c8791 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -26,6 +26,8 @@ ################################################################################ include GensrcCommon.gmk +include GensrcProperties.gmk +include GensrcStreamPreProcessing.gmk include gensrc/GensrcBuffer.gmk include gensrc/GensrcCharacterData.gmk @@ -71,8 +73,6 @@ TARGETS += $(CLDR_GEN_DONE) ################################################################################ -include GensrcProperties.gmk - $(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \ SRC_DIRS := $(MODULE_SRC)/share/classes/sun/launcher/resources, \ CLASS := ListResourceBundle, \ diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk index dd91c8c870a..edefd60b6d4 100644 --- a/make/modules/java.base/gensrc/GensrcBuffer.gmk +++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk @@ -28,363 +28,222 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_BUFFER := +BUFFER_INPUT_DIR := $(MODULE_SRC)/share/classes/java/nio +BUFFER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio +################################################################################ +# Helper method to setup generation of bin snippets. +# Will add the generated snippet file name to $1_BIN_SNIPPET_FILES. +# +# arg $1: $1 as passed into SetupGenBuffer +# arg $2: type for this bin snippet +define SetupGenBufferBinSnippets + $1_$2_TMP := $$(BUFFER_OUTPUT_DIR)/$1.java.bin-snippet.$2 -GENSRC_BUFFER_SRC := $(MODULE_SRC)/share/classes/java/nio - -### - -$(GENSRC_BUFFER_DST)/_the.buffer.dir: - $(call LogInfo, Generating buffer classes) - $(call MakeDir, $(@D)) - $(TOUCH) $@ - -define fixRw - $1_RW := $2 - $1_rwkey := rw - ifeq (R, $2) - $1_rwkey := ro - endif -endef - -define typesAndBits - # param 1 target - # param 2 type - # param 3 BO - $1_a := a - $1_A := A - - $1_type := $2 - - ifeq ($2, byte) - $1_x := b - $1_Type := Byte - $1_fulltype := byte - $1_Fulltype := Byte - $1_category := integralType - $1_LBPV := 0 - endif - - ifeq ($2, char) - $1_x := c - $1_Type := Char - $1_fulltype := character - $1_Fulltype := Character - $1_category := integralType - $1_streams := streamableType - $1_streamtype := int - $1_Streamtype := Int - $1_LBPV := 1 - endif - - ifeq ($2, short) - $1_x := s - $1_Type := Short - $1_fulltype := short - $1_Fulltype := Short - $1_category := integralType - $1_LBPV := 1 - endif - - ifeq ($2, int) - $1_a := an - $1_A := An - $1_x := i - $1_Type := Int - $1_fulltype := integer - $1_Fulltype := Integer - $1_category := integralType - $1_LBPV := 2 - endif - - ifeq ($2, long) - $1_x := l - $1_Type := Long - $1_fulltype := long - $1_Fulltype := Long - $1_category := integralType - $1_LBPV := 3 - endif - - ifeq ($2, float) - $1_x := f - $1_Type := Float - $1_fulltype := float - $1_Fulltype := Float - $1_category := floatingPointType - $1_LBPV := 2 - endif - - ifeq ($2, double) - $1_x := d - $1_Type := Double - $1_fulltype := double - $1_Fulltype := Double - $1_category := floatingPointType - $1_LBPV := 3 - endif - - $1_Swaptype := $$($1_Type) - $1_memtype := $2 - $1_Memtype := $$($1_Type) - - ifeq ($2, float) - $1_memtype := int - $1_Memtype := Int - ifneq ($3, U) - $1_Swaptype := Int - $1_fromBits := Float.intBitsToFloat - $1_toBits := Float.floatToRawIntBits - endif - endif - - ifeq ($2, double) - $1_memtype := long - $1_Memtype := Long - ifneq ($3, U) - $1_Swaptype := Long - $1_fromBits := Double.longBitsToDouble - $1_toBits := Double.doubleToRawLongBits - endif - endif - - ifeq ($3, S) - $1_swap := Bits.swap - endif -endef - -define genBinOps - # param 1 target - # param 2 type - # param 3 BO - # param 4 RW - # param 5 nbytes - # param 6 nbytesButOne - $(call typesAndBits,$1,$2,$3) - $(call fixRw,$1,$4) - $1_nbytes := $5 - $1_nbytesButOne := $6 - $1_CMD := $(TOOL_SPP) \ - -Dtype=$$($1_type) \ - -DType=$$($1_Type) \ - -Dfulltype=$$($1_fulltype) \ - -Dmemtype=$$($1_memtype) \ - -DMemtype=$$($1_Memtype) \ - -DfromBits=$$($1_fromBits) \ - -DtoBits=$$($1_toBits) \ - -DLG_BYTES_PER_VALUE=$$($1_LBPV) \ - -DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \ - -Dnbytes=$$($1_nbytes) \ - -DnbytesButOne=$$($1_nbytesButOne) \ - -DRW=$$($1_RW) \ - -K$$($1_rwkey) \ - -Da=$$($1_a) \ - -be -endef - -define SetupGenBuffer - # param 1 is for output file - # param 2 is template dependency - # param 3-9 are named args. - # type := - # BIN := - # RW := Mutability (R)ead-only (W)ritable - # BO := (U)nswapped/(S)wapped/(L)ittle/(B)ig - # - $(if $3,$1_$(strip $3)) - $(if $4,$1_$(strip $4)) - $(if $5,$1_$(strip $5)) - $(if $6,$1_$(strip $6)) - $(if $7,$1_$(strip $7)) - $(if $8,$1_$(strip $8)) - $(if $9,$1_$(strip $9)) - $(if $(10),$1_$(strip $(10))) - $(if $(11),$1_$(strip $(11))) - $(if $(12),$1_$(strip $(12))) - $(if $(13),$1_$(strip $(13))) - $(if $(14),$1_$(strip $(14))) - $(foreach i,3 4 5 6 7 8 9 10 11 12 13 14 15,$(if $($i),$1_$(strip $($i)))$(NEWLINE)) - $(call LogSetupMacroEntry,SetupGenBuffer($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15)) - $(if $(16),$(error Internal makefile error: Too many arguments to SetupGenBuffer, please update GensrcBuffer.gmk)) - - $(call fixRw,$1,$$($1_RW)) - $(call typesAndBits,$1,$$($1_type),$$($1_BO)) - - $1_DST := $(GENSRC_BUFFER_DST)/$1.java - $1_SRC := $(GENSRC_BUFFER_SRC)/$(strip $2).java.template - $1_SRC_BIN := $(GENSRC_BUFFER_SRC)/$(strip $2)-bin.java.template - - $1_DEP := $$($1_SRC) - ifneq ($$($1_BIN), 1) - $1_DEP := $$($1_SRC) - $1_OUT := $$($1_DST) + $1_$2_LBPV := $$(call Conv, $2, LBPV) + ifeq ($$($1_READ_ONLY), true) + $1_$2_RW_KEYS := ro + $1_$2_RW_REPLACEMENT := R else - $1_DEP += $$($1_SRC) $$($1_SRC_BIN) - $1_OUT := $(GENSRC_BUFFER_DST)/$1.binop.0.java + $1_$2_RW_KEYS := rw + $1_$2_RW_REPLACEMENT := endif - ifeq ($$($1_BIN), 1) - $(call genBinOps,$1_char,char,$$($1_BO),$$($1_RW),two,one) - $(call genBinOps,$1_short,short,$$($1_BO),$$($1_RW),two,one) - $(call genBinOps,$1_int,int,$$($1_BO),$$($1_RW),four,three) - $(call genBinOps,$1_long,long,$$($1_BO),$$($1_RW),eight,seven) - $(call genBinOps,$1_float,float,$$($1_BO),$$($1_RW),four,three) - $(call genBinOps,$1_double,double,$$($1_BO),$$($1_RW),eight,seven) - endif - - $$($1_DST): $$($1_DEP) $(GENSRC_BUFFER_DST)/_the.buffer.dir - $(RM) $$($1_OUT).tmp - $(TOOL_SPP) -i$$($1_SRC) -o$$($1_OUT).tmp \ - -K$$($1_type) \ - -K$$($1_category) \ - -K$$($1_streams) \ - -Dtype=$$($1_type) \ - -DType=$$($1_Type) \ - -Dfulltype=$$($1_fulltype) \ - -DFulltype=$$($1_Fulltype) \ - -Dstreamtype=$$($1_streamtype) \ - -DStreamtype=$$($1_Streamtype) \ - -Dx=$$($1_x) \ - -Dmemtype=$$($1_memtype) \ - -DMemtype=$$($1_Memtype) \ - -DSwaptype=$$($1_Swaptype) \ - -DfromBits=$$($1_fromBits) \ - -DtoBits=$$($1_toBits) \ - -DLG_BYTES_PER_VALUE=$$($1_LBPV) \ - -DBYTES_PER_VALUE="(1 << $$($1_LBPV))" \ - -DBO=$$($1_BO) \ - -Dswap=$$($1_swap) \ - -DRW=$$($1_RW) \ - -K$$($1_rwkey) \ - -Da=$$($1_a) \ - -DA=$$($1_A) \ - -Kbo$$($1_BO) - $(MV) $$($1_OUT).tmp $$($1_OUT) - # Do the extra bin thing - ifeq ($$($1_BIN), 1) - $(SED) -e '/#BIN/,$$$$d' < $$($1_OUT) > $$($1_DST).tmp - $(RM) $$($1_OUT) - $$($1_char_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_short_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_int_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_long_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_float_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $$($1_double_CMD) -i$$($1_SRC_BIN) -o$$($1_DST).tmp - $(ECHO) "}" >> $$($1_DST).tmp - mv $$($1_DST).tmp $$($1_DST) - endif - - GENSRC_BUFFER += $$($1_DST) + $$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_BIN_$1_$2, \ + SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE)-bin.java.template, \ + OUTPUT_FILE := $$($1_$2_TMP), \ + INFO := Generating buffer class bin snippets for $1 ($2), \ + BEGIN_END := true, \ + KEYS := \ + $$($1_$2_RW_KEYS), \ + REPLACEMENTS := \ + type=$2 \ + RW=$$($1_$2_RW_REPLACEMENT) \ + LG_BYTES_PER_VALUE=$$($1_$2_LBPV) \ + BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \ + a=$$(call Conv, $2, a) \ + fulltype=$$(call Conv, $2, fulltype) \ + memtype=$$(call Conv, $2, memtype) \ + Memtype=$$(call Conv, $2, Memtype) \ + nbytes=$$(call Conv, $2, nbytes) \ + nbytesButOne=$$(call Conv, $2, nbytesButOne) \ + Type=$$(call Conv, $2, Type) \ + fromBits=$$(call Conv, $2, fromBits, $$($1_BYTE_ORDER)) \ + toBits=$$(call Conv, $2, toBits, $$($1_BYTE_ORDER)), \ + )) + TARGETS += $$(GEN_BUFFER_$1_$2) + $1_BIN_SNIPPET_FILES += $$($1_$2_TMP) endef -### - -X_BUF := X-Buffer - -$(eval $(call SetupGenBuffer,ByteBuffer, $(X_BUF), type := byte, BIN := 1)) -$(eval $(call SetupGenBuffer,CharBuffer, $(X_BUF), type := char)) -$(eval $(call SetupGenBuffer,ShortBuffer, $(X_BUF), type := short)) -$(eval $(call SetupGenBuffer,IntBuffer, $(X_BUF), type := int)) -$(eval $(call SetupGenBuffer,LongBuffer, $(X_BUF), type := long)) -$(eval $(call SetupGenBuffer,FloatBuffer, $(X_BUF), type := float)) -$(eval $(call SetupGenBuffer,DoubleBuffer,$(X_BUF), type := double)) - -# Buffers whose contents are heap-allocated +################################################################################ +# Setup make rules that creates a generated buffer class java source file, +# according to specifications provided. # -HEAP_X_BUF := Heap-X-Buffer - -$(eval $(call SetupGenBuffer,HeapByteBuffer, $(HEAP_X_BUF), type := byte)) -$(eval $(call SetupGenBuffer,HeapByteBufferR, $(HEAP_X_BUF), type := byte, RW := R)) -$(eval $(call SetupGenBuffer,HeapCharBuffer, $(HEAP_X_BUF), type := char)) -$(eval $(call SetupGenBuffer,HeapCharBufferR, $(HEAP_X_BUF), type := char, RW := R)) -$(eval $(call SetupGenBuffer,HeapShortBuffer, $(HEAP_X_BUF), type := short)) -$(eval $(call SetupGenBuffer,HeapShortBufferR, $(HEAP_X_BUF), type := short, RW := R)) -$(eval $(call SetupGenBuffer,HeapIntBuffer, $(HEAP_X_BUF), type := int)) -$(eval $(call SetupGenBuffer,HeapIntBufferR, $(HEAP_X_BUF), type := int, RW := R)) -$(eval $(call SetupGenBuffer,HeapLongBuffer, $(HEAP_X_BUF), type := long)) -$(eval $(call SetupGenBuffer,HeapLongBufferR, $(HEAP_X_BUF), type := long, RW := R)) -$(eval $(call SetupGenBuffer,HeapFloatBuffer, $(HEAP_X_BUF), type := float)) -$(eval $(call SetupGenBuffer,HeapFloatBufferR, $(HEAP_X_BUF), type := float, RW := R)) -$(eval $(call SetupGenBuffer,HeapDoubleBuffer, $(HEAP_X_BUF), type := double)) -$(eval $(call SetupGenBuffer,HeapDoubleBufferR,$(HEAP_X_BUF), type := double, RW := R)) - -# Direct byte buffer +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. The output +# file name is also based on this. # -DIRECT_X_BUF := Direct-X-Buffer - -$(eval $(call SetupGenBuffer,DirectByteBuffer, $(DIRECT_X_BUF), type := byte, BIN := 1)) -$(eval $(call SetupGenBuffer,DirectByteBufferR,$(DIRECT_X_BUF), type := byte, BIN := 1, RW := R)) - -# Unswapped views of direct byte buffers +# Remaining parameters are named arguments. These include: +# TYPE The native type +# TEMPLATE The base file name of the template to use +# BYTE_ORDER (U)nswapped/(S)wapped/(L)ittle/(B)ig +# READ_ONLY Set to true to generate read-only buffers (default: false) +# GENERATE_BIN Set to true to generate bin snippets (default: false) # -$(eval $(call SetupGenBuffer,DirectCharBufferU, $(DIRECT_X_BUF), type := char, BO := U)) -$(eval $(call SetupGenBuffer,DirectCharBufferRU, $(DIRECT_X_BUF), type := char, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectShortBufferU, $(DIRECT_X_BUF), type := short, BO := U)) -$(eval $(call SetupGenBuffer,DirectShortBufferRU, $(DIRECT_X_BUF), type := short, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectIntBufferU, $(DIRECT_X_BUF), type := int, BO := U)) -$(eval $(call SetupGenBuffer,DirectIntBufferRU, $(DIRECT_X_BUF), type := int, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectLongBufferU, $(DIRECT_X_BUF), type := long, BO := U)) -$(eval $(call SetupGenBuffer,DirectLongBufferRU, $(DIRECT_X_BUF), type := long, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectFloatBufferU, $(DIRECT_X_BUF), type := float, BO := U)) -$(eval $(call SetupGenBuffer,DirectFloatBufferRU, $(DIRECT_X_BUF), type := float, RW := R, BO := U)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferU, $(DIRECT_X_BUF), type := double, BO := U)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferRU,$(DIRECT_X_BUF), type := double, RW := R, BO := U)) +SetupGenBuffer = $(NamedParamsMacroTemplate) +define SetupGenBufferBody + $1_OUTPUT := $$(BUFFER_OUTPUT_DIR)/$1.java + ifeq ($$($1_GENERATE_BIN), true) + # After generating the buffer class, we need to do further post processing, + # so output to a temporary file + $1_REAL_OUTPUT := $$($1_OUTPUT) + $1_OUTPUT := $$($1_OUTPUT).bin-snippet.tmp + endif -# Swapped views of direct byte buffers + $1_LBPV := $$(call Conv, $$($1_TYPE), LBPV) + ifeq ($$($1_READ_ONLY), true) + $1_RW_KEYS := ro + $1_RW_REPLACEMENT := R + else + $1_RW_KEYS := rw + $1_RW_REPLACEMENT := + endif + + $$(eval $$(call SetupStreamPreProcessing, GEN_BUFFER_$1, \ + SOURCE_FILE := $$(BUFFER_INPUT_DIR)/$$($1_TEMPLATE).java.template, \ + OUTPUT_FILE := $$($1_OUTPUT), \ + INFO := Generating buffer class $1.java, \ + KEYS := \ + $$($1_TYPE) \ + $$($1_RW_KEYS) \ + bo$$($1_BYTE_ORDER) \ + $$(call Conv, $$($1_TYPE), category) \ + $$(call Conv, $$($1_TYPE), streams), \ + REPLACEMENTS := \ + type=$$($1_TYPE) \ + BO=$$($1_BYTE_ORDER) \ + RW=$$($1_RW_REPLACEMENT) \ + LG_BYTES_PER_VALUE=$$($1_LBPV) \ + BYTES_PER_VALUE="(1$$$$(SPACE)<<$$$$(SPACE)$$($1_$2_LBPV))" \ + a=$$(call Conv, $$($1_TYPE), a) \ + A=$$(call Conv, $$($1_TYPE), A) \ + fulltype=$$(call Conv, $$($1_TYPE), fulltype) \ + Fulltype=$$(call Conv, $$($1_TYPE), Fulltype) \ + memtype=$$(call Conv, $$($1_TYPE), memtype) \ + Memtype=$$(call Conv, $$($1_TYPE), Memtype) \ + streamtype=$$(call Conv, $$($1_TYPE), streamtype) \ + Streamtype=$$(call Conv, $$($1_TYPE), Streamtype) \ + Type=$$(call Conv, $$($1_TYPE), Type) \ + x=$$(call Conv, $$($1_TYPE), x) \ + fromBits=$$(call Conv, $$($1_TYPE), fromBits, $$($1_BYTE_ORDER)) \ + toBits=$$(call Conv, $$($1_TYPE), toBits, $$($1_BYTE_ORDER)) \ + swap=$$(call Conv, $$($1_TYPE), swap, $$($1_BYTE_ORDER)) \ + Swaptype=$$(call Conv, $$($1_TYPE), Swaptype, $$($1_BYTE_ORDER)), \ + )) + TARGETS += $$(GEN_BUFFER_$1) + $1 += $$(GEN_BUFFER_$1) + + ifeq ($$($1_GENERATE_BIN), true) + # Setup generation of snippet files, one for each non-byte type. This will + # populate $1_BIN_SNIPPET_FILES. + $1_BIN_SNIPPET_FILES := + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBufferBinSnippets,$1,$$t)) \ + ) + + # Inject these snippets in the file generated by GEN_BUFFER_$1 + $$($1_REAL_OUTPUT): $$($1_OUTPUT) $$($1_BIN_SNIPPET_FILES) + $$(call LogInfo, Concatenating buffer class bin snippets for $1) + # Delete everything from the line containing #BIN and below + $$(SED) -e '/#BIN/,$$$$d' < $$($1_OUTPUT) > $$($1_REAL_OUTPUT).tmp + $$(CAT) $$($1_BIN_SNIPPET_FILES) >> $$($1_REAL_OUTPUT).tmp + $$(ECHO) "}" >> $$($1_REAL_OUTPUT).tmp + $$(MV) $$($1_REAL_OUTPUT).tmp $$($1_REAL_OUTPUT) + + TARGETS += $$($1_REAL_OUTPUT) + $1 += $$($1_REAL_OUTPUT) + endif +endef + +################################################################################ +# Helper method to setup generation of all buffer classes, for a given +# modifiability state (read-only or not) # -$(eval $(call SetupGenBuffer,DirectCharBufferS, $(DIRECT_X_BUF), type := char, BO := S)) -$(eval $(call SetupGenBuffer,DirectCharBufferRS, $(DIRECT_X_BUF), type := char, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectShortBufferS, $(DIRECT_X_BUF), type := short, BO := S)) -$(eval $(call SetupGenBuffer,DirectShortBufferRS, $(DIRECT_X_BUF), type := short, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectIntBufferS, $(DIRECT_X_BUF), type := int, BO := S)) -$(eval $(call SetupGenBuffer,DirectIntBufferRS, $(DIRECT_X_BUF), type := int, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectLongBufferS, $(DIRECT_X_BUF), type := long, BO := S)) -$(eval $(call SetupGenBuffer,DirectLongBufferRS, $(DIRECT_X_BUF), type := long, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectFloatBufferS, $(DIRECT_X_BUF), type := float, BO := S)) -$(eval $(call SetupGenBuffer,DirectFloatBufferRS, $(DIRECT_X_BUF), type := float, RW := R, BO := S)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferS, $(DIRECT_X_BUF), type := double, BO := S)) -$(eval $(call SetupGenBuffer,DirectDoubleBufferRS,$(DIRECT_X_BUF), type := double, RW := R, BO := S)) +# arg $1: READ_ONLY argument, true or false +# arg $2: Modifiability marker for class name (R or empty) +define SetupGenerateBuffersWithRO + ifeq ($1, false) + # The basic buffer classes are not generated in READ_ONLY versions + $$(eval $$(call SetupGenBuffer, ByteBuffer, \ + TYPE := byte, \ + TEMPLATE := X-Buffer, \ + GENERATE_BIN := true, \ + )) + TARGETS += $$(ByteBuffer) -# Big-endian views of byte buffers -# -BYTE_X_BUF := ByteBufferAs-X-Buffer + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, $$(call titlecase, $$t)Buffer, \ + TYPE := $$t, \ + TEMPLATE := X-Buffer, \ + )) \ + $$(eval TARGETS += $$($$(call titlecase, $$t)Buffer)) \ + ) + endif -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferB, $(BYTE_X_BUF), type := char, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRB, $(BYTE_X_BUF), type := char, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferB, $(BYTE_X_BUF), type := short, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRB, $(BYTE_X_BUF), type := short, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferB, $(BYTE_X_BUF), type := int, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRB, $(BYTE_X_BUF), type := int, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferB, $(BYTE_X_BUF), type := long, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRB, $(BYTE_X_BUF), type := long, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferB, $(BYTE_X_BUF), type := float, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRB, $(BYTE_X_BUF), type := float, RW := R, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferB, $(BYTE_X_BUF), type := double, BO := B)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRB,$(BYTE_X_BUF), type := double, RW := R, BO := B)) + # Buffers whose contents are heap-allocated, one for every type + $$(foreach t, $$(NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, Heap$$(call titlecase, $$t)Buffer$2, \ + TYPE := $$t, \ + TEMPLATE := Heap-X-Buffer, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(Heap$$(call titlecase, $$t)Buffer$2)) \ + ) -# Little-endian views of byte buffers -# -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferL, $(BYTE_X_BUF), type := char, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsCharBufferRL, $(BYTE_X_BUF), type := char, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferL, $(BYTE_X_BUF), type := short, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsShortBufferRL, $(BYTE_X_BUF), type := short, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferL, $(BYTE_X_BUF), type := int, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsIntBufferRL, $(BYTE_X_BUF), type := int, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferL, $(BYTE_X_BUF), type := long, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsLongBufferRL, $(BYTE_X_BUF), type := long, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferL, $(BYTE_X_BUF), type := float, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsFloatBufferRL, $(BYTE_X_BUF), type := float, RW := R, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferL, $(BYTE_X_BUF), type := double, BO := L)) -$(eval $(call SetupGenBuffer,ByteBufferAsDoubleBufferRL,$(BYTE_X_BUF), type := double, RW := R, BO := L)) + # Treat byte special for DirectByteBuffer classes + $$(eval $$(call SetupGenBuffer, DirectByteBuffer$2, \ + TEMPLATE := Direct-X-Buffer, \ + TYPE := byte, \ + GENERATE_BIN := true, \ + READ_ONLY := $1, \ + )) + TARGETS += $$(DirectByteBuffer$2) -### + # Generate Swapped and Unswapped views of the direct byte buffers, each for + # every non-byte type + $$(foreach b, U S, \ + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, Direct$$(call titlecase, $$t)Buffer$2$$b, \ + TYPE := $$t, \ + TEMPLATE := Direct-X-Buffer, \ + BYTE_ORDER := $$b, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(Direct$$(call titlecase, $$t)Buffer$2$$b)) \ + ) \ + ) -$(GENSRC_BUFFER): $(BUILD_TOOLS_JDK) + # Generate Big and Little endian views of the direct byte buffers, each for + # every non-byte type + $$(foreach b, B L, \ + $$(foreach t, $$(NON_BYTE_NUMBER_TYPES), \ + $$(eval $$(call SetupGenBuffer, ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b, \ + TYPE := $$t, \ + TEMPLATE := ByteBufferAs-X-Buffer, \ + BYTE_ORDER := $$b, \ + READ_ONLY := $1, \ + )) \ + $$(eval TARGETS += $$(ByteBufferAs$$(call titlecase, $$t)Buffer$2$$b)) \ + ) \ + ) +endef -TARGETS += $(GENSRC_BUFFER) +################################################################################ +# Generate buffers in both read-write and read-only variants for all buffers + +$(eval $(call SetupGenerateBuffersWithRO,false,)) +$(eval $(call SetupGenerateBuffersWithRO,true,R)) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk index 3e654d0b7a8..8cc5b92cb2b 100644 --- a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk +++ b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk @@ -28,91 +28,74 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_CHARSETCODER := - -GENSRC_CHARSETCODER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset - -GENSRC_CHARSETCODER_SRC := $(MODULE_SRC)/share/classes/java/nio - -GENSRC_CHARSETCODER_TEMPLATE := $(GENSRC_CHARSETCODER_SRC)/charset/Charset-X-Coder.java.template +CHARSETCODER_INPUT := $(MODULE_SRC)/share/classes/java/nio/charset/Charset-X-Coder.java.template +CHARSETCODER_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset ################################################################################ -$(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java: $(GENSRC_CHARSETCODER_TEMPLATE) - $(call MakeTargetDir) - $(RM) $@.tmp - $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_decoder, \ - $(TOOL_SPP) -i$< -o$@.tmp \ - -Kdecoder \ - -DA='A' \ - -Da='a' \ - -DCode='Decode' \ - -Dcode='decode' \ - -DitypesPhrase='bytes in a specific charset' \ - -DotypesPhrase='sixteen-bit Unicode characters' \ - -Ditype='byte' \ - -Dotype='character' \ - -DItype='Byte' \ - -DOtype='Char' \ - -Dcoder='decoder' \ - -DCoder='Decoder' \ - -Dcoding='decoding' \ - -DOtherCoder='Encoder' \ - -DreplTypeName='string' \ - -DdefaultRepl='"\\uFFFD"' \ - -DdefaultReplName='"\\uFFFD"<\/code>' \ - -DreplType='String' \ - -DreplFQType='java.lang.String' \ - -DreplLength='length()' \ - -DItypesPerOtype='CharsPerByte' \ - -DnotLegal='not legal for this charset' \ - -Dotypes-per-itype='chars-per-byte' \ - -DoutSequence='Unicode character') - $(MV) $@.tmp $@ +$(eval $(call SetupStreamPreProcessing, GEN_CHARSETDECODER, \ + SOURCE_FILE := $(CHARSETCODER_INPUT), \ + OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetDecoder.java, \ + INFO := Generating CharsetDecoder.java, \ + KEYS := decoder, \ + REPLACEMENTS := \ + A='A' \ + a='a' \ + Code='Decode' \ + code='decode' \ + itypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \ + otypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \ + itype='byte' \ + otype='character' \ + Itype='Byte' \ + Otype='Char' \ + coder='decoder' \ + Coder='Decoder' \ + coding='decoding' \ + OtherCoder='Encoder' \ + replTypeName='string' \ + replType='String' \ + replFQType='java.lang.String' \ + replLength='length()' \ + ItypesPerOtype='CharsPerByte' \ + notLegal='not$$(SPACE)legal$$(SPACE)for$$(SPACE)this$$(SPACE)charset' \ + otypes-per-itype='chars-per-byte' \ + outSequence='Unicode$$(SPACE)character', \ +)) -GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java +TARGETS += $(GEN_CHARSETDECODER) -################################################################################ +$(eval $(call SetupStreamPreProcessing, GEN_CHARSETENCODER, \ + SOURCE_FILE := $(CHARSETCODER_INPUT), \ + OUTPUT_FILE := $(CHARSETCODER_OUTPUT_DIR)/CharsetEncoder.java, \ + INFO := Generating CharsetEncoder.java, \ + KEYS := encoder, \ + REPLACEMENTS := \ + A='An' \ + a='an' \ + Code='Encode' \ + code='encode' \ + itypesPhrase='sixteen-bit$$(SPACE)Unicode$$(SPACE)characters' \ + otypesPhrase='bytes$$(SPACE)in$$(SPACE)a$$(SPACE)specific$$(SPACE)charset' \ + itype='character' \ + otype='byte' \ + Itype='Char' \ + Otype='Byte' \ + coder='encoder' \ + Coder='Encoder' \ + coding='encoding' \ + OtherCoder='Decoder' \ + replTypeName='byte$$(SPACE)array' \ + replType='byte[]' \ + replFQType='byte[]' \ + replLength='length' \ + ItypesPerOtype='BytesPerChar' \ + notLegal='not$$(SPACE)a$$(SPACE)legal$$(SPACE)sixteen-bit$$(SPACE)Unicode$$(SPACE)sequence' \ + otypes-per-itype='bytes-per-char' \ + outSequence='byte$$(SPACE)sequence$$(SPACE)in$$(SPACE)the$$(SPACE)given$$(SPACE)charset', \ +)) -$(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java: $(GENSRC_CHARSETCODER_TEMPLATE) - $(call MakeTargetDir) - $(RM) $@.tmp - $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_encoder, \ - $(TOOL_SPP) -i$< -o$@.tmp \ - -Kencoder \ - -DA='An' \ - -Da='an' \ - -DCode='Encode' \ - -Dcode='encode' \ - -DitypesPhrase='sixteen-bit Unicode characters' \ - -DotypesPhrase='bytes in a specific charset' \ - -Ditype='character' \ - -Dotype='byte' \ - -DItype='Char' \ - -DOtype='Byte' \ - -Dcoder='encoder' \ - -DCoder='Encoder' \ - -Dcoding='encoding' \ - -DOtherCoder='Decoder' \ - -DreplTypeName='byte array' \ - -DdefaultRepl='new byte[] { (byte)'"'"\\?"'"' }' \ - -DdefaultReplName='{<\/code>\ (byte)'"'"\\?"'"'<\/code>\ }<\/code>' \ - -DreplType='byte[]' \ - -DreplFQType='byte[]' \ - -DreplLength='length' \ - -DItypesPerOtype='BytesPerChar' \ - -DnotLegal='not a legal sixteen-bit Unicode sequence' \ - -Dotypes-per-itype='bytes-per-char' \ - -DoutSequence='byte sequence in the given charset') - $(MV) $@.tmp $@ - -GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java - -################################################################################ - -$(GENSRC_CHARSETCODER): $(BUILD_TOOLS_JDK) - -TARGETS += $(GENSRC_CHARSETCODER) +TARGETS += $(GEN_CHARSETENCODER) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index ea51e4fd4ee..5444de78c00 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -28,144 +28,77 @@ ifeq ($(INCLUDE), true) ################################################################################ -SCOPED_MEMORY_ACCESS_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc -SCOPED_MEMORY_ACCESS_SRC_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc -SCOPED_MEMORY_ACCESS_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess.java.template -SCOPED_MEMORY_ACCESS_BIN_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess-bin.java.template -SCOPED_MEMORY_ACCESS_DEST := $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)/ScopedMemoryAccess.java +SCOPED_INPUT_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc +SCOPED_INPUT := $(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess.java.template +SCOPED_OUTPUT := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc/ScopedMemoryAccess.java ################################################################################ -# Setup a rule for generating the ScopedMemoryAccess java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized -define GenerateScopedOp +# Helper method to setup generation of scoped snippets. +# Will add the generated snippet file name to SCOPED_SNIPPET_FILES. +# +# arg $1: type for this snippet +define SetupGenScopedSnippets + $1_SCOPED_SNIPPET_FILE := $$(SCOPED_OUTPUT).snippet.$1 - $1_Type := $2 - - ifeq ($$($1_Type), Boolean) - $1_type := boolean - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS + $1_KEYS := $1 CAS + ifneq ($$(filter byte, $1),) + $1_KEYS += byte + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter char short int long, $1),) + $1_KEYS += Unaligned + endif + ifneq ($$(filter boolean byte char short, $1),) + $1_KEYS += ShorterThanInt + endif + ifeq ($$(filter boolean, $1),) + $1_KEYS += AtomicAdd + endif + ifeq ($$(filter float double, $1),) + $1_KEYS += Bitwise endif - ifeq ($$($1_Type), Byte) - $1_type := byte - $1_BoxType := $$($1_Type) + $$(eval $$(call SetupStreamPreProcessing, GEN_SCOPED_SNIPPET_$1, \ + SOURCE_FILE := $$(SCOPED_INPUT_DIR)/X-ScopedMemoryAccess-bin.java.template, \ + OUTPUT_FILE := $$($1_SCOPED_SNIPPET_FILE), \ + INFO := Generating snippets for ScopedMemoryAccess ($1), \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(call Conv, $1, Type), \ + )) + TARGETS += $$(GEN_SCOPED_SNIPPET_$1) - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -Kbyte - endif - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KUnaligned - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), ) - $1_ARGS += -KAtomicAdd - endif - - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), ) - $1_ARGS += -KBitwise - endif - - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char), ) - $1_ARGS += -KShorterThanInt - endif + SCOPED_SNIPPET_FILES += $$($1_SCOPED_SNIPPET_FILE) endef ################################################################################ -# Setup a rule for generating the ScopedMemoryAccess java class +# Setup generation of snippet files, one for each primitive type. This will +# populate SCOPED_SNIPPET_FILES. -SCOPE_MEMORY_ACCESS_TYPES := Boolean Byte Short Char Int Long Float Double -$(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ - $(eval $(call GenerateScopedOp,BIN_$t,$t))) +# SCOPED_TYPES is identical to PRIMITIVE_TYPES, but with a slightly different +# order. Keep the original SCOPED_TYPES order for now to not change the +# generated file. +SCOPED_TYPES := boolean byte short char int long float double -$(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE) $(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) - $(call MakeDir, $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)) - $(CAT) $(SCOPED_MEMORY_ACCESS_TEMPLATE) > $(SCOPED_MEMORY_ACCESS_DEST) - $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ - $(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \ - -i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;) - $(ECHO) "}" >> $(SCOPED_MEMORY_ACCESS_DEST) +SCOPED_SNIPPET_FILES := +$(foreach t, $(SCOPED_TYPES), \ + $(eval $(call SetupGenScopedSnippets,$t)) \ +) -TARGETS += $(SCOPED_MEMORY_ACCESS_DEST) +# Setup a rule for generating the ScopedMemoryAccess java class by incorporating +# those snippets +$(SCOPED_OUTPUT): $(SCOPED_INPUT) $(SCOPED_SNIPPET_FILES) + $(call LogInfo, Concatenating snippets for ScopedMemoryAccess.java) + $(CAT) $(SCOPED_INPUT) > $(SCOPED_OUTPUT).tmp + $(CAT) $(SCOPED_SNIPPET_FILES) >> $(SCOPED_OUTPUT).tmp + $(ECHO) "}" >> $(SCOPED_OUTPUT).tmp + $(MV) $(SCOPED_OUTPUT).tmp $(SCOPED_OUTPUT) + +TARGETS += $(SCOPED_OUTPUT) ################################################################################ diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index ec1aec5c764..e536990c2b1 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -28,277 +28,132 @@ ifeq ($(INCLUDE), true) ################################################################################ -GENSRC_VARHANDLES := - -VARHANDLES_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke -VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke +VARHANDLES_INPUT_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke +VARHANDLES_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke ################################################################################ # Setup a rule for generating a VarHandle java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# +# arg $1: type for this varhandle define GenerateVarHandle + VARHANDLE_$1_type := $$(strip $$(if $$(filter reference, $1), Object, $1)) + VARHANDLE_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandle$$($1_Type)s.java - - $1_ARGS += -KCAS - - ifneq ($$(findstring $$($1_Type), Byte Short Char Int Long Float Double), ) - $1_ARGS += -KAtomicAdd + $1_KEYS := $$(VARHANDLE_$1_type) CAS + ifneq ($$(filter byte short char, $1),) + $1_KEYS += ShorterThanInt + endif + ifeq ($$(filter boolean reference, $1),) + $1_KEYS += AtomicAdd + endif + ifeq ($$(filter float double reference, $1),) + $1_KEYS += Bitwise endif - ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char Int Long), ) - $1_ARGS += -KBitwise - endif - - ifneq ($$(findstring $$($1_Type), Byte Short Char), ) - $1_ARGS += -KShorterThanInt - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandle.java.template $(BUILD_TOOLS_JDK) - ifeq ($$($1_Type), Reference) - $$(eval $1_type := Object) - else - $$(eval $1_type := $$$$(shell $(TR) '[:upper:]' '[:lower:]' <<< $$$$($1_Type))) - endif - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) -Dtype=$$($1_type) -DType=$$($1_Type) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandle.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandle$$(VARHANDLE_$1_Type)s.java, \ + INFO := Generating VarHandle class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$$(VARHANDLE_$1_type) \ + Type=$$(VARHANDLE_$1_Type), \ + )) + TARGETS += $$(GEN_VARHANDLE_$1) endef -################################################################################ - ################################################################################ # Setup a rule for generating a VarHandleByteArray java class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# +# arg $1: type for this varhandle define GenerateVarHandleByteArray + VARHANDLE_BYTEARRAY_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleByteArrayAs$$($1_Type)s.java - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) + $1_KEYS := $1 + ifneq ($$(filter int long float double, $1),) + $1_KEYS += CAS + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter int long, $1),) + $1_KEYS += AtomicAdd Bitwise endif - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleByteArrayView.java.template $(BUILD_TOOLS_JDK) - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) \ - -Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \ - -DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_BYTEARRAY_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleByteArrayView.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleByteArrayAs$$(VARHANDLE_BYTEARRAY_$1_Type)s.java, \ + INFO := Generating VarHandleByteArray class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(VARHANDLE_BYTEARRAY_$1_Type) \ + BoxType=$$(call Conv, $1, Fulltype) \ + rawType=$$(call Conv, $1, memtype) \ + RawType=$$(call Conv, $1, Memtype) \ + RawBoxType=$$(call Conv, $1, FullMemtype), \ + )) + TARGETS += $$(GEN_VARHANDLE_BYTEARRAY_$1) endef ################################################################################ - -################################################################################ -# Setup a rule for generating a memory segment var handle view class -# Param 1 - Variable declaration prefix -# Param 2 - Type with first letter capitalized +# Setup a rule for generating a VarHandleMemorySegment java class +# +# arg $1: type for this varhandle define GenerateVarHandleMemorySegment + VARHANDLE_SEGMENT_$1_Type := $$(call Conv, $1, Type) - $1_Type := $2 - $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java - - ifeq ($$($1_Type), Boolean) - $1_type := boolean - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -Kbyte - $1_ARGS += -KShorterThanInt + $1_KEYS := $1 + ifneq ($$(filter int long float double, $1),) + $1_KEYS += CAS + endif + ifneq ($$(filter boolean byte, $1),) + $1_KEYS += byte + endif + ifneq ($$(filter float double, $1),) + $1_KEYS += floatingPoint + endif + ifneq ($$(filter boolean byte short char, $1),) + $1_KEYS += ShorterThanInt + endif + ifneq ($$(filter int long, $1),) + $1_KEYS += AtomicAdd Bitwise endif - ifeq ($$($1_Type), Byte) - $1_type := byte - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -Kbyte - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Short) - $1_type := short - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Char) - $1_type := char - $1_BoxType := Character - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KShorterThanInt - endif - - ifeq ($$($1_Type), Int) - $1_type := int - $1_BoxType := Integer - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Long) - $1_type := long - $1_BoxType := $$($1_Type) - - $1_rawType := $$($1_type) - $1_RawType := $$($1_Type) - $1_RawBoxType := $$($1_BoxType) - - $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise - endif - - ifeq ($$($1_Type), Float) - $1_type := float - $1_BoxType := $$($1_Type) - - $1_rawType := int - $1_RawType := Int - $1_RawBoxType := Integer - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - ifeq ($$($1_Type), Double) - $1_type := double - $1_BoxType := $$($1_Type) - - $1_rawType := long - $1_RawType := Long - $1_RawBoxType := Long - - $1_ARGS += -KCAS - $1_ARGS += -KfloatingPoint - endif - - $$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleSegmentView.java.template $(BUILD_TOOLS_JDK) - $$(call MakeDir, $$(@D)) - $(RM) $$@ - $(TOOL_SPP) -nel -K$$($1_type) \ - -Dtype=$$($1_type) -DType=$$($1_Type) -DBoxType=$$($1_BoxType) \ - -DrawType=$$($1_rawType) -DRawType=$$($1_RawType) -DRawBoxType=$$($1_RawBoxType) \ - $$($1_ARGS) -i$$< -o$$@ - - GENSRC_VARHANDLES += $$($1_FILENAME) + $$(eval $$(call SetupStreamPreProcessing, GEN_VARHANDLE_SEGMENT_$1, \ + SOURCE_FILE := $$(VARHANDLES_INPUT_DIR)/X-VarHandleSegmentView.java.template, \ + OUTPUT_FILE := $$(VARHANDLES_OUTPUT_DIR)/VarHandleSegmentAs$$(VARHANDLE_SEGMENT_$1_Type)s.java, \ + INFO := Generating VarHandleSegment class for $1, \ + SUBST_EMPTY_LINES := false, \ + KEYS := $$($1_KEYS), \ + REPLACEMENTS := \ + type=$1 \ + Type=$$(VARHANDLE_SEGMENT_$1_Type) \ + BoxType=$$(call Conv, $1, Fulltype) \ + rawType=$$(call Conv, $1, memtype) \ + RawType=$$(call Conv, $1, Memtype) \ + RawBoxType=$$(call Conv, $1, FullMemtype), \ + )) + TARGETS += $$(GEN_VARHANDLE_SEGMENT_$1) endef ################################################################################ +# Generate all VarHandle related classes -# List the types to generate source for, with capitalized first letter -VARHANDLES_TYPES := Boolean Byte Short Char Int Long Float Double Reference -$(foreach t, $(VARHANDLES_TYPES), \ - $(eval $(call GenerateVarHandle,VAR_HANDLE_$t,$t))) +$(foreach t, $(PRIMITIVE_TYPES) reference, \ + $(eval $(call GenerateVarHandle,$t)) \ +) -# List the types to generate source for, with capitalized first letter -VARHANDLES_BYTE_ARRAY_TYPES := Short Char Int Long Float Double -$(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \ - $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t))) +$(foreach t, $(NON_BYTE_NUMBER_TYPES), \ + $(eval $(call GenerateVarHandleByteArray,$t)) \ +) -# List the types to generate source for, with capitalized first letter -VARHANDLES_MEMORY_SEGMENT_TYPES := Boolean Byte Short Char Int Long Float Double -$(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \ - $(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t))) - -TARGETS += $(GENSRC_VARHANDLES) +$(foreach t, $(PRIMITIVE_TYPES), \ + $(eval $(call GenerateVarHandleMemorySegment,$t)) \ +) ################################################################################ diff --git a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template index ca610d476f2..8f0fcc08952 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template +++ b/src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template @@ -97,10 +97,10 @@ import jdk.internal.util.ArraysSupport; * #if[encoder] * is initially set to the $coder$'s default replacement, which often - * (but not always) has the initial value $defaultReplName$; + * (but not always) has the initial value { (byte)'?' }; #end[encoder] #if[decoder] - * has the initial value $defaultReplName$; + * has the initial value "\uFFFD"; #end[decoder] * * its value may be changed via the {@link #replaceWith($replFQType$) @@ -212,7 +212,12 @@ public abstract class Charset$Coder$ { /** * Initializes a new $coder$. The new $coder$ will have the given * $otypes-per-itype$ values and its replacement will be the - * $replTypeName$ $defaultReplName$. +#if[encoder] + * byte array { (byte)'?' }. +#end[encoder] +#if[decoder] + * string "\uFFFD". +#end[decoder] * * @param cs * The charset that created this $coder$ @@ -234,7 +239,12 @@ public abstract class Charset$Coder$ { { this(cs, average$ItypesPerOtype$, max$ItypesPerOtype$, - $defaultRepl$); +#if[encoder] + new byte[] { (byte)'?' }); +#end[encoder] +#if[decoder] + "\uFFFD"); +#end[decoder] } /** diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 61fcbdf522f..d609e8d0227 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -113,6 +113,63 @@ ifneq ($(call equals, $(EQUALS_VALUE2), $(EQUALS_EMPTY)), ) $(error The strings >$(EQUALS_VALUE2)< and >$(EQUALS_EMPTY)< are equal) endif +################################################################################ +# Test string manipulation + +$(call AssertEquals, \ + $(call uppercase, foo bar), \ + FOO BAR, \ + uppercase "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call uppercase, Foo BaR 123), \ + FOO BAR 123, \ + uppercase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call lowercase, FOO BAR), \ + foo bar, \ + lowercase "FOO BAR" failed, \ +) + +$(call AssertEquals, \ + $(call lowercase, Foo BaR 123), \ + foo bar 123, \ + lowercase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, foo bar), \ + Foo Bar, \ + titlecase "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, FOO BAR), \ + Foo Bar, \ + titlecase "FOO BAR" failed, \ +) + +$(call AssertEquals, \ + $(call titlecase, Foo BaR 123), \ + Foo Bar 123, \ + titlecase "Foo BaR 123" failed, \ +) + +$(call AssertEquals, \ + $(call firstchar, foo bar), \ + f, \ + firstchar "foo bar" failed, \ +) + +$(call AssertEquals, \ + $(call firstchar, Foo Bar), \ + F, \ + firstchar "Foo Bar" failed, \ +) + ################################################################################ # Test boolean operators From cb58e6560a3b80655224cb79d52bfd0afa3cf262 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 8 Sep 2025 16:48:35 +0000 Subject: [PATCH 412/471] 8330341: Wrap call to MT in ExecuteWithLog Reviewed-by: erikj --- make/common/native/LinkMicrosoft.gmk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/make/common/native/LinkMicrosoft.gmk b/make/common/native/LinkMicrosoft.gmk index a53afba4001..0d4212f2a4a 100644 --- a/make/common/native/LinkMicrosoft.gmk +++ b/make/common/native/LinkMicrosoft.gmk @@ -113,9 +113,10 @@ define CreateDynamicLibraryOrExecutableMicrosoft $$(CHMOD) +x $$($1_TARGET) endif ifneq ($$($1_MANIFEST), ) - $$($1_MT) -nologo -manifest $$($1_MANIFEST) \ - -identity:"$$($1_NAME).exe, version=$$($1_MANIFEST_VERSION)" \ - -outputresource:$$@;#1 + $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_mt, \ + $$($1_MT) -nologo -manifest $$($1_MANIFEST) \ + -identity:"$$($1_NAME).exe$$(COMMA) version=$$($1_MANIFEST_VERSION)" \ + '-outputresource:$$($1_TARGET);$$(HASH)1') endif ifneq ($(SIGNING_HOOK), ) $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_call_signing_hook, \ From 85441cec3558f76ffa2a785c959397333503d556 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Sep 2025 18:30:18 +0000 Subject: [PATCH 413/471] 8367101: Remove unused includes in cardTable.cpp Reviewed-by: stefank --- src/hotspot/share/gc/shared/cardTable.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index 76fe73abaf6..76b8eb4d718 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -34,9 +34,6 @@ #include "runtime/java.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" -#if INCLUDE_PARALLELGC -#include "gc/parallel/objectStartArray.hpp" -#endif uint CardTable::_card_shift = 0; uint CardTable::_card_size = 0; From 3e68d7d99fcf3039395ba94234ecbebe8e98c754 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Sep 2025 19:13:55 +0000 Subject: [PATCH 414/471] 8366881: Parallel: Obsolete HeapMaximumCompactionInterval Reviewed-by: iwalulya --- .../gc/parallel/parallelScavengeHeap.cpp | 23 ++++------- .../share/gc/parallel/parallel_globals.hpp | 5 --- .../share/gc/parallel/psParallelCompact.cpp | 38 +++++++------------ .../share/gc/parallel/psParallelCompact.hpp | 10 +++-- src/hotspot/share/runtime/arguments.cpp | 1 + 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 9b40475288d..c185b8c4437 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -334,7 +334,9 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, bool is_tlab) { } void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { - PSParallelCompact::invoke(clear_all_soft_refs); + // No need for max-compaction in this context. + const bool should_do_max_compaction = false; + PSParallelCompact::invoke(clear_all_soft_refs, should_do_max_compaction); } static bool check_gc_heap_free_limit(size_t free_bytes, size_t capacity_bytes) { @@ -394,21 +396,11 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t } } - // If we reach this point, we're really out of memory. Try every trick - // we can to reclaim memory. Force collection of soft references. Force - // a complete compaction of the heap. Any additional methods for finding - // free memory should be here, especially if they are expensive. If this - // attempt fails, an OOM exception will be thrown. + // Last resort GC; clear soft refs and do max-compaction before throwing OOM. { - // Make sure the heap is fully compacted - uintx old_interval = HeapMaximumCompactionInterval; - HeapMaximumCompactionInterval = 0; - const bool clear_all_soft_refs = true; - PSParallelCompact::invoke(clear_all_soft_refs); - - // Restore - HeapMaximumCompactionInterval = old_interval; + const bool should_do_max_compaction = true; + PSParallelCompact::invoke(clear_all_soft_refs, should_do_max_compaction); } if (check_gc_overhead_limit()) { @@ -493,7 +485,8 @@ void ParallelScavengeHeap::collect_at_safepoint(bool full) { } // Upgrade to Full-GC if young-gc fails } - PSParallelCompact::invoke(clear_soft_refs); + const bool should_do_max_compaction = false; + PSParallelCompact::invoke(clear_soft_refs, should_do_max_compaction); } void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { diff --git a/src/hotspot/share/gc/parallel/parallel_globals.hpp b/src/hotspot/share/gc/parallel/parallel_globals.hpp index 83b378d5bbe..84d884f128c 100644 --- a/src/hotspot/share/gc/parallel/parallel_globals.hpp +++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp @@ -31,11 +31,6 @@ product_pd, \ range, \ constraint) \ - product(uintx, HeapMaximumCompactionInterval, 20, \ - "How often should we maximally compact the heap (not allowing " \ - "any dead space)") \ - range(0, max_uintx) \ - \ product(bool, UseMaximumCompactionOnSystemGC, true, \ "Use maximum compaction in the Parallel Old garbage collector " \ "for a system GC") \ diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 5a0dbe3d4e6..bac536234b6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -826,7 +826,8 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { } } -bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, +bool PSParallelCompact::check_maximum_compaction(bool should_do_max_compaction, + size_t total_live_words, MutableSpace* const old_space, HeapWord* full_region_prefix_end) { @@ -839,25 +840,17 @@ bool PSParallelCompact::check_maximum_compaction(size_t total_live_words, // Check if all live objs are too much for old-gen. const bool is_old_gen_too_full = (total_live_words >= old_space->capacity_in_words()); - // JVM flags - const uint total_invocations = heap->total_full_collections(); - assert(total_invocations >= _maximum_compaction_gc_num, "sanity"); - const size_t gcs_since_max = total_invocations - _maximum_compaction_gc_num; - const bool is_interval_ended = gcs_since_max > HeapMaximumCompactionInterval; - // If all regions in old-gen are full const bool is_region_full = full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); - if (is_max_on_system_gc || is_old_gen_too_full || is_interval_ended || is_region_full) { - _maximum_compaction_gc_num = total_invocations; - return true; - } - - return false; + return should_do_max_compaction + || is_max_on_system_gc + || is_old_gen_too_full + || is_region_full; } -void PSParallelCompact::summary_phase() +void PSParallelCompact::summary_phase(bool should_do_max_compaction) { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); @@ -880,9 +873,10 @@ void PSParallelCompact::summary_phase() _space_info[i].set_dense_prefix(space->bottom()); } - bool maximum_compaction = check_maximum_compaction(total_live_words, - old_space, - full_region_prefix_end); + should_do_max_compaction = check_maximum_compaction(should_do_max_compaction, + total_live_words, + old_space, + full_region_prefix_end); { GCTraceTime(Info, gc, phases) tm("Summary Phase: expand", &_gc_timer); // Try to expand old-gen in order to fit all live objs and waste. @@ -891,7 +885,7 @@ void PSParallelCompact::summary_phase() ParallelScavengeHeap::heap()->old_gen()->try_expand_till_size(target_capacity_bytes); } - HeapWord* dense_prefix_end = maximum_compaction + HeapWord* dense_prefix_end = should_do_max_compaction ? full_region_prefix_end : compute_dense_prefix_for_old_space(old_space, full_region_prefix_end); @@ -961,11 +955,7 @@ void PSParallelCompact::summary_phase() } } -// This method invokes a full collection. The argument controls whether -// soft-refs should be cleared or not. -// Note that this method should only be called from the vm_thread while at a -// safepoint. -bool PSParallelCompact::invoke(bool clear_all_soft_refs) { +bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_compaction) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); @@ -1020,7 +1010,7 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs) { marking_phase(&_gc_tracer); - summary_phase(); + summary_phase(should_do_max_compaction); #if COMPILER2_OR_JVMCI assert(DerivedPointerTable::is_active(), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 874c72d5671..a28df24830c 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -727,7 +727,8 @@ private: static void pre_compact(); static void post_compact(); - static bool check_maximum_compaction(size_t total_live_words, + static bool check_maximum_compaction(bool should_do_max_compaction, + size_t total_live_words, MutableSpace* const old_space, HeapWord* full_region_prefix_end); @@ -742,7 +743,7 @@ private: // make the heap parsable. static void fill_dense_prefix_end(SpaceId id); - static void summary_phase(); + static void summary_phase(bool should_do_max_compaction); static void adjust_pointers(); static void forward_to_new_addr(); @@ -761,7 +762,10 @@ private: public: static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); - static bool invoke(bool clear_all_soft_refs); + // This method invokes a full collection. + // clear_all_soft_refs controls whether soft-refs should be cleared or not. + // should_do_max_compaction controls whether all spaces for dead objs should be reclaimed. + static bool invoke(bool clear_all_soft_refs, bool should_do_max_compaction); template static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 21706eb7726..6cfeb1dcb0f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -568,6 +568,7 @@ static SpecialFlag const special_jvm_flags[] = { { "UsePSAdaptiveSurvivorSizePolicy", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, { "PretenureSizeThreshold", JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, + { "HeapMaximumCompactionInterval",JDK_Version::undefined(), JDK_Version::jdk(26), JDK_Version::jdk(27) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, From 56e37352d5b0a749ccd150c36c9248e37d280eb6 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 8 Sep 2025 20:52:31 +0000 Subject: [PATCH 415/471] 8367130: JDK builds broken by 8366837: Clean up gensrc by spp.Spp Reviewed-by: liach --- make/modules/java.base/gensrc/GensrcVarHandles.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index e536990c2b1..341a8c9dc2c 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -157,7 +157,7 @@ $(foreach t, $(PRIMITIVE_TYPES), \ ################################################################################ -GENSRC_VARHANDLEGUARDS := $(VARHANDLES_GENSRC_DIR)/VarHandleGuards.java +GENSRC_VARHANDLEGUARDS := $(VARHANDLES_OUTPUT_DIR)/VarHandleGuards.java $(GENSRC_VARHANDLEGUARDS): $(BUILD_TOOLS_JDK) $(call LogInfo, Generating $@) From 81a1e8e1363446de499a59fc706221efde12dd86 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Mon, 8 Sep 2025 21:44:18 +0000 Subject: [PATCH 416/471] 8364936: Shenandoah: Switch nmethod entry barriers to conc_instruction_and_data_patch Reviewed-by: fyang, dzhang, kdnilsen, wkemper --- .../cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp | 8 +------- .../cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp | 3 +-- .../cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp | 2 -- .../shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp | 2 +- src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp | 3 +-- .../gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp | 2 +- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp | 4 ---- .../cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp | 3 +-- .../cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp | 2 -- .../gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp | 2 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 - .../src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java | 5 ++--- 12 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 869e26d3359..302701e1cad 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -331,13 +331,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo __ ldr(rscratch2, thread_disarmed_and_epoch_addr); __ cmp(rscratch1, rscratch2); } else { - assert(patching_type == NMethodPatchingType::conc_data_patch, "must be"); - // Subsequent loads of oops must occur after load of guard value. - // BarrierSetNMethod::disarm sets guard with release semantics. - __ membar(__ LoadLoad); - Address thread_disarmed_addr(rthread, in_bytes(bs_nm->thread_disarmed_guard_value_offset())); - __ ldrw(rscratch2, thread_disarmed_addr); - __ cmpw(rscratch1, rscratch2); + ShouldNotReachHere(); } __ br(condition, barrier_target); diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 0d6bfc98a72..fa093a6ef69 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -39,8 +39,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index c45611c882b..88c90a548d1 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -58,8 +58,6 @@ static int entry_barrier_offset(nmethod* nm) { return -4 * (4 + slow_path_size(nm)); case NMethodPatchingType::conc_instruction_and_data_patch: return -4 * (10 + slow_path_size(nm)); - case NMethodPatchingType::conc_data_patch: - return -4 * (5 + slow_path_size(nm)); } ShouldNotReachHere(); return 0; diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp index a12d4e2beec..c89847b9d52 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -67,7 +67,7 @@ private: Register scratch, RegSet saved_regs); public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp index f48b1bc5f66..390623f48a1 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp @@ -40,8 +40,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp index 6ee70b4b4ea..b058dcf1a2e 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp @@ -69,7 +69,7 @@ private: Register preserve); public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } /* ==== C1 stubs ==== */ #ifdef COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 7e9bea381a5..387db778c1f 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -241,10 +241,6 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo __ lwu(t0, *guard); switch (patching_type) { - case NMethodPatchingType::conc_data_patch: - // Subsequent loads of oops must occur after load of guard value. - // BarrierSetNMethod::disarm sets guard with release semantics. - __ membar(MacroAssembler::LoadLoad); // fall through to stw_instruction_and_data_patch case NMethodPatchingType::stw_instruction_and_data_patch: { // With STW patching, no data or instructions are updated concurrently, diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp index 7061dca738c..63a7032bb84 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -40,8 +40,7 @@ class Node; enum class NMethodPatchingType { stw_instruction_and_data_patch, - conc_instruction_and_data_patch, - conc_data_patch + conc_instruction_and_data_patch }; class BarrierSetAssembler: public CHeapObj { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index f24e4f789bc..ac619f83f7d 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -50,8 +50,6 @@ static int entry_barrier_offset(nmethod* nm) { switch (bs_asm->nmethod_patching_type()) { case NMethodPatchingType::stw_instruction_and_data_patch: return -4 * (4 + slow_path_size(nm)); - case NMethodPatchingType::conc_data_patch: - return -4 * (5 + slow_path_size(nm)); case NMethodPatchingType::conc_instruction_and_data_patch: return -4 * (15 + slow_path_size(nm)); } diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp index 7d12cc8cbb6..3fe7c8d1740 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp @@ -69,7 +69,7 @@ private: public: - virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_data_patch; } + virtual NMethodPatchingType nmethod_patching_type() { return NMethodPatchingType::conc_instruction_and_data_patch; } #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 47ebe5aa7a7..3ddf7de0510 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -828,7 +828,6 @@ \ AARCH64_ONLY(declare_constant(NMethodPatchingType::stw_instruction_and_data_patch)) \ AARCH64_ONLY(declare_constant(NMethodPatchingType::conc_instruction_and_data_patch)) \ - AARCH64_ONLY(declare_constant(NMethodPatchingType::conc_data_patch)) \ \ declare_constant(ObjectMonitor::NO_OWNER) \ declare_constant(ObjectMonitor::ANONYMOUS_OWNER) \ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index 79a0aa60892..a26872b96ae 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -67,11 +67,10 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { // There currently only 2 variants in use that differ only by the presence of a // dmb instruction int stw = getConstant("NMethodPatchingType::stw_instruction_and_data_patch", Integer.class); - int conc1 = getConstant("NMethodPatchingType::conc_data_patch", Integer.class); - int conc2 = getConstant("NMethodPatchingType::conc_instruction_and_data_patch", Integer.class); + int conc = getConstant("NMethodPatchingType::conc_instruction_and_data_patch", Integer.class); if (patchingType == stw) { patchConcurrent = false; - } else if (patchingType == conc1 || patchingType == conc2) { + } else if (patchingType == conc) { patchConcurrent = true; } else { throw new IllegalArgumentException("unsupported barrier sequence " + patchingType); From 4ec63e8f5d1768ea78d0bbf477d68bcf3c6f96b6 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 9 Sep 2025 00:05:56 +0000 Subject: [PATCH 417/471] 8366850: Test com/sun/jdi/JdbStopInNotificationThreadTest.java failed Reviewed-by: ayang, lmesnik, syan --- test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java index 761c84d2c4c..7490d26fe6f 100644 --- a/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java +++ b/test/jdk/com/sun/jdi/JdbStopInNotificationThreadTest.java @@ -113,7 +113,7 @@ public class JdbStopInNotificationThreadTest extends JdbTest { private static final String DEBUGGEE_CLASS = JdbStopInNotificationThreadTestTarg.class.getName(); private static final String PATTERN1_TEMPLATE = "^Breakpoint hit: \"thread=Notification Thread\", " + "JdbStopInNotificationThreadTestTarg\\$1\\.handleNotification\\(\\), line=%LINE_NUMBER.*\\R%LINE_NUMBER\\s+System\\.out\\.println\\(\"Memory usage low!!!\"\\);.*"; - private static final String[] DEBUGGEE_OPTIONS = {"-Xmx64M"}; + private static final String[] DEBUGGEE_OPTIONS = {"-Xmx256M"}; private JdbStopInNotificationThreadTest() { super(new LaunchOptions(DEBUGGEE_CLASS) From 0aee7bf24d7f2578d3867bcfa25646cb0bd06d9a Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 9 Sep 2025 00:38:15 +0000 Subject: [PATCH 418/471] 8367048: RISC-V: Correct pipeline descriptions of the architecture Reviewed-by: fyang, fjiang, mli --- src/hotspot/cpu/riscv/riscv.ad | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index e02d781972b..eab19e74f93 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -3833,13 +3833,18 @@ opclass immIorL(immI, immL); pipeline %{ attributes %{ - // RISC-V instructions are of fixed length - fixed_size_instructions; // Fixed size instructions TODO does - max_instructions_per_bundle = 2; // Generic RISC-V 1, Sifive Series 7 2 - // RISC-V instructions come in 32-bit word units - instruction_unit_size = 4; // An instruction is 4 bytes long - instruction_fetch_unit_size = 64; // The processor fetches one line - instruction_fetch_units = 1; // of 64 bytes + // RISC-V instructions are of length 2 or 4 bytes. + variable_size_instructions; + instruction_unit_size = 2; + + // Up to 4 instructions per bundle + max_instructions_per_bundle = 4; + + // The RISC-V processor fetches 64 bytes... + instruction_fetch_unit_size = 64; + + // ...in one line. + instruction_fetch_units = 1; // List of nop instructions nops( MachNop ); From 680bf758980452511ea72224066358e5fd38f060 Mon Sep 17 00:00:00 2001 From: erifan Date: Tue, 9 Sep 2025 06:58:00 +0000 Subject: [PATCH 419/471] 8365911: AArch64: Fix encoding error in sve_cpy for negative floats Reviewed-by: aph, epeter --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 10 +- test/hotspot/gtest/aarch64/aarch64-asmtest.py | 2 + test/hotspot/gtest/aarch64/asmtest.out.h | 251 +++++++++--------- 3 files changed, 136 insertions(+), 127 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 4b0a0e77915..a5d2cbfac98 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -3814,7 +3814,11 @@ private: starti; assert(T != Q, "invalid size"); int sh = 0; - if (imm8 <= 127 && imm8 >= -128) { + if (isFloat) { + assert(T != B, "invalid size"); + assert((imm8 >> 8) == 0, "invalid immediate"); + sh = 0; + } else if (imm8 <= 127 && imm8 >= -128) { sh = 0; } else if (T != B && imm8 <= 32512 && imm8 >= -32768 && (imm8 & 0xff) == 0) { sh = 1; @@ -3824,7 +3828,7 @@ private: } int m = isMerge ? 1 : 0; f(0b00000101, 31, 24), f(T, 23, 22), f(0b01, 21, 20); - prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), sf(imm8, 12, 5), rf(Zd, 0); + prf(Pg, 16), f(isFloat ? 1 : 0, 15), f(m, 14), f(sh, 13), f(imm8 & 0xff, 12, 5), rf(Zd, 0); } public: @@ -3834,7 +3838,7 @@ public: } // SVE copy floating-point immediate to vector elements (predicated) void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, double d) { - sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); + sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); } // SVE conditionally select elements from two vectors diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 62274e2c10f..e1abddf3e1c 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -1958,6 +1958,8 @@ generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);", ["cpy", "__ sve_cpy(z5, __ D, p0, -32768, false);", "mov\tz5.d, p0/z, -32768"], ["cpy", "__ sve_cpy(z10, __ B, p0, -1, false);", "mov\tz10.b, p0/z, -1"], ["cpy", "__ sve_cpy(z11, __ S, p0, -1, false);", "mov\tz11.s, p0/z, -1"], + ["fcpy", "__ sve_cpy(z11, __ S, p0, 0.5);", "fcpy\tz11.s, p0/m, #0.5"], + ["fcpy", "__ sve_cpy(z11, __ S, p0, -1.0);", "fcpy\tz11.s, p0/m, #-1.0"], ["inc", "__ sve_inc(r0, __ S);", "incw\tx0"], ["dec", "__ sve_dec(r1, __ H);", "dech\tx1"], ["lsl", "__ sve_lsl(z0, __ B, z1, 7);", "lsl\tz0.b, z1.b, #7"], diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index f08c69a27dd..7a3225eaed4 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -971,6 +971,8 @@ __ sve_cpy(z5, __ D, p0, -32768, false); // mov z5.d, p0/z, -32768 __ sve_cpy(z10, __ B, p0, -1, false); // mov z10.b, p0/z, -1 __ sve_cpy(z11, __ S, p0, -1, false); // mov z11.s, p0/z, -1 + __ sve_cpy(z11, __ S, p0, 0.5); // fcpy z11.s, p0/m, #0.5 + __ sve_cpy(z11, __ S, p0, -1.0); // fcpy z11.s, p0/m, #-1.0 __ sve_inc(r0, __ S); // incw x0 __ sve_dec(r1, __ H); // dech x1 __ sve_lsl(z0, __ B, z1, 7); // lsl z0.b, z1.b, #7 @@ -1442,30 +1444,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x140004b4, 0x94000000, - 0x97ffffd4, 0x940004b1, 0x3400000a, 0x34fffa2a, - 0x340095ca, 0x35000008, 0x35fff9c8, 0x35009568, - 0xb400000b, 0xb4fff96b, 0xb400950b, 0xb500001d, - 0xb5fff91d, 0xb50094bd, 0x10000013, 0x10fff8b3, - 0x10009453, 0x90000013, 0x36300016, 0x3637f836, - 0x363093d6, 0x3758000c, 0x375ff7cc, 0x3758936c, + 0x14000000, 0x17ffffd7, 0x140004b6, 0x94000000, + 0x97ffffd4, 0x940004b3, 0x3400000a, 0x34fffa2a, + 0x3400960a, 0x35000008, 0x35fff9c8, 0x350095a8, + 0xb400000b, 0xb4fff96b, 0xb400954b, 0xb500001d, + 0xb5fff91d, 0xb50094fd, 0x10000013, 0x10fff8b3, + 0x10009493, 0x90000013, 0x36300016, 0x3637f836, + 0x36309416, 0x3758000c, 0x375ff7cc, 0x375893ac, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54009140, 0x54000001, 0x54fff541, 0x540090e1, - 0x54000002, 0x54fff4e2, 0x54009082, 0x54000002, - 0x54fff482, 0x54009022, 0x54000003, 0x54fff423, - 0x54008fc3, 0x54000003, 0x54fff3c3, 0x54008f63, - 0x54000004, 0x54fff364, 0x54008f04, 0x54000005, - 0x54fff305, 0x54008ea5, 0x54000006, 0x54fff2a6, - 0x54008e46, 0x54000007, 0x54fff247, 0x54008de7, - 0x54000008, 0x54fff1e8, 0x54008d88, 0x54000009, - 0x54fff189, 0x54008d29, 0x5400000a, 0x54fff12a, - 0x54008cca, 0x5400000b, 0x54fff0cb, 0x54008c6b, - 0x5400000c, 0x54fff06c, 0x54008c0c, 0x5400000d, - 0x54fff00d, 0x54008bad, 0x5400000e, 0x54ffefae, - 0x54008b4e, 0x5400000f, 0x54ffef4f, 0x54008aef, + 0x54009180, 0x54000001, 0x54fff541, 0x54009121, + 0x54000002, 0x54fff4e2, 0x540090c2, 0x54000002, + 0x54fff482, 0x54009062, 0x54000003, 0x54fff423, + 0x54009003, 0x54000003, 0x54fff3c3, 0x54008fa3, + 0x54000004, 0x54fff364, 0x54008f44, 0x54000005, + 0x54fff305, 0x54008ee5, 0x54000006, 0x54fff2a6, + 0x54008e86, 0x54000007, 0x54fff247, 0x54008e27, + 0x54000008, 0x54fff1e8, 0x54008dc8, 0x54000009, + 0x54fff189, 0x54008d69, 0x5400000a, 0x54fff12a, + 0x54008d0a, 0x5400000b, 0x54fff0cb, 0x54008cab, + 0x5400000c, 0x54fff06c, 0x54008c4c, 0x5400000d, + 0x54fff00d, 0x54008bed, 0x5400000e, 0x54ffefae, + 0x54008b8e, 0x5400000f, 0x54ffef4f, 0x54008b2f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1640,109 +1642,110 @@ 0x4e21c862, 0x0e79c862, 0x4e79c862, 0x4e61b8a4, 0x0e79b8a4, 0x4e79b8a4, 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, 0x05d03005, 0x05101fea, - 0x05901feb, 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, - 0x043f9c35, 0x047f9c20, 0x04ff9c20, 0x04299420, - 0x04319160, 0x0461943e, 0x04a19020, 0x04038100, - 0x040381a0, 0x040387e1, 0x04438be2, 0x04c38fe3, - 0x040181e0, 0x04018100, 0x04018621, 0x04418b22, - 0x04418822, 0x04818c23, 0x040081e0, 0x04008120, - 0x04008761, 0x04008621, 0x04408822, 0x04808c23, - 0x042053ff, 0x047f5401, 0x25208028, 0x2538cfe0, - 0x2578d001, 0x25b8efe2, 0x25f8f007, 0x2538dfea, - 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, 0xa4484be0, - 0xa467afe0, 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, - 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, 0xe408ffff, - 0xe420e7e0, 0xe4484be0, 0xe460efe0, 0xe547e400, - 0xe4014be0, 0xe4a84fe0, 0xe5f15000, 0x858043e0, - 0x85a043ff, 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, - 0x04a0e3eb, 0x04e0e3ec, 0x25104042, 0x25104871, - 0x25904861, 0x25904c92, 0x05344020, 0x05744041, - 0x05b44062, 0x05f44083, 0x252c8840, 0x253c1420, - 0x25681572, 0x25a21ce3, 0x25ea1e34, 0x253c0421, - 0x25680572, 0x25a20ce3, 0x25ea0e34, 0x0522c020, - 0x05e6c0a4, 0x2401a001, 0x2443a051, 0x24858881, - 0x24c78cd1, 0x24850891, 0x24c70cc1, 0x250f9001, - 0x25508051, 0x25802491, 0x25df28c1, 0x25850c81, - 0x251e10d1, 0x65816001, 0x65c36051, 0x65854891, - 0x65c74cc1, 0x05733820, 0x05b238a4, 0x05f138e6, - 0x0570396a, 0x65d0a001, 0x65d6a443, 0x65d4a826, - 0x6594ac26, 0x6554ac26, 0x6556ac26, 0x6552ac26, - 0x65cbac85, 0x65caac01, 0x6589ac85, 0x6588ac01, - 0x65c9ac85, 0x65c8ac01, 0x65dea833, 0x659ca509, - 0x65d8a801, 0x65dcac01, 0x655cb241, 0x0520a1e0, - 0x0521a601, 0x052281e0, 0x05238601, 0x04a14026, - 0x042244a6, 0x046344a6, 0x04a444a6, 0x04e544a7, - 0x0568aca7, 0x05b23230, 0x05302a30, 0x05702a30, - 0x05b02a30, 0x05f02a30, 0x853040af, 0xc5b040af, - 0xe57080af, 0xe5b080af, 0x25034440, 0x254054c4, - 0x25034640, 0x25415a05, 0x25834440, 0x25c54489, - 0x250b5d3a, 0x2550dc20, 0x2518e3e1, 0x2518e021, - 0x2518e0a1, 0x2518e121, 0x2518e1a1, 0x2558e3e2, - 0x2558e042, 0x2558e0c2, 0x2558e142, 0x2598e3e3, - 0x2598e063, 0x2598e0e3, 0x2598e163, 0x25d8e3e4, - 0x25d8e084, 0x25d8e104, 0x25d8e184, 0x2518e407, - 0x05214800, 0x05614800, 0x05a14800, 0x05e14800, - 0x05214c00, 0x05614c00, 0x05a14c00, 0x05e14c00, - 0x05304001, 0x05314001, 0x05a18610, 0x05e18610, - 0x05271e11, 0x6545e891, 0x6585e891, 0x65c5e891, - 0x6545c891, 0x6585c891, 0x65c5c891, 0x45b0c210, - 0x45f1c231, 0x1e601000, 0x1e603000, 0x1e621000, - 0x1e623000, 0x1e641000, 0x1e643000, 0x1e661000, - 0x1e663000, 0x1e681000, 0x1e683000, 0x1e6a1000, - 0x1e6a3000, 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, - 0x1e6e3000, 0x1e701000, 0x1e703000, 0x1e721000, - 0x1e723000, 0x1e741000, 0x1e743000, 0x1e761000, - 0x1e763000, 0x1e781000, 0x1e783000, 0x1e7a1000, - 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, - 0x1e7e3000, 0xf8268267, 0xf82d023c, 0xf8301046, - 0xf83d2083, 0xf8263290, 0xf82d528c, 0xf8284299, - 0xf8337160, 0xf8386286, 0xf8bf820e, 0xf8a600e0, - 0xf8af1353, 0xf8a922ea, 0xf8b53396, 0xf8a251e3, - 0xf8b340f4, 0xf8a470fd, 0xf8a06209, 0xf8f48097, - 0xf8f002ea, 0xf8eb10d9, 0xf8ff21b0, 0xf8f7302c, - 0xf8ee52a9, 0xf8f041fa, 0xf8e471e4, 0xf8e863c6, - 0xf864823d, 0xf87d013a, 0xf86f1162, 0xf87d20e3, - 0xf86132bb, 0xf870510e, 0xf8704336, 0xf86572b4, - 0xf8706217, 0xb83e8294, 0xb8200264, 0xb8381284, - 0xb8242358, 0xb8333102, 0xb828530e, 0xb83042df, - 0xb824703f, 0xb82a6194, 0xb8a080e9, 0xb8b80090, - 0xb8bb1146, 0xb8bb21b8, 0xb8b032df, 0xb8b653f4, - 0xb8bd41c9, 0xb8b47287, 0xb8bc6169, 0xb8ee828c, - 0xb8e10138, 0xb8f3126d, 0xb8f020b0, 0xb8e03183, - 0xb8e851ef, 0xb8f041e4, 0xb8fe7005, 0xb8ea6376, - 0xb8638120, 0xb873015d, 0xb8781284, 0xb86723b8, - 0xb86e3175, 0xb87b51ed, 0xb87f41d1, 0xb863721e, - 0xb87660f4, 0xce216874, 0xce104533, 0xce648c15, - 0xce8e3302, 0xce6e82ab, 0xce6c87d1, 0xcec08063, - 0xce638937, 0x25e0c358, 0x25a1c7d3, 0x0580785a, - 0x05426328, 0x05009892, 0x25a0cc29, 0x2561cec8, - 0x058044b3, 0x05401c99, 0x05006b49, 0x25e0d6f7, - 0x2561c528, 0x0583c8bc, 0x0542522f, 0x05001ec0, - 0x25e0de65, 0x25a1c113, 0x05803cad, 0x0540f3c0, - 0x0500ab15, 0x2560c28c, 0x2561d7c0, 0x05801ed7, - 0x0542633b, 0x05003696, 0x2560d4b4, 0x25e1c918, - 0x058021ff, 0x05400e15, 0x0500f3de, 0x0473025a, - 0x04bd05ab, 0x658e0025, 0x658a08e2, 0x659a0493, - 0x043e1062, 0x04f418b4, 0x046d15bd, 0x04611fce, - 0x04d6a07c, 0x04001929, 0x041a09da, 0x04d098f4, - 0x04db10d4, 0x0459a3ad, 0x041aa029, 0x041919fb, - 0x04d39e24, 0x04118302, 0x04101dba, 0x04d7ae16, - 0x04dea571, 0x04180210, 0x05e786fc, 0x05e4915c, - 0x04881cf1, 0x044a0f04, 0x04090969, 0x048b16c4, - 0x044101e4, 0x04dcbf44, 0x65809745, 0x658d833f, - 0x65c68468, 0x65c79b07, 0x65829e38, 0x049dafca, - 0x6582bba8, 0x65c0b7ff, 0x65c1b4e0, 0x658dbadd, - 0x65819a9d, 0x65ed9246, 0x65b30815, 0x65e6263c, - 0x65eebb94, 0x65bad14e, 0x65efe178, 0x65fc5697, - 0x65e07f14, 0x040c55a6, 0x04977f4d, 0x043d3046, - 0x04b733a0, 0x046830a4, 0x04ed322d, 0x05686948, - 0x05bd6c13, 0x65c88ef0, 0x450db3d7, 0x4540b6d9, - 0x043e3979, 0x445896ce, 0x445a9005, 0x44d98069, - 0x445b87ae, 0x04da348e, 0x04982edb, 0x0499397f, - 0x0408338c, 0x04ca309c, 0x65c721e6, 0x65c63641, - 0x65982882, 0x04812b8b, 0x0e251083, 0x4e3712d5, - 0x0e61101f, 0x4e6d118b, 0x0eba1338, 0x4eb712d5, - 0x2e31120f, 0x6e2e11ac, 0x2e6810e6, 0x6e6f11cd, - 0x2eaa1128, 0x6eb1120f, + 0x05901feb, 0x0590cc0b, 0x0590de0b, 0x04b0e3e0, + 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, + 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, + 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, + 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, + 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, + 0x040081e0, 0x04008120, 0x04008761, 0x04008621, + 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, + 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, + 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, + 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, + 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, + 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, + 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, + 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, + 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, + 0x25104042, 0x25104871, 0x25904861, 0x25904c92, + 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, + 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, + 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, + 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, + 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, + 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, + 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, + 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, + 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, + 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, + 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, + 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, + 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, + 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, + 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, + 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, + 0x05302a30, 0x05702a30, 0x05b02a30, 0x05f02a30, + 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, + 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, + 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, + 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, + 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, + 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, + 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, + 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, + 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, + 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, + 0x05a18610, 0x05e18610, 0x05271e11, 0x6545e891, + 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, + 0x65c5c891, 0x45b0c210, 0x45f1c231, 0x1e601000, + 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, + 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, + 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, + 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, + 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, + 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, + 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, + 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf8268267, + 0xf82d023c, 0xf8301046, 0xf83d2083, 0xf8263290, + 0xf82d528c, 0xf8284299, 0xf8337160, 0xf8386286, + 0xf8bf820e, 0xf8a600e0, 0xf8af1353, 0xf8a922ea, + 0xf8b53396, 0xf8a251e3, 0xf8b340f4, 0xf8a470fd, + 0xf8a06209, 0xf8f48097, 0xf8f002ea, 0xf8eb10d9, + 0xf8ff21b0, 0xf8f7302c, 0xf8ee52a9, 0xf8f041fa, + 0xf8e471e4, 0xf8e863c6, 0xf864823d, 0xf87d013a, + 0xf86f1162, 0xf87d20e3, 0xf86132bb, 0xf870510e, + 0xf8704336, 0xf86572b4, 0xf8706217, 0xb83e8294, + 0xb8200264, 0xb8381284, 0xb8242358, 0xb8333102, + 0xb828530e, 0xb83042df, 0xb824703f, 0xb82a6194, + 0xb8a080e9, 0xb8b80090, 0xb8bb1146, 0xb8bb21b8, + 0xb8b032df, 0xb8b653f4, 0xb8bd41c9, 0xb8b47287, + 0xb8bc6169, 0xb8ee828c, 0xb8e10138, 0xb8f3126d, + 0xb8f020b0, 0xb8e03183, 0xb8e851ef, 0xb8f041e4, + 0xb8fe7005, 0xb8ea6376, 0xb8638120, 0xb873015d, + 0xb8781284, 0xb86723b8, 0xb86e3175, 0xb87b51ed, + 0xb87f41d1, 0xb863721e, 0xb87660f4, 0xce216874, + 0xce104533, 0xce648c15, 0xce8e3302, 0xce6e82ab, + 0xce6c87d1, 0xcec08063, 0xce638937, 0x25e0c358, + 0x25a1c7d3, 0x0580785a, 0x05426328, 0x05009892, + 0x25a0cc29, 0x2561cec8, 0x058044b3, 0x05401c99, + 0x05006b49, 0x25e0d6f7, 0x2561c528, 0x0583c8bc, + 0x0542522f, 0x05001ec0, 0x25e0de65, 0x25a1c113, + 0x05803cad, 0x0540f3c0, 0x0500ab15, 0x2560c28c, + 0x2561d7c0, 0x05801ed7, 0x0542633b, 0x05003696, + 0x2560d4b4, 0x25e1c918, 0x058021ff, 0x05400e15, + 0x0500f3de, 0x0473025a, 0x04bd05ab, 0x658e0025, + 0x658a08e2, 0x659a0493, 0x043e1062, 0x04f418b4, + 0x046d15bd, 0x04611fce, 0x04d6a07c, 0x04001929, + 0x041a09da, 0x04d098f4, 0x04db10d4, 0x0459a3ad, + 0x041aa029, 0x041919fb, 0x04d39e24, 0x04118302, + 0x04101dba, 0x04d7ae16, 0x04dea571, 0x04180210, + 0x05e786fc, 0x05e4915c, 0x04881cf1, 0x044a0f04, + 0x04090969, 0x048b16c4, 0x044101e4, 0x04dcbf44, + 0x65809745, 0x658d833f, 0x65c68468, 0x65c79b07, + 0x65829e38, 0x049dafca, 0x6582bba8, 0x65c0b7ff, + 0x65c1b4e0, 0x658dbadd, 0x65819a9d, 0x65ed9246, + 0x65b30815, 0x65e6263c, 0x65eebb94, 0x65bad14e, + 0x65efe178, 0x65fc5697, 0x65e07f14, 0x040c55a6, + 0x04977f4d, 0x043d3046, 0x04b733a0, 0x046830a4, + 0x04ed322d, 0x05686948, 0x05bd6c13, 0x65c88ef0, + 0x450db3d7, 0x4540b6d9, 0x043e3979, 0x445896ce, + 0x445a9005, 0x44d98069, 0x445b87ae, 0x04da348e, + 0x04982edb, 0x0499397f, 0x0408338c, 0x04ca309c, + 0x65c721e6, 0x65c63641, 0x65982882, 0x04812b8b, + 0x0e251083, 0x4e3712d5, 0x0e61101f, 0x4e6d118b, + 0x0eba1338, 0x4eb712d5, 0x2e31120f, 0x6e2e11ac, + 0x2e6810e6, 0x6e6f11cd, 0x2eaa1128, 0x6eb1120f, + }; // END Generated code -- do not edit From ecfba66d3d7c1fef755f0824f342189d0f231007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 9 Sep 2025 07:31:14 +0000 Subject: [PATCH 420/471] 8366363: MemBaseline accesses VMT without using lock Co-authored-by: Casper Norrbin Reviewed-by: azafari, cnorrbin --- src/hotspot/share/nmt/memBaseline.cpp | 72 +++++++------------ src/hotspot/share/nmt/memBaseline.hpp | 13 ++-- src/hotspot/share/nmt/memReporter.cpp | 10 ++- .../share/nmt/nmtNativeCallStackStorage.cpp | 18 +++++ .../share/nmt/nmtNativeCallStackStorage.hpp | 3 +- src/hotspot/share/nmt/regionsTree.cpp | 13 +++- src/hotspot/share/nmt/regionsTree.hpp | 10 ++- src/hotspot/share/nmt/vmatree.cpp | 7 ++ src/hotspot/share/nmt/vmatree.hpp | 11 ++- src/hotspot/share/utilities/rbTree.hpp | 4 ++ src/hotspot/share/utilities/rbTree.inline.hpp | 49 +++++++++++++ test/hotspot/gtest/utilities/test_rbtree.cpp | 40 +++++++++++ 12 files changed, 185 insertions(+), 65 deletions(-) diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 35dff0d8646..9b796ce0c41 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -27,8 +27,7 @@ #include "memory/metaspaceUtils.hpp" #include "nmt/memBaseline.hpp" #include "nmt/memTracker.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/safepoint.hpp" +#include "nmt/regionsTree.inline.hpp" /* * Sizes are sorted in descenting order for reporting @@ -104,38 +103,6 @@ class MallocAllocationSiteWalker : public MallocSiteWalker { } }; -// Walk all virtual memory regions for baselining -class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { - private: - typedef LinkedListImpl EntryList; - EntryList _virtual_memory_regions; - DEBUG_ONLY(address _last_base;) - public: - VirtualMemoryAllocationWalker() { - DEBUG_ONLY(_last_base = nullptr); - } - - bool do_allocation_site(const ReservedMemoryRegion* rgn) { - assert(rgn->base() >= _last_base, "region unordered?"); - DEBUG_ONLY(_last_base = rgn->base()); - if (rgn->size() > 0) { - if (_virtual_memory_regions.add(*rgn) != nullptr) { - return true; - } else { - return false; - } - } else { - // Ignore empty sites. - return true; - } - } - - LinkedList* virtual_memory_allocations() { - return &_virtual_memory_regions; - } -}; - void MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); @@ -158,14 +125,15 @@ bool MemBaseline::baseline_allocation_sites() { // The malloc sites are collected in size order _malloc_sites_order = by_size; - // Virtual memory allocation sites - VirtualMemoryAllocationWalker virtual_memory_walker; - if (!VirtualMemoryTracker::Instance::walk_virtual_memory(&virtual_memory_walker)) { - return false; - } + assert(_vma_allocations == nullptr, "must"); - // Virtual memory allocations are collected in call stack order - _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations()); + { + MemTracker::NmtVirtualMemoryLocker locker; + _vma_allocations = new (mtNMT, std::nothrow) RegionsTree(*VirtualMemoryTracker::Instance::tree()); + if (_vma_allocations == nullptr) { + return false; + } + } if (!aggregate_virtual_memory_allocation_sites()) { return false; @@ -202,20 +170,28 @@ int compare_allocation_site(const VirtualMemoryAllocationSite& s1, bool MemBaseline::aggregate_virtual_memory_allocation_sites() { SortedLinkedList allocation_sites; - VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); - const ReservedMemoryRegion* rgn; VirtualMemoryAllocationSite* site; - while ((rgn = itr.next()) != nullptr) { - VirtualMemoryAllocationSite tmp(*rgn->call_stack(), rgn->mem_tag()); + bool failed_oom = false; + _vma_allocations->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { + VirtualMemoryAllocationSite tmp(*rgn.call_stack(), rgn.mem_tag()); site = allocation_sites.find(tmp); if (site == nullptr) { LinkedListNode* node = allocation_sites.add(tmp); - if (node == nullptr) return false; + if (node == nullptr) { + failed_oom = true; + return false; + } site = node->data(); } - site->reserve_memory(rgn->size()); - site->commit_memory(VirtualMemoryTracker::Instance::committed_size(rgn)); + site->reserve_memory(rgn.size()); + + site->commit_memory(_vma_allocations->committed_size(rgn)); + return true; + }); + + if (failed_oom) { + return false; } _virtual_memory_sites.move(&allocation_sites); diff --git a/src/hotspot/share/nmt/memBaseline.hpp b/src/hotspot/share/nmt/memBaseline.hpp index 2fff4cc666c..3f1ea46d815 100644 --- a/src/hotspot/share/nmt/memBaseline.hpp +++ b/src/hotspot/share/nmt/memBaseline.hpp @@ -35,7 +35,6 @@ typedef LinkedListIterator MallocSiteIterator; typedef LinkedListIterator VirtualMemorySiteIterator; -typedef LinkedListIterator VirtualMemoryAllocationIterator; /* * Baseline a memory snapshot @@ -71,7 +70,7 @@ class MemBaseline { LinkedListImpl _malloc_sites; // All virtual memory allocations - LinkedListImpl _virtual_memory_allocations; + RegionsTree* _vma_allocations; // Virtual memory allocations by allocation sites, always in by_address // order @@ -86,6 +85,7 @@ class MemBaseline { // create a memory baseline MemBaseline(): _instance_class_count(0), _array_class_count(0), _thread_count(0), + _vma_allocations(nullptr), _baseline_type(Not_baselined) { } @@ -110,9 +110,9 @@ class MemBaseline { // Virtual memory allocation iterator always returns in virtual memory // base address order. - VirtualMemoryAllocationIterator virtual_memory_allocations() { - assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline"); - return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head()); + RegionsTree* virtual_memory_allocations() { + assert(_vma_allocations != nullptr, "Not detail baseline"); + return _vma_allocations; } // Total reserved memory = total malloc'd memory + total reserved virtual @@ -185,7 +185,8 @@ class MemBaseline { _malloc_sites.clear(); _virtual_memory_sites.clear(); - _virtual_memory_allocations.clear(); + delete _vma_allocations; + _vma_allocations = nullptr; } private: diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 65d4d76942b..84f0f90f6e5 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -394,13 +394,11 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() { void MemDetailReporter::report_virtual_memory_map() { // Virtual memory map always in base address order - VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations(); - const ReservedMemoryRegion* rgn; - output()->print_cr("Virtual memory map:"); - while ((rgn = itr.next()) != nullptr) { - report_virtual_memory_region(rgn); - } + _baseline.virtual_memory_allocations()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { + report_virtual_memory_region(&rgn); + return true; + }); } void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 3e5c1d2f0ea..9a2ecd57ecc 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -57,3 +57,21 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ NativeCallStackStorage::~NativeCallStackStorage() { FREE_C_HEAP_ARRAY(LinkPtr, _table); } + +NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) + : _table_size(other._table_size), + _table(nullptr), + _stacks(), + _is_detailed_mode(other._is_detailed_mode), + _fake_stack(other._fake_stack) { + if (_is_detailed_mode) { + _table = NEW_C_HEAP_ARRAY(TableEntryIndex, _table_size, mtNMT); + for (int i = 0; i < _table_size; i++) { + _table[i] = other._table[i]; + } + } + _stacks.reserve(other._stacks.length()); + for (int i = 0; i < other._stacks.length(); i++) { + _stacks.at_grow(i) = other._stacks.at(i); + } +} diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 6f194cfa5a1..6ead8f49248 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -95,7 +95,8 @@ public: } NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size); - + NativeCallStackStorage(const NativeCallStackStorage& other); + NativeCallStackStorage& operator=(const NativeCallStackStorage& other) = delete; ~NativeCallStackStorage(); }; diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index 370c69a2485..8644a2d4731 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -22,6 +22,8 @@ * */ #include "nmt/regionsTree.hpp" +#include "nmt/regionsTree.inline.hpp" +#include "nmt/virtualMemoryTracker.hpp" VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); @@ -54,4 +56,13 @@ void RegionsTree::print_on(outputStream* st) { return true; }); } -#endif \ No newline at end of file +#endif + +size_t RegionsTree::committed_size(ReservedMemoryRegion& rgn) { + size_t result = 0; + visit_committed_regions(rgn, [&](CommittedMemoryRegion& crgn) { + result += crgn.size(); + return true; + }); + return result; +} diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index bf2ab711b2d..b0c5d928bab 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -40,6 +40,12 @@ class RegionsTree : public VMATree { public: RegionsTree(bool with_storage) : VMATree() , _ncs_storage(with_storage), _with_storage(with_storage) { } + RegionsTree(const RegionsTree& other) + : VMATree(other), + _ncs_storage(other._ncs_storage), + _with_storage(other._with_storage) {} + RegionsTree& operator=(const RegionsTree& other) = delete; + ReservedMemoryRegion find_reserved_region(address addr); SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); @@ -91,6 +97,8 @@ class RegionsTree : public VMATree { NativeCallStackStorage::StackIndex si = node.out_stack_index(); return _ncs_storage.get(si); } + + size_t committed_size(ReservedMemoryRegion& rgn); }; -#endif // NMT_REGIONSTREE_HPP \ No newline at end of file +#endif // NMT_REGIONSTREE_HPP diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 4f6f8e12185..69887068cb2 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -744,3 +744,10 @@ void VMATree::SummaryDiff::print_on(outputStream* out) { } } #endif + +void VMATree::clear() { + _tree.remove_all(); +}; +bool VMATree::is_empty() { + return _tree.size() == 0; +}; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 1b5729054e4..88b680a045c 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -30,6 +30,7 @@ #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/rbTree.hpp" #include "utilities/rbTree.inline.hpp" #include @@ -39,7 +40,7 @@ // For example, the state may go from released memory to committed memory, // or from committed memory of a certain MemTag to committed memory of a different MemTag. // The set of points is stored in a balanced binary tree for efficient querying and updating. -class VMATree { +class VMATree : public CHeapObjBase { friend class NMTVMATreeTest; friend class VMTWithVMATreeTest; // A position in memory. @@ -65,7 +66,6 @@ private: static const char* statetype_strings[static_cast(StateType::st_number_of_states)]; public: - NONCOPYABLE(VMATree); static const char* statetype_to_string(StateType type) { assert(type < StateType::st_number_of_states, "must be"); @@ -226,6 +226,10 @@ private: public: VMATree() : _tree() {} + VMATree(const VMATree& other) : _tree() { + assert(other._tree.copy_into(_tree), "VMATree dies on OOM"); + } + VMATree& operator=(VMATree const&) = delete; struct SingleDiff { using delta = int64_t; @@ -329,5 +333,8 @@ public: _tree.visit_range_in_order(from, to, f); } VMARBTree& tree() { return _tree; } + + void clear(); + bool is_empty(); }; #endif diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 4c358b53ff0..fd0e25051f5 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -428,6 +428,7 @@ public: template void visit_in_order(F f); + // Visit all RBNodes in ascending order whose keys are in range [from, to], calling f on each node. // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template @@ -475,6 +476,7 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} + NONCOPYABLE(RBTree); ~RBTree() { remove_all(); } RBTree(const RBTree& other) : BaseType(), _allocator() { assert(std::is_copy_constructible(), "Value type must be copy-constructible"); @@ -485,6 +487,8 @@ public: } RBTree& operator=(const RBTree& other) = delete; + bool copy_into(RBTree& other) const; + typedef typename BaseType::Cursor Cursor; using BaseType::cursor; using BaseType::insert_at_cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index f28923eb867..b7de0a7ac4c 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -753,4 +753,53 @@ void AbstractRBTree::print_on(outputStream* st, const P } } +template +bool RBTree::copy_into(RBTree& other) const { + assert(other.size() == 0, "You can only copy into an empty RBTree"); + assert(std::is_copy_constructible::value, "Key type must be copy-constructible when copying a RBTree"); + assert(std::is_copy_constructible::value, "Value type must be copy-constructible when copying a RBTree"); + enum class Dir { Left, Right }; + struct node_pair { const IntrusiveRBNode* current; IntrusiveRBNode* other_parent; Dir dir; }; + struct stack { + node_pair s[64]; + int idx = 0; + stack() : idx(0) {} + node_pair pop() { idx--; return s[idx]; }; + void push(node_pair n) { s[idx] = n; idx++; }; + bool is_empty() { return idx == 0; }; + }; + + stack visit_stack; + if (this->_root == nullptr) { + return true; + } + RBNode* root = static_cast*>(this->_root); + other._root = other.allocate_node(root->key(), root->val()); + if (other._root == nullptr) return false; + + visit_stack.push({this->_root->_left, other._root, Dir::Left}); + visit_stack.push({this->_root->_right, other._root, Dir::Right}); + while (!visit_stack.is_empty()) { + node_pair n = visit_stack.pop(); + const RBNode* current = static_cast*>(n.current); + if (current == nullptr) continue; + RBNode* new_node = other.allocate_node(current->key(), current->val()); + if (new_node == nullptr) { + return false; + } + if (n.dir == Dir::Left) { + n.other_parent->_left = new_node; + } else { + n.other_parent->_right = new_node; + } + new_node->set_parent(n.other_parent); + new_node->_parent |= n.current->_parent & 0x1; + visit_stack.push({n.current->_left, new_node, Dir::Left}); + visit_stack.push({n.current->_right, new_node, Dir::Right}); + } + other._num_nodes = this->_num_nodes; + DEBUG_ONLY(other._expected_visited = this->_expected_visited); + return true; +} + #endif // SHARE_UTILITIES_RBTREE_INLINE_HPP diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index ff234dd764a..a351e2141e8 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1200,6 +1200,46 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } +TEST_VM_F(RBTreeTest, TestCopyInto) { + { + RBTreeInt rbtree1; + RBTreeInt rbtree2; + + rbtree1.copy_into(rbtree2); + rbtree2.verify_self(); + } + + RBTreeInt rbtree1; + RBTreeInt rbtree2; + + int size = 1000; + for (int i = 0; i < size; i++) { + rbtree1.upsert(i, i); + } + + rbtree1.copy_into(rbtree2); + rbtree2.verify_self(); + + ResourceMark rm; + GrowableArray allocations(size); + int size1 = 0; + rbtree1.visit_in_order([&](RBTreeIntNode* node) { + size1++; + allocations.append(node->key()); + return true; + }); + + int size2 = 0; + rbtree2.visit_in_order([&](RBTreeIntNode* node) { + EXPECT_EQ(node->key(), allocations.at(size2++)); + return true; + }); + + EXPECT_EQ(size1, size2); + EXPECT_EQ(rbtree1.size(), rbtree2.size()); + EXPECT_EQ(size2, static_cast(rbtree2.size())); +} + struct OomAllocator { void* allocate(size_t sz) { return nullptr; From 67bb22f3d661d7edf7a0949612d9fb64f0124cad Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Tue, 9 Sep 2025 07:36:57 +0000 Subject: [PATCH 421/471] 8367085: Sort os/posix includes Reviewed-by: ayang, dholmes --- src/hotspot/os/posix/attachListener_posix.cpp | 8 ++++---- src/hotspot/os/posix/os_posix.cpp | 5 ++--- src/hotspot/os/posix/os_posix.inline.hpp | 4 ++-- src/hotspot/os/posix/perfMemory_posix.cpp | 13 ++++++------- src/hotspot/os/posix/safefetch_sigjmp.cpp | 2 +- src/hotspot/os/posix/semaphore_posix.cpp | 3 ++- src/hotspot/os/posix/threadLocalStorage_posix.cpp | 1 + .../jtreg/sources/TestIncludesAreSorted.java | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/hotspot/os/posix/attachListener_posix.cpp b/src/hotspot/os/posix/attachListener_posix.cpp index d3e24807124..a7cf1703128 100644 --- a/src/hotspot/os/posix/attachListener_posix.cpp +++ b/src/hotspot/os/posix/attachListener_posix.cpp @@ -24,19 +24,19 @@ #include "logging/log.hpp" #include "memory/allocation.inline.hpp" +#include "os_posix.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.inline.hpp" -#include "os_posix.hpp" #include "services/attachListener.hpp" #include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" -#include #include -#include #include -#include #include +#include +#include +#include #if INCLUDE_SERVICES #ifndef AIX diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 6a39c95db52..8f188ef002f 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -70,14 +70,13 @@ #include #include #include -#include #include +#include #include +#include #include #include #include -#include -#include #include #include #include diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp index cf81c5d6286..67be82e4d63 100644 --- a/src/hotspot/os/posix/os_posix.inline.hpp +++ b/src/hotspot/os/posix/os_posix.inline.hpp @@ -30,9 +30,9 @@ #include "runtime/mutex.hpp" #include "runtime/os.hpp" -#include -#include #include +#include +#include // Aix does not have NUMA support but need these for compilation. inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index c58f216b2c3..ed83487265c 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -40,15 +40,14 @@ #include "os_linux.hpp" #endif -// put OS-includes here -# include -# include # include -# include -# include -# include -# include # include +# include +# include +# include +# include +# include +# include #if defined(LINUX) # include diff --git a/src/hotspot/os/posix/safefetch_sigjmp.cpp b/src/hotspot/os/posix/safefetch_sigjmp.cpp index 57f0f8460bf..9f6ef34070b 100644 --- a/src/hotspot/os/posix/safefetch_sigjmp.cpp +++ b/src/hotspot/os/posix/safefetch_sigjmp.cpp @@ -32,8 +32,8 @@ #ifdef SAFEFETCH_METHOD_SIGSETJMP // For SafeFetch we need POSIX TLS and sigsetjmp/longjmp. -#include #include +#include static pthread_key_t g_jmpbuf_key; struct InitTLSKey { InitTLSKey() { pthread_key_create(&g_jmpbuf_key, nullptr); } }; diff --git a/src/hotspot/os/posix/semaphore_posix.cpp b/src/hotspot/os/posix/semaphore_posix.cpp index 23a5225eba3..cb0afaafe42 100644 --- a/src/hotspot/os/posix/semaphore_posix.cpp +++ b/src/hotspot/os/posix/semaphore_posix.cpp @@ -25,9 +25,10 @@ #ifndef __APPLE__ #include "os_posix.hpp" #include "runtime/os.hpp" -#include "utilities/debug.hpp" // POSIX unnamed semaphores are not supported on OS X. #include "semaphore_posix.hpp" +#include "utilities/debug.hpp" + #include PosixSemaphore::PosixSemaphore(uint value) { diff --git a/src/hotspot/os/posix/threadLocalStorage_posix.cpp b/src/hotspot/os/posix/threadLocalStorage_posix.cpp index 44a1d294cd5..8d1dad54a01 100644 --- a/src/hotspot/os/posix/threadLocalStorage_posix.cpp +++ b/src/hotspot/os/posix/threadLocalStorage_posix.cpp @@ -24,6 +24,7 @@ #include "runtime/threadLocalStorage.hpp" #include "utilities/debug.hpp" + #include static pthread_key_t _thread_key; diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 119f32ffe2e..e0e77992ace 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -44,6 +44,7 @@ public class TestIncludesAreSorted { */ private static final String[] HOTSPOT_SOURCES_TO_CHECK = { "os/linux", + "os/posix", "share" }; From e16c510071f84bdbd57a8b2d3810c484c314ccf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 9 Sep 2025 08:14:55 +0000 Subject: [PATCH 422/471] 8367231: [BACKOUT] JDK-8366363: MemBaseline accesses VMT without using lock Reviewed-by: kbarrett, dholmes --- src/hotspot/share/nmt/memBaseline.cpp | 72 ++++++++++++------- src/hotspot/share/nmt/memBaseline.hpp | 13 ++-- src/hotspot/share/nmt/memReporter.cpp | 10 +-- .../share/nmt/nmtNativeCallStackStorage.cpp | 18 ----- .../share/nmt/nmtNativeCallStackStorage.hpp | 3 +- src/hotspot/share/nmt/regionsTree.cpp | 13 +--- src/hotspot/share/nmt/regionsTree.hpp | 10 +-- src/hotspot/share/nmt/vmatree.cpp | 7 -- src/hotspot/share/nmt/vmatree.hpp | 11 +-- src/hotspot/share/utilities/rbTree.hpp | 4 -- src/hotspot/share/utilities/rbTree.inline.hpp | 49 ------------- test/hotspot/gtest/utilities/test_rbtree.cpp | 40 ----------- 12 files changed, 65 insertions(+), 185 deletions(-) diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 9b796ce0c41..35dff0d8646 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -27,7 +27,8 @@ #include "memory/metaspaceUtils.hpp" #include "nmt/memBaseline.hpp" #include "nmt/memTracker.hpp" -#include "nmt/regionsTree.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/safepoint.hpp" /* * Sizes are sorted in descenting order for reporting @@ -103,6 +104,38 @@ class MallocAllocationSiteWalker : public MallocSiteWalker { } }; +// Walk all virtual memory regions for baselining +class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { + private: + typedef LinkedListImpl EntryList; + EntryList _virtual_memory_regions; + DEBUG_ONLY(address _last_base;) + public: + VirtualMemoryAllocationWalker() { + DEBUG_ONLY(_last_base = nullptr); + } + + bool do_allocation_site(const ReservedMemoryRegion* rgn) { + assert(rgn->base() >= _last_base, "region unordered?"); + DEBUG_ONLY(_last_base = rgn->base()); + if (rgn->size() > 0) { + if (_virtual_memory_regions.add(*rgn) != nullptr) { + return true; + } else { + return false; + } + } else { + // Ignore empty sites. + return true; + } + } + + LinkedList* virtual_memory_allocations() { + return &_virtual_memory_regions; + } +}; + void MemBaseline::baseline_summary() { MallocMemorySummary::snapshot(&_malloc_memory_snapshot); VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); @@ -125,16 +158,15 @@ bool MemBaseline::baseline_allocation_sites() { // The malloc sites are collected in size order _malloc_sites_order = by_size; - assert(_vma_allocations == nullptr, "must"); - - { - MemTracker::NmtVirtualMemoryLocker locker; - _vma_allocations = new (mtNMT, std::nothrow) RegionsTree(*VirtualMemoryTracker::Instance::tree()); - if (_vma_allocations == nullptr) { - return false; - } + // Virtual memory allocation sites + VirtualMemoryAllocationWalker virtual_memory_walker; + if (!VirtualMemoryTracker::Instance::walk_virtual_memory(&virtual_memory_walker)) { + return false; } + // Virtual memory allocations are collected in call stack order + _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations()); + if (!aggregate_virtual_memory_allocation_sites()) { return false; } @@ -170,28 +202,20 @@ int compare_allocation_site(const VirtualMemoryAllocationSite& s1, bool MemBaseline::aggregate_virtual_memory_allocation_sites() { SortedLinkedList allocation_sites; + VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; VirtualMemoryAllocationSite* site; - bool failed_oom = false; - _vma_allocations->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { - VirtualMemoryAllocationSite tmp(*rgn.call_stack(), rgn.mem_tag()); + while ((rgn = itr.next()) != nullptr) { + VirtualMemoryAllocationSite tmp(*rgn->call_stack(), rgn->mem_tag()); site = allocation_sites.find(tmp); if (site == nullptr) { LinkedListNode* node = allocation_sites.add(tmp); - if (node == nullptr) { - failed_oom = true; - return false; - } + if (node == nullptr) return false; site = node->data(); } - site->reserve_memory(rgn.size()); - - site->commit_memory(_vma_allocations->committed_size(rgn)); - return true; - }); - - if (failed_oom) { - return false; + site->reserve_memory(rgn->size()); + site->commit_memory(VirtualMemoryTracker::Instance::committed_size(rgn)); } _virtual_memory_sites.move(&allocation_sites); diff --git a/src/hotspot/share/nmt/memBaseline.hpp b/src/hotspot/share/nmt/memBaseline.hpp index 3f1ea46d815..2fff4cc666c 100644 --- a/src/hotspot/share/nmt/memBaseline.hpp +++ b/src/hotspot/share/nmt/memBaseline.hpp @@ -35,6 +35,7 @@ typedef LinkedListIterator MallocSiteIterator; typedef LinkedListIterator VirtualMemorySiteIterator; +typedef LinkedListIterator VirtualMemoryAllocationIterator; /* * Baseline a memory snapshot @@ -70,7 +71,7 @@ class MemBaseline { LinkedListImpl _malloc_sites; // All virtual memory allocations - RegionsTree* _vma_allocations; + LinkedListImpl _virtual_memory_allocations; // Virtual memory allocations by allocation sites, always in by_address // order @@ -85,7 +86,6 @@ class MemBaseline { // create a memory baseline MemBaseline(): _instance_class_count(0), _array_class_count(0), _thread_count(0), - _vma_allocations(nullptr), _baseline_type(Not_baselined) { } @@ -110,9 +110,9 @@ class MemBaseline { // Virtual memory allocation iterator always returns in virtual memory // base address order. - RegionsTree* virtual_memory_allocations() { - assert(_vma_allocations != nullptr, "Not detail baseline"); - return _vma_allocations; + VirtualMemoryAllocationIterator virtual_memory_allocations() { + assert(!_virtual_memory_allocations.is_empty(), "Not detail baseline"); + return VirtualMemoryAllocationIterator(_virtual_memory_allocations.head()); } // Total reserved memory = total malloc'd memory + total reserved virtual @@ -185,8 +185,7 @@ class MemBaseline { _malloc_sites.clear(); _virtual_memory_sites.clear(); - delete _vma_allocations; - _vma_allocations = nullptr; + _virtual_memory_allocations.clear(); } private: diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 84f0f90f6e5..65d4d76942b 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -394,11 +394,13 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() { void MemDetailReporter::report_virtual_memory_map() { // Virtual memory map always in base address order + VirtualMemoryAllocationIterator itr = _baseline.virtual_memory_allocations(); + const ReservedMemoryRegion* rgn; + output()->print_cr("Virtual memory map:"); - _baseline.virtual_memory_allocations()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { - report_virtual_memory_region(&rgn); - return true; - }); + while ((rgn = itr.next()) != nullptr) { + report_virtual_memory_region(rgn); + } } void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 9a2ecd57ecc..3e5c1d2f0ea 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -57,21 +57,3 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ NativeCallStackStorage::~NativeCallStackStorage() { FREE_C_HEAP_ARRAY(LinkPtr, _table); } - -NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) - : _table_size(other._table_size), - _table(nullptr), - _stacks(), - _is_detailed_mode(other._is_detailed_mode), - _fake_stack(other._fake_stack) { - if (_is_detailed_mode) { - _table = NEW_C_HEAP_ARRAY(TableEntryIndex, _table_size, mtNMT); - for (int i = 0; i < _table_size; i++) { - _table[i] = other._table[i]; - } - } - _stacks.reserve(other._stacks.length()); - for (int i = 0; i < other._stacks.length(); i++) { - _stacks.at_grow(i) = other._stacks.at(i); - } -} diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp index 6ead8f49248..6f194cfa5a1 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.hpp @@ -95,8 +95,7 @@ public: } NativeCallStackStorage(bool is_detailed_mode, int table_size = default_table_size); - NativeCallStackStorage(const NativeCallStackStorage& other); - NativeCallStackStorage& operator=(const NativeCallStackStorage& other) = delete; + ~NativeCallStackStorage(); }; diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index 8644a2d4731..370c69a2485 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -22,8 +22,6 @@ * */ #include "nmt/regionsTree.hpp" -#include "nmt/regionsTree.inline.hpp" -#include "nmt/virtualMemoryTracker.hpp" VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); @@ -56,13 +54,4 @@ void RegionsTree::print_on(outputStream* st) { return true; }); } -#endif - -size_t RegionsTree::committed_size(ReservedMemoryRegion& rgn) { - size_t result = 0; - visit_committed_regions(rgn, [&](CommittedMemoryRegion& crgn) { - result += crgn.size(); - return true; - }); - return result; -} +#endif \ No newline at end of file diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index b0c5d928bab..bf2ab711b2d 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -40,12 +40,6 @@ class RegionsTree : public VMATree { public: RegionsTree(bool with_storage) : VMATree() , _ncs_storage(with_storage), _with_storage(with_storage) { } - RegionsTree(const RegionsTree& other) - : VMATree(other), - _ncs_storage(other._ncs_storage), - _with_storage(other._with_storage) {} - RegionsTree& operator=(const RegionsTree& other) = delete; - ReservedMemoryRegion find_reserved_region(address addr); SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); @@ -97,8 +91,6 @@ class RegionsTree : public VMATree { NativeCallStackStorage::StackIndex si = node.out_stack_index(); return _ncs_storage.get(si); } - - size_t committed_size(ReservedMemoryRegion& rgn); }; -#endif // NMT_REGIONSTREE_HPP +#endif // NMT_REGIONSTREE_HPP \ No newline at end of file diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 69887068cb2..4f6f8e12185 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -744,10 +744,3 @@ void VMATree::SummaryDiff::print_on(outputStream* out) { } } #endif - -void VMATree::clear() { - _tree.remove_all(); -}; -bool VMATree::is_empty() { - return _tree.size() == 0; -}; diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 88b680a045c..1b5729054e4 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -30,7 +30,6 @@ #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" -#include "utilities/rbTree.hpp" #include "utilities/rbTree.inline.hpp" #include @@ -40,7 +39,7 @@ // For example, the state may go from released memory to committed memory, // or from committed memory of a certain MemTag to committed memory of a different MemTag. // The set of points is stored in a balanced binary tree for efficient querying and updating. -class VMATree : public CHeapObjBase { +class VMATree { friend class NMTVMATreeTest; friend class VMTWithVMATreeTest; // A position in memory. @@ -66,6 +65,7 @@ private: static const char* statetype_strings[static_cast(StateType::st_number_of_states)]; public: + NONCOPYABLE(VMATree); static const char* statetype_to_string(StateType type) { assert(type < StateType::st_number_of_states, "must be"); @@ -226,10 +226,6 @@ private: public: VMATree() : _tree() {} - VMATree(const VMATree& other) : _tree() { - assert(other._tree.copy_into(_tree), "VMATree dies on OOM"); - } - VMATree& operator=(VMATree const&) = delete; struct SingleDiff { using delta = int64_t; @@ -333,8 +329,5 @@ public: _tree.visit_range_in_order(from, to, f); } VMARBTree& tree() { return _tree; } - - void clear(); - bool is_empty(); }; #endif diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index fd0e25051f5..4c358b53ff0 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -428,7 +428,6 @@ public: template void visit_in_order(F f); - // Visit all RBNodes in ascending order whose keys are in range [from, to], calling f on each node. // If f returns `true` the iteration continues, otherwise it is stopped at the current node. template @@ -476,7 +475,6 @@ class RBTree : public AbstractRBTree, COMPARATOR> { public: RBTree() : BaseType(), _allocator() {} - NONCOPYABLE(RBTree); ~RBTree() { remove_all(); } RBTree(const RBTree& other) : BaseType(), _allocator() { assert(std::is_copy_constructible(), "Value type must be copy-constructible"); @@ -487,8 +485,6 @@ public: } RBTree& operator=(const RBTree& other) = delete; - bool copy_into(RBTree& other) const; - typedef typename BaseType::Cursor Cursor; using BaseType::cursor; using BaseType::insert_at_cursor; diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index b7de0a7ac4c..f28923eb867 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -753,53 +753,4 @@ void AbstractRBTree::print_on(outputStream* st, const P } } -template -bool RBTree::copy_into(RBTree& other) const { - assert(other.size() == 0, "You can only copy into an empty RBTree"); - assert(std::is_copy_constructible::value, "Key type must be copy-constructible when copying a RBTree"); - assert(std::is_copy_constructible::value, "Value type must be copy-constructible when copying a RBTree"); - enum class Dir { Left, Right }; - struct node_pair { const IntrusiveRBNode* current; IntrusiveRBNode* other_parent; Dir dir; }; - struct stack { - node_pair s[64]; - int idx = 0; - stack() : idx(0) {} - node_pair pop() { idx--; return s[idx]; }; - void push(node_pair n) { s[idx] = n; idx++; }; - bool is_empty() { return idx == 0; }; - }; - - stack visit_stack; - if (this->_root == nullptr) { - return true; - } - RBNode* root = static_cast*>(this->_root); - other._root = other.allocate_node(root->key(), root->val()); - if (other._root == nullptr) return false; - - visit_stack.push({this->_root->_left, other._root, Dir::Left}); - visit_stack.push({this->_root->_right, other._root, Dir::Right}); - while (!visit_stack.is_empty()) { - node_pair n = visit_stack.pop(); - const RBNode* current = static_cast*>(n.current); - if (current == nullptr) continue; - RBNode* new_node = other.allocate_node(current->key(), current->val()); - if (new_node == nullptr) { - return false; - } - if (n.dir == Dir::Left) { - n.other_parent->_left = new_node; - } else { - n.other_parent->_right = new_node; - } - new_node->set_parent(n.other_parent); - new_node->_parent |= n.current->_parent & 0x1; - visit_stack.push({n.current->_left, new_node, Dir::Left}); - visit_stack.push({n.current->_right, new_node, Dir::Right}); - } - other._num_nodes = this->_num_nodes; - DEBUG_ONLY(other._expected_visited = this->_expected_visited); - return true; -} - #endif // SHARE_UTILITIES_RBTREE_INLINE_HPP diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index a351e2141e8..ff234dd764a 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -1200,46 +1200,6 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) { } } -TEST_VM_F(RBTreeTest, TestCopyInto) { - { - RBTreeInt rbtree1; - RBTreeInt rbtree2; - - rbtree1.copy_into(rbtree2); - rbtree2.verify_self(); - } - - RBTreeInt rbtree1; - RBTreeInt rbtree2; - - int size = 1000; - for (int i = 0; i < size; i++) { - rbtree1.upsert(i, i); - } - - rbtree1.copy_into(rbtree2); - rbtree2.verify_self(); - - ResourceMark rm; - GrowableArray allocations(size); - int size1 = 0; - rbtree1.visit_in_order([&](RBTreeIntNode* node) { - size1++; - allocations.append(node->key()); - return true; - }); - - int size2 = 0; - rbtree2.visit_in_order([&](RBTreeIntNode* node) { - EXPECT_EQ(node->key(), allocations.at(size2++)); - return true; - }); - - EXPECT_EQ(size1, size2); - EXPECT_EQ(rbtree1.size(), rbtree2.size()); - EXPECT_EQ(size2, static_cast(rbtree2.size())); -} - struct OomAllocator { void* allocate(size_t sz) { return nullptr; From cfb809344c0205875b35991ce6807333df41c949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Tue, 9 Sep 2025 09:01:46 +0000 Subject: [PATCH 423/471] 8364103: Convert existing sprintf-chains to stringStream Reviewed-by: kbarrett, dholmes, iklam --- src/hotspot/share/classfile/javaClasses.cpp | 69 +++++++-------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 8cc00d1feb9..3617f318b83 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2583,85 +2583,64 @@ class BacktraceIterator : public StackObj { }; -// Print stack trace element to resource allocated buffer +// Print stack trace element to the specified output stream. +// The output is formatted into a stringStream and written to the outputStream in one step. static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id, int version, int bci, Symbol* name) { ResourceMark rm; + stringStream ss; - // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* klass_name = holder->external_name(); - int buf_len = (int)strlen(klass_name); - char* method_name = name->as_C_string(); - buf_len += (int)strlen(method_name); + ss.print("\tat %s.%s(", klass_name, method_name); + + // Print module information + ModuleEntry* module = holder->module(); + if (module->is_named()) { + char* module_name = module->name()->as_C_string(); + if (module->version() != nullptr) { + char* module_version = module->version()->as_C_string(); + ss.print("%s@%s/", module_name, module_version); + } else { + ss.print("%s/", module_name); + } + } char* source_file_name = nullptr; Symbol* source = Backtrace::get_source_file_name(holder, version); if (source != nullptr) { source_file_name = source->as_C_string(); - buf_len += (int)strlen(source_file_name); - } - - char *module_name = nullptr, *module_version = nullptr; - ModuleEntry* module = holder->module(); - if (module->is_named()) { - module_name = module->name()->as_C_string(); - buf_len += (int)strlen(module_name); - if (module->version() != nullptr) { - module_version = module->version()->as_C_string(); - buf_len += (int)strlen(module_version); - } - } - - // Allocate temporary buffer with extra space for formatting and line number - const size_t buf_size = buf_len + 64; - char* buf = NEW_RESOURCE_ARRAY(char, buf_size); - - // Print stack trace line in buffer - int buf_off = os::snprintf(buf, buf_size, "\tat %s.%s(", klass_name, method_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - // Print module information - if (module_name != nullptr) { - if (module_version != nullptr) { - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s@%s/", module_name, module_version); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - } else { - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s/", module_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); - } } // The method can be null if the requested class version is gone Method* method = holder->method_with_orig_idnum(method_id, version); if (!version_matches(method, version)) { - strcat(buf, "Redefined)"); + ss.print("Redefined)"); } else { int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) { - strcat(buf, "Native Method)"); + ss.print("Native Method)"); } else { if (source_file_name != nullptr && (line_number != -1)) { // Sourcename and linenumber - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s:%d)", source_file_name, line_number); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("%s:%d)", source_file_name, line_number); } else if (source_file_name != nullptr) { // Just sourcename - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "%s)", source_file_name); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("%s)", source_file_name); } else { // Neither sourcename nor linenumber - buf_off += os::snprintf(buf + buf_off, buf_size - buf_off, "Unknown Source)"); - assert(static_cast(buf_off) < buf_size, "buffer is wrong size"); + ss.print("Unknown Source)"); } nmethod* nm = method->code(); if (WizardMode && nm != nullptr) { - os::snprintf_checked(buf + buf_off, buf_size - buf_off, "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); + ss.print("(nmethod " INTPTR_FORMAT ")", p2i(nm)); } } } - st->print_cr("%s", buf); + ss.cr(); + st->print_raw(ss.freeze(), ss.size()); } void java_lang_Throwable::print_stack_element(outputStream *st, Method* method, int bci) { From f51e442b0e26d0e9ebb6ec0da9584ba4f548322c Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 9 Sep 2025 09:29:23 +0000 Subject: [PATCH 424/471] 8367098: RISC-V: sync CPU features with related JVM flags for dependant ones Reviewed-by: fyang --- src/hotspot/cpu/riscv/vm_version_riscv.hpp | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index a0a42fb5463..188f7e0b1c3 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -86,25 +86,27 @@ class VM_Version : public Abstract_VM_Version { } \ } \ - #define UPDATE_DEFAULT_DEP(flag, dep) \ - void update_flag() { \ - assert(enabled(), "Must be."); \ - /* dep must be declared before */ \ - assert((uintptr_t)(this) > \ - (uintptr_t)(&dep), "Invalid");\ - if (FLAG_IS_DEFAULT(flag)) { \ - if (dep.enabled()) { \ - FLAG_SET_DEFAULT(flag, true); \ - } else { \ - FLAG_SET_DEFAULT(flag, false); \ - } \ - } else { \ - /* Sync CPU features with flags */ \ - if (!flag) { \ - disable_feature(); \ - } \ - } \ - } \ + #define UPDATE_DEFAULT_DEP(flag, dep) \ + void update_flag() { \ + assert(enabled(), "Must be."); \ + /* dep must be declared before */ \ + assert((uintptr_t)(this) > \ + (uintptr_t)(&dep), "Invalid"); \ + if (FLAG_IS_DEFAULT(flag)) { \ + if (dep.enabled()) { \ + FLAG_SET_DEFAULT(flag, true); \ + } else { \ + FLAG_SET_DEFAULT(flag, false); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } else { \ + /* Sync CPU features with flags */ \ + if (!flag) { \ + disable_feature(); \ + } \ + } \ + } \ #define NO_UPDATE_DEFAULT \ void update_flag() {} \ From 4fc917c25005d1f88fe43069fe623e243bd022c3 Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Tue, 9 Sep 2025 10:15:53 +0000 Subject: [PATCH 425/471] 8366486: Test jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java is timing out Reviewed-by: jbachorik --- .../profiling/TestCPUTimeSampleMultipleRecordings.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java index 976d08f1250..efc4da28021 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java @@ -39,20 +39,15 @@ import jdk.test.lib.jfr.EventNames; * @run main/timeout=480 jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings */ public class TestCPUTimeSampleMultipleRecordings { - - static String nativeEvent = EventNames.CPUTimeSample; - static volatile boolean alive = true; public static void main(String[] args) throws Exception { Thread t = new Thread(TestCPUTimeSampleMultipleRecordings::nativeMethod); - t.setDaemon(true); t.start(); for (int i = 0; i < 2; i++) { try (RecordingStream rs = new RecordingStream()) { - rs.enable(nativeEvent).with("throttle", "1ms"); - rs.onEvent(nativeEvent, e -> { - alive = false; + rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); + rs.onEvent(EventNames.CPUTimeSample, e -> { rs.close(); }); @@ -60,6 +55,7 @@ public class TestCPUTimeSampleMultipleRecordings { } } alive = false; + t.join(); } public static void nativeMethod() { From 002f936ef21943ff1c8c03618091793768e756ac Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Tue, 9 Sep 2025 10:16:22 +0000 Subject: [PATCH 426/471] 8366082: Improve queue size computation in CPU-time sampler Reviewed-by: jbachorik --- .../sampling/jfrCPUTimeThreadSampler.cpp | 101 +++++++++--- .../sampling/jfrCPUTimeThreadSampler.hpp | 20 ++- .../periodic/sampling/jfrThreadSampling.cpp | 1 + .../share/jfr/support/jfrThreadLocal.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 30 ++++ .../TestCPUTimeSampleQueueAutoSizes.java | 154 ++++++++++++++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 7 + 7 files changed, 292 insertions(+), 23 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index db3ca758cc1..579710a62a7 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -25,7 +25,6 @@ #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "logging/log.hpp" - #if defined(LINUX) #include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -67,7 +66,7 @@ static JavaThread* get_java_thread_if_valid() { } JfrCPUTimeTraceQueue::JfrCPUTimeTraceQueue(u4 capacity) : - _data(nullptr), _capacity(capacity), _head(0), _lost_samples(0) { + _data(nullptr), _capacity(capacity), _head(0), _lost_samples(0), _lost_samples_due_to_queue_full(0) { if (capacity != 0) { _data = JfrCHeapObj::new_array(capacity); } @@ -110,10 +109,13 @@ void JfrCPUTimeTraceQueue::set_size(u4 size) { } u4 JfrCPUTimeTraceQueue::capacity() const { - return _capacity; + return Atomic::load_acquire(&_capacity); } void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { + if (capacity == Atomic::load(&_capacity)) { + return; + } _head = 0; if (_data != nullptr) { assert(_capacity != 0, "invariant"); @@ -124,7 +126,7 @@ void JfrCPUTimeTraceQueue::set_capacity(u4 capacity) { } else { _data = nullptr; } - _capacity = capacity; + Atomic::release_store(&_capacity, capacity); } bool JfrCPUTimeTraceQueue::is_empty() const { @@ -140,28 +142,51 @@ void JfrCPUTimeTraceQueue::increment_lost_samples() { Atomic::inc(&_lost_samples); } +void JfrCPUTimeTraceQueue::increment_lost_samples_due_to_queue_full() { + Atomic::inc(&_lost_samples_due_to_queue_full); +} + u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples() { return Atomic::xchg(&_lost_samples, (u4)0); } -void JfrCPUTimeTraceQueue::resize(u4 capacity) { - if (capacity != _capacity) { - set_capacity(capacity); - } +u4 JfrCPUTimeTraceQueue::get_and_reset_lost_samples_due_to_queue_full() { + return Atomic::xchg(&_lost_samples_due_to_queue_full, (u4)0); } -void JfrCPUTimeTraceQueue::resize_for_period(u4 period_millis) { - u4 capacity = CPU_TIME_QUEUE_CAPACITY; - if (period_millis > 0 && period_millis < 10) { - capacity = (u4) ((double) capacity * 10 / period_millis); - } - resize(capacity); +void JfrCPUTimeTraceQueue::init() { + set_capacity(JfrCPUTimeTraceQueue::CPU_TIME_QUEUE_INITIAL_CAPACITY); } void JfrCPUTimeTraceQueue::clear() { Atomic::release_store(&_head, (u4)0); } +void JfrCPUTimeTraceQueue::resize_if_needed() { + u4 lost_samples_due_to_queue_full = get_and_reset_lost_samples_due_to_queue_full(); + if (lost_samples_due_to_queue_full == 0) { + return; + } + u4 capacity = Atomic::load(&_capacity); + if (capacity < CPU_TIME_QUEUE_MAX_CAPACITY) { + float ratio = (float)lost_samples_due_to_queue_full / (float)capacity; + int factor = 1; + if (ratio > 8) { // idea is to quickly scale the queue in the worst case + factor = ratio; + } else if (ratio > 2) { + factor = 8; + } else if (ratio > 0.5) { + factor = 4; + } else if (ratio > 0.01) { + factor = 2; + } + if (factor > 1) { + u4 new_capacity = MIN2(CPU_TIME_QUEUE_MAX_CAPACITY, capacity * factor); + set_capacity(new_capacity); + } + } +} + // A throttle is either a rate or a fixed period class JfrCPUSamplerThrottle { @@ -205,6 +230,8 @@ class JfrCPUSamplerThread : public NonJavaThread { volatile bool _is_async_processing_of_cpu_time_jfr_requests_triggered; volatile bool _warned_about_timer_creation_failure; volatile bool _signal_handler_installed; + DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled;) + DEBUG_ONLY(volatile u8 _out_of_stack_walking_iterations;) static const u4 STOP_SIGNAL_BIT = 0x80000000; @@ -250,6 +277,16 @@ public: void stop_timer(); void trigger_async_processing_of_cpu_time_jfr_requests(); + + #ifdef ASSERT + void set_out_of_stack_walking_enabled(bool runnable) { + Atomic::release_store(&_out_of_stack_walking_enabled, runnable); + } + + u8 out_of_stack_walking_iterations() const { + return Atomic::load(&_out_of_stack_walking_iterations); + } + #endif }; JfrCPUSamplerThread::JfrCPUSamplerThread(JfrCPUSamplerThrottle& throttle) : @@ -275,7 +312,7 @@ void JfrCPUSamplerThread::on_javathread_create(JavaThread* thread) { } JfrThreadLocal* tl = thread->jfr_thread_local(); assert(tl != nullptr, "invariant"); - tl->cpu_time_jfr_queue().resize_for_period(_current_sampling_period_ns / 1000000); + tl->cpu_time_jfr_queue().init(); timer_t timerid; if (create_timer_for_thread(thread, timerid)) { tl->set_cpu_timer(&timerid); @@ -294,12 +331,14 @@ void JfrCPUSamplerThread::on_javathread_terminate(JavaThread* thread) { if (timer == nullptr) { return; // no timer was created for this thread } + tl->acquire_cpu_time_jfr_dequeue_lock(); tl->unset_cpu_timer(); tl->deallocate_cpu_time_jfr_queue(); s4 lost_samples = tl->cpu_time_jfr_queue().lost_samples(); if (lost_samples > 0) { JfrCPUTimeThreadSampling::send_lost_event(JfrTicks::now(), JfrThreadLocal::thread_id(thread), lost_samples); } + tl->release_cpu_time_jfr_queue_lock(); } void JfrCPUSamplerThread::start_thread() { @@ -352,10 +391,12 @@ void JfrCPUSamplerThread::run() { recompute_period_if_needed(); last_recompute_check = os::javaTimeNanos(); } - - if (Atomic::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { - stackwalk_threads_in_native(); - } + DEBUG_ONLY(if (Atomic::load_acquire(&_out_of_stack_walking_enabled)) {) + if (Atomic::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { + DEBUG_ONLY(Atomic::inc(&_out_of_stack_walking_iterations);) + stackwalk_threads_in_native(); + } + DEBUG_ONLY(}) os::naked_sleep(100); } } @@ -545,6 +586,21 @@ void JfrCPUTimeThreadSampling::handle_timer_signal(siginfo_t* info, void* contex _sampler->decrement_signal_handler_count(); } +#ifdef ASSERT +void JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { + if (_instance != nullptr && _instance->_sampler != nullptr) { + _instance->_sampler->set_out_of_stack_walking_enabled(runnable); + } +} + +u8 JfrCPUTimeThreadSampling::out_of_stack_walking_iterations() { + if (_instance != nullptr && _instance->_sampler != nullptr) { + return _instance->_sampler->out_of_stack_walking_iterations(); + } + return 0; +} +#endif + void JfrCPUSamplerThread::sample_thread(JfrSampleRequest& request, void* ucontext, JavaThread* jt, JfrThreadLocal* tl, JfrTicks& now) { JfrSampleRequestBuilder::build_cpu_time_sample_request(request, ucontext, jt, jt->jfr_thread_local(), now); } @@ -590,6 +646,7 @@ void JfrCPUSamplerThread::handle_timer_signal(siginfo_t* info, void* context) { } } else { queue.increment_lost_samples(); + queue.increment_lost_samples_due_to_queue_full(); } if (jt->thread_state() == _thread_in_native) { @@ -807,4 +864,10 @@ void JfrCPUTimeThreadSampling::on_javathread_create(JavaThread* thread) { void JfrCPUTimeThreadSampling::on_javathread_terminate(JavaThread* thread) { } +#ifdef ASSERT +static void set_out_of_stack_walking_enabled(bool runnable) { + warn(); +} +#endif + #endif // defined(LINUX) && defined(INCLUDE_JFR) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index dae0be5c3a7..e17e63fc3ed 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -50,12 +50,15 @@ class JfrCPUTimeTraceQueue { static const u4 CPU_TIME_QUEUE_CAPACITY = 500; JfrCPUTimeSampleRequest* _data; - u4 _capacity; + volatile u4 _capacity; // next unfilled index volatile u4 _head; volatile u4 _lost_samples; + volatile u4 _lost_samples_due_to_queue_full; + static const u4 CPU_TIME_QUEUE_INITIAL_CAPACITY = 20; + static const u4 CPU_TIME_QUEUE_MAX_CAPACITY = 2000; public: JfrCPUTimeTraceQueue(u4 capacity); @@ -81,12 +84,17 @@ public: void increment_lost_samples(); + void increment_lost_samples_due_to_queue_full(); + // returns the previous lost samples count u4 get_and_reset_lost_samples(); - void resize(u4 capacity); + u4 get_and_reset_lost_samples_due_to_queue_full(); - void resize_for_period(u4 period_millis); + void resize_if_needed(); + + // init the queue capacity + void init(); void clear(); @@ -130,6 +138,10 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj { static void send_lost_event(const JfrTicks& time, traceid tid, s4 lost_samples); static void trigger_async_processing_of_cpu_time_jfr_requests(); + + DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable);) + + DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) }; #else @@ -150,6 +162,8 @@ private: static void on_javathread_create(JavaThread* thread); static void on_javathread_terminate(JavaThread* thread); + DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable)); + DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) }; #endif // defined(LINUX) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp index ddc9d59b295..f7a725fce6d 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampling.cpp @@ -368,6 +368,7 @@ static void drain_enqueued_cpu_time_requests(const JfrTicks& now, JfrThreadLocal tl->set_has_cpu_time_jfr_requests(false); if (queue.lost_samples() > 0) { JfrCPUTimeThreadSampling::send_lost_event( now, JfrThreadLocal::thread_id(jt), queue.get_and_reset_lost_samples()); + queue.resize_if_needed(); } if (lock) { tl->release_cpu_time_jfr_queue_lock(); diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp index 291169b9aa7..037faee1b9f 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp @@ -656,7 +656,7 @@ JfrCPUTimeTraceQueue& JfrThreadLocal::cpu_time_jfr_queue() { } void JfrThreadLocal::deallocate_cpu_time_jfr_queue() { - cpu_time_jfr_queue().resize(0); + cpu_time_jfr_queue().set_capacity(0); } void JfrThreadLocal::set_do_async_processing_of_cpu_time_jfr_requests(bool wants) { diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index cbb135a82d9..4b3583edf51 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -46,6 +46,7 @@ #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/gcConfig.hpp" #include "gc/shared/genArguments.hpp" +#include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jvm.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" @@ -2660,6 +2661,32 @@ WB_ENTRY(void, WB_WaitUnsafe(JNIEnv* env, jobject wb, jint time)) os::naked_short_sleep(time); WB_END +WB_ENTRY(void, WB_BusyWait(JNIEnv* env, jobject wb, jint time)) + ThreadToNativeFromVM ttn(thread); + u8 start = os::current_thread_cpu_time(); + u8 target_duration = time * (u8)1000000; + while (os::current_thread_cpu_time() - start < target_duration) { + for (volatile int i = 0; i < 1000000; i++); + } +WB_END + +WB_ENTRY(jboolean, WB_CPUSamplerSetOutOfStackWalking(JNIEnv* env, jobject wb, jboolean enable)) + #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) + JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE); + return JNI_TRUE; + #else + return JNI_FALSE; + #endif +WB_END + +WB_ENTRY(jlong, WB_CPUSamplerOutOfStackWalkingIterations(JNIEnv* env, jobject wb)) + #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) + return (jlong)JfrCPUTimeThreadSampling::out_of_stack_walking_iterations(); + #else + return 0; + #endif +WB_END + WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o)) ThreadToNativeFromVM ttn(thread); jstring info_string = env->NewStringUTF(XSTR(LIBC)); @@ -3013,6 +3040,9 @@ static JNINativeMethod methods[] = { {CC"isJVMTIIncluded", CC"()Z", (void*)&WB_IsJVMTIIncluded}, {CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe}, + {CC"busyWait", CC"(I)V", (void*)&WB_BusyWait}, + {CC"cpuSamplerSetOutOfStackWalking", CC"(Z)Z", (void*)&WB_CPUSamplerSetOutOfStackWalking}, + {CC"cpuSamplerOutOfStackWalkingIterations", CC"()J",(void*)&WB_CPUSamplerOutOfStackWalkingIterations}, {CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName}, {CC"pinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_PinObject}, diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java new file mode 100644 index 00000000000..1ea96e3bad3 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025 SAP SE. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.stream.Collectors; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.internal.JVM; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.whitebox.WhiteBox; + + +/* + * Tests the sample queues increase in size as needed, when loss is recorded. + * @test + * @requires vm.hasJFR & os.family == "linux" & vm.debug + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:StartFlightRecording:dumponexit=true jdk.jfr.event.profiling.TestCPUTimeSampleQueueAutoSizes + */ +public class TestCPUTimeSampleQueueAutoSizes { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final String BURST_THREAD_NAME = "Burst-Thread-1"; + + static volatile boolean alive = true; + + record LossEvent(long relativeTimeMillis, long lostSamples) {} + + /** A data collection from the CPUTimeSampleLost events for the burst thread */ + static class LossEventCollection { + private final List events = new ArrayList<>(); + + public synchronized void addEvent(LossEvent event) { + events.add(event); + } + + public synchronized List getSortedEvents() { + return events.stream() + .sorted(Comparator.comparingLong(e -> e.relativeTimeMillis)) + .collect(Collectors.toList()); + } + + public List getEventsPerInterval(long widthMillis, long stopTimeMillis) { + List ret = new ArrayList<>(); + for (long start = 0; start < stopTimeMillis; start += widthMillis) { + long actualStart = Math.min(start, stopTimeMillis - widthMillis); + long lostSamples = events.stream() + .filter(e -> e.relativeTimeMillis >= actualStart && e.relativeTimeMillis < actualStart + widthMillis) + .mapToLong(e -> e.lostSamples) + .sum(); + ret.add(new LossEvent(actualStart, lostSamples)); + } + return ret; + } + + } + + public static void main(String[] args) throws Exception { + try (RecordingStream rs = new RecordingStream()) { + // setup recording + AtomicLong firstSampleTimeMillis = new AtomicLong(0); + AtomicLong lastSampleTimeMillis = new AtomicLong(0); + LossEventCollection lossEvents = new LossEventCollection(); + rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); + rs.onEvent(EventNames.CPUTimeSample, e -> { + if (firstSampleTimeMillis.get() == 0 && e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + firstSampleTimeMillis.set(e.getStartTime().toEpochMilli()); + } + if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + lastSampleTimeMillis.set(e.getStartTime().toEpochMilli()); + } + }); + rs.enable(EventNames.CPUTimeSamplesLost); + rs.onEvent(EventNames.CPUTimeSamplesLost, e -> { + if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + long eventTime = e.getStartTime().toEpochMilli(); + long relativeTime = firstSampleTimeMillis.get() > 0 ? (eventTime - firstSampleTimeMillis.get()) : eventTime; + System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime); + lossEvents.addEvent(new LossEvent(relativeTime, e.getLong("lostSamples"))); + } + }); + WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + rs.startAsync(); + // this thread runs all along + Thread burstThread = new Thread(() -> WHITE_BOX.busyWait(11000)); + burstThread.setName(BURST_THREAD_NAME); + burstThread.start(); + // now we toggle out-of-stack-walking off, wait 1 second and then turn it on for 500ms a few times + for (int i = 0; i < 5; i++) { + boolean supported = WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + if (!supported) { + System.out.println("Out-of-stack-walking not supported, skipping test"); + Asserts.assertFalse(true); + return; + } + Thread.sleep(700); + long iterations = WHITE_BOX.cpuSamplerOutOfStackWalkingIterations(); + WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); + Thread.sleep(300); + while (WHITE_BOX.cpuSamplerOutOfStackWalkingIterations() == iterations) { + Thread.sleep(50); // just to make sure the stack walking really ran + } + } + rs.close(); + checkThatLossDecreased(lossEvents, lastSampleTimeMillis.get() - firstSampleTimeMillis.get()); + } + } + + static void checkThatLossDecreased(LossEventCollection lossEvents, long lastSampleTimeMillis) { + List intervalLosses = lossEvents.getEventsPerInterval(1000, lastSampleTimeMillis); + for (LossEvent interval : intervalLosses) { + System.out.println("Lost samples in interval " + interval.relativeTimeMillis + ": " + interval.lostSamples); + } + // check that there are at least 3 intervals + Asserts.assertTrue(intervalLosses.size() > 2); + // check that the second to last interval has far fewer lost samples than the first + Asserts.assertTrue(intervalLosses.get(intervalLosses.size() - 2).lostSamples < + intervalLosses.get(0).lostSamples / 2); + } +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index ce8b61b6393..5adb7bf5127 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -841,6 +841,13 @@ public class WhiteBox { public native void waitUnsafe(int time_ms); + public native void busyWait(int cpuTimeMs); + + // returns true if supported, false if not + public native boolean cpuSamplerSetOutOfStackWalking(boolean enable); + + public native long cpuSamplerOutOfStackWalkingIterations(); + public native void pinObject(Object o); public native void unpinObject(Object o); From a25dde6279c100dcff266d19b263e764f5da244e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 9 Sep 2025 10:58:21 +0000 Subject: [PATCH 427/471] 8365231: Don't build gtest with /EHsc Reviewed-by: kbarrett, stuefe --- make/hotspot/lib/CompileGtest.gmk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index d2cdc7685c9..30d3e3b524c 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -62,13 +62,13 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ DISABLED_WARNINGS_gcc := format-nonliteral maybe-uninitialized undef \ unused-result zero-as-null-pointer-constant, \ DISABLED_WARNINGS_clang := format-nonliteral undef unused-result, \ + DISABLED_WARNINGS_microsoft := 4530, \ DEFAULT_CFLAGS := false, \ CFLAGS := $(JVM_CFLAGS) \ -I$(GTEST_FRAMEWORK_SRC)/googletest \ -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ -I$(GTEST_FRAMEWORK_SRC)/googlemock \ -I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \ - CFLAGS_windows := -EHsc, \ CFLAGS_macosx := -DGTEST_OS_MAC=1, \ OPTIMIZATION := $(JVM_OPTIMIZATION), \ COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \ @@ -98,7 +98,6 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ -I$(GTEST_FRAMEWORK_SRC)/googlemock/include \ $(addprefix -I, $(GTEST_TEST_SRC)), \ - CFLAGS_windows := -EHsc, \ CFLAGS_macosx := -DGTEST_OS_MAC=1, \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \ undef stringop-overflow, \ @@ -110,7 +109,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ self-assign-overloaded, \ DISABLED_WARNINGS_clang_test_g1ServiceThread.cpp := delete-abstract-non-virtual-dtor, \ DISABLED_WARNINGS_clang_test_logDecorations.cpp := missing-field-initializers, \ - DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \ + DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) 4530, \ LD_SET_ORIGIN := false, \ DEFAULT_LDFLAGS := false, \ LDFLAGS := $(JVM_LDFLAGS), \ From a1ab12b77266c7124a297e1b2e0a8608b8facb2a Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 9 Sep 2025 11:17:33 +0000 Subject: [PATCH 428/471] 8366854: Extend jtreg failure handler with THP info Reviewed-by: ayang, shade, tschatzl, lmesnik, sjohanss --- test/failure_handler/src/share/conf/linux.properties | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/failure_handler/src/share/conf/linux.properties b/test/failure_handler/src/share/conf/linux.properties index 44d96620ad0..08e4ea8bd87 100644 --- a/test/failure_handler/src/share/conf/linux.properties +++ b/test/failure_handler/src/share/conf/linux.properties @@ -78,6 +78,8 @@ environment=\ process.top process.ps \ memory.free memory.vmstat.default memory.vmstat.statistics \ memory.vmstat.slabinfo memory.vmstat.disk \ + memory.proc_meminfo memory.proc_vmstat \ + memory.thp \ files \ locks \ net.sockets net.statistics net.ifconfig net.hostsfile \ @@ -115,6 +117,15 @@ memory.vmstat.default.args=3 3 memory.vmstat.statistics.args=-s memory.vmstat.slabinfo.args=-m memory.vmstat.disk.args=-d +memory.proc_meminfo.app=bash +memory.proc_meminfo.args=-c\0cat /proc/meminfo +memory.proc_meminfo.delimiter=\0 +memory.proc_vmstat.app=bash +memory.proc_vmstat.args=-c\0cat /proc/vmstat +memory.proc_vmstat.delimiter=\0 +memory.thp.app=bash +memory.thp.args=-c\0cat /sys/kernel/mm/transparent_hugepage/{enabled,defrag,shmem_enabled} +memory.thp.delimiter=\0 files.app=lsof locks.app=lslocks From 0632617670f991da23c3892d357e8d1f051d29a0 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 9 Sep 2025 11:17:48 +0000 Subject: [PATCH 429/471] 8367135: Test compiler/loopstripmining/CheckLoopStripMining.java needs internal timeouts adjusted Reviewed-by: thartmann, chagedorn --- .../compiler/loopstripmining/CheckLoopStripMining.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java index cdbf5affd01..3ed50619f77 100644 --- a/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java +++ b/test/hotspot/jtreg/compiler/loopstripmining/CheckLoopStripMining.java @@ -42,8 +42,8 @@ public class CheckLoopStripMining { "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", - "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(300), - "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(300), + "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(1200), + "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(1200), "-XX:-TieredCompilation", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", @@ -58,8 +58,8 @@ public class CheckLoopStripMining { "-XX:+SafepointTimeout", "-XX:+SafepointALot", "-XX:+AbortVMOnSafepointTimeout", - "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(300), - "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(300), + "-XX:SafepointTimeoutDelay=" + Utils.adjustTimeout(1200), + "-XX:GuaranteedSafepointInterval=" + Utils.adjustTimeout(1200), "-XX:-TieredCompilation", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000", From f10c85fbc336f6908a4f1ecae9fb5ab52984f636 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 9 Sep 2025 13:13:08 +0000 Subject: [PATCH 430/471] 8367027: java/lang/ProcessBuilder/Basic.java fails on Windows AArch64 Reviewed-by: rriggs --- test/jdk/java/lang/ProcessBuilder/Basic.java | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index c06ecbdb871..551a4869e86 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -212,7 +212,7 @@ public class Basic { private static String winEnvFilter(String env) { return env.replaceAll("\r", "") - .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n",""); + .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT|PROCESSOR_ARCHITECTURE)=.*\n",""); } private static String unixEnvProg() { @@ -811,6 +811,14 @@ public class Basic { return vars.replace("AIXTHREAD_GUARDPAGES=0,", ""); } + /* Only used for Windows AArch64 -- + * Windows AArch64 adds the variable PROCESSOR_ARCHITECTURE=ARM64 to the environment. + * Remove it from the list of env variables + */ + private static String removeWindowsAArch64ExpectedVars(String vars) { + return vars.replace("PROCESSOR_ARCHITECTURE=ARM64,", ""); + } + private static String sortByLinesWindowsly(String text) { String[] lines = text.split("\n"); Arrays.sort(lines, new WindowsComparator()); @@ -1321,6 +1329,9 @@ public class Basic { if (AIX.is()) { result = removeAixExpectedVars(result); } + if (Windows.is() && Platform.isAArch64()) { + result = removeWindowsAArch64ExpectedVars(result); + } equal(result, expected); } catch (Throwable t) { unexpected(t); } @@ -1833,6 +1844,9 @@ public class Basic { if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } equal(commandOutput, expected); if (Windows.is()) { ProcessBuilder pb = new ProcessBuilder(childArgs); @@ -1840,7 +1854,11 @@ public class Basic { pb.environment().put("SystemRoot", systemRoot); pb.environment().put("=ExitValue", "3"); pb.environment().put("=C:", "\\"); - equal(commandOutput(pb), expected); + commandOutput = commandOutput(pb); + if (Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } + equal(commandOutput, expected); } } catch (Throwable t) { unexpected(t); } @@ -1892,6 +1910,9 @@ public class Basic { if (AIX.is()) { commandOutput = removeAixExpectedVars(commandOutput); } + if (Windows.is() && Platform.isAArch64()) { + commandOutput = removeWindowsAArch64ExpectedVars(commandOutput); + } check(commandOutput.equals(Windows.is() ? "LC_ALL=C,SystemRoot="+systemRoot+"," : AIX.is() From b653ae92d5941202780873fad1a7cefd51e4e7a8 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 9 Sep 2025 15:02:54 +0000 Subject: [PATCH 431/471] 8367051: Build failure with clang on linux and AIX after switch to C++17 Reviewed-by: dholmes, ayang, mbaesken, mdoerr --- src/hotspot/share/utilities/forbiddenFunctions.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp index a8dcba95a6d..871fff5b727 100644 --- a/src/hotspot/share/utilities/forbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -38,6 +38,15 @@ #include #endif +// Workaround for noexcept functions in glibc when using clang. +// clang errors if declaration without exception specification preceeds +// noexcept declaration, but not the other way around. +#ifdef __clang__ +#include +#include +#include +#endif + #ifdef _WINDOWS #include "forbiddenFunctions_windows.hpp" #else From cc6d34b2fa299a68a05e65e25c1f41dffa67c118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 9 Sep 2025 15:08:30 +0000 Subject: [PATCH 432/471] 8366971: C2: Remove unused nop_list from PhaseOutput::init_buffer Reviewed-by: epeter, dlong --- src/hotspot/cpu/aarch64/aarch64.ad | 3 --- src/hotspot/cpu/arm/arm.ad | 3 --- src/hotspot/cpu/ppc/ppc.ad | 4 ---- src/hotspot/cpu/riscv/riscv.ad | 3 --- src/hotspot/cpu/x86/x86_64.ad | 3 --- src/hotspot/share/adlc/adlparse.cpp | 32 ++--------------------------- src/hotspot/share/adlc/formsopt.cpp | 8 +------- src/hotspot/share/adlc/formsopt.hpp | 5 +---- src/hotspot/share/adlc/output_c.cpp | 14 +------------ src/hotspot/share/adlc/output_h.cpp | 6 ------ src/hotspot/share/opto/output.cpp | 7 +------ 11 files changed, 6 insertions(+), 82 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 33466453b76..e0459716122 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -5965,9 +5965,6 @@ attributes %{ instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 64; // The processor fetches one line instruction_fetch_units = 1; // of 64 bytes - - // List of nop instructions - nops( MachNop ); %} // We don't use an actual pipeline model so don't care about resources diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 3b6faa6c81a..45d51aaac57 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -2638,9 +2638,6 @@ attributes %{ instruction_unit_size = 4; // An instruction is 4 bytes long instruction_fetch_unit_size = 16; // The processor fetches one line instruction_fetch_units = 1; // of 16 bytes - - // List of nop instructions - nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR ); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index cd71e298b7d..290369360fc 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -4920,10 +4920,6 @@ attributes %{ // ...in one line instruction_fetch_units = 1 - - // Unused, list one so that array generated by adlc is not empty. - // Aix compiler chokes if _nop_count = 0. - nops(fxNop); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index eab19e74f93..0c4dd7b71e2 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -3845,9 +3845,6 @@ attributes %{ // ...in one line. instruction_fetch_units = 1; - - // List of nop instructions - nops( MachNop ); %} // We don't use an actual pipeline model so don't care about resources diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 932dc9e1ca7..0914bea82a1 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -3429,9 +3429,6 @@ attributes %{ instruction_unit_size = 1; // An instruction is 1 bytes long instruction_fetch_unit_size = 16; // The processor fetches one line instruction_fetch_units = 1; // of 16 bytes - - // List of nop instructions - nops( MachNop ); %} //----------RESOURCES---------------------------------------------------------- diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 033e8d26ca7..15dbf070674 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -1507,36 +1507,8 @@ void ADLParser::pipe_parse(void) { } if (!strcmp(ident, "nops")) { + parse_err(WARN, "Using obsolete token, nops"); skipws(); - if (_curchar != '(') { - parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar); - break; - } - - next_char(); skipws(); - - while (_curchar != ')') { - ident = get_ident(); - if (ident == nullptr) { - parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar); - break; - } - - pipeline->_noplist.addName(ident); - pipeline->_nopcnt++; - skipws(); - - if (_curchar == ',') { - next_char(); skipws(); - } - } - - next_char(); skipws(); - - if (_curchar == ';') { - next_char(); skipws(); - } - continue; } diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 5de8974e2c0..01fe6288c53 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -511,8 +511,6 @@ PipelineForm::PipelineForm() , _stagecnt (0) , _classlist () , _classcnt (0) - , _noplist () - , _nopcnt (0) , _variableSizeInstrs (false) , _branchHasDelaySlot (false) , _maxInstrsPerBundle (0) @@ -533,7 +531,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files const char *res; const char *stage; const char *cls; - const char *nop; int count = 0; fprintf(fp,"\nPipeline:"); @@ -574,9 +571,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files for ( _classlist.reset(); (cls = _classlist.iter()) != nullptr; ) _classdict[cls]->is_pipeclass()->output(fp); - fprintf(fp,"\nNop Instructions:"); - for ( _noplist.reset(); (nop = _noplist.iter()) != nullptr; ) - fprintf(fp, " \"%s\"", nop); fprintf(fp,"\n"); } diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index d183a46b875..db7b9dbd8d8 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. 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 @@ -386,9 +386,6 @@ public: FormDict _classdict; // Class Name -> PipeClassForm mapping int _classcnt; // Number of classes - NameList _noplist; // List of NOP instructions - int _nopcnt; // Number of nop instructions - bool _variableSizeInstrs; // Indicates if this architecture has variable sized instructions bool _branchHasDelaySlot; // Indicates that branches have delay slot instructions int _maxInstrsPerBundle; // Indicates the maximum number of instructions for ILP diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 0620f2f4496..abebf39a2b2 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -977,18 +977,6 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { } fprintf(fp_cpp, "}\n\n"); - // Output the list of nop nodes - fprintf(fp_cpp, "// Descriptions for emitting different functional unit nops\n"); - const char *nop; - int nopcnt = 0; - for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != nullptr; nopcnt++ ); - - fprintf(fp_cpp, "void Bundle::initialize_nops(MachNode * nop_list[%d]) {\n", nopcnt); - int i = 0; - for ( _pipeline->_noplist.reset(); (nop = _pipeline->_noplist.iter()) != nullptr; i++ ) { - fprintf(fp_cpp, " nop_list[%d] = (MachNode *) new %sNode();\n", i, nop); - } - fprintf(fp_cpp, "};\n\n"); fprintf(fp_cpp, "#ifndef PRODUCT\n"); fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n"); fprintf(fp_cpp, " static const char * bundle_flags[] = {\n"); @@ -1004,7 +992,7 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount); // Don't add compound resources to the list of resource names const char* resource; - i = 0; + int i = 0; for (_pipeline->_reslist.reset(); (resource = _pipeline->_reslist.iter()) != nullptr;) { if (_pipeline->_resdict[resource]->is_resource()->is_discrete()) { fprintf(fp_cpp, " \"%s\"%c", resource, i < _pipeline->_rescount - 1 ? ',' : ' '); diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index cbcc00efa3b..78cf5ea7988 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -1115,12 +1115,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " bool use_delay() { return ((_flags & _use_delay) != 0); }\n"); fprintf(fp_hpp, " bool used_in_delay() { return ((_flags & _used_in_delay) != 0); }\n\n"); - fprintf(fp_hpp, " enum {\n"); - fprintf(fp_hpp, " _nop_count = %d\n", - _pipeline->_nopcnt); - fprintf(fp_hpp, " };\n\n"); - fprintf(fp_hpp, " static void initialize_nops(MachNode *nop_list[%d]);\n\n", - _pipeline->_nopcnt); fprintf(fp_hpp, "#ifndef PRODUCT\n"); fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n"); fprintf(fp_hpp, "#endif\n"); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 124b00a6549..9a6970ebf20 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -1399,10 +1399,6 @@ CodeBuffer* PhaseOutput::init_buffer() { cb->initialize_stubs_size(stub_req); cb->initialize_oop_recorder(C->env()->oop_recorder()); - // fill in the nop array for bundling computations - MachNode *_nop_list[Bundle::_nop_count]; - Bundle::initialize_nops(_nop_list); - return cb; } @@ -2062,8 +2058,7 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) // Create a MachNopNode _nop = new MachNopNode(); - // Now that the nops are in the array, save the count - // (but allow entries for the nops) + // Save the count _node_bundling_limit = compile.unique(); uint node_max = _regalloc->node_regs_max_index(); From a12e9fcebda1d7b75cb892e7920333d73fb5de9c Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 9 Sep 2025 19:37:57 +0000 Subject: [PATCH 433/471] 8366261: Provide utility methods for sun.security.util.Password Reviewed-by: smarks, weijun --- .../share/classes/java/io/Console.java | 26 +++++++++-- .../jdk/internal/access/JavaIOAccess.java | 3 +- .../jdk/internal/io/JdkConsoleImpl.java | 43 ++++++++++++++++++- .../unix/native/libjava/Console_md.c | 19 ++++++-- .../windows/native/libjava/Console_md.c | 27 +++++++----- .../java/io/Console/ModuleSelectionTest.java | 13 +++--- 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 2878de79718..96df4c5fd24 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -25,6 +25,7 @@ package java.io; +import java.lang.annotation.Native; import java.util.*; import java.nio.charset.Charset; import jdk.internal.access.JavaIOAccess; @@ -550,7 +551,12 @@ public sealed class Console implements Flushable permits ProxyingConsole { "Console class itself does not provide implementation"); } - private static final boolean istty = istty(); + @Native static final int TTY_STDIN_MASK = 0x00000001; + @Native static final int TTY_STDOUT_MASK = 0x00000002; + @Native static final int TTY_STDERR_MASK = 0x00000004; + // ttyStatus() returns bit patterns above, a bit is set if the corresponding file + // descriptor is a character device + private static final int ttyStatus = ttyStatus(); private static final Charset STDIN_CHARSET = Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE); private static final Charset STDOUT_CHARSET = @@ -562,6 +568,9 @@ public sealed class Console implements Flushable permits ProxyingConsole { public Console console() { return cons; } + public boolean isStdinTty() { + return Console.isStdinTty(); + } }); } @@ -583,7 +592,7 @@ public sealed class Console implements Flushable permits ProxyingConsole { for (var jcp : ServiceLoader.load(ModuleLayer.boot(), JdkConsoleProvider.class)) { if (consModName.equals(jcp.getClass().getModule().getName())) { - var jc = jcp.console(istty, STDIN_CHARSET, STDOUT_CHARSET); + var jc = jcp.console(isStdinTty() && isStdoutTty(), STDIN_CHARSET, STDOUT_CHARSET); if (jc != null) { c = new ProxyingConsole(jc); } @@ -594,12 +603,21 @@ public sealed class Console implements Flushable permits ProxyingConsole { } // If not found, default to built-in Console - if (istty && c == null) { + if (isStdinTty() && isStdoutTty() && c == null) { c = new ProxyingConsole(new JdkConsoleImpl(STDIN_CHARSET, STDOUT_CHARSET)); } return c; } - private static native boolean istty(); + private static boolean isStdinTty() { + return (ttyStatus & TTY_STDIN_MASK) != 0; + } + private static boolean isStdoutTty() { + return (ttyStatus & TTY_STDOUT_MASK) != 0; + } + private static boolean isStderrTty() { + return (ttyStatus & TTY_STDERR_MASK) != 0; + } + private static native int ttyStatus(); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java index 532c1f259d4..bdeb2282a02 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaIOAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -29,4 +29,5 @@ import java.io.Console; public interface JavaIOAccess { Console console(); + boolean isStdinTty(); } diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index ec94d4ec4d6..c9c6b53fcda 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -38,10 +38,13 @@ import java.util.Arrays; import java.util.Formatter; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.StaticProperty; import sun.nio.cs.StreamDecoder; import sun.nio.cs.StreamEncoder; +import sun.nio.cs.UTF_8; /** * JdkConsole implementation based on the platform's TTY. @@ -103,6 +106,42 @@ public final class JdkConsoleImpl implements JdkConsole { @Override public char[] readPassword(Locale locale, String format, Object ... args) { + return readPassword0(false, locale, format, args); + } + + // These two methods are intended for sun.security.util.Password, so tools like keytool can + // use JdkConsoleImpl even when standard output is redirected. The Password class should first + // check if `System.console()` returns a Console instance and use it if available. Otherwise, + // it should call this method to obtain a JdkConsoleImpl. This ensures only one Console + // instance exists in the Java runtime. + private static final StableValue> INSTANCE = StableValue.of(); + public static Optional passwordConsole() { + return INSTANCE.orElseSet(() -> { + // If there's already a proper console, throw an exception + if (System.console() != null) { + throw new IllegalStateException("Can’t create a dedicated password " + + "console since a real console already exists"); + } + + // If stdin is NOT redirected, return an Optional containing a JdkConsoleImpl + // instance, otherwise an empty Optional. + return SharedSecrets.getJavaIOAccess().isStdinTty() ? + Optional.of( + new JdkConsoleImpl( + Charset.forName(StaticProperty.stdinEncoding(), UTF_8.INSTANCE), + Charset.forName(StaticProperty.stdoutEncoding(), UTF_8.INSTANCE))) : + Optional.empty(); + }); + } + + // Dedicated entry for sun.security.util.Password when stdout is redirected. + // This method strictly avoids producing any output by using noNewLine = true + // and an empty format string. + public char[] readPasswordNoNewLine() { + return readPassword0(true, Locale.getDefault(Locale.Category.FORMAT), ""); + } + + private char[] readPassword0(boolean noNewLine, Locale locale, String format, Object ... args) { char[] passwd = null; synchronized (writeLock) { synchronized(readLock) { @@ -146,7 +185,9 @@ public final class JdkConsoleImpl implements JdkConsole { throw ioe; } } - pw.println(); + if (!noNewLine) { + pw.println(); + } } } return passwd; diff --git a/src/java.base/unix/native/libjava/Console_md.c b/src/java.base/unix/native/libjava/Console_md.c index 1e71ab3a6b2..17643779b31 100644 --- a/src/java.base/unix/native/libjava/Console_md.c +++ b/src/java.base/unix/native/libjava/Console_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -31,8 +31,19 @@ #include #include -JNIEXPORT jboolean JNICALL -Java_java_io_Console_istty(JNIEnv *env, jclass cls) +JNIEXPORT jint JNICALL +Java_java_io_Console_ttyStatus(JNIEnv *env, jclass cls) { - return isatty(fileno(stdin)) && isatty(fileno(stdout)); + jint ret = 0; + + if (isatty(fileno(stdin))) { + ret |= java_io_Console_TTY_STDIN_MASK; + } + if (isatty(fileno(stdout))) { + ret |= java_io_Console_TTY_STDOUT_MASK; + } + if (isatty(fileno(stderr))) { + ret |= java_io_Console_TTY_STDERR_MASK; + } + return ret; } diff --git a/src/java.base/windows/native/libjava/Console_md.c b/src/java.base/windows/native/libjava/Console_md.c index f73e62f8e26..07749f2775a 100644 --- a/src/java.base/windows/native/libjava/Console_md.c +++ b/src/java.base/windows/native/libjava/Console_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. 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 @@ -31,21 +31,28 @@ #include #include -JNIEXPORT jboolean JNICALL -Java_java_io_Console_istty(JNIEnv *env, jclass cls) +JNIEXPORT jint JNICALL +Java_java_io_Console_ttyStatus(JNIEnv *env, jclass cls) { + jint ret = 0; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE); - if (hStdIn == INVALID_HANDLE_VALUE || - hStdOut == INVALID_HANDLE_VALUE) { - return JNI_FALSE; + if (hStdIn != INVALID_HANDLE_VALUE && + GetFileType(hStdIn) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDIN_MASK; } - if (GetFileType(hStdIn) != FILE_TYPE_CHAR || - GetFileType(hStdOut) != FILE_TYPE_CHAR) { - return JNI_FALSE; + if (hStdOut != INVALID_HANDLE_VALUE && + GetFileType(hStdOut) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDOUT_MASK; } - return JNI_TRUE; + if (hStdErr != INVALID_HANDLE_VALUE && + GetFileType(hStdErr) == FILE_TYPE_CHAR) { + ret |= java_io_Console_TTY_STDERR_MASK; + } + + return ret; } diff --git a/test/jdk/java/io/Console/ModuleSelectionTest.java b/test/jdk/java/io/Console/ModuleSelectionTest.java index 332acf83fbd..f5f02ae13f4 100644 --- a/test/jdk/java/io/Console/ModuleSelectionTest.java +++ b/test/jdk/java/io/Console/ModuleSelectionTest.java @@ -21,9 +21,9 @@ * questions. */ -/** +/* * @test - * @bug 8295803 8299689 8351435 8361613 + * @bug 8295803 8299689 8351435 8361613 8366261 * @summary Tests System.console() returns correct Console (or null) from the expected * module. * @library /test/lib @@ -92,9 +92,12 @@ public class ModuleSelectionTest { var con = System.console(); var pc = Class.forName("java.io.ProxyingConsole"); var jdkc = Class.forName("jdk.internal.io.JdkConsole"); - var istty = (boolean)MethodHandles.privateLookupIn(Console.class, MethodHandles.lookup()) - .findStatic(Console.class, "istty", MethodType.methodType(boolean.class)) - .invoke(); + var lookup = MethodHandles.privateLookupIn(Console.class, MethodHandles.lookup()); + var istty = (boolean)lookup.findStatic(Console.class, "isStdinTty", MethodType.methodType(boolean.class)) + .invoke() && + (boolean)lookup.findStatic(Console.class, "isStdoutTty", MethodType.methodType(boolean.class)) + .invoke(); + var impl = con != null ? MethodHandles.privateLookupIn(pc, MethodHandles.lookup()) .findGetter(pc, "delegate", jdkc) .invoke(con) : null; From 24a734938e555882857cf0b06ea693ec6f18085f Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 9 Sep 2025 22:03:25 +0000 Subject: [PATCH 434/471] 8366733: Re-examine older java.text NF, DF, and DFS serialization tests Reviewed-by: naoto --- .../DecimalFormat/DFSSerializationTest.java | 90 ++++- .../DecimalFormat.114.txt | 0 .../DecimalFormatSymbols.114.txt | 0 .../DecimalFormatSymbols.142.txt | 0 .../NumberFormat4185761a.ser.txt | 0 .../NumberFormat4185761b.ser.txt | 0 .../DecimalFormat/SerializationTest.java | 355 ++++++++++++++++-- .../NumberFormat/DFSDeserialization142.java | 56 --- .../Format/NumberFormat/DFSSerialization.java | 162 -------- .../NumberFormat/DFSSerialization142.java | 54 --- .../Format/NumberFormat/NumberRegression.java | 101 +---- .../NumberFormat/SerializationLoadTest.java | 89 ----- .../NumberFormat/SerializationSaveTest.java | 81 ---- 13 files changed, 397 insertions(+), 591 deletions(-) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormat.114.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormatSymbols.114.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/DecimalFormatSymbols.142.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/NumberFormat4185761a.ser.txt (100%) rename test/jdk/java/text/Format/{NumberFormat => DecimalFormat}/NumberFormat4185761b.ser.txt (100%) delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSSerialization.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java delete mode 100644 test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java diff --git a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java index 9e875e851c8..d4ccb77c137 100644 --- a/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/DFSSerializationTest.java @@ -23,7 +23,9 @@ /* * @test - * @bug 8366401 + * @bug 4068067 4101150 8366401 + * @library /java/text/testlib + * @build HexDumpReader * @summary Check serialization of DecimalFormatSymbols. That is, ensure the * behavior for each stream version is correct during de-serialization. * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED DFSSerializationTest @@ -35,9 +37,11 @@ import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.reflect.Field; import java.text.DecimalFormatSymbols; import java.util.Currency; @@ -51,13 +55,36 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class DFSSerializationTest { + // Test that rely on hex dump files that were written from older JDK versions @Nested - class VersionTests { + class HexDumpTests { + + @Test // See 4068067 and CDFS which is the class in the serialized hex dump + void JDK1_1_4Test() { + // Reconstruct a class serialized during 1.1.4 which has a DFS holder + var cdfs = (CheckDecimalFormatSymbols) assertDoesNotThrow( + () -> deSer("DecimalFormatSymbols.114.txt")); + assertDoesNotThrow(cdfs::Update); // Checks getDigit call succeeds + } + + @Test // See 4068067 + void JDK1_4_2Test() { + // Reconstruct a 1.4.2 DFS + var dfs = (DecimalFormatSymbols) assertDoesNotThrow( + () -> deSer("DecimalFormatSymbols.142.txt")); + // Checks curr symbol is saved, and exponent separator default set + assertEquals("E", dfs.getExponentSeparator()); + assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol()); + } + } + + @Nested + class StreamVersionTests { // Ensure correct monetarySeparator and exponential field defaults // Reads monetary from decimal, and sets exponential to 'E' @Test - public void version0Test() { + void version0Test() { var crafted = new DFSBuilder() .setVer(0) .set("monetarySeparator", '~') @@ -76,7 +103,7 @@ public class DFSSerializationTest { // Note that other versions did allow a locale field, which was nullable. // E.g. see nullableLocaleTest which does not set locale when it is `null` @Test - public void version1Test() { + void version1Test() { var crafted = new DFSBuilder() .setVer(1) .set("locale", null) @@ -89,7 +116,7 @@ public class DFSSerializationTest { // Version 2 did not have an exponential separator, and created it via exponent // char field. @Test - public void version2Test() { + void version2Test() { var crafted = new DFSBuilder() .setVer(2) .set("exponentialSeparator", null) @@ -103,7 +130,7 @@ public class DFSSerializationTest { // Version 3 didn't have perMillText, percentText, and minusSignText. // These were created from the corresponding char equivalents. @Test - public void version3Test() { + void version3Test() { var crafted = new DFSBuilder() .setVer(3) .set("perMillText", null) @@ -125,7 +152,7 @@ public class DFSSerializationTest { // Version 4 did not have monetaryGroupingSeparator. It should be based // off of groupingSeparator. @Test - public void version4Test() { + void version4Test() { var crafted = new DFSBuilder() .setVer(4) .set("monetaryGroupingSeparator", 'Z') @@ -142,7 +169,7 @@ public class DFSSerializationTest { // the case and previous stream versions can contain a null locale. Thus, // ensure that a null locale does not cause number data loading to fail. @Test - public void nullableLocaleTest() { + void nullableLocaleTest() { var bytes = ser(new DFSBuilder() .set("locale", null) .set("minusSignText", "zFoo") @@ -157,7 +184,7 @@ public class DFSSerializationTest { // readObject fails when the {@code char} and {@code String} representations // of percent, per mille, and/or minus sign disagree. @Test - public void disagreeingTextTest() { + void disagreeingTextTest() { var expected = "'char' and 'String' representations of either percent, " + "per mille, and/or minus sign disagree."; assertEquals(expected, assertThrows(InvalidObjectException.class, () -> @@ -179,7 +206,7 @@ public class DFSSerializationTest { // Ensure the serial version is updated to the current after de-serialization. @Test - public void updatedVersionTest() { + void updatedVersionTest() { var bytes = ser(new DFSBuilder().setVer(-25).build()); var dfs = assertDoesNotThrow(() -> deSer(bytes)); assertEquals(5, readField(dfs, "serialVersionOnStream")); @@ -187,7 +214,7 @@ public class DFSSerializationTest { // Should set currency from 4217 code when it is valid. @Test - public void validIntlCurrencyTest() { + void validIntlCurrencyTest() { var bytes = ser(new DFSBuilder().set("intlCurrencySymbol", "JPY").build()); var dfs = assertDoesNotThrow(() -> deSer(bytes)); assertEquals(Currency.getInstance("JPY"), dfs.getCurrency()); @@ -195,7 +222,7 @@ public class DFSSerializationTest { // Should not set currency when 4217 code is invalid, it remains null. @Test - public void invalidIntlCurrencyTest() { + void invalidIntlCurrencyTest() { var bytes = ser(new DFSBuilder() .set("intlCurrencySymbol", ">.,") .set("locale", Locale.JAPAN) @@ -205,6 +232,26 @@ public class DFSSerializationTest { assertNull(dfs.getCurrency()); } + // Ensure the currency symbol is read properly + @Test + void currencySymbolTest() { + var crafted = new DecimalFormatSymbols(); + crafted.setCurrencySymbol("*SpecialCurrencySymbol*"); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("*SpecialCurrencySymbol*", dfs.getCurrencySymbol()); + } + + // Ensure the exponent separator is read properly + @Test + void exponentSeparatorTest() { + var crafted = new DecimalFormatSymbols(); + crafted.setExponentSeparator("*SpecialExponentSeparator*"); + var bytes = ser(crafted); + var dfs = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals("*SpecialExponentSeparator*", dfs.getExponentSeparator()); + } + // Utilities ---- // Utility to serialize @@ -218,7 +265,7 @@ public class DFSSerializationTest { }, "Unexpected error during serialization"); } - // Utility to deserialize + // Utility to deserialize from byte array private static DecimalFormatSymbols deSer(byte[] bytes) throws IOException, ClassNotFoundException { try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { @@ -226,6 +273,14 @@ public class DFSSerializationTest { } } + // Utility to deserialize from file in hex format + private static Object deSer(String file) throws IOException, ClassNotFoundException { + try (InputStream stream = HexDumpReader.getStreamFromHexDump(file); + ObjectInputStream ois = new ObjectInputStream(stream)) { + return ois.readObject(); + } + } + // Utility to read a private field private static Object readField(DecimalFormatSymbols dfs, String name) { return assertDoesNotThrow(() -> { @@ -262,3 +317,12 @@ public class DFSSerializationTest { } } } + +// Not nested, so that it can be cast correctly for the 1.1.4 test +class CheckDecimalFormatSymbols implements Serializable { + DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); + public char Update() + { + return _decFormatSymbols.getDigit(); + } +} diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormat.114.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormat.114.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormat.114.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormat.114.txt diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.114.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.114.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.114.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.114.txt diff --git a/test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.142.txt b/test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.142.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/DecimalFormatSymbols.142.txt rename to test/jdk/java/text/Format/DecimalFormat/DecimalFormatSymbols.142.txt diff --git a/test/jdk/java/text/Format/NumberFormat/NumberFormat4185761a.ser.txt b/test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761a.ser.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/NumberFormat4185761a.ser.txt rename to test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761a.ser.txt diff --git a/test/jdk/java/text/Format/NumberFormat/NumberFormat4185761b.ser.txt b/test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761b.ser.txt similarity index 100% rename from test/jdk/java/text/Format/NumberFormat/NumberFormat4185761b.ser.txt rename to test/jdk/java/text/Format/DecimalFormat/NumberFormat4185761b.ser.txt diff --git a/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java b/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java index 09e3f6cf809..6a639b8fea1 100644 --- a/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/SerializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. 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 @@ -22,65 +22,344 @@ */ /* * @test - * @bug 8327640 - * @summary Check parseStrict correctness for DecimalFormat serialization - * @run junit/othervm SerializationTest + * @bug 4069754 4067878 4101150 4185761 8327640 + * @library /java/text/testlib + * @build HexDumpReader + * @summary Check de-serialization correctness for DecimalFormat. That is, ensure the + * behavior for each stream version is correct during de-serialization. + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED SerializationTest */ -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.math.RoundingMode; +import java.text.DateFormat; +import java.text.DecimalFormat; import java.text.NumberFormat; -import java.text.ParseException; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Random; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SerializationTest { - private static final NumberFormat FORMAT = NumberFormat.getInstance(); + @Nested // Test that rely on hex dump files that were written from older JDK versions + class HexDumpTests { - @BeforeAll - public static void mutateFormat() { - FORMAT.setStrict(true); - } + @Test // See 4101150 and CDF which is the serialized hex dump + void JDK1_1_4Test() { + // Reconstruct a 1.1.4 serializable class which has a DF holder + var cdf = (CheckDecimalFormat) assertDoesNotThrow( + () -> deSer("DecimalFormat.114.txt")); + assertDoesNotThrow(cdf::Update); // Checks format call succeeds + } - @Test - public void testSerialization() throws IOException, ClassNotFoundException { - // Serialize - serialize("fmt.ser", FORMAT); - // Deserialize - deserialize("fmt.ser", FORMAT); - } + @Test // See 4185761 + void minMaxDigitsTest() { + // Reconstructing a DFS stream from an older JDK version + // The min digits are smaller than the max digits and should fail + // minint maxint minfrac maxfrac + // 0x122 0x121 0x124 0x123 + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, + () -> deSer("NumberFormat4185761a.ser.txt")).getMessage()); + } - private void serialize(String fileName, NumberFormat... formats) - throws IOException { - try (ObjectOutputStream os = new ObjectOutputStream( - new FileOutputStream(fileName))) { - for (NumberFormat fmt : formats) { - os.writeObject(fmt); - } + @Test // See 4185761 + void digitLimitTest() { + // Reconstructing a DFS stream from an older JDK version + // The digit values exceed the class invariant limits + // minint maxint minfrac maxfrac + // 0x311 0x312 0x313 0x314 + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, + () -> deSer("NumberFormat4185761b.ser.txt")).getMessage()); } } - private static void deserialize(String fileName, NumberFormat... formats) - throws IOException, ClassNotFoundException { - try (ObjectInputStream os = new ObjectInputStream( - new FileInputStream(fileName))) { - for (NumberFormat fmt : formats) { - NumberFormat obj = (NumberFormat) os.readObject(); - assertEquals(fmt, obj, "Serialized and deserialized" - + " objects do not match"); + @Nested + class VersionTests { - String badNumber = "fooofooo23foo"; - assertThrows(ParseException.class, () -> fmt.parse(badNumber)); - assertThrows(ParseException.class, () -> obj.parse(badNumber)); + // Version 0 did not have exponential fields and defaulted the value to false + @Test + void version0Test() { + var crafted = new DFBuilder() + .setVer(0) + .set("useExponentialNotation", true) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + // Ensure we do not observe exponential notation form + assertFalse(df.format(0).contains("E")); + } + + // Version 1 did not support the affix pattern Strings. Ensure when they + // are read in from the stream they are not defaulted and remain null. + @Test + void version1Test() { + var crafted = new DFBuilder() + .setVer(1) + .set("posPrefixPattern", null) + .set("posSuffixPattern", null) + .set("negPrefixPattern", null) + .set("negSuffixPattern", null) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertNull(readField(df, "posPrefixPattern")); + assertNull(readField(df, "posSuffixPattern")); + assertNull(readField(df, "negPrefixPattern")); + assertNull(readField(df, "negSuffixPattern")); + } + + // Version 2 did not support the min/max int and frac digits. + // Ensure the proper defaults are set. + @Test + void version2Test() { + var crafted = new DFBuilder() + .setVer(2) + .set("maximumIntegerDigits", -1) + .set("maximumFractionDigits", -1) + .set("minimumIntegerDigits", -1) + .set("minimumFractionDigits", -1) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(1, df.getMinimumIntegerDigits()); + assertEquals(3, df.getMaximumFractionDigits()); + assertEquals(309, df.getMaximumIntegerDigits()); + assertEquals(0, df.getMinimumFractionDigits()); + } + + // Version 3 did not support rounding mode. Should default to HALF_EVEN + @Test + void version3Test() { + var crafted = new DFBuilder() + .setVer(3) + .set("roundingMode", RoundingMode.UNNECESSARY) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(RoundingMode.HALF_EVEN, df.getRoundingMode()); + } + } + + // Some invariant checking in DF relies on checking NF fields. + // Either via NF.readObject() or through super calls in DF.readObject + @Nested // For all these nested tests, see 4185761 + class NumberFormatTests { + + // Ensure the max integer value invariant is not exceeded + @Test + void integerTest() { + var crafted = new DFBuilder() + .setSuper("maximumIntegerDigits", 786) + .setSuper("minimumIntegerDigits", 785) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the max fraction value invariant is not exceeded + @Test + void fractionTest() { + var crafted = new DFBuilder() + .setSuper("maximumFractionDigits", 788) + .setSuper("minimumFractionDigits", 787) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count out of range", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the minimum integer digits cannot be greater than the max + @Test + void maxMinIntegerTest() { + var crafted = new DFBuilder() + .setSuper("maximumIntegerDigits", 5) + .setSuper("minimumIntegerDigits", 6) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + + // Ensure the minimum fraction digits cannot be greater than the max + @Test + void maxMinFractionTest() { + var crafted = new DFBuilder() + .setSuper("maximumFractionDigits", 5) + .setSuper("minimumFractionDigits", 6) + .build(); + var bytes = ser(crafted); + assertEquals("Digit count range invalid", + assertThrows(InvalidObjectException.class, () -> deSer(bytes)).getMessage()); + } + } + + // Ensure the serial version is updated to the current after de-serialization. + @Test + void versionTest() { + var bytes = ser(new DFBuilder().setVer(-25).build()); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(4, readField(df, "serialVersionOnStream")); + } + + // Ensure strictness value is read properly when it is set. + @Test + void strictnessTest() { + var crafted = new DecimalFormat(); + crafted.setStrict(true); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertTrue(df.isStrict()); + } + + // Ensure invalid grouping sizes are corrected to the default invariant. + @Test + void groupingSizeTest() { + var crafted = new DFBuilder() + .set("groupingSize", (byte) -5) + .build(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertEquals(3, df.getGroupingSize()); + } + + // Ensure a de-serialized dFmt does not throw NPE from missing digitList + // later when formatting. i.e. re-construct the transient digitList field + @Test // See 4069754, 4067878 + void digitListTest() { + var crafted = new DecimalFormat(); + var bytes = ser(crafted); + var df = assertDoesNotThrow(() -> deSer(bytes)); + assertDoesNotThrow(() -> df.format(1)); + assertNotNull(readField(df, "digitList")); + } + + // Similar to the previous test, but the original regression test + // which was a failure in DateFormat due to DecimalFormat NPE + @Test // See 4069754 and 4067878 + void digitListDateFormatTest() { + var fmt = new FooFormat(); + fmt.now(); + var bytes = ser(fmt); + var ff = (FooFormat) assertDoesNotThrow(() -> deSer0(bytes)); + assertDoesNotThrow(ff::now); + } + + static class FooFormat implements Serializable { + DateFormat dateFormat = DateFormat.getDateInstance(); + + public String now() { + GregorianCalendar calendar = new GregorianCalendar(); + Date t = calendar.getTime(); + return dateFormat.format(t); + } + } + +// Utilities ---- + + // Utility to serialize + private static byte[] ser(Object obj) { + return assertDoesNotThrow(() -> { + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream)) { + oos.writeObject(obj); + return byteArrayOutputStream.toByteArray(); } + }, "Unexpected error during serialization"); + } + + // Utility to deserialize + private static Object deSer0(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) { + return ois.readObject(); + } + } + + // Convenience cast to DF + private static DecimalFormat deSer(byte[] bytes) throws IOException, ClassNotFoundException { + return (DecimalFormat) deSer0(bytes); + } + + // Utility to deserialize from file in hex format + private static Object deSer(String file) throws IOException, ClassNotFoundException { + try (InputStream stream = HexDumpReader.getStreamFromHexDump(file); + ObjectInputStream ois = new ObjectInputStream(stream)) { + return ois.readObject(); + } + } + + // Utility to read a private field + private static Object readField(DecimalFormat df, String name) { + return assertDoesNotThrow(() -> { + var field = DecimalFormat.class.getDeclaredField(name); + field.setAccessible(true); + return field.get(df); + }, "Unexpected error during field reading"); + } + + // Utility class to build instances of DF via reflection + private static class DFBuilder { + + private final DecimalFormat df; + + private DFBuilder() { + df = new DecimalFormat(); + } + + private DFBuilder setVer(Object value) { + return set("serialVersionOnStream", value); + } + + private DFBuilder setSuper(String field, Object value) { + return set(df.getClass().getSuperclass(), field, value); + } + + private DFBuilder set(String field, Object value) { + return set(df.getClass(), field, value); + } + + private DFBuilder set(Class clzz, String field, Object value) { + return assertDoesNotThrow(() -> { + Field f = clzz.getDeclaredField(field); + f.setAccessible(true); + f.set(df, value); + return this; + }, "Unexpected error during reflection setting"); + } + + private DecimalFormat build() { + return df; } } } + +// Not nested, so that it can be recognized and cast correctly for the 1.1.4 test +class CheckDecimalFormat implements Serializable { + DecimalFormat _decFormat = (DecimalFormat) NumberFormat.getInstance(); + public String Update() { + Random r = new Random(); + return _decFormat.format(r.nextDouble()); + } +} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java b/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java deleted file mode 100644 index 2927f4e2c3b..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSDeserialization142.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * No at-test for this test, because it needs to be run on older version JDK than 1.6 to test. - * It was tested using 1.4.2. The file object was created using JDK1.6. - */ - - - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class DFSDeserialization142{ - - public static void main(String[] args) - { - try { - - File file = new File("DecimalFormatSymbols.current"); - FileInputStream istream = new FileInputStream(file); - ObjectInputStream p = new ObjectInputStream(istream); - DecimalFormatSymbols dfs = (DecimalFormatSymbols)p.readObject(); - if (dfs.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println("Serialization/Deserialization Test Passed."); - }else{ - throw new Exception("Serialization/Deserialization Test Failed:"+dfs.getCurrencySymbol()); - } - istream.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java b/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java deleted file mode 100644 index dea1d68ff6e..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSSerialization.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4068067 - * @library /java/text/testlib - * @build DFSSerialization HexDumpReader - * @run junit DFSSerialization - * @summary Three different tests are done. - * 1. read from the object created using jdk1.4.2 - * 2. create a valid DecimalFormatSymbols object with current JDK, then read the object - * 3. Try to create an valid DecimalFormatSymbols object by passing null to set null - * for the exponent separator symbol. Expect the NullPointerException. - */ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.fail; - -public class DFSSerialization{ - - @Test - public void TestDFSSerialization(){ - /* - * 1. read from the object created using jdk1.4.2 - */ - File oldFile = new File(System.getProperty("test.src", "."), "DecimalFormatSymbols.142.txt"); - DecimalFormatSymbols dfs142 = readTestObject(oldFile); - if (dfs142 != null){ - if (dfs142.getExponentSeparator().equals("E") && dfs142.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println("\n Deserialization of JDK1.4.2 Object from the current JDK: Passed."); - System.out.println(" Deserialization of JDK1.4.2 Object from the current JDK: Passed."); - } else { - fail(" Deserialization of JDK1.4.2 Object from the current JDK was Failed:" - +dfs142.getCurrencySymbol()+" "+dfs142.getExponentSeparator()); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Deserialization of JDK1.4.2 Object from the current JDK was Failed:" - +dfs142.getCurrencySymbol()+" "+dfs142.getExponentSeparator()); - } - } - /* - * 2. create a valid DecimalFormatSymbols object with current JDK, then read the object - */ - String validObject = "DecimalFormatSymbols.current"; - File currentFile = createTestObject(validObject, "*SpecialExponentSeparator*"); - - DecimalFormatSymbols dfsValid = readTestObject(currentFile); - if (dfsValid != null){ - if (dfsValid.getExponentSeparator().equals("*SpecialExponentSeparator*") && - dfsValid.getCurrencySymbol().equals("*SpecialCurrencySymbol*")){ - System.out.println(" Deserialization of current JDK Object from the current JDK: Passed."); - System.out.println(" Deserialization of current JDK Object from the current JDK: Passed."); - } else { - fail(" Deserialization of current JDK Object from the current JDK was Failed:" - +dfsValid.getCurrencySymbol()+" "+dfsValid.getExponentSeparator()); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Deserialization of current Object from the current JDK was Failed:" - +dfsValid.getCurrencySymbol()+" "+dfsValid.getExponentSeparator()); - } - } - /* - * 3. Try to create an valid DecimalFormatSymbols object by passing null - * to set null for the exponent separator symbol. Expect the NullPointerException. - */ - DecimalFormatSymbols symNPE = new DecimalFormatSymbols(Locale.US); - boolean npePassed = false; - try { - symNPE.setExponentSeparator(null); - } catch (NullPointerException npe){ - npePassed = true; - System.out.println(" Trying to set exponent separator with null: Passed."); - System.out.println(" Trying to set exponent separator with null: Passed."); - } - if (!npePassed){ - System.out.println(" Trying to set exponent separator with null:Failed."); - fail(" Trying to set exponent separator with null:Failed."); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException(" Trying to set exponent separator with null:Failed."); - } - - } - - private DecimalFormatSymbols readTestObject(File inputFile){ - try (InputStream istream = inputFile.getName().endsWith(".txt") ? - HexDumpReader.getStreamFromHexDump(inputFile) : - new FileInputStream(inputFile)) { - ObjectInputStream p = new ObjectInputStream(istream); - DecimalFormatSymbols dfs = (DecimalFormatSymbols)p.readObject(); - return dfs; - } catch (Exception e) { - fail("Test Malfunction in DFSSerialization: Exception while reading the object"); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException("Test Malfunction: re-throwing the exception", e); - } - } - - private File createTestObject(String objectName, String expString){ - DecimalFormatSymbols dfs= new DecimalFormatSymbols(); - dfs.setExponentSeparator(expString); - dfs.setCurrencySymbol("*SpecialCurrencySymbol*"); - System.out.println(" The special exponent separator is set : " + dfs.getExponentSeparator()); - System.out.println(" The special currency symbol is set : " + dfs.getCurrencySymbol()); - - // 6345659: create a test object in the test.class dir where test user has a write permission. - File file = new File(System.getProperty("test.class", "."), objectName); - try (FileOutputStream ostream = new FileOutputStream(file)) { - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(dfs); - //System.out.println(" The special currency symbol is set : " + dfs.getCurrencySymbol()); - return file; - } catch (Exception e){ - fail("Test Malfunction in DFSSerialization: Exception while creating an object"); - /* - * logically should not throw this exception as errln throws exception - * if not thrown yet - but in case errln got changed - */ - throw new RuntimeException("Test Malfunction: re-throwing the exception", e); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java b/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java deleted file mode 100644 index 4a5e873ee23..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/DFSSerialization142.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * No at-test for this test, because it needs to be run on JDK 1.4.2 - * Instead, the resulting serialized file - * DecimalFormatSymbols.142 is archived. - */ - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class DFSSerialization142 { - - public static void main(String[] args) - { - try { - - DecimalFormatSymbols dfs= new DecimalFormatSymbols(); - System.out.println("Default currency symbol in the default locale : " + dfs.getCurrencySymbol()); - dfs.setCurrencySymbol("*SpecialCurrencySymbol*"); - System.out.println("The special currency symbol is set : " + dfs.getCurrencySymbol()); - FileOutputStream ostream = new FileOutputStream("DecimalFormatSymbols.142"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(dfs); - ostream.close(); - System.out.println("DecimalFormatSymbols saved ok."); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index 2ff111f0e4b..dcc87643b2b 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 @@ -28,9 +28,8 @@ * 4087251 4087535 4088161 4088503 4090489 4090504 4092480 4092561 4095713 * 4098741 4099404 4101481 4106658 4106662 4106664 4108738 4110936 4122840 * 4125885 4134034 4134300 4140009 4141750 4145457 4147295 4147706 4162198 - * 4162852 4167494 4170798 4176114 4179818 4185761 4212072 4212073 4216742 - * 4217661 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 - * 8174269 + * 4162852 4167494 4170798 4176114 4179818 4212072 4212073 4216742 4217661 + * 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 8174269 * @summary Regression tests for NumberFormat and associated classes * @library /java/text/testlib * @build HexDumpReader TestUtils @@ -307,33 +306,6 @@ public class NumberRegression { Locale.setDefault(savedLocale); } - /* bugs 4069754, 4067878 - * null pointer thrown when accessing a deserialized DecimalFormat - * object. - */ - @Test - public void Test4069754() - { - try { - myformat it = new myformat(); - System.out.println(it.Now()); - FileOutputStream ostream = new FileOutputStream("t.tmp"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(it); - ostream.close(); - System.out.println("Saved ok."); - - FileInputStream istream = new FileInputStream("t.tmp"); - ObjectInputStream p2 = new ObjectInputStream(istream); - myformat it2 = (myformat)p2.readObject(); - System.out.println(it2.Now()); - istream.close(); - System.out.println("Loaded ok."); - } catch (Exception foo) { - fail("Test for bug 4069754 or 4057878 failed => Exception: " + foo.getMessage()); - } - } - /** * DecimalFormat.applyPattern(String) allows illegal patterns */ @@ -1485,59 +1457,6 @@ public class NumberRegression { } } - @Test - public void Test4185761() throws IOException, ClassNotFoundException { - /* Code used to write out the initial files, which are - * then edited manually: - NumberFormat nf = NumberFormat.getInstance(Locale.US); - nf.setMinimumIntegerDigits(0x111); // Keep under 309 - nf.setMaximumIntegerDigits(0x112); // Keep under 309 - nf.setMinimumFractionDigits(0x113); // Keep under 340 - nf.setMaximumFractionDigits(0x114); // Keep under 340 - FileOutputStream ostream = - new FileOutputStream("NumberFormat4185761"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(nf); - ostream.close(); - */ - - // File minint maxint minfrac maxfrac - // NumberFormat4185761a 0x122 0x121 0x124 0x123 - // NumberFormat4185761b 0x311 0x312 0x313 0x314 - // File a is bad because the mins are smaller than the maxes. - // File b is bad because the values are too big for a DecimalFormat. - // These files have a sufix ".ser.txt". - - InputStream istream = HexDumpReader.getStreamFromHexDump("NumberFormat4185761a.ser.txt"); - ObjectInputStream p = new ObjectInputStream(istream); - try { - NumberFormat nf = (NumberFormat) p.readObject(); - fail("FAIL: Deserialized bogus NumberFormat int:" + - nf.getMinimumIntegerDigits() + ".." + - nf.getMaximumIntegerDigits() + " frac:" + - nf.getMinimumFractionDigits() + ".." + - nf.getMaximumFractionDigits()); - } catch (InvalidObjectException e) { - System.out.println("Ok: " + e.getMessage()); - } - istream.close(); - - istream = HexDumpReader.getStreamFromHexDump("NumberFormat4185761b.ser.txt"); - p = new ObjectInputStream(istream); - try { - NumberFormat nf = (NumberFormat) p.readObject(); - fail("FAIL: Deserialized bogus DecimalFormat int:" + - nf.getMinimumIntegerDigits() + ".." + - nf.getMaximumIntegerDigits() + " frac:" + - nf.getMinimumFractionDigits() + ".." + - nf.getMaximumFractionDigits()); - } catch (InvalidObjectException e) { - System.out.println("Ok: " + e.getMessage()); - } - istream.close(); - } - - /** * Some DecimalFormatSymbols changes are not picked up by DecimalFormat. * This includes the minus sign, currency symbol, international currency @@ -1930,20 +1849,6 @@ public class NumberRegression { } } -@SuppressWarnings("serial") -class myformat implements Serializable -{ - DateFormat _dateFormat = DateFormat.getDateInstance(); - - public String Now() - { - GregorianCalendar calendar = new GregorianCalendar(); - Date t = calendar.getTime(); - String nowStr = _dateFormat.format(t); - return nowStr; - } -} - @SuppressWarnings("serial") class MyNumberFormatTest extends NumberFormat { public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { diff --git a/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java b/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java deleted file mode 100644 index 501af54c7da..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/SerializationLoadTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4101150 - * @library /java/text/testlib - * @build SerializationLoadTest HexDumpReader - * @run main SerializationLoadTest - * @summary test serialization compatibility of DecimalFormat and DecimalFormatSymbols - * @key randomness - */ - -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.util.Random; - -public class SerializationLoadTest { - - public static void main(String[] args) - { - try { - InputStream istream1 = HexDumpReader.getStreamFromHexDump("DecimalFormat.114.txt"); - ObjectInputStream p = new ObjectInputStream(istream1); - CheckDecimalFormat it = (CheckDecimalFormat)p.readObject(); - System.out.println("1.1.4 DecimalFormat Loaded ok."); - System.out.println(it.Update()); - System.out.println("Called Update successfully."); - istream1.close(); - - InputStream istream2 = HexDumpReader.getStreamFromHexDump("DecimalFormatSymbols.114.txt"); - ObjectInputStream p2 = new ObjectInputStream(istream2); - CheckDecimalFormatSymbols it2 = (CheckDecimalFormatSymbols)p2.readObject(); - System.out.println("1.1.4 DecimalFormatSymbols Loaded ok."); - System.out.println("getDigit : " + it2.Update()); - System.out.println("Called Update successfully."); - istream2.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormat implements Serializable -{ - DecimalFormat _decFormat = (DecimalFormat)NumberFormat.getInstance(); - - public String Update() - { - Random r = new Random(); - return _decFormat.format(r.nextDouble()); - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormatSymbols implements Serializable -{ - DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); - - public char Update() - { - return _decFormatSymbols.getDigit(); - } -} diff --git a/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java b/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java deleted file mode 100644 index 0332efeca0f..00000000000 --- a/test/jdk/java/text/Format/NumberFormat/SerializationSaveTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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. - * - * 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. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * No at-test for this test, because it needs to be run on JDK 1.1.4. - * Instead, the resulting serialized files DecimalFormat.114 and - * DecimalFormatSymbols.114 are archived. - */ - -import java.awt.*; -import java.text.*; -import java.util.*; -import java.io.*; - -public class SerializationSaveTest { - - public static void main(String[] args) - { - try { - CheckDecimalFormat it = new CheckDecimalFormat(); - System.out.println(it.Update()); - FileOutputStream ostream = new FileOutputStream("DecimalFormat.114"); - ObjectOutputStream p = new ObjectOutputStream(ostream); - p.writeObject(it); - ostream.close(); - System.out.println("DecimalFormat saved ok."); - CheckDecimalFormatSymbols it2 = new CheckDecimalFormatSymbols(); - System.out.println("getDigit : " + it2.Update()); - FileOutputStream ostream2 = new FileOutputStream("DecimalFormatSymbols.114"); - ObjectOutputStream p2 = new ObjectOutputStream(ostream2); - p2.writeObject(it2); - ostream2.close(); - System.out.println("DecimalFormatSymbols saved ok."); - } catch (Exception e) { - e.printStackTrace(); - } - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormat implements Serializable -{ - DecimalFormat _decFormat = (DecimalFormat)NumberFormat.getInstance(); - - public String Update() - { - Random r = new Random(); - return _decFormat.format(r.nextDouble()); - } -} - -@SuppressWarnings("serial") -class CheckDecimalFormatSymbols implements Serializable -{ - DecimalFormatSymbols _decFormatSymbols = new DecimalFormatSymbols(); - - public char Update() - { - return _decFormatSymbols.getDigit(); - } -} From f96403986b99008593e025c4991ee865fce59bb1 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 9 Sep 2025 23:27:33 +0000 Subject: [PATCH 435/471] 8361376: Regressions 1-6% in several Renaissance in 26-b4 only MacOSX aarch64 Co-authored-by: Martin Doerr Reviewed-by: mdoerr, aph, eosterlund --- .../gc/shared/barrierSetNMethod_aarch64.cpp | 22 ++++++-- .../arm/gc/shared/barrierSetNMethod_arm.cpp | 22 ++++++-- .../ppc/gc/shared/barrierSetAssembler_ppc.cpp | 12 +++-- .../ppc/gc/shared/barrierSetNMethod_ppc.cpp | 53 ++++++++++++++----- src/hotspot/cpu/ppc/nativeInst_ppc.hpp | 6 ++- .../gc/shared/barrierSetNMethod_riscv.cpp | 22 ++++++-- .../s390/gc/shared/barrierSetNMethod_s390.cpp | 27 +++++++--- .../x86/gc/shared/barrierSetNMethod_x86.cpp | 29 ++++++++-- .../zero/gc/shared/barrierSetNMethod_zero.cpp | 2 +- .../share/gc/shared/barrierSetNMethod.cpp | 27 ++-------- .../share/gc/shared/barrierSetNMethod.hpp | 19 +++---- src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 28 ---------- src/hotspot/share/gc/z/zBarrierSetNMethod.hpp | 8 --- src/hotspot/share/runtime/mutexLocker.cpp | 3 -- src/hotspot/share/runtime/mutexLocker.hpp | 1 - 15 files changed, 169 insertions(+), 112 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index 88c90a548d1..3a4ba913a8f 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -115,8 +115,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } bool check_barrier(err_msg& msg) const; @@ -179,7 +193,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -196,7 +210,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { } NativeNMethodBarrier barrier(nm); - barrier.set_value(value); + barrier.set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp index 52d71ca65c2..81b14f28c35 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp @@ -51,8 +51,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } void verify() const; @@ -115,7 +129,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -123,7 +137,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier. // Symmetric "LDR; DMB ISHLD" is in the nmethod barrier. NativeNMethodBarrier* barrier = native_nmethod_barrier(nm); - barrier->set_value(value); + barrier->set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 405ac4b2310..b2e830bcdb8 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -183,12 +183,9 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); assert_different_registers(tmp, R0); - __ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {"); + __ align(8); // must align the following block which requires atomic updates - // Load stub address using toc (fixed instruction size, unlike load_const_optimized) - __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(), - true, true, false); // 2 instructions - __ mtctr(tmp); + __ block_comment("nmethod_entry_barrier (nmethod_entry_barrier) {"); // This is a compound instruction. Patching support is provided by NativeMovRegMem. // Actual patching is done in (platform-specific part of) BarrierSetNMethod. @@ -198,6 +195,11 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Register t __ ld(R0, in_bytes(bs_nm->thread_disarmed_guard_value_offset()), R16_thread); __ cmpw(CR0, R0, tmp); + // Load stub address using toc (fixed instruction size, unlike load_const_optimized) + __ calculate_address_from_global_toc(tmp, StubRoutines::method_entry_barrier(), + true, true, false); // 2 instructions + __ mtctr(tmp); + __ bnectrl(CR0); // Oops may have been changed. Make those updates observable. diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp index d3bb9cc3c04..02423e13308 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp @@ -38,7 +38,7 @@ class NativeNMethodBarrier: public NativeInstruction { NativeMovRegMem* get_patchable_instruction_handle() const { // Endianness is handled by NativeMovRegMem - return reinterpret_cast(get_barrier_start_address() + 3 * 4); + return reinterpret_cast(get_barrier_start_address()); } public: @@ -47,7 +47,7 @@ public: return get_patchable_instruction_handle()->offset(); } - void release_set_guard_value(int value) { + void release_set_guard_value(int value, int bit_mask) { // Patching is not atomic. // Stale observations of the "armed" state is okay as invoking the barrier stub in that case has no // unwanted side effects. Disarming is thus a non-critical operation. @@ -55,8 +55,37 @@ public: OrderAccess::release(); // Release modified oops - // Set the guard value (naming of 'offset' function is misleading). - get_patchable_instruction_handle()->set_offset(value); + if (bit_mask == ~0) { + // Set the guard value (naming of 'offset' function is misleading). + get_patchable_instruction_handle()->set_offset(value); + return; + } + + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + + NativeMovRegMem* mov = get_patchable_instruction_handle(); + assert(align_up(mov->instruction_address(), sizeof(uint64_t)) == + align_down(mov->instruction_address(), sizeof(uint64_t)), "instruction not aligned"); + uint64_t *instr = (uint64_t*)mov->instruction_address(); + assert(NativeMovRegMem::instruction_size == sizeof(*instr), "must be"); + union { + u_char buf[NativeMovRegMem::instruction_size]; + uint64_t u64; + } new_mov_instr, old_mov_instr; + new_mov_instr.u64 = old_mov_instr.u64 = Atomic::load(instr); + while (true) { + // Only bits in the mask are changed + int old_value = nativeMovRegMem_at(old_mov_instr.buf)->offset(); + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) return; // skip icache flush if nothing changed + nativeMovRegMem_at(new_mov_instr.buf)->set_offset(new_value, false /* no icache flush */); + // Swap in the new value + uint64_t v = Atomic::cmpxchg(instr, old_mov_instr.u64, new_mov_instr.u64, memory_order_relaxed); + if (v == old_mov_instr.u64) break; + old_mov_instr.u64 = v; + } + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); } void verify() const { @@ -66,12 +95,6 @@ public: uint* current_instruction = reinterpret_cast(get_barrier_start_address()); - // calculate_address_from_global_toc (compound instruction) - verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction)); - verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction)); - - verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction)); - get_patchable_instruction_handle()->verify(); current_instruction += 2; @@ -80,6 +103,12 @@ public: // cmpw (mnemonic) verify_op_code(current_instruction, Assembler::CMP_OPCODE); + // calculate_address_from_global_toc (compound instruction) + verify_op_code_manually(current_instruction, MacroAssembler::is_addis(*current_instruction)); + verify_op_code_manually(current_instruction, MacroAssembler::is_addi(*current_instruction)); + + verify_op_code_manually(current_instruction, MacroAssembler::is_mtctr(*current_instruction)); + // bnectrl (mnemonic) (weak check; not checking the exact type) verify_op_code(current_instruction, Assembler::BCCTR_OPCODE); @@ -117,13 +146,13 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { // Thus, there's nothing to do here. } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeNMethodBarrier* barrier = get_nmethod_barrier(nm); - barrier->release_set_guard_value(value); + barrier->release_set_guard_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp index 38126ec858d..d5dec3f4b1f 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.hpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.hpp @@ -462,7 +462,7 @@ class NativeMovRegMem: public NativeInstruction { return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF); } - void set_offset(intptr_t x) { + void set_offset(intptr_t x, bool flush_icache = true) { #ifdef VM_LITTLE_ENDIAN short *hi_ptr = (short*)(addr_at(0)); short *lo_ptr = (short*)(addr_at(4)); @@ -472,7 +472,9 @@ class NativeMovRegMem: public NativeInstruction { #endif *hi_ptr = x >> 16; *lo_ptr = x & 0xFFFF; - ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + if (flush_icache) { + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + } } void add_offset_in_bytes(intptr_t radd_offset) { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index ac619f83f7d..4fa9b4b04fb 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -109,8 +109,22 @@ public: return Atomic::load_acquire(guard_addr()); } - void set_value(int value) { - Atomic::release_store(guard_addr(), value); + void set_value(int value, int bit_mask) { + if (bit_mask == ~0) { + Atomic::release_store(guard_addr(), value); + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int old_value = Atomic::load(guard_addr()); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(guard_addr(), old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } bool check_barrier(err_msg& msg) const; @@ -192,7 +206,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } @@ -209,7 +223,7 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { } NativeNMethodBarrier barrier(nm); - barrier.set_value(value); + barrier.set_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp index 88b3199e4e1..1a609ad8d45 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp @@ -53,11 +53,26 @@ class NativeMethodBarrier: public NativeInstruction { return *((int32_t*)data_addr); } - void set_guard_value(int value) { - int32_t* data_addr = (int32_t*)get_patchable_data_address(); + void set_guard_value(int value, int bit_mask) { + if (bit_mask == ~0) { + int32_t* data_addr = (int32_t*)get_patchable_data_address(); - // Set guard instruction value - *data_addr = value; + // Set guard instruction value + *data_addr = value; + return; + } + assert((value & ~bit_mask) == 0, "trying to set bits outside the mask"); + value &= bit_mask; + int32_t* data_addr = (int32_t*)get_patchable_data_address(); + int old_value = Atomic::load(data_addr); + while (true) { + // Only bits in the mask are changed + int new_value = value | (old_value & ~bit_mask); + if (new_value == old_value) break; + int v = Atomic::cmpxchg(data_addr, old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } } #ifdef ASSERT @@ -100,13 +115,13 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { return; } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeMethodBarrier* barrier = get_nmethod_barrier(nm); - barrier->set_guard_value(value); + barrier->set_guard_value(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp index c27af4a29cd..124daef4fa7 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp @@ -50,8 +50,31 @@ public: address instruction_address() const { return addr_at(0); } address immediate_address() const { return addr_at(imm_offset); } + NativeNMethodCmpBarrier* nativeNMethodCmpBarrier_at(address a) { return (NativeNMethodCmpBarrier*)a; } + jint get_immediate() const { return int_at(imm_offset); } - void set_immediate(jint imm) { set_int_at(imm_offset, imm); } + void set_immediate(jint imm, int bit_mask) { + if (bit_mask == ~0) { + set_int_at(imm_offset, imm); + return; + } + + assert((imm & ~bit_mask) == 0, "trying to set bits outside the mask"); + imm &= bit_mask; + + assert(align_up(immediate_address(), sizeof(jint)) == + align_down(immediate_address(), sizeof(jint)), "immediate not aligned"); + jint* data_addr = (jint*)immediate_address(); + jint old_value = Atomic::load(data_addr); + while (true) { + // Only bits in the mask are changed + jint new_value = imm | (old_value & ~bit_mask); + if (new_value == old_value) break; + jint v = Atomic::cmpxchg(data_addr, old_value, new_value, memory_order_release); + if (v == old_value) break; + old_value = v; + } + } bool check_barrier(err_msg& msg) const; void verify() const { #ifdef ASSERT @@ -159,13 +182,13 @@ static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) { return barrier; } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { if (!supports_entry_barrier(nm)) { return; } NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm); - cmp->set_immediate(value); + cmp->set_immediate(value, bit_mask); } int BarrierSetNMethod::guard_value(nmethod* nm) { diff --git a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp index 62e7134ed61..e9220ff57e4 100644 --- a/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp +++ b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp @@ -29,7 +29,7 @@ void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { ShouldNotReachHere(); } -void BarrierSetNMethod::set_guard_value(nmethod* nm, int value) { +void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) { ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 522000e0a99..0e5c5d02d1c 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -72,21 +72,12 @@ bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) { } void BarrierSetNMethod::disarm(nmethod* nm) { - guard_with(nm, disarmed_guard_value()); + set_guard_value(nm, disarmed_guard_value()); } void BarrierSetNMethod::guard_with(nmethod* nm, int value) { assert((value & not_entrant) == 0, "not_entrant bit is reserved"); - // Enter critical section. Does not block for safepoint. - ConditionalMutexLocker ml(NMethodEntryBarrier_lock, !NMethodEntryBarrier_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); - // Do not undo sticky bit - if (is_not_entrant(nm)) { - value |= not_entrant; - } - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } + set_guard_value(nm, value); } bool BarrierSetNMethod::is_armed(nmethod* nm) { @@ -119,6 +110,8 @@ bool BarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { return true; } + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); + // If the nmethod is the only thing pointing to the oops, and we are using a // SATB GC, then it is important that this code marks them live. // Also, with concurrent GC, it is possible that frames in continuation stack @@ -179,10 +172,6 @@ void BarrierSetNMethod::arm_all_nmethods() { } int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { - // Enable WXWrite: the function is called directly from nmethod_entry_barrier - // stub. - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); - address return_address = *return_address_ptr; AARCH64_PORT_ONLY(return_address = pauth_strip_pointer(return_address)); CodeBlob* cb = CodeCache::find_blob(return_address); @@ -243,13 +232,7 @@ oop BarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { // nmethod_stub_entry_barrier() may appear to be spurious, because is_armed() still returns // false and nmethod_entry_barrier() is not called. void BarrierSetNMethod::make_not_entrant(nmethod* nm) { - // Enter critical section. Does not block for safepoint. - ConditionalMutexLocker ml(NMethodEntryBarrier_lock, !NMethodEntryBarrier_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); - int value = guard_value(nm) | not_entrant; - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } + set_guard_value(nm, not_entrant, not_entrant); } bool BarrierSetNMethod::is_not_entrant(nmethod* nm) { diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp index b905e8869b5..88bae4d5c1c 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp @@ -36,17 +36,18 @@ class nmethod; class BarrierSetNMethod: public CHeapObj { private: int _current_phase; + + void deoptimize(nmethod* nm, address* return_addr_ptr); + +protected: enum { not_entrant = 1 << 31, // armed sticky bit, see make_not_entrant armed = 0, initial = 1, }; - void deoptimize(nmethod* nm, address* return_addr_ptr); - -protected: - virtual int guard_value(nmethod* nm); - void set_guard_value(nmethod* nm, int value); + int guard_value(nmethod* nm); + void set_guard_value(nmethod* nm, int value, int bit_mask = ~not_entrant); public: BarrierSetNMethod() : _current_phase(initial) {} @@ -60,13 +61,13 @@ public: static int nmethod_stub_entry_barrier(address* return_address_ptr); bool nmethod_osr_entry_barrier(nmethod* nm); - virtual bool is_armed(nmethod* nm); + bool is_armed(nmethod* nm); void arm(nmethod* nm) { guard_with(nm, armed); } void disarm(nmethod* nm); - virtual void make_not_entrant(nmethod* nm); - virtual bool is_not_entrant(nmethod* nm); + void make_not_entrant(nmethod* nm); + bool is_not_entrant(nmethod* nm); - virtual void guard_with(nmethod* nm, int value); + void guard_with(nmethod* nm, int value); virtual void arm_all_nmethods(); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index 392d194a65b..d80ce4e149d 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -106,34 +106,6 @@ oop ZBarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { return ZNMethod::oop_load_phantom(nm, index); } -void ZBarrierSetNMethod::guard_with(nmethod* nm, int value) { - assert((value & not_entrant) == 0, "not_entrant bit is reserved"); - ZLocker locker(ZNMethod::lock_for_nmethod(nm)); - // Preserve the sticky bit - if (is_not_entrant(nm)) { - value |= not_entrant; - } - if (guard_value(nm) != value) { - // Patch the code only if needed. - set_guard_value(nm, value); - } -} - -bool ZBarrierSetNMethod::is_armed(nmethod* nm) { - int value = guard_value(nm) & ~not_entrant; - return value != disarmed_guard_value(); -} - -void ZBarrierSetNMethod::make_not_entrant(nmethod* nm) { - ZLocker locker(ZNMethod::lock_for_nmethod(nm)); - int value = guard_value(nm) | not_entrant; // permanent sticky value - set_guard_value(nm, value); -} - -bool ZBarrierSetNMethod::is_not_entrant(nmethod* nm) { - return (guard_value(nm) & not_entrant) != 0; -} - uintptr_t ZBarrierSetNMethod::color(nmethod* nm) { // color is stored at low order bits of int; conversion to uintptr_t is fine return uintptr_t(guard_value(nm) & ~not_entrant); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp index e0b7ba6c773..f51aa53a7e9 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp @@ -30,10 +30,6 @@ class nmethod; class ZBarrierSetNMethod : public BarrierSetNMethod { - enum : int { - not_entrant = 1 << 31, // armed sticky bit, see make_not_entrant - }; - protected: virtual bool nmethod_entry_barrier(nmethod* nm); @@ -46,10 +42,6 @@ public: virtual oop oop_load_no_keepalive(const nmethod* nm, int index); virtual oop oop_load_phantom(const nmethod* nm, int index); - virtual void make_not_entrant(nmethod* nm); - virtual bool is_not_entrant(nmethod* nm); - virtual void guard_with(nmethod* nm, int value); - virtual bool is_armed(nmethod* nm); virtual void arm_all_nmethods() { ShouldNotCallThis(); } }; diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 3f8915973e2..0c604205939 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -36,7 +36,6 @@ // Mutexes used in the VM (see comment in mutexLocker.hpp): Mutex* NMethodState_lock = nullptr; -Mutex* NMethodEntryBarrier_lock = nullptr; Monitor* SystemDictionary_lock = nullptr; Mutex* InvokeMethodTypeTable_lock = nullptr; Monitor* InvokeMethodIntrinsicTable_lock = nullptr; @@ -207,8 +206,6 @@ void assert_lock_strong(const Mutex* lock) { void mutex_init() { MUTEX_DEFN(tty_lock , PaddedMutex , tty); // allow to lock in VM - MUTEX_DEFN(NMethodEntryBarrier_lock , PaddedMutex , service-1); - MUTEX_DEFN(STS_lock , PaddedMonitor, nosafepoint); #if INCLUDE_G1GC diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f888c789eb7..3a73edc7bf2 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -34,7 +34,6 @@ class Thread; // Mutexes used in the VM. extern Mutex* NMethodState_lock; // a lock used to guard a compiled method state -extern Mutex* NMethodEntryBarrier_lock; // protects nmethod entry barrier extern Monitor* SystemDictionary_lock; // a lock on the system dictionary extern Mutex* InvokeMethodTypeTable_lock; extern Monitor* InvokeMethodIntrinsicTable_lock; From 8cd4e7d856dcc68243505f4e771dc8ab87176584 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 9 Sep 2025 23:50:33 +0000 Subject: [PATCH 436/471] 8365192: post_meth_exit should be in vm state when calling get_jvmti_thread_state Reviewed-by: mdoerr, dholmes --- src/hotspot/share/prims/jvmtiExport.cpp | 68 +++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 8c10a371e5a..2da9a074fb6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -418,6 +418,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { JvmtiThreadState* JvmtiExport::get_jvmti_thread_state(JavaThread *thread, bool allow_suspend) { assert(thread == JavaThread::current(), "must be current thread"); + assert(thread->thread_state() == _thread_in_vm, "thread should be in vm"); if (thread->is_vthread_mounted() && thread->jvmti_thread_state() == nullptr) { JvmtiEventController::thread_started(thread); if (allow_suspend && thread->is_suspended()) { @@ -1826,47 +1827,50 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu } void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) { + // At this point we only have the address of a "raw result" and + // we just call into the interpreter to convert this into a jvalue. + // This method always makes transition to vm and back where GC can happen. + // So it is needed to preserve result and then restore it + // even if events are not actually posted. + // Saving oop_result into value.j is deferred until jvmti state is ready. HandleMark hm(thread); methodHandle mh(thread, method); - - JvmtiThreadState *state = get_jvmti_thread_state(thread); - - if (state == nullptr || !state->is_interp_only_mode()) { - // for any thread that actually wants method exit, interp_only_mode is set - return; - } - Handle result; + oop oop_result; jvalue value; value.j = 0L; - - if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { - // At this point we only have the address of a "raw result" and - // we just call into the interpreter to convert this into a jvalue. - oop oop_result; - BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); - assert(type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, - "Stack shouldn't be empty"); - if (is_reference_type(type)) { - result = Handle(thread, oop_result); - value.l = JNIHandles::make_local(thread, result()); - } + BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); + assert(mh->is_native() || type == T_VOID || current_frame.interpreter_frame_expression_stack_size() > 0, + "Stack shouldn't be empty"); + if (is_reference_type(type)) { + result = Handle(thread, oop_result); } - - // Do not allow NotifyFramePop to add new FramePop event request at - // depth 0 as it is already late in the method exiting dance. - state->set_top_frame_is_exiting(); - - // Deferred transition to VM, so we can stash away the return oop before GC. + JvmtiThreadState* state; // should be initialized in vm state only JavaThread* current = thread; // for JRT_BLOCK + bool interp_only; // might be changed in JRT_BLOCK_END JRT_BLOCK - post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); + state = get_jvmti_thread_state(thread); + interp_only = state != nullptr && state->is_interp_only_mode(); + if (interp_only) { + if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { + // Deferred saving Object result into value. + if (is_reference_type(type)) { + value.l = JNIHandles::make_local(thread, result()); + } + } + + // Do not allow NotifyFramePop to add new FramePop event request at + // depth 0 as it is already late in the method exiting dance. + state->set_top_frame_is_exiting(); + + post_method_exit_inner(thread, mh, state, false /* not exception exit */, current_frame, value); + } JRT_BLOCK_END - - // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava desctructor. Now it is safe to allow - // adding FramePop event requests as no safepoint can happen before removing activation. - state->clr_top_frame_is_exiting(); - + if (interp_only) { + // The JRT_BLOCK_END can safepoint in ThreadInVMfromJava destructor. Now it is safe to allow + // adding FramePop event requests as no safepoint can happen before removing activation. + state->clr_top_frame_is_exiting(); + } if (result.not_null() && !mh->is_native()) { // We have to restore the oop on the stack for interpreter frames *(oop*)current_frame.interpreter_frame_tos_address() = result(); From 53b3e0567d2801ddf62c5849b219324ddfcb264a Mon Sep 17 00:00:00 2001 From: erifan Date: Wed, 10 Sep 2025 01:49:55 +0000 Subject: [PATCH 437/471] 8366588: VectorAPI: Re-intrinsify VectorMask.laneIsSet where the input index is a variable Reviewed-by: shade, xgong, epeter --- src/hotspot/share/opto/vectorIntrinsics.cpp | 2 +- .../compiler/lib/ir_framework/IRNode.java | 5 + .../vectorapi/VectorMaskLaneIsSetTest.java | 160 ++++++++++++++++++ .../vector/VectorExtractBenchmark.java | 5 +- 4 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 43ca51fca67..85d9790c0eb 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -2502,7 +2502,7 @@ bool LibraryCallKit::inline_vector_extract() { if (vector_klass == nullptr || vector_klass->const_oop() == nullptr || elem_klass == nullptr || elem_klass->const_oop() == nullptr || vlen == nullptr || !vlen->is_con() || - idx == nullptr || !idx->is_con()) { + idx == nullptr) { log_if_needed(" ** missing constant: vclass=%s etype=%s vlen=%s", NodeClassNames[argument(0)->Opcode()], NodeClassNames[argument(1)->Opcode()], diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 16c6d99a64f..52fc9a05f98 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1417,6 +1417,11 @@ public class IRNode { beforeMatchingNameRegex(VECTOR_MASK_TO_LONG, "VectorMaskToLong"); } + public static final String VECTOR_MASK_LANE_IS_SET = PREFIX + "VECTOR_MASK_LANE_IS_SET" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_LANE_IS_SET, "ExtractUB"); + } + // Can only be used if avx512_vnni is available. public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; static { diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java new file mode 100644 index 00000000000..b7f2103c56c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8366588 + * @key randomness + * @library /test/lib / + * @summary VectorAPI: Re-intrinsify VectorMask.laneIsSet where the input index is a variable + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorMaskLaneIsSetTest + */ + +public class VectorMaskLaneIsSetTest { + static final VectorSpecies B_SPECIES = ByteVector.SPECIES_MAX; + static final VectorSpecies S_SPECIES = ShortVector.SPECIES_MAX; + static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + static final int LENGTH = 512; + static boolean[] ma; + static VectorMask mask_b; + static VectorMask mask_s; + static VectorMask mask_i; + static VectorMask mask_l; + static VectorMask mask_f; + static VectorMask mask_d; + + static { + ma = new boolean[LENGTH]; + for (int i = 0; i < LENGTH; i++) { + ma[i] = i % 2 == 0; + } + mask_b = VectorMask.fromArray(B_SPECIES, ma, 0); + mask_s = VectorMask.fromArray(S_SPECIES, ma, 0); + mask_i = VectorMask.fromArray(I_SPECIES, ma, 0); + mask_l = VectorMask.fromArray(L_SPECIES, ma, 0); + mask_f = VectorMask.fromArray(F_SPECIES, ma, 0); + mask_d = VectorMask.fromArray(D_SPECIES, ma, 0); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 6" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeature = { "avx2", "true" }) + public static void testVectorMaskLaneIsSetByte_const() { + Asserts.assertEquals(ma[0], mask_b.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_s.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_i.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_l.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_f.laneIsSet(0)); + Asserts.assertEquals(ma[0], mask_d.laneIsSet(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Byte_variable(int i) { + return mask_b.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Byte_variable") + public static void testVectorMaskLaneIsSet_Byte_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Byte_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Short_variable(int i) { + return mask_s.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Short_variable") + public static void testVectorMaskLaneIsSet_Short_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Short_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Int_variable(int i) { + return mask_i.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Int_variable") + public static void testVectorMaskLaneIsSet_Int_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Int_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + public static boolean testVectorMaskLaneIsSet_Long_variable(int i) { + return mask_l.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Long_variable") + public static void testVectorMaskLaneIsSet_Long_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Long_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + public static boolean testVectorMaskLaneIsSet_Float_variable(int i) { + return mask_f.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Float_variable") + public static void testVectorMaskLaneIsSet_Float_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Float_variable(0)); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + public static boolean testVectorMaskLaneIsSet_Double_variable(int i) { + return mask_d.laneIsSet(i); + } + + @Run(test = "testVectorMaskLaneIsSet_Double_variable") + public static void testVectorMaskLaneIsSet_Double_variable_runner() { + Asserts.assertEquals(ma[0], testVectorMaskLaneIsSet_Double_variable(0)); + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java index 6358cb0a5d4..84c9031739c 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorExtractBenchmark.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Arm Limited. All rights reserved. + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. 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 @@ -28,7 +29,9 @@ import org.openjdk.jmh.annotations.*; @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorExtractBenchmark { private int idx = 0; private boolean[] res = new boolean[8]; From af9b9050ec51d0c43690fc42658741bd865b0310 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 10 Sep 2025 03:30:16 +0000 Subject: [PATCH 438/471] 8366057: HotSpot Style Guide should permit trailing return types Reviewed-by: dholmes, stefank, kvn, adinn, jsjolen --- doc/hotspot-style.html | 52 ++++++++++++++++++++++++++++++++++++++---- doc/hotspot-style.md | 37 ++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 98d813242a5..fb4cffc9d43 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -75,6 +75,9 @@ Standard Library

        • Deduction
        • Expression SFINAE
        • +
        • Trailing return type +syntax for functions
        • Non-type template parameter values
        • @@ -719,11 +722,14 @@ href="http://wg21.link/p0127r2">p0127r2)
          auto may be used as a placeholder for the type of a non-type template parameter. The type is deduced from the value provided in a template instantiation.

          -
        • Function return type deduction ( +

          * Function return type +deduction (n3638)
          Only use if the function body has a very small number of return -statements, and generally relatively little other code.

        • -
        • Class template argument deduction ( +

            +
          • Class template argument deduction (n3602, p0091r3)
            The template arguments of a class template may be deduced from the arguments to a constructor. @@ -736,7 +742,7 @@ harder to understand, because explicit type information is lacking. But it can also remove the need to be explicit about types that are either obvious, or that are very hard to write. For example, these allow the addition of a scope-guard mechanism with nice syntax; something like -this

          • +this
            ScopeGuard guard{[&]{ ... cleanup code ... }};
            @@ -771,6 +777,44 @@ class="uri">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468
            https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html

            +

            Trailing return type +syntax for functions

            +

            A function's return type may be specified after the parameters and +qualifiers (n2541). +In such a declaration the normal return type is auto and +the return type is indicated by -> followed by the type. +Although both use auto in the "normal" leading return type +position, this differs from function return type +deduction, in that the return type is explicit rather than deduced, +but specified in a trailing position.

            +

            Use of trailing return types is permitted. However, the normal, +leading position for the return type is preferred. A trailing return +type should only be used where it provides some benefit. Such benefits +usually arise because a trailing return type is in a different scope +than a leading return type.

            +
              +
            • If the function identifier is a nested name specifier, then the +trailing return type occurs in the nested scope. This may permit simpler +naming in the return type because of the different name lookup +context.

            • +
            • The trailing return type is in the scope of the parameters, +making their types accessible via decltype. For +example

            • +
            +
            template<typename T, typename U> auto add(T t, U u) -> decltype(t + u);
            +

            rather than

            +
            template<typename T, typename U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
            +
              +
            • Complex calculated leading return types may obscure the normal +syntactic boundaries, making it more difficult for a reader to find the +function name and parameters. This is particularly common in cases where +the return type is being used for SFINAE. A trailing +return type may be preferable in such situations.
            • +

            Non-type template parameter values

            C++17 extended the arguments permitted for non-type template diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index e3ba4b470ce..3fd5468d531 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -642,6 +642,7 @@ use can make code much harder to understand. parameter. The type is deduced from the value provided in a template instantiation. + * Function return type deduction ([n3638](https://isocpp.org/files/papers/N3638.html))
            Only use if the function body has a very small number of `return` @@ -691,6 +692,42 @@ Here are a few closely related example bugs:

            +### Trailing return type syntax for functions + +A function's return type may be specified after the parameters and qualifiers +([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)). +In such a declaration the normal return type is `auto` and the return type is +indicated by `->` followed by the type. Although both use `auto` in the +"normal" leading return type position, this differs from +[function return type deduction](#function-return-type-deduction), +in that the return type is explicit rather than deduced, but specified in a +trailing position. + +Use of trailing return types is permitted. However, the normal, leading +position for the return type is preferred. A trailing return type should only +be used where it provides some benefit. Such benefits usually arise because a +trailing return type is in a different scope than a leading return type. + +* If the function identifier is a nested name specifier, then the trailing +return type occurs in the nested scope. This may permit simpler naming in the +return type because of the different name lookup context. + +* The trailing return type is in the scope of the parameters, making their +types accessible via `decltype`. For example +``` +template auto add(T t, U u) -> decltype(t + u); +``` +rather than +``` +template decltype((*(T*)0) + (*(U*)0)) add(T t, U u); +``` + +* Complex calculated leading return types may obscure the normal syntactic +boundaries, making it more difficult for a reader to find the function name and +parameters. This is particularly common in cases where the return type is +being used for [SFINAE]. A trailing return type may be preferable in such +situations. + ### Non-type template parameter values C++17 extended the arguments permitted for non-type template parameters From 8ab8d02e40e987a5eb5e8036ff4f12146ac2b16a Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 10 Sep 2025 05:45:31 +0000 Subject: [PATCH 439/471] 8366938: Test runtime/handshake/HandshakeTimeoutTest.java crashed Reviewed-by: kbarrett --- .../hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java index a1a5ff68c31..7f1ee4be711 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeTimeoutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -36,7 +36,7 @@ import jdk.test.whitebox.WhiteBox; * @library /testlibrary /test/lib * @build HandshakeTimeoutTest * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver HandshakeTimeoutTest + * @run driver/timeout=480 HandshakeTimeoutTest */ public class HandshakeTimeoutTest { From 2705e880b64825044e67487f01263121780d8f7a Mon Sep 17 00:00:00 2001 From: Disha Date: Wed, 10 Sep 2025 06:16:12 +0000 Subject: [PATCH 440/471] 8366764: Deproblemlist java/awt/ScrollPane/ScrollPositionTest.java Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index aac9d9a8a21..475704f7e95 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -455,7 +455,6 @@ java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java 6848810 macosx-all java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java 8194751 linux-all java/awt/image/VolatileImage/BitmaskVolatileImage.java 8133102 linux-all java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 8203004 linux-all -java/awt/ScrollPane/ScrollPositionTest.java 8040070 linux-all java/awt/ScrollPane/ScrollPaneEventType.java 8296516 macosx-all java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all From b7b01d6f564ae34e913ae51bd2f8243a32807136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 10 Sep 2025 06:16:39 +0000 Subject: [PATCH 441/471] 8366984: Remove delay slot support Reviewed-by: dlong, epeter --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 5 - src/hotspot/cpu/arm/arm.ad | 20 +- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 5 - src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 5 - .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 - src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 4 - src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 5 - src/hotspot/share/adlc/adlparse.cpp | 32 +- src/hotspot/share/adlc/formsopt.cpp | 4 - src/hotspot/share/adlc/formsopt.hpp | 4 - src/hotspot/share/adlc/output_c.cpp | 23 +- src/hotspot/share/adlc/output_h.cpp | 42 +-- src/hotspot/share/c1/c1_LIR.cpp | 20 -- src/hotspot/share/c1/c1_LIR.hpp | 24 -- src/hotspot/share/c1/c1_LIRAssembler.cpp | 3 +- src/hotspot/share/c1/c1_LIRAssembler.hpp | 6 +- src/hotspot/share/code/relocInfo.hpp | 4 +- src/hotspot/share/opto/output.cpp | 304 ++---------------- src/hotspot/share/runtime/sharedRuntime.cpp | 2 - 19 files changed, 54 insertions(+), 460 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index e9bb2350b5b..d788c0c201a 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -2585,11 +2585,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 45d51aaac57..2835a256153 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -3281,18 +3281,18 @@ pipe_class loadPollP(iRegP poll) %{ %} pipe_class br(Universe br, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; BR : R; %} pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; cr : E(read); BR : R; %} pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{ - single_instruction_with_delay_slot; + single_instruction; op1 : E(read); BR : R; MS : R; @@ -3323,14 +3323,14 @@ pipe_class call(method meth) %{ %} pipe_class tail_call(Universe ignore, label labl) %{ - single_instruction; has_delay_slot; + single_instruction; fixed_latency(100); BR : R(1); MS : R(1); %} pipe_class ret(Universe ignore) %{ - single_instruction; has_delay_slot; + single_instruction; BR : R(1); MS : R(1); %} @@ -3373,14 +3373,6 @@ pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{ IALU : R(3) %} -// Perform a compare, then move conditionally in a branch delay slot. -pipe_class min_max( iRegI src2, iRegI srcdst ) %{ - src2 : E(read); - srcdst : E(read); - IALU : R; - BR : R; -%} - // Define the class for the Nop node define %{ MachNop = ialu_nop; @@ -9053,7 +9045,7 @@ instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dum format %{ "MOV $zero,0\n" " MOV $temp,$cnt\n" "loop: SUBS $temp,$temp,4\t! Count down a dword of bytes\n" - " STR.ge $zero,[$base+$temp]\t! delay slot" + " STR.ge $zero,[$base+$temp]\n" " B.gt loop\t\t! Clearing loop\n" %} ins_encode %{ __ mov($zero$$Register, 0); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index c3b91e8c76f..d6ed82dcdb2 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -2552,11 +2552,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { fatal("Type profiling not implemented on this platform"); } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); __ add_slow(dst->as_pointer_register(), mon_addr.base(), mon_addr.disp()); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 73509c22134..3ca75305eca 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2747,11 +2747,6 @@ void LIR_Assembler::align_backward_branch_target() { } -void LIR_Assembler::emit_delay(LIR_OpDelay* op) { - Unimplemented(); -} - - void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { // tmp must be unused assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index f60be85a141..c3fe72870cf 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1590,8 +1590,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 87dc8b9286d..b875eeca9ad 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -2816,10 +2816,6 @@ void LIR_Assembler::align_backward_branch_target() { __ align(OptoLoopAlignment); } -void LIR_Assembler::emit_delay(LIR_OpDelay* op) { - ShouldNotCallThis(); // There are no delay slots on ZARCH_64. -} - void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { // tmp must be unused assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index a30bbe08c55..98759295bb1 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -3001,11 +3001,6 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(next); } -void LIR_Assembler::emit_delay(LIR_OpDelay*) { - Unimplemented(); -} - - void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { __ lea(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); } diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 15dbf070674..356c24760e8 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -1389,13 +1389,8 @@ void ADLParser::pipe_parse(void) { } if (!strcmp(ident, "branch_has_delay_slot")) { - skipws(); - if (_curchar == ';') { - next_char(); skipws(); - } - - pipeline->_branchHasDelaySlot = true; - continue; + parse_err(SYNERR, "Using obsolete token, branch_has_delay_slot"); + break; } if (!strcmp(ident, "max_instructions_per_bundle")) { @@ -1762,16 +1757,8 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { if (!strcmp(ident, "one_instruction_with_delay_slot") || !strcmp(ident, "single_instruction_with_delay_slot")) { - skipws(); - if (_curchar != ';') { - parse_err(SYNERR, "missing \";\" in latency definition\n"); - return; - } - - pipe_class->setInstructionCount(1); - pipe_class->setBranchDelay(true); - next_char(); skipws(); - continue; + parse_err(SYNERR, "Using obsolete token, %s", ident); + return; } if (!strcmp(ident, "one_instruction") || @@ -1831,15 +1818,8 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { } if (!strcmp(ident, "has_delay_slot")) { - skipws(); - if (_curchar != ';') { - parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n"); - return; - } - - pipe_class->setBranchDelay(true); - next_char(); skipws(); - continue; + parse_err(SYNERR, "Using obsolete token, %s", ident); + return; } if (!strcmp(ident, "force_serialization")) { diff --git a/src/hotspot/share/adlc/formsopt.cpp b/src/hotspot/share/adlc/formsopt.cpp index 01fe6288c53..92489da2f5a 100644 --- a/src/hotspot/share/adlc/formsopt.cpp +++ b/src/hotspot/share/adlc/formsopt.cpp @@ -512,7 +512,6 @@ PipelineForm::PipelineForm() , _classlist () , _classcnt (0) , _variableSizeInstrs (false) - , _branchHasDelaySlot (false) , _maxInstrsPerBundle (0) , _maxBundlesPerCycle (1) , _instrUnitSize (0) @@ -546,8 +545,6 @@ void PipelineForm::output(FILE *fp) { // Write info to output files fprintf(fp," fixed-sized bundles of %d bytes", _bundleUnitSize); else fprintf(fp," fixed-sized instructions"); - if (_branchHasDelaySlot) - fprintf(fp,", branch has delay slot"); if (_maxInstrsPerBundle > 0) fprintf(fp,", max of %d instruction%s in parallel", _maxInstrsPerBundle, _maxInstrsPerBundle > 1 ? "s" : ""); @@ -637,7 +634,6 @@ PipeClassForm::PipeClassForm(const char *id, int num) , _fixed_latency(0) , _instruction_count(0) , _has_multiple_bundles(false) - , _has_branch_delay_slot(false) , _force_serialization(false) , _may_have_no_code(false) { } diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index db7b9dbd8d8..34cbc24bed0 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -387,7 +387,6 @@ public: int _classcnt; // Number of classes bool _variableSizeInstrs; // Indicates if this architecture has variable sized instructions - bool _branchHasDelaySlot; // Indicates that branches have delay slot instructions int _maxInstrsPerBundle; // Indicates the maximum number of instructions for ILP int _maxBundlesPerCycle; // Indicates the maximum number of bundles for ILP int _instrUnitSize; // The minimum instruction unit size, in bytes @@ -499,7 +498,6 @@ public: int _fixed_latency; // Always takes this number of cycles int _instruction_count; // Number of instructions in first bundle bool _has_multiple_bundles; // Indicates if 1 or multiple bundles - bool _has_branch_delay_slot; // Has branch delay slot as last instruction bool _force_serialization; // This node serializes relative to surrounding nodes bool _may_have_no_code; // This node may generate no code based on register allocation @@ -518,13 +516,11 @@ public: void setInstructionCount(int i) { _instruction_count = i; } void setMultipleBundles(bool b) { _has_multiple_bundles = b; } - void setBranchDelay(bool s) { _has_branch_delay_slot = s; } void setForceSerialization(bool s) { _force_serialization = s; } void setMayHaveNoCode(bool s) { _may_have_no_code = s; } int InstructionCount() const { return _instruction_count; } bool hasMultipleBundles() const { return _has_multiple_bundles; } - bool hasBranchDelay() const { return _has_branch_delay_slot; } bool forceSerialization() const { return _force_serialization; } bool mayHaveNoCode() const { return _may_have_no_code; } diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index abebf39a2b2..caf2c9952a6 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -794,8 +794,8 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { // Create the pipeline class description - fprintf(fp_cpp, "static const Pipeline pipeline_class_Zero_Instructions(0, 0, true, 0, 0, false, false, false, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); - fprintf(fp_cpp, "static const Pipeline pipeline_class_Unknown_Instructions(0, 0, true, 0, 0, false, true, true, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); + fprintf(fp_cpp, "static const Pipeline pipeline_class_Zero_Instructions(0, 0, true, 0, 0, false, false, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); + fprintf(fp_cpp, "static const Pipeline pipeline_class_Unknown_Instructions(0, 0, true, 0, 0, true, true, false, nullptr, nullptr, nullptr, Pipeline_Use(0, 0, 0, nullptr));\n\n"); fprintf(fp_cpp, "const Pipeline_Use_Element Pipeline_Use::elaborated_elements[%d] = {\n", _pipeline->_rescount); for (int i1 = 0; i1 < _pipeline->_rescount; i1++) { @@ -895,12 +895,11 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, "(uint)stage_%s", _pipeline->_stages.name(maxWriteStage)); else fprintf(fp_cpp, "((uint)stage_%s)+%d", _pipeline->_stages.name(maxWriteStage), maxMoreInstrs); - fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s, %s,\n", + fprintf(fp_cpp, ", %d, %s, %d, %d, %s, %s, %s,\n", paramcount, pipeclass->hasFixedLatency() ? "true" : "false", pipeclass->fixedLatency(), pipeclass->InstructionCount(), - pipeclass->hasBranchDelay() ? "true" : "false", pipeclass->hasMultipleBundles() ? "true" : "false", pipeclass->forceSerialization() ? "true" : "false", pipeclass->mayHaveNoCode() ? "true" : "false" ); @@ -979,16 +978,6 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { fprintf(fp_cpp, "#ifndef PRODUCT\n"); fprintf(fp_cpp, "void Bundle::dump(outputStream *st) const {\n"); - fprintf(fp_cpp, " static const char * bundle_flags[] = {\n"); - fprintf(fp_cpp, " \"\",\n"); - fprintf(fp_cpp, " \"use nop delay\",\n"); - fprintf(fp_cpp, " \"use unconditional delay\",\n"); - fprintf(fp_cpp, " \"use conditional delay\",\n"); - fprintf(fp_cpp, " \"used in conditional delay\",\n"); - fprintf(fp_cpp, " \"used in unconditional delay\",\n"); - fprintf(fp_cpp, " \"used in all conditional delays\",\n"); - fprintf(fp_cpp, " };\n\n"); - fprintf(fp_cpp, " static const char *resource_names[%d] = {", _pipeline->_rescount); // Don't add compound resources to the list of resource names const char* resource; @@ -1003,12 +992,8 @@ void ArchDesc::build_pipe_classes(FILE *fp_cpp) { // See if the same string is in the table fprintf(fp_cpp, " bool needs_comma = false;\n\n"); - fprintf(fp_cpp, " if (_flags) {\n"); - fprintf(fp_cpp, " st->print(\"%%s\", bundle_flags[_flags]);\n"); - fprintf(fp_cpp, " needs_comma = true;\n"); - fprintf(fp_cpp, " };\n"); fprintf(fp_cpp, " if (instr_count()) {\n"); - fprintf(fp_cpp, " st->print(\"%%s%%d instr%%s\", needs_comma ? \", \" : \"\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n"); + fprintf(fp_cpp, " st->print(\"%%d instr%%s\", instr_count(), instr_count() != 1 ? \"s\" : \"\");\n"); fprintf(fp_cpp, " needs_comma = true;\n"); fprintf(fp_cpp, " };\n"); fprintf(fp_cpp, " uint r = resources_used();\n"); diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index 78cf5ea7988..e3fde235443 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -935,8 +935,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { _pipeline->_variableSizeInstrs ? 1 : 0); fprintf(fp_hpp, " _fixed_size_instructions = %d,\n", _pipeline->_variableSizeInstrs ? 0 : 1); - fprintf(fp_hpp, " _branch_has_delay_slot = %d,\n", - _pipeline->_branchHasDelaySlot ? 1 : 0); fprintf(fp_hpp, " _max_instrs_per_bundle = %d,\n", _pipeline->_maxInstrsPerBundle); fprintf(fp_hpp, " _max_bundles_per_cycle = %d,\n", @@ -983,7 +981,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " const unsigned char _fixed_latency;\n"); fprintf(fp_hpp, " const unsigned char _instruction_count;\n"); fprintf(fp_hpp, " const bool _has_fixed_latency;\n"); - fprintf(fp_hpp, " const bool _has_branch_delay;\n"); fprintf(fp_hpp, " const bool _has_multiple_bundles;\n"); fprintf(fp_hpp, " const bool _force_serialization;\n"); fprintf(fp_hpp, " const bool _may_have_no_code;\n"); @@ -998,7 +995,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " bool has_fixed_latency,\n"); fprintf(fp_hpp, " uint fixed_latency,\n"); fprintf(fp_hpp, " uint instruction_count,\n"); - fprintf(fp_hpp, " bool has_branch_delay,\n"); fprintf(fp_hpp, " bool has_multiple_bundles,\n"); fprintf(fp_hpp, " bool force_serialization,\n"); fprintf(fp_hpp, " bool may_have_no_code,\n"); @@ -1011,7 +1007,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " , _fixed_latency(fixed_latency)\n"); fprintf(fp_hpp, " , _instruction_count(instruction_count)\n"); fprintf(fp_hpp, " , _has_fixed_latency(has_fixed_latency)\n"); - fprintf(fp_hpp, " , _has_branch_delay(has_branch_delay)\n"); fprintf(fp_hpp, " , _has_multiple_bundles(has_multiple_bundles)\n"); fprintf(fp_hpp, " , _force_serialization(force_serialization)\n"); fprintf(fp_hpp, " , _may_have_no_code(may_have_no_code)\n"); @@ -1046,8 +1041,6 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " return (_resource_use._count); }\n\n"); fprintf(fp_hpp, " uint instructionCount() const {\n"); fprintf(fp_hpp, " return (_instruction_count); }\n\n"); - fprintf(fp_hpp, " bool hasBranchDelay() const {\n"); - fprintf(fp_hpp, " return (_has_branch_delay); }\n\n"); fprintf(fp_hpp, " bool hasMultipleBundles() const {\n"); fprintf(fp_hpp, " return (_has_multiple_bundles); }\n\n"); fprintf(fp_hpp, " bool forceSerialization() const {\n"); @@ -1071,50 +1064,19 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { uint rshift = rescount; fprintf(fp_hpp, "protected:\n"); - fprintf(fp_hpp, " enum {\n"); - fprintf(fp_hpp, " _unused_delay = 0x%x,\n", 0); - fprintf(fp_hpp, " _use_nop_delay = 0x%x,\n", 1); - fprintf(fp_hpp, " _use_unconditional_delay = 0x%x,\n", 2); - fprintf(fp_hpp, " _use_conditional_delay = 0x%x,\n", 3); - fprintf(fp_hpp, " _used_in_conditional_delay = 0x%x,\n", 4); - fprintf(fp_hpp, " _used_in_unconditional_delay = 0x%x,\n", 5); - fprintf(fp_hpp, " _used_in_all_conditional_delays = 0x%x,\n", 6); - fprintf(fp_hpp, "\n"); - fprintf(fp_hpp, " _use_delay = 0x%x,\n", 3); - fprintf(fp_hpp, " _used_in_delay = 0x%x\n", 4); - fprintf(fp_hpp, " };\n\n"); - fprintf(fp_hpp, " uint _flags : 3,\n"); - fprintf(fp_hpp, " _starts_bundle : 1,\n"); + fprintf(fp_hpp, " uint _starts_bundle : 1,\n"); fprintf(fp_hpp, " _instr_count : %d,\n", mshift); fprintf(fp_hpp, " _resources_used : %d;\n", rshift); fprintf(fp_hpp, "public:\n"); - fprintf(fp_hpp, " Bundle() : _flags(_unused_delay), _starts_bundle(0), _instr_count(0), _resources_used(0) {}\n\n"); + fprintf(fp_hpp, " Bundle() : _starts_bundle(0), _instr_count(0), _resources_used(0) {}\n\n"); fprintf(fp_hpp, " void set_instr_count(uint i) { _instr_count = i; }\n"); fprintf(fp_hpp, " void set_resources_used(uint i) { _resources_used = i; }\n"); - fprintf(fp_hpp, " void clear_usage() { _flags = _unused_delay; }\n"); fprintf(fp_hpp, " void set_starts_bundle() { _starts_bundle = true; }\n"); - fprintf(fp_hpp, " uint flags() const { return (_flags); }\n"); fprintf(fp_hpp, " uint instr_count() const { return (_instr_count); }\n"); fprintf(fp_hpp, " uint resources_used() const { return (_resources_used); }\n"); fprintf(fp_hpp, " bool starts_bundle() const { return (_starts_bundle != 0); }\n"); - fprintf(fp_hpp, " void set_use_nop_delay() { _flags = _use_nop_delay; }\n"); - fprintf(fp_hpp, " void set_use_unconditional_delay() { _flags = _use_unconditional_delay; }\n"); - fprintf(fp_hpp, " void set_use_conditional_delay() { _flags = _use_conditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_unconditional_delay() { _flags = _used_in_unconditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_conditional_delay() { _flags = _used_in_conditional_delay; }\n"); - fprintf(fp_hpp, " void set_used_in_all_conditional_delays() { _flags = _used_in_all_conditional_delays; }\n"); - - fprintf(fp_hpp, " bool use_nop_delay() { return (_flags == _use_nop_delay); }\n"); - fprintf(fp_hpp, " bool use_unconditional_delay() { return (_flags == _use_unconditional_delay); }\n"); - fprintf(fp_hpp, " bool use_conditional_delay() { return (_flags == _use_conditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_unconditional_delay() { return (_flags == _used_in_unconditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_conditional_delay() { return (_flags == _used_in_conditional_delay); }\n"); - fprintf(fp_hpp, " bool used_in_all_conditional_delays() { return (_flags == _used_in_all_conditional_delays); }\n"); - fprintf(fp_hpp, " bool use_delay() { return ((_flags & _use_delay) != 0); }\n"); - fprintf(fp_hpp, " bool used_in_delay() { return ((_flags & _used_in_delay) != 0); }\n\n"); - fprintf(fp_hpp, "#ifndef PRODUCT\n"); fprintf(fp_hpp, " void dump(outputStream *st = tty) const;\n"); fprintf(fp_hpp, "#endif\n"); diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index 4c8ebd5a09d..f11e178bd55 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -800,15 +800,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { } -// LIR_OpDelay - case lir_delay_slot: { - assert(op->as_OpDelay() != nullptr, "must be"); - LIR_OpDelay* opDelay = (LIR_OpDelay*)op; - - visit(opDelay->delay_op()); - break; - } - // LIR_OpTypeCheck case lir_instanceof: case lir_checkcast: @@ -1073,10 +1064,6 @@ void LIR_OpAssert::emit_code(LIR_Assembler* masm) { } #endif -void LIR_OpDelay::emit_code(LIR_Assembler* masm) { - masm->emit_delay(this); -} - void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) { masm->emit_profile_call(this); } @@ -1761,8 +1748,6 @@ const char * LIR_Op::name() const { // LIR_OpLock case lir_lock: s = "lock"; break; case lir_unlock: s = "unlock"; break; - // LIR_OpDelay - case lir_delay_slot: s = "delay"; break; // LIR_OpTypeCheck case lir_instanceof: s = "instanceof"; break; case lir_checkcast: s = "checkcast"; break; @@ -2044,11 +2029,6 @@ void LIR_OpAssert::print_instr(outputStream* out) const { #endif -void LIR_OpDelay::print_instr(outputStream* out) const { - _op->print_on(out); -} - - // LIR_OpProfileCall void LIR_OpProfileCall::print_instr(outputStream* out) const { profiled_method()->name()->print_symbol_on(out); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index c7726bf5c3f..0427c868e6f 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -879,7 +879,6 @@ class LIR_OpConvert; class LIR_OpAllocObj; class LIR_OpReturn; class LIR_Op2; -class LIR_OpDelay; class LIR_Op3; class LIR_OpAllocArray; class LIR_Op4; @@ -985,9 +984,6 @@ enum LIR_Code { , lir_lock , lir_unlock , end_opLock - , begin_delay_slot - , lir_delay_slot - , end_delay_slot , begin_opTypeCheck , lir_instanceof , lir_checkcast @@ -1124,7 +1120,6 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_OpCall* as_OpCall() { return nullptr; } virtual LIR_OpJavaCall* as_OpJavaCall() { return nullptr; } virtual LIR_OpLabel* as_OpLabel() { return nullptr; } - virtual LIR_OpDelay* as_OpDelay() { return nullptr; } virtual LIR_OpLock* as_OpLock() { return nullptr; } virtual LIR_OpAllocArray* as_OpAllocArray() { return nullptr; } virtual LIR_OpAllocObj* as_OpAllocObj() { return nullptr; } @@ -1886,25 +1881,6 @@ class LIR_OpLoadKlass: public LIR_Op { void print_instr(outputStream* out) const PRODUCT_RETURN; }; -class LIR_OpDelay: public LIR_Op { - friend class LIR_OpVisitState; - - private: - LIR_Op* _op; - - public: - LIR_OpDelay(LIR_Op* op, CodeEmitInfo* info): - LIR_Op(lir_delay_slot, LIR_OprFact::illegalOpr, info), - _op(op) { - assert(op->code() == lir_nop, "should be filling with nops"); - } - virtual void emit_code(LIR_Assembler* masm); - virtual LIR_OpDelay* as_OpDelay() { return this; } - void print_instr(outputStream* out) const PRODUCT_RETURN; - LIR_Op* delay_op() const { return _op; } - CodeEmitInfo* call_info() const { return info(); } -}; - #ifdef ASSERT // LIR_OpAssert class LIR_OpAssert : public LIR_Op2 { diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 7cf414ae7dc..6dbd35f054f 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -194,8 +194,7 @@ void LIR_Assembler::emit_exception_entries(ExceptionInfoList* info_list) { XHandler* handler = handlers->handler_at(j); assert(handler->lir_op_id() != -1, "handler not processed by LinearScan"); assert(handler->entry_code() == nullptr || - handler->entry_code()->instructions_list()->last()->code() == lir_branch || - handler->entry_code()->instructions_list()->last()->code() == lir_delay_slot, "last operation must be branch"); + handler->entry_code()->instructions_list()->last()->code() == lir_branch, "last operation must be branch"); if (handler->entry_pco() == -1) { // entry code not emitted yet diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index a4c5fd61d4c..4cb313af901 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. 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 @@ -154,8 +154,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_block(BlockBegin* block); void emit_lir_list(LIR_List* list); - // any last minute peephole optimizations are performed here. In - // particular sparc uses this for delay slot filling. + // any last minute peephole optimizations are performed here. void peephole(LIR_List* list); void return_op(LIR_Opr result, C1SafepointPollStub* code_stub); @@ -204,7 +203,6 @@ class LIR_Assembler: public CompilationResourceObj { void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); void emit_profile_type(LIR_OpProfileType* op); - void emit_delay(LIR_OpDelay* op); void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info); void arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info); diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 714a964b28d..a6a08815d10 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -186,8 +186,7 @@ class nmethod; // relative offset. (Both n and l are relative to the call's first byte.) // // The limit l of the search is exclusive. However, if it points within -// the call (e.g., offset zero), it is adjusted to point after the call and -// any associated machine-specific delay slot. +// the call (e.g., offset zero), it is adjusted to point after the call. // // Since the offsets could be as wide as 32-bits, these conventions // put no restrictions whatever upon code reorganization. @@ -1109,7 +1108,6 @@ class virtual_call_Relocation : public CallRelocation { // data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll] // oop_limit is set to 0 if the limit falls somewhere within the call. // When unpacking, a zero oop_limit is taken to refer to the end of the call. - // (This has the effect of bringing in the call's delay slot on SPARC.) void pack_data_to(CodeSection* dest) override; void unpack_data() override; diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 9a6970ebf20..90d24b609a7 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -106,12 +106,6 @@ private: // Remember the next node Node *_next_node; - // Use this for an unconditional branch delay slot - Node *_unconditional_delay_slot; - - // Pointer to a Nop - MachNopNode *_nop; - // Length of the current bundle, in instructions uint _bundle_instr_count; @@ -128,9 +122,6 @@ private: public: Scheduling(Arena *arena, Compile &compile); - // Destructor - NOT_PRODUCT( ~Scheduling(); ) - // Step ahead "i" cycles void step(uint i); @@ -194,10 +185,7 @@ public: #ifndef PRODUCT private: // Gather information on size of nops relative to total - uint _branches, _unconditional_delays; - static uint _total_nop_size, _total_method_size; - static uint _total_branches, _total_unconditional_delays; static uint _total_instructions_per_bundle[Pipeline::_max_instrs_per_cycle+1]; public: @@ -1472,7 +1460,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } // Now fill in the code buffer - Node* delay_slot = nullptr; for (uint i = 0; i < nblocks; i++) { Block* block = C->cfg()->get_block(i); _block = block; @@ -1511,15 +1498,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { // Get the node Node* n = block->get_node(j); - // See if delay slots are supported - if (valid_bundle_info(n) && node_bundling(n)->used_in_unconditional_delay()) { - assert(delay_slot == nullptr, "no use of delay slot node"); - assert(n->size(C->regalloc()) == Pipeline::instr_unit_size(), "delay slot instruction wrong size"); - - delay_slot = n; - continue; - } - // If this starts a new instruction group, then flush the current one // (but allow split bundles) if (Pipeline::requires_bundling() && starts_bundle(n)) @@ -1538,9 +1516,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { current_offset = masm->offset(); } - // A padding may be needed again since a previous instruction - // could be moved to delay slot. - // align the instruction if necessary int padding = mach->compute_padding(current_offset); // Make sure safepoint node for polling is distinct from a call's @@ -1613,13 +1588,10 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { // This requires the TRUE branch target be in succs[0] uint block_num = block->non_connector_successor(0)->_pre_order; - // Try to replace long branch if delay slot is not used, + // Try to replace long branch, // it is mostly for back branches since forward branch's // distance is not updated yet. - bool delay_slot_is_used = valid_bundle_info(n) && - C->output()->node_bundling(n)->use_unconditional_delay(); - if (!delay_slot_is_used && mach->may_be_short_branch()) { - assert(delay_slot == nullptr, "not expecting delay slot node"); + if (mach->may_be_short_branch()) { int br_size = n->size(C->regalloc()); int offset = blk_starts[block_num] - current_offset; if (block_num >= i) { @@ -1753,44 +1725,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { last_avoid_back_to_back_offset = current_offset; } - // See if this instruction has a delay slot - if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) { - guarantee(delay_slot != nullptr, "expecting delay slot node"); - - // Back up 1 instruction - masm->code()->set_insts_end(masm->code()->insts_end() - Pipeline::instr_unit_size()); - - // Save the offset for the listing -#if defined(SUPPORT_OPTO_ASSEMBLY) - if ((node_offsets != nullptr) && (delay_slot->_idx < node_offset_limit)) { - node_offsets[delay_slot->_idx] = masm->offset(); - } -#endif - - // Support a SafePoint in the delay slot - if (delay_slot->is_MachSafePoint()) { - MachNode *mach = delay_slot->as_Mach(); - // !!!!! Stubs only need an oopmap right now, so bail out - if (!mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == nullptr) { - // Write the oopmap directly to the code blob??!! - delay_slot = nullptr; - continue; - } - - int adjusted_offset = current_offset - Pipeline::instr_unit_size(); - non_safepoints.observe_safepoint(mach->as_MachSafePoint()->jvms(), - adjusted_offset); - // Generate an OopMap entry - Process_OopMap_Node(mach, adjusted_offset); - } - - // Insert the delay slot instruction - delay_slot->emit(masm, C->regalloc()); - - // Don't reuse it - delay_slot = nullptr; - } - } // End for all instructions in block // If the next block is the top of a loop, pad this block out to align @@ -2031,8 +1965,6 @@ void PhaseOutput::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_s #ifndef PRODUCT uint Scheduling::_total_nop_size = 0; uint Scheduling::_total_method_size = 0; -uint Scheduling::_total_branches = 0; -uint Scheduling::_total_unconditional_delays = 0; uint Scheduling::_total_instructions_per_bundle[Pipeline::_max_instrs_per_cycle+1]; #endif @@ -2050,14 +1982,7 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) _bundle_instr_count(0), _bundle_cycle_number(0), _bundle_use(0, 0, resource_count, &_bundle_use_elements[0]) -#ifndef PRODUCT - , _branches(0) - , _unconditional_delays(0) -#endif { - // Create a MachNopNode - _nop = new MachNopNode(); - // Save the count _node_bundling_limit = compile.unique(); uint node_max = _regalloc->node_regs_max_index(); @@ -2087,14 +2012,6 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) _next_node = block->get_node(block->number_of_nodes() - 1); } -#ifndef PRODUCT -// Scheduling destructor -Scheduling::~Scheduling() { - _total_branches += _branches; - _total_unconditional_delays += _unconditional_delays; -} -#endif - // Step ahead "i" cycles void Scheduling::step(uint i) { @@ -2199,15 +2116,6 @@ void PhaseOutput::print_scheduling(outputStream* output_stream) { bool Scheduling::NodeFitsInBundle(Node *n) { uint n_idx = n->_idx; - // If this is the unconditional delay instruction, then it fits - if (n == _unconditional_delay_slot) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# NodeFitsInBundle [%4d]: TRUE; is in unconditional delay slot\n", n->_idx); -#endif - return (true); - } - // If the node cannot be scheduled this cycle, skip it if (_current_latency[n_idx] > _bundle_cycle_number) { #ifndef PRODUCT @@ -2223,8 +2131,6 @@ bool Scheduling::NodeFitsInBundle(Node *n) { uint instruction_count = node_pipeline->instructionCount(); if (node_pipeline->mayHaveNoCode() && n->size(_regalloc) == 0) instruction_count = 0; - else if (node_pipeline->hasBranchDelay() && !_unconditional_delay_slot) - instruction_count++; if (_bundle_instr_count + instruction_count > Pipeline::_max_instrs_per_cycle) { #ifndef PRODUCT @@ -2436,99 +2342,6 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { const Pipeline *node_pipeline = n->pipeline(); const Pipeline_Use& node_usage = node_pipeline->resourceUse(); - // Check for instructions to be placed in the delay slot. We - // do this before we actually schedule the current instruction, - // because the delay slot follows the current instruction. - if (Pipeline::_branch_has_delay_slot && - node_pipeline->hasBranchDelay() && - !_unconditional_delay_slot) { - - uint siz = _available.size(); - - // Conditional branches can support an instruction that - // is unconditionally executed and not dependent by the - // branch, OR a conditionally executed instruction if - // the branch is taken. In practice, this means that - // the first instruction at the branch target is - // copied to the delay slot, and the branch goes to - // the instruction after that at the branch target - if ( n->is_MachBranch() ) { - - assert( !n->is_MachNullCheck(), "should not look for delay slot for Null Check" ); - assert( !n->is_Catch(), "should not look for delay slot for Catch" ); - -#ifndef PRODUCT - _branches++; -#endif - - // At least 1 instruction is on the available list - // that is not dependent on the branch - for (uint i = 0; i < siz; i++) { - Node *d = _available[i]; - const Pipeline *avail_pipeline = d->pipeline(); - - // Don't allow safepoints in the branch shadow, that will - // cause a number of difficulties - if ( avail_pipeline->instructionCount() == 1 && - !avail_pipeline->hasMultipleBundles() && - !avail_pipeline->hasBranchDelay() && - Pipeline::instr_has_unit_size() && - d->size(_regalloc) == Pipeline::instr_unit_size() && - NodeFitsInBundle(d) && - !node_bundling(d)->used_in_delay()) { - - if (d->is_Mach() && !d->is_MachSafePoint()) { - // A node that fits in the delay slot was found, so we need to - // set the appropriate bits in the bundle pipeline information so - // that it correctly indicates resource usage. Later, when we - // attempt to add this instruction to the bundle, we will skip - // setting the resource usage. - _unconditional_delay_slot = d; - node_bundling(n)->set_use_unconditional_delay(); - node_bundling(d)->set_used_in_unconditional_delay(); - _bundle_use.add_usage(avail_pipeline->resourceUse()); - _current_latency[d->_idx] = _bundle_cycle_number; - _next_node = d; - ++_bundle_instr_count; -#ifndef PRODUCT - _unconditional_delays++; -#endif - break; - } - } - } - } - - // No delay slot, add a nop to the usage - if (!_unconditional_delay_slot) { - // See if adding an instruction in the delay slot will overflow - // the bundle. - if (!NodeFitsInBundle(_nop)) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(1 instruction for delay slot) ***\n"); -#endif - step(1); - } - - _bundle_use.add_usage(_nop->pipeline()->resourceUse()); - _next_node = _nop; - ++_bundle_instr_count; - } - - // See if the instruction in the delay slot requires a - // step of the bundles - if (!NodeFitsInBundle(n)) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(branch won't fit) ***\n"); -#endif - // Update the state information - _bundle_instr_count = 0; - _bundle_cycle_number += 1; - _bundle_use.step(1); - } - } // Get the number of instructions uint instruction_count = node_pipeline->instructionCount(); @@ -2556,47 +2369,40 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { } } - // If this was placed in the delay slot, ignore it - if (n != _unconditional_delay_slot) { - - if (delay == 0) { - if (node_pipeline->hasMultipleBundles()) { + if (delay == 0) { + if (node_pipeline->hasMultipleBundles()) { #ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(multiple instructions) ***\n"); + if (_cfg->C->trace_opto_output()) + tty->print("# *** STEP(multiple instructions) ***\n"); #endif - step(1); - } - - else if (instruction_count + _bundle_instr_count > Pipeline::_max_instrs_per_cycle) { -#ifndef PRODUCT - if (_cfg->C->trace_opto_output()) - tty->print("# *** STEP(%d >= %d instructions) ***\n", - instruction_count + _bundle_instr_count, - Pipeline::_max_instrs_per_cycle); -#endif - step(1); - } + step(1); } - if (node_pipeline->hasBranchDelay() && !_unconditional_delay_slot) - _bundle_instr_count++; - - // Set the node's latency - _current_latency[n->_idx] = _bundle_cycle_number; - - // Now merge the functional unit information - if (instruction_count > 0 || !node_pipeline->mayHaveNoCode()) - _bundle_use.add_usage(node_usage); - - // Increment the number of instructions in this bundle - _bundle_instr_count += instruction_count; - - // Remember this node for later - if (n->is_Mach()) - _next_node = n; + else if (instruction_count + _bundle_instr_count > Pipeline::_max_instrs_per_cycle) { +#ifndef PRODUCT + if (_cfg->C->trace_opto_output()) + tty->print("# *** STEP(%d >= %d instructions) ***\n", + instruction_count + _bundle_instr_count, + Pipeline::_max_instrs_per_cycle); +#endif + step(1); + } } + // Set the node's latency + _current_latency[n->_idx] = _bundle_cycle_number; + + // Now merge the functional unit information + if (instruction_count > 0 || !node_pipeline->mayHaveNoCode()) + _bundle_use.add_usage(node_usage); + + // Increment the number of instructions in this bundle + _bundle_instr_count += instruction_count; + + // Remember this node for later + if (n->is_Mach()) + _next_node = n; + // It's possible to have a BoxLock in the graph and in the _bbs mapping but // not in the bb->_nodes array. This happens for debug-info-only BoxLocks. // 'Schedule' them (basically ignore in the schedule) but do not insert them @@ -2647,9 +2453,6 @@ void Scheduling::ComputeUseCount(const Block *bb) { _available.clear(); _scheduled.clear(); - // No delay slot specified - _unconditional_delay_slot = nullptr; - #ifdef ASSERT for( uint i=0; i < bb->number_of_nodes(); i++ ) assert( _uses[bb->get_node(i)->_idx] == 0, "_use array not clean" ); @@ -2767,11 +2570,7 @@ void Scheduling::DoScheduling() { break; // Funny loop structure to be sure... } // Compute last "interesting" instruction in block - last instruction we - // might schedule. _bb_end points just after last schedulable inst. We - // normally schedule conditional branches (despite them being forced last - // in the block), because they have delay slots we can fill. Calls all - // have their delay slots filled in the template expansions, so we don't - // bother scheduling them. + // might schedule. _bb_end points just after last schedulable inst. Node *last = bb->get_node(_bb_end); // Ignore trailing NOPs. while (_bb_end > 0 && last->is_Mach() && @@ -2837,7 +2636,7 @@ void Scheduling::DoScheduling() { Node *n = bb->get_node(j); if( valid_bundle_info(n) ) { Bundle *bundle = node_bundling(n); - if (bundle->instr_count() > 0 || bundle->flags() > 0) { + if (bundle->instr_count() > 0) { tty->print("*** Bundle: "); bundle->dump(); } @@ -3273,16 +3072,6 @@ void Scheduling::print_statistics() { ((double)_total_nop_size) / ((double) _total_method_size) * 100.0); tty->print("\n"); - // Print the number of branch shadows filled - if (Pipeline::_branch_has_delay_slot) { - tty->print("Of %d branches, %d had unconditional delay slots filled", - _total_branches, _total_unconditional_delays); - if (_total_branches > 0) - tty->print(", for %.2f%%", - ((double)_total_unconditional_delays) / ((double)_total_branches) * 100.0); - tty->print("\n"); - } - uint total_instructions = 0, total_bundles = 0; for (uint i = 1; i <= Pipeline::_max_instrs_per_cycle; i++) { @@ -3572,7 +3361,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { } // For all instructions - Node *delay = nullptr; for (uint j = 0; j < block->number_of_nodes(); j++) { if (VMThread::should_terminate()) { cut_short = true; @@ -3581,10 +3369,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { n = block->get_node(j); if (valid_bundle_info(n)) { Bundle* bundle = node_bundling(n); - if (bundle->used_in_unconditional_delay()) { - delay = n; - continue; - } if (bundle->starts_bundle()) { starts_bundle = '+'; } @@ -3617,29 +3401,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { st->cr(); } - // If we have an instruction with a delay slot, and have seen a delay, - // then back up and print it - if (valid_bundle_info(n) && node_bundling(n)->use_unconditional_delay()) { - // Coverity finding - Explicit null dereferenced. - guarantee(delay != nullptr, "no unconditional delay instruction"); - if (WizardMode) delay->dump(); - - if (node_bundling(delay)->starts_bundle()) - starts_bundle = '+'; - if ((pcs != nullptr) && (n->_idx < pc_limit)) { - pc = pcs[n->_idx]; - st->print("%*.*x", pc_digits, pc_digits, pc); - } else { - st->fill_to(pc_digits); - } - st->print(" %c ", starts_bundle); - starts_bundle = ' '; - st->fill_to(prefix_len); - delay->format(C->regalloc(), st); - st->cr(); - delay = nullptr; - } - // Dump the exception table as well if( n->is_Catch() && (Verbose || WizardMode) ) { // Print the exception table for this offset @@ -3648,7 +3409,6 @@ void PhaseOutput::dump_asm_on(outputStream* st, int* pcs, uint pc_limit) { st->bol(); // Make sure we start on a new line } st->cr(); // one empty line between blocks - assert(cut_short || delay == nullptr, "no unconditional delay branch"); } // End of per-block dump if (cut_short) st->print_cr("*** disassembly is cut short ***"); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 60161643315..710d34c3ccb 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3502,8 +3502,6 @@ frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* curren if (cb != nullptr && cb->is_nmethod()) { nm = cb->as_nmethod(); method = nm->method(); - // scope_desc_near() must be used, instead of scope_desc_at() because on - // SPARC, the pcDesc can be on the delay slot after the call instruction. for (ScopeDesc *sd = nm->scope_desc_near(fr.pc()); sd != nullptr; sd = sd->sender()) { method = sd->method(); if (method != nullptr && method->has_reserved_stack_access()) { From 9e3fa3216fd4ebd73da6e003a7b767cf001a1169 Mon Sep 17 00:00:00 2001 From: Kazuhisa Takakuri Date: Wed, 10 Sep 2025 06:37:17 +0000 Subject: [PATCH 442/471] 8349288: runtime/os/windows/TestAvailableProcessors.java fails on localized Windows platform Reviewed-by: dholmes, alanb --- .../os/windows/TestAvailableProcessors.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java index 795b3d76e54..f15514d024e 100644 --- a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java +++ b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java @@ -34,6 +34,7 @@ * @run testng/othervm/native TestAvailableProcessors */ +import java.io.File; import java.io.IOException; import java.util.List; import java.util.HashSet; @@ -58,7 +59,23 @@ public class TestAvailableProcessors { private static String getWindowsVersion() throws IOException { String systeminfoPath = "systeminfo.exe"; - var processBuilder = new ProcessBuilder(systeminfoPath); + List command = new ArrayList<>(); + + String systemRoot = System.getenv("SystemRoot"); + if (systemRoot == null) { + systemRoot = System.getenv("WINDIR"); + if (systemRoot == null) { + throw new RuntimeException("SystemRoot or WINDIR environment variable is not set."); + } + } + String system32 = Path.of(systemRoot, "System32").toString(); + + // It switches the active code page to cp437, the default code page for US english. + command.addAll(List.of("cmd.exe", "/c", "set", "PATH=%PATH%;" + system32 + ";" + system32 + "\\wbem", "&&")); + command.addAll(List.of("chcp", "437", ">nul", "2>&1", "&&")); + command.add(systeminfoPath); + + var processBuilder = new ProcessBuilder(command); OutputAnalyzer outputAnalyzer = new OutputAnalyzer(processBuilder.start()); outputAnalyzer.shouldHaveExitValue(0); outputAnalyzer.shouldContain(osVersionMessage); From f3de386263e16e33c2812706cf41410da2cd58c6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 10 Sep 2025 08:46:07 +0000 Subject: [PATCH 443/471] 8367309: Test runtime/os/windows/TestAvailableProcessors.java fails to compile after mis-merge Reviewed-by: shade, alanb --- .../jtreg/runtime/os/windows/TestAvailableProcessors.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java index f15514d024e..d5e5b1626b6 100644 --- a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java +++ b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java @@ -34,8 +34,10 @@ * @run testng/othervm/native TestAvailableProcessors */ -import java.io.File; + import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.HashSet; import java.util.Set; From 1d3364b00725f9d2afa8274e2244357a109be545 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Sep 2025 09:45:05 +0000 Subject: [PATCH 444/471] 8365239: Spec Clarification - InterfaceAddress:getBroadcast() returning null for loop back address Reviewed-by: msheppar, djelinski, jpai --- src/java.base/share/classes/java/net/InterfaceAddress.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/net/InterfaceAddress.java b/src/java.base/share/classes/java/net/InterfaceAddress.java index 6df2de353e3..44b3456c6fc 100644 --- a/src/java.base/share/classes/java/net/InterfaceAddress.java +++ b/src/java.base/share/classes/java/net/InterfaceAddress.java @@ -63,8 +63,8 @@ public final class InterfaceAddress { * Only IPv4 networks have broadcast address therefore, in the case * of an IPv6 network, {@code null} will be returned. *

            - * Certain network interfaces, such as the loopback interface, do not support - * broadcasting and will also return {@code null}. + * Some network interfaces do not support broadcasting and may + * also return {@code null}. * * @return the {@code InetAddress} representing the broadcast * address or {@code null} if there is no broadcast address. From 5c9f60dc5a6e64be55819469bbf10948803d0fd5 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 09:57:44 +0000 Subject: [PATCH 445/471] 8367259: Clean up make/scripts and bin directory Reviewed-by: erikj --- {make/scripts => bin}/generate-symbol-data.sh | 31 ++- {make/scripts => bin}/lic_check.sh | 4 +- {make/scripts => bin}/normalizer.pl | 0 bin/unshuffle_list.txt | 191 -------------- bin/unshuffle_patch.sh | 237 ------------------ .../scripts => bin}/update_copyright_year.sh | 0 {make/scripts => bin}/update_pch.sh | 12 +- make/autoconf/compare.sh.template | 2 +- make/scripts/{logger.sh => compare-logger.sh} | 0 .../hide_important_warnings_from_javac.sh | 36 --- 10 files changed, 43 insertions(+), 470 deletions(-) rename {make/scripts => bin}/generate-symbol-data.sh (83%) rename {make/scripts => bin}/lic_check.sh (98%) rename {make/scripts => bin}/normalizer.pl (100%) delete mode 100644 bin/unshuffle_list.txt delete mode 100644 bin/unshuffle_patch.sh rename {make/scripts => bin}/update_copyright_year.sh (100%) rename {make/scripts => bin}/update_pch.sh (92%) rename make/scripts/{logger.sh => compare-logger.sh} (100%) delete mode 100644 make/scripts/hide_important_warnings_from_javac.sh diff --git a/make/scripts/generate-symbol-data.sh b/bin/generate-symbol-data.sh similarity index 83% rename from make/scripts/generate-symbol-data.sh rename to bin/generate-symbol-data.sh index 6f38d873009..283757a6918 100644 --- a/make/scripts/generate-symbol-data.sh +++ b/bin/generate-symbol-data.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2025, Oracle and/or its affiliates. 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 @@ -52,12 +52,39 @@ # include the SCM state that was used to build it, which can be found in ${JDK_N_INSTALL}/release, # in property "SOURCE". +source_path="$(dirname ${0})" +this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)" +if test -z "${this_script_dir}"; then + echo "Error: Could not determine location of this script" + exit 1 +fi + +symbols_dir="$(dirname $this_script_dir)/src/jdk.compiler/share/data/symbols" +if [ ! -d $symbols_dir ] ; then + echo "Cannot locate symbols directory: $symbols_dir" >&2 + exit 1 +fi + +generator_dir="$(dirname $this_script_dir)/make/langtools/src/classes/build/tools/symbolgenerator" + if [ "$1x" = "x" ] ; then echo "Must provide the target JDK as a parameter:" >&2 echo "$0 " >&2 exit 1 fi; +if [ ! -d $1 ] ; then + echo "Target JDK argument is not a directory:" $1 >&2 + exit 1 +fi; + +if [ ! -x $1/bin/java ] ; then + echo "Target JDK argument is not a valid JDK: $1" >&2 + exit 1 +fi; + +cd $symbols_dir + if [ ! -f symbols ] ; then echo "Must run inside the src/jdk.compiler/share/data/symbols directory" >&2 exit 1 @@ -72,5 +99,5 @@ $1/bin/java --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-modules jdk.jdeps \ - ../../../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ + $generator_dir/CreateSymbols.java \ build-description-incremental symbols include.list diff --git a/make/scripts/lic_check.sh b/bin/lic_check.sh similarity index 98% rename from make/scripts/lic_check.sh rename to bin/lic_check.sh index d70d8914181..2fc6abf4d82 100644 --- a/make/scripts/lic_check.sh +++ b/bin/lic_check.sh @@ -1,6 +1,6 @@ #! /bin/sh -f # -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2025, Oracle and/or its affiliates. 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 @@ -62,7 +62,7 @@ B=`basename "${script_directory}"` script_dir="`cd \"${D}\" 2>/dev/null && pwd || echo \"${D}\"`/${B}" # set up a variable for the template directory -template_dir=${script_dir}/../data/license-templates +template_dir=${script_dir}/../make/data/license-templates # Check existence of the template directory. if [ ! -d ${template_dir} ] ; then diff --git a/make/scripts/normalizer.pl b/bin/normalizer.pl similarity index 100% rename from make/scripts/normalizer.pl rename to bin/normalizer.pl diff --git a/bin/unshuffle_list.txt b/bin/unshuffle_list.txt deleted file mode 100644 index a910f6b4621..00000000000 --- a/bin/unshuffle_list.txt +++ /dev/null @@ -1,191 +0,0 @@ -# -# Copyright (c) 2014, 2025, Oracle and/or its affiliates. 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. -# -# 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. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -src/bsd : jdk/src/bsd -src/demo : jdk/src/demo -src/java.activation : jaxws/src/java.activation -src/java.base : jdk/src/java.base -src/java.compiler : langtools/src/java.compiler -src/java.corba : corba/src/java.corba -src/java.datatransfer : jdk/src/java.datatransfer -src/java.desktop : jdk/src/java.desktop -src/java.instrument : jdk/src/java.instrument -src/java.logging : jdk/src/java.logging -src/java.management : jdk/src/java.management -src/java.management.rmi : jdk/src/java.management.rmi -src/java.naming : jdk/src/java.naming -src/java.prefs : jdk/src/java.prefs -src/java.rmi : jdk/src/java.rmi -src/java.scripting : jdk/src/java.scripting -src/java.se : jdk/src/java.se -src/java.security.jgss : jdk/src/java.security.jgss -src/java.security.sasl : jdk/src/java.security.sasl -src/java.se.ee : jdk/src/java.se.ee -src/java.smartcardio : jdk/src/java.smartcardio -src/java.sql : jdk/src/java.sql -src/java.sql.rowset : jdk/src/java.sql.rowset -src/java.transaction : jdk/src/java.transaction -src/java.xml : jaxp/src/java.xml -src/java.xml.bind : jaxws/src/java.xml.bind -src/java.xml.crypto : jdk/src/java.xml.crypto -src/java.xml.ws : jaxws/src/java.xml.ws -src/java.xml.ws.annotation : jaxws/src/java.xml.ws.annotation -src/jdk.accessibility : jdk/src/jdk.accessibility -src/jdk.aot : hotspot/src/jdk.aot -src/jdk.attach : jdk/src/jdk.attach -src/jdk.charsets : jdk/src/jdk.charsets -src/jdk.compiler : jdk/src/jdk.compiler langtools/src/jdk.compiler -src/jdk.crypto.cryptoki : jdk/src/jdk.crypto.cryptoki -src/jdk.crypto.ec : jdk/src/jdk.crypto.ec -src/jdk.crypto.mscapi : jdk/src/jdk.crypto.mscapi -src/jdk.dynalink : nashorn/src/jdk.dynalink -src/jdk.editpad : jdk/src/jdk.editpad -src/jdk.hotspot.agent : hotspot/src/jdk.hotspot.agent -src/jdk.httpserver : jdk/src/jdk.httpserver -src/jdk.incubator.httpclient : jdk/src/jdk.incubator.httpclient -src/jdk.internal.ed : jdk/src/jdk.internal.ed -src/jdk.internal.jvmstat : jdk/src/jdk.internal.jvmstat -src/jdk.internal.le : jdk/src/jdk.internal.le -src/jdk.internal.opt : jdk/src/jdk.internal.opt -src/jdk.internal.vm.ci : hotspot/src/jdk.internal.vm.ci -src/jdk.internal.vm.compiler : hotspot/src/jdk.internal.vm.compiler -src/jdk.jartool : jdk/src/jdk.jartool -src/jdk.javadoc : langtools/src/jdk.javadoc -src/jdk.jcmd : jdk/src/jdk.jcmd -src/jdk.jconsole : jdk/src/jdk.jconsole -src/jdk.jdeps : langtools/src/jdk.jdeps -src/jdk.jdi : jdk/src/jdk.jdi -src/jdk.jdwp.agent : jdk/src/jdk.jdwp.agent -src/jdk.jlink : jdk/src/jdk.jlink -src/jdk.jshell : langtools/src/jdk.jshell -src/jdk.jstatd : jdk/src/jdk.jstatd -src/jdk.localedata : jdk/src/jdk.localedata -src/jdk.management : jdk/src/jdk.management -src/jdk.management.agent : jdk/src/jdk.management.agent -src/jdk.naming.dns : jdk/src/jdk.naming.dns -src/jdk.naming.rmi : jdk/src/jdk.naming.rmi -src/jdk.net : jdk/src/jdk.net -src/jdk.pack : jdk/src/jdk.pack -src/jdk.scripting.nashorn : nashorn/src/jdk.scripting.nashorn -src/jdk.scripting.nashorn.shell : nashorn/src/jdk.scripting.nashorn.shell -src/jdk.sctp : jdk/src/jdk.sctp -src/jdk.security.auth : jdk/src/jdk.security.auth -src/jdk.security.jgss : jdk/src/jdk.security.jgss -src/jdk.unsupported : jdk/src/jdk.unsupported -src/jdk.xml.bind : jaxws/src/jdk.xml.bind -src/jdk.xml.dom : jaxp/src/jdk.xml.dom -src/jdk.xml.ws : jaxws/src/jdk.xml.ws -src/jdk.zipfs : jdk/src/jdk.zipfs -src/langtools/sample : langtools/src/sample -src/linux : jdk/src/linux -src/sample : jdk/src/sample -src/hotspot/share : hotspot/src/share/vm -src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm -src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm -src/hotspot/cpu/ppc : hotspot/src/cpu/ppc/vm -src/hotspot/cpu/s390 : hotspot/src/cpu/s390/vm -src/hotspot/cpu/x86 : hotspot/src/cpu/x86/vm -src/hotspot/cpu/zero : hotspot/src/cpu/zero/vm -src/hotspot/os/aix : hotspot/src/os/aix/vm -src/hotspot/os/bsd : hotspot/src/os/bsd/vm -src/hotspot/os/linux : hotspot/src/os/linux/vm -src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace -src/hotspot/os/posix : hotspot/src/os/posix/vm -src/hotspot/os/windows : hotspot/src/os/windows/vm -src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm -src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm -src/hotspot/os_cpu/bsd_zero : hotspot/src/os_cpu/bsd_zero/vm -src/hotspot/os_cpu/linux_aarch64 : hotspot/src/os_cpu/linux_aarch64/vm -src/hotspot/os_cpu/linux_arm : hotspot/src/os_cpu/linux_arm/vm -src/hotspot/os_cpu/linux_ppc : hotspot/src/os_cpu/linux_ppc/vm -src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm -src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm -src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm -src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm -src/hotspot : hotspot/src -src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer -src/utils/LogCompilation : hotspot/src/share/tools/LogCompilation -src/utils/hsdis : hotspot/src/share/tools/hsdis -src/utils/reorder : jdk/make/non-build-utils/reorder -src/utils/src/build : jdk/make/non-build-utils/src/build -make/BuildNashorn.gmk : nashorn/make/BuildNashorn.gmk -make/CompileDemos.gmk : jdk/make/CompileDemos.gmk -make/CompileInterimLangtools.gmk : langtools/make/CompileInterim.gmk -make/CompileModuleTools.gmk : jdk/make/CompileModuleTools.gmk -make/CompileToolsHotspot.gmk : hotspot/make/CompileTools.gmk -make/CompileToolsJdk.gmk : jdk/make/CompileTools.gmk -make/CopyInterimCLDRConverter.gmk : jdk/make/CopyInterimCLDRConverter.gmk -make/GenerateModuleSummary.gmk : jdk/make/GenerateModuleSummary.gmk -make/ModuleTools.gmk : jdk/make/ModuleTools.gmk -make/ToolsJdk.gmk : jdk/make/Tools.gmk -make/ToolsLangtools.gmk : langtools/make/Tools.gmk -make/UnpackSecurity.gmk : jdk/make/UnpackSecurity.gmk -make/autoconf : common/autoconf -make/conf : common/conf -make/copy : jdk/make/copy -make/copy/Copy-java.corba.gmk : corba/make/copy/Copy-java.corba.gmk -make/corba : corba/make -make/data : jdk/make/data -make/gendata : jdk/make/gendata -make/gendata/Gendata-jdk.compiler.gmk : langtools/make/gendata/Gendata-jdk.compiler.gmk -make/gensrc : jdk/make/gensrc -make/gensrc/Gensrc-java.corba.gmk : corba/make/gensrc/Gensrc-java.corba.gmk -make/gensrc/Gensrc-jdk.compiler.gmk : langtools/make/gensrc/Gensrc-jdk.compiler.gmk -make/gensrc/Gensrc-jdk.hotspot.agent.gmk : hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk -make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk : hotspot/make/gensrc/Gensrc-jdk.internal.vm.compiler.gmk -make/gensrc/Gensrc-jdk.javadoc.gmk : langtools/make/gensrc/Gensrc-jdk.javadoc.gmk -make/gensrc/Gensrc-jdk.jdeps.gmk : langtools/make/gensrc/Gensrc-jdk.jdeps.gmk -make/gensrc/Gensrc-jdk.jshell.gmk : langtools/make/gensrc/Gensrc-jdk.jshell.gmk -make/gensrc/GensrcCommonLangtools.gmk : langtools/make/gensrc/GensrcCommon.gmk -make/hotspot : hotspot/make -make/jdk : jdk/make -make/langtools : langtools/make -make/launcher : jdk/make/launcher -make/lib : jdk/make/lib -make/lib/Lib-jdk.hotspot.agent.gmk : hotspot/make/lib/Lib-jdk.hotspot.agent.gmk -make/mapfiles : jdk/make/mapfiles -make/mapfiles/libjsig : hotspot/make/mapfiles/libjsig -make/mapfiles/libjvm_db : hotspot/make/mapfiles/libjvm_db -make/mapfiles/libjvm_dtrace : hotspot/make/mapfiles/libjvm_dtrace -make/mapfiles/libsaproc : hotspot/make/mapfiles/libsaproc -make/nashorn : nashorn/make -make/nb_native : common/nb_native -make/scripts/addNotices.sh : jdk/make/scripts/addNotices.sh -make/scripts/compare.sh : common/bin/compare.sh -make/scripts/compare_exceptions.sh.incl : common/bin/compare_exceptions.sh.incl -make/scripts/genExceptions.sh : jdk/make/scripts/genExceptions.sh -make/scripts/hide_important_warnings_from_javac.sh : common/bin/hide_important_warnings_from_javac.sh -make/scripts/logger.sh : common/bin/logger.sh -make/src/native/fixpath.c : common/src/fixpath.c -make/test/JtregNativeHotspot.gmk : hotspot/make/test/JtregNative.gmk -make/test/JtregNativeJdk.gmk : jdk/make/test/JtregNative.gmk -test/jdk : jdk/test -test/langtools : langtools/test -test/nashorn : nashorn/test -test/jaxp : jaxp/test -test/hotspot/gtest : hotspot/test/native -test/hotspot/jtreg : hotspot/test -bin : common/bin -bin/nashorn : nashorn/bin -doc : common/doc -doc/nashorn : nashorn/docs diff --git a/bin/unshuffle_patch.sh b/bin/unshuffle_patch.sh deleted file mode 100644 index c5cdc3851c3..00000000000 --- a/bin/unshuffle_patch.sh +++ /dev/null @@ -1,237 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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. -# -# 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. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# Script for updating a patch file as per the shuffled/unshuffled source location. - -usage() { - echo "Usage: $0 [-h|--help] [-v|--verbose] [-to9|-to10] [-r ] " - echo "where:" - echo " -to9 create patches appropriate for a JDK 9 source tree" - echo " When going to 9, the output patches will be suffixed with the" - echo " repo name" - echo " -to10 create patches appropriate for a JDK 10 source tree" - echo " -r specify repo for source patch, set to 'top' for top repo" - echo " is the input patch file, that needs shuffling/unshuffling" - echo " is the updated patch file " - echo " " - exit 1 -} - -SCRIPT_DIR=`dirname $0` -UNSHUFFLE_LIST=$SCRIPT_DIR"/unshuffle_list.txt" - -if [ ! -f "$UNSHUFFLE_LIST" ] ; then - echo "FATAL: cannot find $UNSHUFFLE_LIST" >&2 - exit 1 -fi - -vflag="false" -while [ $# -gt 0 ] -do - case $1 in - -h | --help ) - usage - ;; - - -v | --verbose ) - vflag="true" - ;; - - -r) - repo="$2" - shift - ;; - - -to9) - shuffle_to=9 - ;; - - -to10) - shuffle_to=10 - ;; - - -*) # bad option - usage - ;; - - * ) # non option - break - ;; - esac - shift -done - -# Make sure we have the right number of arguments -if [ ! $# -eq 2 ] ; then - echo "ERROR: Invalid number of arguments." >&2 - usage -fi - -# Check the given repo -repos="top corba jaxp jaxws jdk langtools nashorn hotspot" -found="false" -if [ -n "$repo" ]; then - for r in $repos ; do - if [ $repo = "$r" ] ; then - found="true" - break; - fi - done - if [ $found = "false" ] ; then - echo "ERROR: Unknown repo: $repo. Should be one of [$repos]." >&2 - usage - fi -fi - -if [ "$shuffle_to" != "9" -a "$shuffle_to" != "10" ]; then - echo "ERROR: Must pick either -to9 or -to10" - exit 1 -fi - -# When going to 10, a repo must be specified for the source patch -if [ "$shuffle_to" = "10" -a -z "$repo" ]; then - echo "ERROR: Must specify src repo for JDK 9 patch" - exit 1 -fi - -# Check given input/output files -input="$1" -if [ "x$input" = "x-" ] ; then - input="/dev/stdin" -fi - -if [ ! -f $input -a "x$input" != "x/dev/stdin" ] ; then - echo "ERROR: Cannot find input patch file: $input" >&2 - exit 1 -fi - -output="$2" -if [ "x$output" = "x-" ] ; then - output="/dev/stdout" -fi -base_output="$output" - -if [ "$shuffle_to" = "10" ]; then - if [ -f $output -a "x$output" != "x/dev/stdout" ] ; then - echo "ERROR: Output patch already exists: $output" >&2 - exit 1 - fi -else - for r in $repos; do - if [ -f "$output.$r" ]; then - echo "ERROR: Output patch already exists: $output.$r" >&2 - exit 1 - fi - done -fi - -verbose() { - if [ ${vflag} = "true" ] ; then - echo "$@" >&2 - fi -} - -unshuffle() { - line=$@ - verbose "Attempting to rewrite: \"$line\"" - - # Retrieve the file name - path= - if echo "$line" | egrep '^diff' > /dev/null ; then - if ! echo "$line" | egrep '\-\-git' > /dev/null ; then - echo "ERROR: Only git patches supported. Please use 'hg export --git ...'." >&2 - exit 1 - fi - path="`echo "$line" | sed -e s@'diff --git a/'@@ -e s@' b/.*$'@@`" - elif echo "$line" | egrep '^\-\-\-' > /dev/null ; then - path="`echo "$line" | sed -e s@'--- a/'@@`" - elif echo "$line" | egrep '^\+\+\+' > /dev/null ; then - path="`echo "$line" | sed s@'+++ b/'@@`" - fi - verbose "Extracted path: \"$path\"" - - # Find the most specific matches in the shuffle list - matches= - if [ -n "$repo" -a "$repo" != "top" ]; then - matchpath="$repo"/"$path"/x - else - matchpath="$path"/x - fi - while [ "$matchpath" != "" ] ; do - matchpath="`echo $matchpath | sed s@'\(.*\)/.*$'@'\1'@`" - - if [ "$shuffle_to" = "10" ] ; then - pattern=": $matchpath$" - else - pattern="^$matchpath :" - fi - verbose "Attempting to find \"$matchpath\"" - matches=`egrep "$pattern" "$UNSHUFFLE_LIST"` - if ! [ "x${matches}" = "x" ] ; then - verbose "Got matches: [$matches]" - break; - fi - - if ! echo "$matchpath" | egrep '.*/.*' > /dev/null ; then - break; - fi - done - - # Rewrite the line, if we have a match - if ! [ "x${matches}" = "x" ] ; then - shuffled="${matches%% : *}" - unshuffled="${matches#* : }" - patch_suffix_9="" - for r in $repos; do - if [ "$unshuffled" != "${unshuffled#$r}" ]; then - unshuffled="${unshuffled#$r\/}" - patch_suffix_9=".$r" - fi - done - verbose "shuffled: $shuffled" - verbose "unshuffled: $unshuffled" - verbose "patch_suffix_9: $patch_suffix_9" - if [ "$shuffle_to" = "10" ] ; then - newline="`echo "$line" | sed -e s@"$unshuffled"@"$shuffled"@g`" - else - newline="`echo "$line" | sed -e s@"$shuffled"@"$unshuffled"@g`" - output=$base_output$patch_suffix_9 - verbose "Writing to $output" - fi - verbose "Rewriting to \"$newline\"" - echo "$newline" >> $output - else - echo "WARNING: no match found for $path" - echo "$line" >> $output - fi -} - -while IFS= read -r line -do - if echo "$line" | egrep '^diff|^\-\-\-|^\+\+\+' > /dev/null ; then - unshuffle "$line" - else - printf "%s\n" "$line" >> $output - fi -done < "$input" diff --git a/make/scripts/update_copyright_year.sh b/bin/update_copyright_year.sh similarity index 100% rename from make/scripts/update_copyright_year.sh rename to bin/update_copyright_year.sh diff --git a/make/scripts/update_pch.sh b/bin/update_pch.sh similarity index 92% rename from make/scripts/update_pch.sh rename to bin/update_pch.sh index 534525353fd..d7871fdd753 100644 --- a/make/scripts/update_pch.sh +++ b/bin/update_pch.sh @@ -23,9 +23,19 @@ # The output of this script may require some degree of human curation: # - Redundant headers, e.g. both x.hpp, x.inline.hpp are included; # - Headers relative to a non-default feature should be protected by an -# appropriate 'if' clause to make sure all variants can build without +# appropriate 'if' clause to make sure all variants can build without # errors. +source_path="$(dirname ${0})" +this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)" +if test -z "${this_script_dir}"; then + echo "Error: Could not determine location of this script" + exit 1 +fi + +# Work in top directory +cd $this_script_dir/.. + # Time threshold for header compilation, if the time exceeds the # threshold the header will be precompiled. if [ -z "$MIN_MS" ]; then diff --git a/make/autoconf/compare.sh.template b/make/autoconf/compare.sh.template index bcb5608855a..84421035ab9 100644 --- a/make/autoconf/compare.sh.template +++ b/make/autoconf/compare.sh.template @@ -110,4 +110,4 @@ $MV $OUTPUTDIR/compare.log $OUTPUTDIR/compare.log.old 2> /dev/null export SCRIPT_DIR="$( cd "$( dirname "$0" )" > /dev/null && pwd )" -$BASH $TOPDIR/make/scripts/logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@" +$BASH $TOPDIR/make/scripts/compare-logger.sh $OUTPUTDIR/compare.log $BASH "$REAL_COMPARE_SCRIPT" "$@" diff --git a/make/scripts/logger.sh b/make/scripts/compare-logger.sh similarity index 100% rename from make/scripts/logger.sh rename to make/scripts/compare-logger.sh diff --git a/make/scripts/hide_important_warnings_from_javac.sh b/make/scripts/hide_important_warnings_from_javac.sh deleted file mode 100644 index 392ed33247a..00000000000 --- a/make/scripts/hide_important_warnings_from_javac.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. 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. -# -# 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. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -GREP=grep - -# -EXP="Note: Some input files use or override a deprecated API." -EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details." -EXP="${EXP}|Note: Some input files use unchecked or unsafe operations." -EXP="${EXP}|Note: Recompile with -Xlint:unchecked for details." -EXP="${EXP}| warning" -EXP="${EXP}|uses or overrides a deprecated API." -EXP="${EXP}|uses unchecked or unsafe operations." -# -${GREP} --line-buffered -v -E "${EXP}" From 33244c82445994131a9168451275216916ce635c Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 10:00:15 +0000 Subject: [PATCH 446/471] 8344030: Improved handling of TOOLCHAIN_PATH Reviewed-by: erikj --- make/autoconf/basic.m4 | 24 ++++-------------------- make/autoconf/basic_tools.m4 | 19 ++----------------- make/autoconf/build-performance.m4 | 7 +------ make/autoconf/flags-ldflags.m4 | 2 +- make/autoconf/toolchain.m4 | 17 ++++------------- make/autoconf/util_paths.m4 | 12 ++++++------ 6 files changed, 18 insertions(+), 63 deletions(-) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 2d3e071dd52..316bfc5037d 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -210,17 +210,8 @@ AC_DEFUN([BASIC_SETUP_XCODE_SYSROOT], if test $? -ne 0; then AC_MSG_ERROR([The xcodebuild tool in the devkit reports an error: $XCODEBUILD_OUTPUT]) fi - elif test "x$TOOLCHAIN_PATH" != x; then - UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild, $TOOLCHAIN_PATH) - if test "x$XCODEBUILD" != x; then - XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1` - if test $? -ne 0; then - AC_MSG_WARN([Ignoring the located xcodebuild tool $XCODEBUILD due to an error: $XCODEBUILD_OUTPUT]) - XCODEBUILD= - fi - fi else - UTIL_LOOKUP_PROGS(XCODEBUILD, xcodebuild) + UTIL_LOOKUP_TOOLCHAIN_PROGS(XCODEBUILD, xcodebuild) if test "x$XCODEBUILD" != x; then XCODEBUILD_OUTPUT=`"$XCODEBUILD" -version 2>&1` if test $? -ne 0; then @@ -348,21 +339,11 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], # You can force the sysroot if the sysroot encoded into the compiler tools # is not correct. - AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], - [alias for --with-sysroot for backwards compatibility])], - [SYSROOT=$with_sys_root] - ) - AC_ARG_WITH(sysroot, [AS_HELP_STRING([--with-sysroot], [use this directory as sysroot])], [SYSROOT=$with_sysroot] ) - AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], - [alias for --with-toolchain-path for backwards compatibility])], - [UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_tools_dir)] - ) - AC_ARG_WITH([toolchain-path], [AS_HELP_STRING([--with-toolchain-path], [prepend these directories when searching for toolchain binaries (compilers etc)])], [UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_toolchain_path)] @@ -371,6 +352,9 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], AC_ARG_WITH([xcode-path], [AS_HELP_STRING([--with-xcode-path], [set up toolchain on Mac OS using a path to an Xcode installation])]) + UTIL_DEPRECATED_ARG_WITH(sys-root) + UTIL_DEPRECATED_ARG_WITH(tools-dir) + if test "x$with_xcode_path" != x; then if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then UTIL_PREPEND_TO_PATH([TOOLCHAIN_PATH], diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index 5815c55c962..5367db46679 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -207,29 +207,14 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE], UTIL_SETUP_TOOL(MAKE, [ # Try our hardest to locate a correct version of GNU make - UTIL_LOOKUP_PROGS(CHECK_GMAKE, gmake) + UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_GMAKE, gmake) BASIC_CHECK_MAKE_VERSION("$CHECK_GMAKE", [gmake in PATH]) if test "x$FOUND_MAKE" = x; then - UTIL_LOOKUP_PROGS(CHECK_MAKE, make) + UTIL_LOOKUP_TOOLCHAIN_PROGS(CHECK_MAKE, make) BASIC_CHECK_MAKE_VERSION("$CHECK_MAKE", [make in PATH]) fi - if test "x$FOUND_MAKE" = x; then - if test "x$TOOLCHAIN_PATH" != x; then - # We have a toolchain path, check that as well before giving up. - OLD_PATH=$PATH - PATH=$TOOLCHAIN_PATH:$PATH - UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_GMAKE, gmake) - BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_GMAKE", [gmake in tools-dir]) - if test "x$FOUND_MAKE" = x; then - UTIL_LOOKUP_PROGS(CHECK_TOOLSDIR_MAKE, make) - BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_MAKE", [make in tools-dir]) - fi - PATH=$OLD_PATH - fi - fi - if test "x$FOUND_MAKE" = x; then AC_MSG_ERROR([Cannot find GNU make $MAKE_REQUIRED_VERSION or newer! Please put it in the path, or add e.g. MAKE=/opt/gmake3.81/make as argument to configure.]) fi diff --git a/make/autoconf/build-performance.m4 b/make/autoconf/build-performance.m4 index 10e86e75199..dfc9e979d2f 100644 --- a/make/autoconf/build-performance.m4 +++ b/make/autoconf/build-performance.m4 @@ -162,12 +162,7 @@ AC_DEFUN([BPERF_SETUP_CCACHE], # Check if ccache is available CCACHE_AVAILABLE=true - OLD_PATH="$PATH" - if test "x$TOOLCHAIN_PATH" != x; then - PATH=$TOOLCHAIN_PATH:$PATH - fi - UTIL_LOOKUP_PROGS(CCACHE, ccache) - PATH="$OLD_PATH" + UTIL_LOOKUP_TOOLCHAIN_PROGS(CCACHE, ccache) AC_MSG_CHECKING([if ccache is available]) if test "x$TOOLCHAIN_TYPE" != "xgcc" && test "x$TOOLCHAIN_TYPE" != "xclang"; then diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 509e0dd825f..a12a6e7f9a6 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -74,7 +74,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # Clang needs the lld linker to work correctly BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL" if test "x$CXX_IS_USER_SUPPLIED" = xfalse && test "x$CC_IS_USER_SUPPLIED" = xfalse; then - UTIL_REQUIRE_PROGS(LLD, lld, $TOOLCHAIN_PATH:$PATH) + UTIL_REQUIRE_TOOLCHAIN_PROGS(LLD, lld) fi fi if test "x$OPENJDK_TARGET_OS" = xaix; then diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index f3ef44d382b..4662c62d901 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -276,9 +276,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], ORG_CFLAGS="$CFLAGS" ORG_CXXFLAGS="$CXXFLAGS" - # autoconf magic only relies on PATH, so update it if tools dir is specified - OLD_PATH="$PATH" - if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then if test "x$XCODEBUILD" != x; then XCODE_VERSION_OUTPUT=`"$XCODEBUILD" -version 2> /dev/null | $HEAD -n 1` @@ -300,9 +297,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], fi AC_SUBST(TOOLCHAIN_VERSION) - # Finally prepend TOOLCHAIN_PATH to the PATH, to allow --with-tools-dir to - # override all other locations. - if test "x$TOOLCHAIN_PATH" != x; then + # For the microsoft toolchain the toolchain path needs to be added to the + # normal path, or the compiler will not work in some situations in later + # configure checks. + if test "x$TOOLCHAIN_TYPE" = "xmicrosoft" && test "x$TOOLCHAIN_PATH" != x; then export PATH=$TOOLCHAIN_PATH:$PATH fi ]) @@ -310,13 +308,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], # Restore path, etc AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], [ - # Restore old path, except for the microsoft toolchain, which requires the - # toolchain path to remain in place. Otherwise the compiler will not work in - # some situations in later configure checks. - if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then - PATH="$OLD_PATH" - fi - # Restore the flags to the user specified values. # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" diff --git a/make/autoconf/util_paths.m4 b/make/autoconf/util_paths.m4 index 40864680aad..abe79c40fb6 100644 --- a/make/autoconf/util_paths.m4 +++ b/make/autoconf/util_paths.m4 @@ -458,17 +458,18 @@ AC_DEFUN([UTIL_LOOKUP_PROGS], ################################################################################ # Call UTIL_SETUP_TOOL with AC_CHECK_TOOLS to locate the tool. This will look -# first for cross-compilation tools. +# first for tools using the cross-compilation prefix, and then for tools without +# this prefix. For each of these name variants, it will look first in the +# toolchain path, and then in the normal path. # $1: variable to set # $2: executable name (or list of names) to look for -# $3: [path] AC_DEFUN([UTIL_LOOKUP_TOOLCHAIN_PROGS], [ if test "x$ac_tool_prefix" = x; then - UTIL_LOOKUP_PROGS($1, $2, $3) + UTIL_LOOKUP_PROGS($1, $2, [$TOOLCHAIN_PATH:$PATH]) else prefixed_names=$(for name in $2; do echo ${ac_tool_prefix}${name} $name; done) - UTIL_LOOKUP_PROGS($1, $prefixed_names, $3) + UTIL_LOOKUP_PROGS($1, $prefixed_names, [$TOOLCHAIN_PATH:$PATH]) fi ]) @@ -497,10 +498,9 @@ AC_DEFUN([UTIL_REQUIRE_PROGS], # Like UTIL_LOOKUP_PROGS but fails if no tool was found. # $1: variable to set # $2: executable name (or list of names) to look for -# $3: [path] AC_DEFUN([UTIL_REQUIRE_TOOLCHAIN_PROGS], [ - UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2, $3) + UTIL_LOOKUP_TOOLCHAIN_PROGS($1, $2) UTIL_CHECK_NONEMPTY($1) ]) From edae355e95f23294eda092dbedcb7f6cf165b0f8 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 10 Sep 2025 10:27:38 +0000 Subject: [PATCH 447/471] 8246325: Add DRYRUN facility to SetupExecute Reviewed-by: erikj --- make/Bundles.gmk | 4 ++-- make/autoconf/spec.gmk.template | 10 ++++++---- make/common/Execute.gmk | 20 ++++++++++++++++---- test/make/TestExecute.gmk | 24 ++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/make/Bundles.gmk b/make/Bundles.gmk index ba8ec0c864b..cf3b77e4e52 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -301,7 +301,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) $(call LogWarn, Signing $(JDK_BUNDLE_NAME)) $(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \ --timestamp --options runtime --deep --force \ - $(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG) + $(JDK_MACOSX_BUNDLE_DIR_SIGNED)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG) $(TOUCH) $@ $(eval $(call SetupBundleFile, BUILD_JDK_BUNDLE, \ @@ -330,7 +330,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) $(call LogWarn, Signing $(JRE_BUNDLE_NAME)) $(CODESIGN) -s "$(MACOSX_CODESIGN_IDENTITY)" \ --timestamp --options runtime --deep --force \ - $(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_DIR) $(LOG_DEBUG) + $(JRE_MACOSX_BUNDLE_DIR_SIGNED)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR) $(LOG_DEBUG) $(TOUCH) $@ $(eval $(call SetupBundleFile, BUILD_JRE_BUNDLE, \ diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index e3345940101..ab6bb51c27e 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -898,12 +898,14 @@ JDK_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR) JRE_MACOSX_BUNDLE_DIR = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR) JDK_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JDK_MACOSX_BUNDLE_SUBDIR_SIGNED) JRE_MACOSX_BUNDLE_DIR_SIGNED = $(IMAGES_OUTPUTDIR)/$(JRE_MACOSX_BUNDLE_SUBDIR_SIGNED) -JDK_MACOSX_BUNDLE_TOP_DIR = jdk-$(VERSION_NUMBER).jdk -JRE_MACOSX_BUNDLE_TOP_DIR = jre-$(VERSION_NUMBER).jre -JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_DIR)/Contents -JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_DIR)/Contents +JDK_MACOSX_BUNDLE_TOP_SUBDIR = jdk-$(VERSION_NUMBER).jdk +JRE_MACOSX_BUNDLE_TOP_SUBDIR = jre-$(VERSION_NUMBER).jre +JDK_MACOSX_CONTENTS_SUBDIR = $(JDK_MACOSX_BUNDLE_TOP_SUBDIR)/Contents +JRE_MACOSX_CONTENTS_SUBDIR = $(JRE_MACOSX_BUNDLE_TOP_SUBDIR)/Contents JDK_MACOSX_CONTENTS_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_CONTENTS_SUBDIR) JRE_MACOSX_CONTENTS_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_CONTENTS_SUBDIR) +JDK_MACOSX_BUNDLE_TOP_DIR = $(JDK_MACOSX_BUNDLE_DIR)/$(JDK_MACOSX_BUNDLE_TOP_SUBDIR) +JRE_MACOSX_BUNDLE_TOP_DIR = $(JRE_MACOSX_BUNDLE_DIR)/$(JRE_MACOSX_BUNDLE_TOP_SUBDIR) # Bundle names ifneq ($(VERSION_BUILD), ) diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index 1ee3c28261b..4199e8f13b7 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -82,6 +82,8 @@ ifeq ($(INCLUDE), true) # INFO : Message to display at LOG=info level when running command (optional) # WARN : Message to display at LOG=warn level when running command (optional) # DEPS : Dependencies for the execution to take place +# DRYRUN : Set to true to perform everything but executing the command \ +# (defaults to false, primarily intended for debugging) # # Setup make rules for copying files, with an option to do more complex @@ -161,8 +163,13 @@ define SetupExecuteBody $$(TOUCH) $$@ $$($1_EXEC_RESULT): $$($1_PRE_MARKER) - $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + ifneq ($$($1_DRYRUN), true) + $$(call ExecuteWithLog, $$($1_BASE)_exec, \ + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + else + $$(call LogWarn, DRYRUN enabled for $1, not actually running command) + $$(TOUCH) $$@ + endif ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif @@ -177,8 +184,13 @@ define SetupExecuteBody $$(call LogInfo, $$($1_INFO)) endif $$(call MakeDir, $$(call EncodeSpace, $$($1_WORKING_DIR)) $$(call EncodeSpace, $$($1_SUPPORT_DIR)) $$(call EncodeSpace, $$($1_OUTPUT_DIR))) - $$(call ExecuteWithLog, $$($1_BASE)_exec, \ - cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + ifneq ($$($1_DRYRUN), true) + $$(call ExecuteWithLog, $$($1_BASE)_exec, \ + cd $$($1_WORKING_DIR) && $$($1_COMMAND)) + else + $$(call LogWarn, DRYRUN enabled for $1, not actually running command) + $$(TOUCH) $$@ + endif ifeq ($$($1_EXEC_RESULT), $$($1_EXEC_MARKER)) $$(TOUCH) $$@ endif diff --git a/test/make/TestExecute.gmk b/test/make/TestExecute.gmk index f71a402502e..5d57d244c39 100644 --- a/test/make/TestExecute.gmk +++ b/test/make/TestExecute.gmk @@ -60,10 +60,30 @@ $(eval $(call SetupExecute, EXEC_2, \ run-test2: $(EXEC_2) test -f $(OUTPUT_DIR)/exec_2/special/specialfile +$(eval $(call SetupExecute, EXEC_3, \ + INFO := Testing that SetupExecute with DRYRUN does nothing, \ + OUTPUT_DIR := $(OUTPUT_DIR)/exec_3, \ + DRYRUN := true, \ + COMMAND := $(ECHO) "This should not happen" > $(OUTPUT_DIR)/exec_3/dryrunfile, \ +)) -TEST_TARGETS += run-test1 run-test2 +run-test3: $(EXEC_3) + test ! -f $(OUTPUT_DIR)/exec_3/dryrunfile -.PHONY: run-test1 run-test2 +$(eval $(call SetupExecute, EXEC_4, \ + INFO := Testing that SetupExecute with DRYRUN does nothing but touches output file, \ + OUTPUT_FILE := $(OUTPUT_DIR)/exec_4/output, \ + DRYRUN := true, \ + COMMAND := $(ECHO) "This should not happen" > $(OUTPUT_DIR)/exec_4/dryrunfile, \ +)) + +run-test4: $(EXEC_4) + test ! -f $(OUTPUT_DIR)/exec_4/dryrunfile + test -f $(OUTPUT_DIR)/exec_4/output + +TEST_TARGETS += run-test1 run-test2 run-test3 run-test4 + +.PHONY: run-test1 run-test2 run-test3 run-test4 ################################################################################ From 4d4e51c41fed79427fb621fd9fcc8e5e23bfb287 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Wed, 10 Sep 2025 11:49:02 +0000 Subject: [PATCH 448/471] 8365483: Test sun/rmi/runtime/Log/6409194/NoConsoleOutput.java sometimes fails Reviewed-by: dfuchs, jpai --- .../java/util/logging/StreamHandler.java | 13 +- .../logging/StreamHandlerRacyCloseTest.java | 137 ++++++++++++++++++ 2 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java diff --git a/src/java.logging/share/classes/java/util/logging/StreamHandler.java b/src/java.logging/share/classes/java/util/logging/StreamHandler.java index ddfea9674dc..3b9af54814d 100644 --- a/src/java.logging/share/classes/java/util/logging/StreamHandler.java +++ b/src/java.logging/share/classes/java/util/logging/StreamHandler.java @@ -214,13 +214,16 @@ public class StreamHandler extends Handler { try { synchronized (this) { + // Re-check writer between isLoggable() and here. Writer writer = this.writer; - if (!doneHeader) { - writer.write(formatter.getHead(this)); - doneHeader = true; + if (writer != null) { + if (!doneHeader) { + writer.write(formatter.getHead(this)); + doneHeader = true; + } + writer.write(msg); + synchronousPostWriteHook(); } - writer.write(msg); - synchronousPostWriteHook(); } } catch (Exception ex) { // We don't want to throw an exception here, but we diff --git a/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java b/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java new file mode 100644 index 00000000000..5bb465088e5 --- /dev/null +++ b/test/jdk/java/util/logging/StreamHandlerRacyCloseTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.ErrorManager; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; +import java.util.logging.StreamHandler; + +import org.junit.jupiter.api.Test; + +/* + * @test + * @bug 8365483 + * @summary verify that concurrent calls to publish() and close() on a + * StreamHandler do not cause unexpected exceptions + * @run junit StreamHandlerRacyCloseTest + */ +public class StreamHandlerRacyCloseTest { + + private static final class ExceptionTrackingErrorManager extends ErrorManager { + private final AtomicReference firstError = new AtomicReference<>(); + + @Override + public void error(String msg, Exception ex, int code) { + // just track one/first exception, that's good enough for this test + this.firstError.compareAndSet(null, new RuntimeException(msg, ex)); + } + } + + @Test + void testRacyClose() throws Exception { + final int numTimes = 100; + try (ExecutorService executor = Executors.newFixedThreadPool(numTimes)) { + final List> tasks = new ArrayList<>(); + for (int i = 1; i <= numTimes; i++) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // construct a StreamHandler with an ErrorManager which propagates + // any errors that happen during publish() + final StreamHandler handler = new StreamHandler(baos, new SimpleFormatter()); + handler.setErrorManager(new ExceptionTrackingErrorManager()); + + final CountDownLatch latch = new CountDownLatch(2); + // create a publisher and closer task which will run concurrently + tasks.add(new Publisher(handler, latch)); + tasks.add(new Closer(handler, latch)); + } + // submit the tasks and expect successful completion of each + final List> completed = executor.invokeAll(tasks); + for (var f : completed) { + f.get(); + } + } + } + + private static final class Closer implements Callable { + private final StreamHandler handler; + private final CountDownLatch startLatch; + + private Closer(final StreamHandler handler, final CountDownLatch startLatch) { + this.handler = handler; + this.startLatch = startLatch; + } + + @Override + public Void call() throws Exception { + // notify the other task of our readiness + this.startLatch.countDown(); + // wait for the other task to arrive + this.startLatch.await(); + // close the handler + this.handler.close(); + // propagate any exception that may have been caught by the error manager + final var errMgr = (ExceptionTrackingErrorManager) this.handler.getErrorManager(); + if (errMgr.firstError.get() != null) { + throw errMgr.firstError.get(); + } + return null; + } + } + + private static final class Publisher implements Callable { + private final StreamHandler handler; + private final CountDownLatch startLatch; + + private Publisher(final StreamHandler handler, final CountDownLatch startLatch) { + this.handler = handler; + this.startLatch = startLatch; + } + + @Override + public Void call() throws Exception { + final LogRecord record = new LogRecord(Level.WARNING, "hello world"); + // notify the other task of our readiness + this.startLatch.countDown(); + // wait for the other task to arrive + this.startLatch.await(); + // publish the record + this.handler.publish(record); + // propagate any exception that may have been caught by the error manager + final var errMgr = (ExceptionTrackingErrorManager) this.handler.getErrorManager(); + if (errMgr.firstError.get() != null) { + throw errMgr.firstError.get(); + } + return null; + } + } +} From 703d930e4d52a6f9741cf9affee8caade550e67b Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Wed, 10 Sep 2025 11:55:31 +0000 Subject: [PATCH 449/471] 8366980: TestTransparentHugePagesHeap.java fails when run with -UseCompressedOops Reviewed-by: aboldtch, tschatzl --- .../gc/TestTransparentHugePagesHeap.java | 81 +++++++++++++------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java index 25044d2c3e4..2c2e19b87c4 100644 --- a/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java +++ b/test/hotspot/jtreg/gc/TestTransparentHugePagesHeap.java @@ -49,6 +49,7 @@ * @run driver TestTransparentHugePagesHeap Serial */ +import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -98,47 +99,76 @@ public class TestTransparentHugePagesHeap { class VerifyTHPEnabledForHeap { public static void main(String args[]) throws Exception { - String heapAddress = readHeapAddressInLog(); + // Extract the heap start from pagesize logging + BigInteger heapStart = extractHeapStartFromLog(); + Path smaps = makeSmapsCopy(); - final Pattern heapSection = Pattern.compile("^" + heapAddress + ".*"); - final Pattern thpEligible = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); + final Pattern addressRangePattern = Pattern.compile("([0-9a-f]*?)-([0-9a-f]*?) .*"); + final Pattern thpEligiblePattern = Pattern.compile("THPeligible:\\s+(\\d)\\s*"); Scanner smapsFile = new Scanner(smaps); while (smapsFile.hasNextLine()) { - Matcher heapMatcher = heapSection.matcher(smapsFile.nextLine()); - - if (heapMatcher.matches()) { - // Found the first heap section, verify that it is THP eligible - while (smapsFile.hasNextLine()) { - Matcher m = thpEligible.matcher(smapsFile.nextLine()); - if (m.matches()) { - if (Integer.parseInt(m.group(1)) == 1) { - // THPeligible is 1, heap can be backed by huge pages - return; - } - - throw new RuntimeException("First heap section at 0x" + heapAddress + " is not THPeligible"); - } - } + Matcher addressRangeMatcher = addressRangePattern.matcher(smapsFile.nextLine()); + if (!addressRangeMatcher.matches()) { + continue; } + + // Found an address range line in the smaps file + + BigInteger addressStart = new BigInteger(addressRangeMatcher.group(1), 16); + BigInteger addressEnd = new BigInteger(addressRangeMatcher.group(2), 16); + + // Linux sometimes merges adjacent VMAs so we can't search for a range that + // exactly matches the heap range. Instead we look for the first range that + // contains the start of the heap and verify that that range is THP eligible. + + if (addressStart.compareTo(heapStart) > 0 || heapStart.compareTo(addressEnd) >= 0) { + continue; + } + + // Found a range that contains the start of the heap, verify that it is THP eligible. + + while (smapsFile.hasNextLine()) { + Matcher m = thpEligiblePattern.matcher(smapsFile.nextLine()); + if (!m.matches()) { + continue; + } + + // Found the THPeligible line + + if (m.group(1).equals("1")) { + // Success - THPeligible is 1, heap can be backed by huge pages + return; + } + + throw new RuntimeException("The address range 0x" + addressStart.toString(16) + + "-0x" + addressEnd.toString(16) + + " that contains the heap start" + heapStart + + " is not THPeligible"); + } + + throw new RuntimeException("Couldn't find THPeligible in the smaps file"); } - // Failed to verify THP for heap - throw new RuntimeException("Could not find heap section in smaps file"); + throw new RuntimeException("Could not find an address range containing the heap start " + heapStart + " in the smaps file"); } - private static String readHeapAddressInLog() throws Exception { - final Pattern heapAddress = Pattern.compile(".* Heap: .*base=(0x[0-9A-Fa-f]*).*"); + private static BigInteger extractHeapStartFromLog() throws Exception { + // [0.041s][info][pagesize] Heap: min=128M max=128M base=0x0000ffff5c600000 size=128M page_size=2M + final Pattern heapAddress = Pattern.compile(".* Heap: .*base=0x([0-9A-Fa-f]*).*"); Scanner logFile = new Scanner(Paths.get("thp-" + ProcessHandle.current().pid() + ".log")); while (logFile.hasNextLine()) { - Matcher m = heapAddress.matcher(logFile.nextLine()); + String line = logFile.nextLine(); + + Matcher m = heapAddress.matcher(line); if (m.matches()) { - return Long.toHexString(Long.decode(m.group(1))); + return new BigInteger(m.group(1), 16); } } - throw new RuntimeException("Failed to parse heap address, failing test"); + + throw new RuntimeException("Failed to find heap start"); } private static Path makeSmapsCopy() throws Exception { @@ -149,4 +179,3 @@ public class TestTransparentHugePagesHeap { } } } - From 46ae1ee87152742082e6047d0556944d7ae4567d Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Wed, 10 Sep 2025 12:33:06 +0000 Subject: [PATCH 450/471] 8277444: Data race between JvmtiClassFileReconstituter::copy_bytecodes and class linking Reviewed-by: dholmes, amenkov, coleenp --- .../prims/jvmtiClassFileReconstituter.cpp | 5 + src/hotspot/share/prims/jvmtiEnv.cpp | 22 ++- .../instrument/RetransformBigClassTest.java | 161 ++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/lang/instrument/RetransformBigClassTest.java diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 831f407e7ec..a441d405f8d 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -996,6 +996,11 @@ void JvmtiClassFileReconstituter::write_u8(u8 x) { void JvmtiClassFileReconstituter::copy_bytecodes(const methodHandle& mh, unsigned char* bytecodes) { + // We must copy bytecodes only from linked classes. + // Being linked guarantees we are not getting bytecodes at + // the same time the linking process is rewriting them. + guarantee(mh->method_holder()->is_linked(), "Bytecodes must be copied from a linked class"); + // use a BytecodeStream to iterate over the bytecodes. JVM/fast bytecodes // and the breakpoint bytecode are converted to their original bytecodes. diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 30dd1f77d23..3eb507ba5e3 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -450,6 +450,18 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) { InstanceKlass* ik = InstanceKlass::cast(klass); if (ik->get_cached_class_file_bytes() == nullptr) { + // Link the class to avoid races with the rewriter. This will call the verifier also + // on the class. Linking is also done in VM_RedefineClasses below, but we need + // to keep that for other VM_RedefineClasses callers. + JavaThread* THREAD = current_thread; + ik->link_class(THREAD); + if (HAS_PENDING_EXCEPTION) { + // Retransform/JVMTI swallows error messages. Using this class will rerun the verifier in a context + // that propagates the VerifyError, if thrown. + CLEAR_PENDING_EXCEPTION; + return JVMTI_ERROR_INVALID_CLASS; + } + // Not cached, we need to reconstitute the class file from the // VM representation. We don't attach the reconstituted class // bytes to the InstanceKlass here because they have not been @@ -3407,7 +3419,8 @@ jvmtiError JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) { NULL_CHECK(method, JVMTI_ERROR_INVALID_METHODID); - methodHandle mh(Thread::current(), method); + JavaThread* current_thread = JavaThread::current(); + methodHandle mh(current_thread, method); jint size = (jint)mh->code_size(); jvmtiError err = allocate(size, bytecodes_ptr); if (err != JVMTI_ERROR_NONE) { @@ -3416,6 +3429,13 @@ JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char** (*bytecode_count_ptr) = size; // get byte codes + // Make sure the class is verified and rewritten first. + JavaThread* THREAD = current_thread; + mh->method_holder()->link_class(THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + return JVMTI_ERROR_INVALID_CLASS; + } JvmtiClassFileReconstituter::copy_bytecodes(mh, *bytecodes_ptr); return JVMTI_ERROR_NONE; diff --git a/test/jdk/java/lang/instrument/RetransformBigClassTest.java b/test/jdk/java/lang/instrument/RetransformBigClassTest.java new file mode 100644 index 00000000000..c4788217be1 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformBigClassTest.java @@ -0,0 +1,161 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8277444 + * + * @library /test/lib + * @compile SimpleIdentityTransformer.java + * @run shell MakeJAR.sh retransformAgent + * @run main/othervm -javaagent:retransformAgent.jar RetransformBigClassTest + */ + +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +/* + * JvmtiClassFileReconstituter::copy_bytecodes restores bytecodes rewritten + * by the linking process. It is used by RetransformClasses. + * JDK-8277444 is a data race between copy_bytecodes and the linking process. + * This test puts the linking process in one thread and the retransforming process + * in another thread. The test uses Class.forName("BigClass", false, classLoader) + * which does not link the class. When the class is used, the linking process starts. + * In another thread retransforming of the class is happening. + * We generate a class with big methods. A number of methods and their size are + * chosen to make the linking and retransforming processes run concurrently. + * We delay the retransforming process to follow the linking process. + * If there is no synchronization between the processes, a data race will happen. + */ +public class RetransformBigClassTest extends AInstrumentationTestCase { + + private static final Object LOCK = new Object(); + private static final int COUNTER_INC_COUNT = 2000; // A number of 'c+=1;' statements in methods of a class. + private static final int MIN_LINK_TIME_MS = 60; // Large enough so the linking and retransforming processes run in parallel. + private static final int RETRANSFORM_CLASSES_DELAY_MS = 37; // We manage to create a data race when a delay is in the range 0.52x - 0.62x of MIN_LINK_TIME_MS. + + private static Class bigClass; + private static byte[] bigClassBytecode; + + private Thread retransformThread; + + RetransformBigClassTest() { + super("RetransformBigClassTest"); + } + + public static void main(String[] args) throws Throwable { + new RetransformBigClassTest().runTest(); + } + + protected final void doRunTest() throws Throwable { + ClassLoader classLoader = new ClassLoader() { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("BigClass")) { + return defineClass(name, bigClassBytecode, 0, bigClassBytecode.length); + } + + return super.findClass(name); + } + }; + synchronized (LOCK) { + bigClass = Class.forName("BigClass", false, classLoader); + LOCK.notify(); + } + // Make a use of the BigClass + assertTrue(bigClass.getConstructor().newInstance().hashCode() != 0); + retransformThread.join(); + } + + private byte[] createClassBytecode(String className, int methodCount) throws Exception { + String methodBody = ""; + for (int j = 0; j < COUNTER_INC_COUNT; j++) { + methodBody += "c+=1;"; + } + + String classSrc = "public class " + className + " { int c;"; + + for (int i = 0; i < methodCount; i++) { + classSrc += "\npublic void m" + i + "(){"; + classSrc += methodBody; + classSrc += "\n}"; + } + classSrc += "\n}"; + + return InMemoryJavaCompiler.compile(className, classSrc); + } + + // We need a number of methods such that the linking time is greater than + // or equal to MIN_LINK_TIME_MS. + // We create a class having 5 methods and trigger the linking process. + // We measure the time taken and use it to calculate the needed number. + private int findMethodCount() throws Exception { + int methodCount = 5; + final String className = "BigClass" + methodCount; + final byte[] bytecode = createClassBytecode(className, methodCount); + ClassLoader classLoader = new ClassLoader() { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(className)) { + return defineClass(name, bytecode, 0, bytecode.length); + } + + return super.findClass(name); + } + }; + var bigClass = Class.forName(className, false, classLoader); + long startTime = System.nanoTime(); + assertTrue(bigClass.getConstructor().newInstance().hashCode() != 0); + double linkTimeMs = (System.nanoTime() - startTime) / 1000000.0; + System.out.println("Link time for a class with " + methodCount + " methods each having " + COUNTER_INC_COUNT + " counter increments: " + Math.round(linkTimeMs)); + if (linkTimeMs < MIN_LINK_TIME_MS) { + methodCount = (int)Math.round((MIN_LINK_TIME_MS * methodCount) / linkTimeMs); + } + System.out.println("The number of methods to exceed " + MIN_LINK_TIME_MS + " ms linking time: " + methodCount); + return methodCount; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + bigClassBytecode = createClassBytecode("BigClass", findMethodCount()); + fInst.addTransformer(new SimpleIdentityTransformer()); + retransformThread = new Thread(() -> { + try { + synchronized (LOCK) { + while (bigClass == null) { + System.out.println("[retransformThread]: Waiting for bigClass"); + LOCK.wait(); + } + } + Thread.sleep(RETRANSFORM_CLASSES_DELAY_MS); + fInst.retransformClasses(bigClass); + } catch (Exception e) { + e.printStackTrace(); + } + }); + retransformThread.start(); + Thread.sleep(100); + } +} From 385c13298932f1de16e6161652be35d966d822ec Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Sep 2025 12:49:38 +0000 Subject: [PATCH 451/471] 8367240: Parallel: Refactor PSScavengeCLDClosure Reviewed-by: stefank --- .../share/gc/parallel/psClosure.inline.hpp | 57 ++++++++----------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index 5cc059a09f5..914a16e77a6 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -78,16 +78,17 @@ typedef PSRootsClosure PSScavengeRootsClosure; typedef PSRootsClosure PSPromoteRootsClosure; // Scavenges a single oop in a ClassLoaderData. -class PSScavengeFromCLDClosure: public OopClosure { -private: +class PSScavengeCLDOopClosure : public OopClosure { PSPromotionManager* _pm; - // Used to redirty a scanned cld if it has oops - // pointing to the young generation after being scanned. - ClassLoaderData* _scanned_cld; + public: - PSScavengeFromCLDClosure(PSPromotionManager* pm) : _pm(pm), _scanned_cld(nullptr) { } + // Records whether this CLD contains oops pointing into young-gen after scavenging. + bool _has_oops_into_young_gen; + + PSScavengeCLDOopClosure(PSPromotionManager* pm) : _pm(pm), _has_oops_into_young_gen(false) {} + void do_oop(narrowOop* p) { ShouldNotReachHere(); } - void do_oop(oop* p) { + void do_oop(oop* p) { ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); assert(!psh->is_in_reserved(p), "GC barrier needed"); if (PSScavenge::should_scavenge(p)) { @@ -97,43 +98,33 @@ public: oop new_obj = _pm->copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); - if (PSScavenge::is_obj_in_young(new_obj)) { - do_cld_barrier(); + if (PSScavenge::is_obj_in_young(new_obj) && !_has_oops_into_young_gen) { + _has_oops_into_young_gen = true; } } } - - void set_scanned_cld(ClassLoaderData* cld) { - assert(_scanned_cld == nullptr || cld == nullptr, "Should always only handling one cld at a time"); - _scanned_cld = cld; - } - -private: - void do_cld_barrier() { - assert(_scanned_cld != nullptr, "Should not be called without having a scanned cld"); - _scanned_cld->record_modified_oops(); - } }; // Scavenges the oop in a ClassLoaderData. class PSScavengeCLDClosure: public CLDClosure { -private: - PSScavengeFromCLDClosure _oop_closure; + PSPromotionManager* _pm; + public: - PSScavengeCLDClosure(PSPromotionManager* pm) : _oop_closure(pm) { } + PSScavengeCLDClosure(PSPromotionManager* pm) : _pm(pm) { } + void do_cld(ClassLoaderData* cld) { - // If the cld has not been dirtied we know that there's - // no references into the young gen and we can skip it. + // If the cld has not been dirtied we know that there are + // no references into the young gen, so we can skip it. + if (!cld->has_modified_oops()) { + return; + } - if (cld->has_modified_oops()) { - // Setup the promotion manager to redirty this cld - // if references are left in the young gen. - _oop_closure.set_scanned_cld(cld); + PSScavengeCLDOopClosure oop_closure{_pm}; + // Clean the cld since we're going to scavenge all the metadata. + cld->oops_do(&oop_closure, ClassLoaderData::_claim_none, /*clear_modified_oops*/true); - // Clean the cld since we're going to scavenge all the metadata. - cld->oops_do(&_oop_closure, ClassLoaderData::_claim_none, /*clear_modified_oops*/true); - - _oop_closure.set_scanned_cld(nullptr); + if (oop_closure._has_oops_into_young_gen) { + cld->record_modified_oops(); } } }; From c968a672c034fe533ea5f4ac5efe37ffb76c93e2 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 10 Sep 2025 13:45:06 +0000 Subject: [PATCH 452/471] 8362282: runtime/logging/StressAsyncUL.java failed with exitValue = 134 Reviewed-by: jsjolen, dholmes --- src/hotspot/share/logging/logAsyncWriter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index cfb6a991c4c..d184827f582 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -318,13 +318,13 @@ void AsyncLogWriter::initialize() { AsyncLogWriter* self = new AsyncLogWriter(); if (self->_initialized) { - Atomic::release_store_fence(&AsyncLogWriter::_instance, self); - // All readers of _instance after the fence see non-null. // We use LogOutputList's RCU counters to ensure all synchronous logsites have completed. - // After that, we start AsyncLog Thread and it exclusively takes over all logging I/O. + // After that, we publish the initalized _instance to readers. + // Then we start the AsyncLog Thread and it exclusively takes over all logging I/O. for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { ts->wait_until_no_readers(); } + Atomic::release_store_fence(&AsyncLogWriter::_instance, self); os::start_thread(self); log_debug(logging, thread)("Async logging thread started."); } else { From 5cd7721ad448cc4bdac37b0456252335f6b9d9f5 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 10 Sep 2025 14:36:11 +0000 Subject: [PATCH 453/471] 8366154: Validate thread type requirements in debug commands Reviewed-by: dholmes, simonis, kevinw --- src/hotspot/share/utilities/debug.cpp | 87 ++++++++++++++++++++------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 2865dbc5991..bd82336020a 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -63,6 +63,7 @@ #include "utilities/unsigned5.hpp" #include "utilities/vmError.hpp" +#include #include #include @@ -296,20 +297,40 @@ void report_java_out_of_memory(const char* message) { class Command : public StackObj { private: - ResourceMark _rm; - DebuggingContext _debugging; - public: static int level; - Command(const char* str) { - if (level++ > 0) return; - tty->cr(); - tty->print_cr("\"Executing %s\"", str); + DebuggingContext _debugging; + bool _has_rm; + // Union members of class type are implicitly allocated but not constructed automatically. + // We therefore have to explicitly construct _rm with a placement new call (see 'onThread()') and + // clean it up afterwards with an explicit destructor call (see '~Command()'). + union { ResourceMark _rm; }; + public: + Command(const char* str) : _has_rm(false) { + if (level++ == 0) { + tty->cr(); + tty->print_cr("\"Executing %s\"", str); + } + tty->flush(); } - ~Command() { + if (_has_rm) _rm.~ResourceMark(); tty->flush(); level--; } + + bool onThread() { + Thread* thread = Thread::current_or_null(); + if (thread == nullptr) { + tty->print_cr("Failed: Current thread is not attached"); + return false; + } + + if (!_has_rm) { + ::new (&_rm) ResourceMark(); + _has_rm = true; + } + return true; + } }; int Command::level = 0; @@ -370,6 +391,7 @@ extern "C" DEBUGEXPORT void printnm(intptr_t p) { extern "C" DEBUGEXPORT void universe() { Command c("universe"); + if (!c.onThread()) return; Universe::print_on(tty); } @@ -379,6 +401,7 @@ extern "C" DEBUGEXPORT void verify() { // note: this may not be safe if we're not at a safepoint; for debugging, // this manipulates the safepoint settings to avoid assertion failures Command c("universe verify"); + if (!c.onThread()) return; bool safe = SafepointSynchronize::is_at_safepoint(); if (!safe) { tty->print_cr("warning: not at safepoint -- verify may fail"); @@ -393,6 +416,7 @@ extern "C" DEBUGEXPORT void verify() { extern "C" DEBUGEXPORT void pp(void* p) { Command c("pp"); + if (!c.onThread()) return; FlagSetting fl(DisplayVMOutput, true); if (p == nullptr) { tty->print_cr("null"); @@ -416,14 +440,15 @@ extern "C" DEBUGEXPORT void pp(void* p) { } -extern "C" DEBUGEXPORT void findpc(intptr_t x); - extern "C" DEBUGEXPORT void ps() { // print stack - if (Thread::current_or_null() == nullptr) return; - Command c("ps"); - // Prints the stack of the current Java thread + Command c("ps"); + if (!c.onThread()) return; JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } tty->print(" for thread: "); p->print(); tty->cr(); @@ -450,7 +475,12 @@ extern "C" DEBUGEXPORT void ps() { // print stack extern "C" DEBUGEXPORT void pfl() { // print frame layout Command c("pfl"); + if (!c.onThread()) return; JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } tty->print(" for thread: "); p->print(); tty->cr(); @@ -460,34 +490,39 @@ extern "C" DEBUGEXPORT void pfl() { } extern "C" DEBUGEXPORT void psf() { // print stack frames - { - Command c("psf"); - JavaThread* p = JavaThread::active(); - tty->print(" for thread: "); - p->print(); - tty->cr(); - if (p->has_last_Java_frame()) { - p->trace_frames(); - } + Command c("psf"); + if (!c.onThread()) return; + JavaThread* p = JavaThread::active(); + if (p == nullptr) { + tty->print_cr("Failed: JavaThread::active is null"); + return; + } + tty->print(" for thread: "); + p->print(); + tty->cr(); + if (p->has_last_Java_frame()) { + p->trace_frames(); } } extern "C" DEBUGEXPORT void threads() { Command c("threads"); + if (!c.onThread()) return; Threads::print(false, true); } extern "C" DEBUGEXPORT void psd() { Command c("psd"); + if (!c.onThread()) return; SystemDictionary::print(); } extern "C" DEBUGEXPORT void pss() { // print all stacks - if (Thread::current_or_null() == nullptr) return; Command c("pss"); + if (!c.onThread()) return; Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true)); } @@ -534,12 +569,14 @@ extern "C" DEBUGEXPORT nmethod* findnm(intptr_t addr) { extern "C" DEBUGEXPORT void find(intptr_t x) { Command c("find"); + if (!c.onThread()) return; os::print_location(tty, x, false); } extern "C" DEBUGEXPORT void findpc(intptr_t x) { Command c("findpc"); + if (!c.onThread()) return; os::print_location(tty, x, true); } @@ -551,6 +588,7 @@ extern "C" DEBUGEXPORT void findpc(intptr_t x) { // call findmethod("*ang/Object*", "wait:(*J*)V", 0x1) -> list all "wait" methods in j.l.Object that have a long parameter extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) { Command c("findclass"); + if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); ClassPrinter::print_classes(class_name_pattern, flags, tty); } @@ -558,6 +596,7 @@ extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern, const char* method_pattern, int flags) { Command c("findmethod"); + if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); ClassPrinter::print_methods(class_name_pattern, method_pattern, flags, tty); } @@ -644,6 +683,7 @@ void help() { #ifndef PRODUCT extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack Command c("pns"); + if (!c.onThread()) return; static char buf[O_BUFLEN]; // Call generic frame constructor (certain arguments may be ignored) frame fr(sp, fp, pc); @@ -662,6 +702,7 @@ extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native // extern "C" DEBUGEXPORT void pns2() { // print native stack Command c("pns2"); + if (!c.onThread()) return; static char buf[O_BUFLEN]; address lastpc = nullptr; NativeStackPrinter nsp(Thread::current_or_null()); From 34c3ac0316dbd29ae670db51bd9230a1e77382d9 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 10 Sep 2025 16:00:28 +0000 Subject: [PATCH 454/471] 8162380: [TEST_BUG] MouseEvent/.../AltGraphModifierTest.java has only "Fail" button Reviewed-by: azvegint, aivanov --- test/jdk/ProblemList.txt | 1 - .../AltGraphModifierTest.java | 256 +++--------------- 2 files changed, 44 insertions(+), 213 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 475704f7e95..70e912d7e93 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -794,7 +794,6 @@ java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java 7131438,802 java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java 7187741 linux-all,macosx-all java/awt/xembed/server/TestXEmbedServerJava.java 8001150,8004031 generic-all java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java 8068378 generic-all -java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java 8162380 generic-all java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-all,linux-all java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all diff --git a/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java b/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java index 47d808f336d..c8730b28964 100644 --- a/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java +++ b/test/jdk/java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. 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 @@ -22,51 +22,57 @@ */ /* - @test - @bug 8041928 8158616 - @requires (os.family != "mac") - @summary Confirm that the Alt-Gr Modifier bit is set correctly. - @run main/manual AltGraphModifierTest + * @test + * @bug 8041928 8158616 + * @requires (os.family != "mac") + * @summary Confirm that the Alt-Gr Modifier bit is set correctly. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AltGraphModifierTest */ -import java.awt.Button; -import java.awt.Dialog; import java.awt.Frame; -import java.awt.Panel; -import java.awt.TextArea; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class AltGraphModifierTest { - private static void init() throws Exception { - String[] instructions - = { - "This test is for verifying Alt-Gr modifier of an event.", - "Linux :-", - "1. Please check if Alt-Gr key is present on keyboard.", - "2. If present, press the Alt-Gr key and perform", - " mouse click on the TestWindow.", - "3. Navigate to System Settings-> Keyboard-> Shortcuts->", - " Typing.", - "4. Select an option for the Alternative Characters Key", - " For example. Right Alt", - "5. Close the settings and navigate to test", - "6. Press Right Alt Key & perform mouse click on the", - " TestWindow", - "7. Test will exit by itself with appropriate result.", - " ", - }; - Sysout.createDialog(); - Sysout.printInstructions(instructions); + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is for verifying Alt-Gr modifier of an event. + Please check if Alt-Gr key is present on keyboard. + If not present, press Pass. + On Windows: + Press Alt-Gr or Right Alt key and simultaneously + perform mouse click on the "TestWindow". + On Linux: + Navigate to + System Settings-> Keyboard-> Special Character Entry + Select "Right Alt" option for the "Alternate Characters Key" + Close the settings and navigate to test + Press Right Alt Key & simultaneously + perform mouse click on the "TestWindow". + + If the system does not have such setting, press Pass. + After the test, change the Setting of "Alternate Characters Key" + back to "Layout default". + + If "Alt-Gr Modifier bit is set" message is displayed in logArea, + press Pass else press Fail. + """; + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(AltGraphModifierTest::initTestWindow) + .logArea() + .build() + .awaitAndCheck(); } - static Frame mainFrame; - public static void initTestWindow() { - mainFrame = new Frame(); + public static Frame initTestWindow() { + Frame mainFrame = new Frame(); mainFrame.setTitle("TestWindow"); mainFrame.setBounds(700, 10, 300, 300); mainFrame.addMouseListener(new MouseAdapter() { @@ -74,186 +80,12 @@ public class AltGraphModifierTest { public void mousePressed(MouseEvent e) { int ex = e.getModifiersEx(); if ((ex & InputEvent.ALT_GRAPH_DOWN_MASK) == 0) { - AltGraphModifierTest.fail("Alt-Gr Modifier bit is not set."); + PassFailJFrame.log("Alt-Gr Modifier bit is not set."); } else { - AltGraphModifierTest.pass(); + PassFailJFrame.log("Alt-Gr Modifier bit is set"); } } }); - mainFrame.setVisible(true); - } - - public static void dispose() { - Sysout.dispose(); - mainFrame.dispose(); - } - - /** - * *************************************************** - * Standard Test Machinery Section DO NOT modify anything in this section -- - * it's a standard chunk of code which has all of the synchronisation - * necessary for the test harness. By keeping it the same in all tests, it - * is easier to read and understand someone else's test, as well as insuring - * that all tests behave correctly with the test harness. There is a section - * following this for test-defined classes - * **************************************************** - */ - private static boolean theTestPassed = false; - private static boolean testGeneratedInterrupt = false; - private static String failureMessage = ""; - private static Thread mainThread = null; - final private static int sleepTime = 300000; - - public static void main(String args[]) throws Exception { - mainThread = Thread.currentThread(); - try { - init(); - initTestWindow(); - } catch (Exception e) { - e.printStackTrace(); - } - try { - mainThread.sleep(sleepTime); - } catch (InterruptedException e) { - dispose(); - if (testGeneratedInterrupt && !theTestPassed) { - throw new Exception(failureMessage); - } - } - if (!testGeneratedInterrupt) { - dispose(); - throw new RuntimeException("Timed out after " + sleepTime / 1000 - + " seconds"); - } - } - - public static synchronized void pass() { - theTestPassed = true; - testGeneratedInterrupt = true; - mainThread.interrupt(); - } - - public static synchronized void fail(String whyFailed) { - theTestPassed = false; - testGeneratedInterrupt = true; - failureMessage = whyFailed; - mainThread.interrupt(); - } -} - -// *********** End Standard Test Machinery Section ********** -/** - * ************************************************** - * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk - * of code whose purpose is to make user interaction uniform, and thereby make - * it simpler to read and understand someone else's test. - * ************************************************** - */ -/** - * This is part of the standard test machinery. It creates a dialog (with the - * instructions), and is the interface for sending text messages to the user. To - * print the instructions, send an array of strings to Sysout.createDialog - * WithInstructions method. Put one line of instructions per array entry. To - * display a message for the tester to see, simply call Sysout.println with the - * string to be displayed. This mimics System.out.println but works within the - * test harness as well as standalone. - */ -class Sysout { - private static TestDialog dialog; - private static Frame frame; - - public static void createDialog() { - frame = new Frame(); - dialog = new TestDialog(frame, "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.show(); - println("Any messages for the tester will display here."); - } - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); - } - - public static void dispose() { - dialog.dispose(); - frame.dispose(); - } -} - -/** - * This is part of the standard test machinery. It provides a place for the test - * instructions to be displayed, and a place for interactive messages to the - * user to be displayed. To have the test instructions displayed, see Sysout. To - * have a message to the user be displayed, see Sysout. Do not call anything in - * this dialog directly. - */ -class TestDialog extends Dialog implements ActionListener { - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - Panel buttonP; - Button failB; - - // DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("Center", messageText); - - buttonP = new Panel(); - failB = new Button("Fail"); - failB.setActionCommand("fail"); - failB.addActionListener(this); - buttonP.add("Center", failB); - - add("South", buttonP); - pack(); - setVisible(true); - } - - // DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - instructionsText.setText(""); - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - remainingStr = instructions[i]; - while (remainingStr.length() > 0) { - if (remainingStr.length() >= maxStringLength) { - int posOfSpace = remainingStr. - lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) { - posOfSpace = maxStringLength - 1; - } - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } - else { - printStr = remainingStr; - remainingStr = ""; - } - instructionsText.append(printStr + "\n"); - } - } - } - - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand() == "fail") { - AltGraphModifierTest.fail("User Clicked Fail"); - } + return mainFrame; } } From af18ff8d7c8fdd6437304839caa2e49eb34b6caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 10 Sep 2025 16:43:40 +0000 Subject: [PATCH 455/471] 8367007: javadoc generation of JavaFX docs fails after fix for JDK-8350920 Reviewed-by: liach, nbenalla --- .../formats/html/AbstractMemberWriter.java | 2 +- .../doclets/formats/html/ClassWriter.java | 2 +- .../doclets/toolkit/PropertyUtils.java | 96 ++++++++++--------- .../javadoc/doclet/testJavaFX/TestJavaFX.java | 36 ++++++- .../jdk/javadoc/doclet/testJavaFX/pkg1/B.java | 27 ++++++ 5 files changed, 115 insertions(+), 48 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index e2e286d5856..fabca0a894d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -319,7 +319,7 @@ public abstract class AbstractMemberWriter { inheritedHeader.add(links); if (utils.isIncluded(inheritedClass)) { - var pHelper = writer.getPropertyHelper(); + var pHelper = configuration.propertyUtils.getPropertyHelper(inheritedClass); Table table = createInheritedSummaryTable(inheritedClass); for (Element member : inheritedMembers) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index d301dd6e283..f5a5a48222c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -96,7 +96,7 @@ public class ClassWriter extends SubWriterHolderWriter { this.typeElement = typeElement; this.classTree = classTree; - pHelper = new PropertyUtils.PropertyHelper(configuration, typeElement); + pHelper = configuration.propertyUtils.getPropertyHelper(typeElement); switch (typeElement.getKind()) { case ENUM -> setEnumDocumentation(typeElement); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java index 823f172b360..8913be5b301 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -54,6 +54,8 @@ import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind. */ public class PropertyUtils { + final BaseConfiguration configuration; + final TypeMirror jbObservableType; final Pattern fxMethodPatterns; @@ -62,7 +64,10 @@ public class PropertyUtils { final Types typeUtils; + final Map propertyHelpers = new HashMap<>(); + PropertyUtils(BaseConfiguration configuration) { + this.configuration = configuration; BaseOptions options = configuration.getOptions(); javafx = options.javafx(); @@ -82,30 +87,37 @@ public class PropertyUtils { : null; } + /** + * Returns a property helper for the given type element. + * @param typeElement a type element + * @return the property helper + */ + public PropertyHelper getPropertyHelper(TypeElement typeElement) { + return propertyHelpers.computeIfAbsent(typeElement, te -> new PropertyHelper(configuration, te)); + } + /** * Returns a base name for a property method. Supposing we * have {@code BooleanProperty acmeProperty()}, then "acme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the base name of a property method. */ public String getBaseName(ExecutableElement propertyMethod) { String name = propertyMethod.getSimpleName().toString(); - String baseName = name.substring(0, name.indexOf("Property")); - return baseName; + return name.substring(0, name.indexOf("Property")); } /** * Returns a property getter's name. Supposing we have a property * method {@code DoubleProperty acmeProperty()}, then "getAcme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property getter's name. */ public String getGetName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "get" + fnUppercased; } @@ -113,20 +125,19 @@ public class PropertyUtils { * Returns an "is" method's name for a property method. Supposing * we have a property method {@code BooleanProperty acmeProperty()}, * then "isAcme" will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property is getter's name. */ public String getIsName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "is" + fnUppercased; } /** * Returns true if a property method could have an "is" method, meaning * {@code isAcme} could exist for a property method. - * @param propertyMethod + * @param propertyMethod a property method * @return true if the property could have an "is" method, false otherwise. */ public boolean hasIsMethod(ExecutableElement propertyMethod) { @@ -139,20 +150,19 @@ public class PropertyUtils { * Returns a property setter's name. Supposing we have a property * method {@code DoubleProperty acmeProperty()}, then "setAcme" * will be returned. - * @param propertyMethod + * @param propertyMethod a property method * @return the property setter's method name. */ public String getSetName(ExecutableElement propertyMethod) { String baseName = getBaseName(propertyMethod); - String fnUppercased = "" + - Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + String fnUppercased = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); return "set" + fnUppercased; } /** * Returns true if the given setter method is a valid property setter * method. - * @param setterMethod + * @param setterMethod a setter method * @return true if setter method, false otherwise. */ public boolean isValidSetterMethod(ExecutableElement setterMethod) { @@ -161,28 +171,28 @@ public class PropertyUtils { /** * Returns true if the method is a property method. - * @param propertyMethod + * @param method a method * @return true if the method is a property method, false otherwise. */ - public boolean isPropertyMethod(ExecutableElement propertyMethod) { + public boolean isPropertyMethod(ExecutableElement method) { if (!javafx || - !propertyMethod.getParameters().isEmpty() || - !propertyMethod.getTypeParameters().isEmpty()) { + !method.getParameters().isEmpty() || + !method.getTypeParameters().isEmpty()) { return false; } - String methodName = propertyMethod.getSimpleName().toString(); + String methodName = method.getSimpleName().toString(); if (!methodName.endsWith("Property") || fxMethodPatterns.matcher(methodName).matches()) { return false; } - TypeMirror returnType = propertyMethod.getReturnType(); + TypeMirror returnType = method.getReturnType(); if (jbObservableType == null) { // JavaFX references missing, make a lazy backward compatible check. return returnType.getKind() != TypeKind.VOID; } else { // Apply strict checks since JavaFX references are available - returnType = typeUtils.erasure(propertyMethod.getReturnType()); + returnType = typeUtils.erasure(method.getReturnType()); return typeUtils.isAssignable(returnType, jbObservableType); } } @@ -202,20 +212,13 @@ public class PropertyUtils { * method. If any method does not have a comment, one will be provided. */ public static class PropertyHelper { - private final BaseConfiguration configuration; - private final Utils utils; - private final TypeElement typeElement; + private Map classPropertiesMap = null; - private final Map classPropertiesMap = new HashMap<>(); - - public PropertyHelper(BaseConfiguration configuration, TypeElement typeElement) { - this.configuration = configuration; - this.utils = configuration.utils; - this.typeElement = typeElement; - computeProperties(); + private PropertyHelper(BaseConfiguration configuration, TypeElement typeElement) { + computeProperties(configuration, typeElement); } - private void computeProperties() { + private void computeProperties(BaseConfiguration configuration, TypeElement typeElement) { VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement); List props = ElementFilter.methodsIn(vmt.getVisibleMembers(PROPERTIES)); for (ExecutableElement propertyMethod : props) { @@ -223,37 +226,42 @@ public class PropertyUtils { ExecutableElement setter = vmt.getPropertySetter(propertyMethod); VariableElement field = vmt.getPropertyField(propertyMethod); - addToPropertiesMap(propertyMethod, field, getter, setter); + addToPropertiesMap(configuration, propertyMethod, field, getter, setter); } } - private void addToPropertiesMap(ExecutableElement propertyMethod, + private void addToPropertiesMap(BaseConfiguration configuration, + ExecutableElement propertyMethod, VariableElement field, ExecutableElement getter, ExecutableElement setter) { // determine the preferred element from which to derive the property description - Element e = field == null || !utils.hasDocCommentTree(field) + Element e = field == null || !configuration.utils.hasDocCommentTree(field) ? propertyMethod : field; - if (e == field && utils.hasDocCommentTree(propertyMethod)) { + if (e == field && configuration.utils.hasDocCommentTree(propertyMethod)) { configuration.getReporter().print(Diagnostic.Kind.WARNING, propertyMethod, configuration.getDocResources().getText("doclet.duplicate.comment.for.property")); } - addToPropertiesMap(propertyMethod, e); - addToPropertiesMap(getter, e); - addToPropertiesMap(setter, e); + if (classPropertiesMap == null) { + classPropertiesMap = new HashMap<>(); + } + addToPropertiesMap(configuration, propertyMethod, e); + addToPropertiesMap(configuration, getter, e); + addToPropertiesMap(configuration, setter, e); } - private void addToPropertiesMap(Element propertyMethod, + private void addToPropertiesMap(BaseConfiguration configuration, + Element propertyMethod, Element commentSource) { Objects.requireNonNull(commentSource); if (propertyMethod == null) { return; } - DocCommentTree docTree = utils.hasDocCommentTree(propertyMethod) - ? utils.getDocCommentTree(propertyMethod) + DocCommentTree docTree = configuration.utils.hasDocCommentTree(propertyMethod) + ? configuration.utils.getDocCommentTree(propertyMethod) : null; /* The second condition is required for the property buckets. In @@ -271,7 +279,7 @@ public class PropertyUtils { * @return the element for the property documentation, null if there is none. */ public Element getPropertyElement(Element element) { - return classPropertiesMap.get(element); + return classPropertiesMap == null ? null : classPropertiesMap.get(element); } } } diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index 4fa89ee0ead..04e032dbe05 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -25,7 +25,7 @@ * @test * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 * 8167967 8172528 8175200 8178830 8182257 8186332 8182765 8025091 - * 8203791 8184205 8249633 8261976 8350920 + * 8203791 8184205 8249633 8261976 8350920 8367007 * @summary Test of the JavaFX doclet features. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -54,11 +54,18 @@ public class TestJavaFX extends JavadocTester { "-sourcepath", testSrc, "-javafx", "--disable-javafx-strict-checks", - "-Xdoclint:all,-missing", "-package", "pkg1"); checkExit(Exit.OK); + checkOutput(Output.OUT, true, + "C.java:78: warning: no comment"); + checkOutput(Output.OUT, false, + "C.java:59: warning: no comment", + "C.java:61: warning: no comment", + "C.java:63: warning: no comment", + "C.java:67: warning: no comment"); + checkOutput("pkg1/C.html", true, """

            See Also:
            @@ -266,6 +273,31 @@ public class TestJavaFX extends JavadocTester { """); checkOutput("pkg1/D.html", false, "shouldNotAppear"); + + // Test for inherited properties and property methods. + checkOrder("pkg1/B.html", + """ + Properties inherited from class C""", + """ +
            Defines if paused.
            """, + """ +
            Defines the direction/speed at which the Timeline is expected to + be played.
            """, + """ + Methods inherited from class C""", + """ +
            Gets the value of the rate property.
            """, + """ +
            Gets the value of the paused property.
            """, + """ +
            Defines if paused.
            """, + """ +
            Defines the direction/speed at which the Timeline is expected to + be played.
            """, + """ +
            Sets the value of the paused property.
            """, + """ +
            Sets the value of the rate property.
            """); } /* diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java new file mode 100644 index 00000000000..2ec6f77833a --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/B.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg1; + +public class B extends C { +} From 7a3025e3d7d33ed02db34c1485aa3c7b44b2d8ee Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 10 Sep 2025 17:24:53 +0000 Subject: [PATCH 456/471] 8367348: Enhance PassFailJFrame to support links in HTML Reviewed-by: aivanov --- .../awt/regtesthelpers/PassFailJFrame.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index c0a483056df..49e56493488 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -72,6 +72,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; import javax.swing.border.Border; +import javax.swing.event.HyperlinkListener; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -98,7 +99,8 @@ import static javax.swing.SwingUtilities.isEventDispatchThread; * tester. The instructions can be either plain text or HTML. If the * text of the instructions starts with {@code ""}, the * instructions are displayed as HTML, as supported by Swing, which - * provides richer formatting options. + * provides richer formatting options. To handle navigating links in the + * instructions, call {@link Builder#hyperlinkListener} to install a listener. *

            * The instructions are displayed in a text component with word-wrapping * so that there's no horizontal scroll bar. If the text doesn't fit, a @@ -592,6 +594,7 @@ public final class PassFailJFrame { frame.add(createInstructionUIPanel(instructions, testTimeOut, rows, columns, + null, false, false, 0), BorderLayout.CENTER); @@ -610,6 +613,7 @@ public final class PassFailJFrame { createInstructionUIPanel(builder.instructions, builder.testTimeOut, builder.rows, builder.columns, + builder.hyperlinkListener, builder.screenCapture, builder.addLogArea, builder.logAreaRows); @@ -631,6 +635,7 @@ public final class PassFailJFrame { private static JComponent createInstructionUIPanel(String instructions, long testTimeOut, int rows, int columns, + HyperlinkListener hyperlinkListener, boolean enableScreenCapture, boolean addLogArea, int logAreaRows) { @@ -643,6 +648,9 @@ public final class PassFailJFrame { JTextComponent text = instructions.startsWith("") ? configureHTML(instructions, rows, columns) : configurePlainText(instructions, rows, columns); + if (hyperlinkListener != null && text instanceof JEditorPane ep) { + ep.addHyperlinkListener(hyperlinkListener); + } text.setEditable(false); text.setBorder(createTextBorder()); text.setCaretPosition(0); @@ -716,7 +724,7 @@ public final class PassFailJFrame { // Reduce the list default margins styles.addRule("ol, ul { margin-left-ltr: 30; margin-left-rtl: 30 }"); // Make the size of code (and other elements) the same as other text - styles.addRule("code, kbd, samp, pre { font-size: inherit }"); + styles.addRule("code, kbd, samp, pre { font-size: inherit; background: #DDD; }"); return text; } @@ -1398,6 +1406,7 @@ public final class PassFailJFrame { private int rows; private int columns; private boolean screenCapture; + private HyperlinkListener hyperlinkListener; private boolean addLogArea; private int logAreaRows = 10; @@ -1478,6 +1487,18 @@ public final class PassFailJFrame { return this; } + /** + * Sets a {@link HyperlinkListener} for navigating links inside + * the instructions pane. + * + * @param hyperlinkListener the listener + * @return this builder + */ + public Builder hyperlinkListener(HyperlinkListener hyperlinkListener) { + this.hyperlinkListener = hyperlinkListener; + return this; + } + public Builder screenCapture() { this.screenCapture = true; return this; From 4e2a85f7500876d65c36aeaf54f5361a1549e7f5 Mon Sep 17 00:00:00 2001 From: Man Cao Date: Wed, 10 Sep 2025 17:42:15 +0000 Subject: [PATCH 457/471] 8366118: DontCompileHugeMethods is not respected with -XX:-TieredCompilation Co-authored-by: Chuck Rasbold Co-authored-by: Justin King Reviewed-by: rasbold, iveresov, jiangli --- .../share/compiler/compilationPolicy.cpp | 39 +++--- .../runtime/TestDontCompileHugeMethods.java | 122 ++++++++++++++++++ 2 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 5db6cb1b0cc..36b597b6e37 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -922,28 +922,29 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level return; } - if (!CompilationModeFlag::disable_intermediate()) { - // Check if the method can be compiled. If it cannot be compiled with C1, continue profiling - // in the interpreter and then compile with C2 (the transition function will request that, - // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with - // pure C1. - if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { - compile(mh, bci, CompLevel_simple, THREAD); - } - return; + // Check if the method can be compiled. Additional logic for TieredCompilation: + // If it cannot be compiled with C1, continue profiling in the interpreter + // and then compile with C2 (the transition function will request that, + // see common() ). If the method cannot be compiled with C2 but still can with C1, compile it with + // pure C1. + if ((bci == InvocationEntryBci && !can_be_compiled(mh, level))) { + if (!CompilationModeFlag::disable_intermediate() && + level == CompLevel_full_optimization && can_be_compiled(mh, CompLevel_simple)) { + compile(mh, bci, CompLevel_simple, THREAD); } - if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { - if (level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { - nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); - if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { - // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. - osr_nm->make_not_entrant(nmethod::InvalidationReason::OSR_INVALIDATION_FOR_COMPILING_WITH_C1); - } - compile(mh, bci, CompLevel_simple, THREAD); + return; + } + if ((bci != InvocationEntryBci && !can_be_osr_compiled(mh, level))) { + if (!CompilationModeFlag::disable_intermediate() && + level == CompLevel_full_optimization && can_be_osr_compiled(mh, CompLevel_simple)) { + nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); + if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { + // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. + osr_nm->make_not_entrant(nmethod::InvalidationReason::OSR_INVALIDATION_FOR_COMPILING_WITH_C1); } - return; + compile(mh, bci, CompLevel_simple, THREAD); } + return; } if (bci != InvocationEntryBci && mh->is_not_osr_compilable(level)) { return; diff --git a/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java b/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java new file mode 100644 index 00000000000..c5e035edbd0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestDontCompileHugeMethods.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025, Google LLC. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8366118 + * @summary Check that a huge method is not compiled under -XX:+DontCompileHugeMethods. + * @library /test/lib + * @run main compiler.runtime.TestDontCompileHugeMethods + */ +package compiler.runtime; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class TestDontCompileHugeMethods { + + private static final String HUGE_SWITCH_CLASS_NAME = "HugeSwitch"; + + private static void generateClass(Writer writer) throws IOException { + writer.write(""" + public class HugeSwitch { + private static int hugeSwitch(int x) { + switch (x) { + """); + for (int i = 0; i < 2000; i++) { + writer.write(" case " + i + ": return " + i + " + 1;\n"); + } + writer.write(""" + default: + return 0; + } + } + private static int shortMethod(int x) { + if (x % 3 == 0) { + return x - 1; + } + return x + 1; + } + public static void main(String[] args) { + int val = 0; + for (int i = 0; i < 100000; i++) { + val += hugeSwitch(shortMethod(i)); + } + System.out.println(val); + } + } + """); + } + + private static void compileClass(Path workDir, Path sourceFile) throws Exception { + JDKToolLauncher javac = JDKToolLauncher.create("javac").addToolArg("-d") + .addToolArg(workDir.toAbsolutePath().toString()).addToolArg("-cp") + .addToolArg(Utils.TEST_CLASS_PATH).addToolArg(sourceFile.toAbsolutePath().toString()); + + OutputAnalyzer output = ProcessTools.executeProcess(javac.getCommand()); + output.shouldHaveExitValue(0); + } + + private static void generateAndCompileClass(Path workDir) throws Exception { + Path sourceFile = workDir.resolve(HUGE_SWITCH_CLASS_NAME + ".java"); + try (Writer writer = Files.newBufferedWriter(sourceFile)) { + generateClass(writer); + } catch (IOException e) { + throw new RuntimeException(e); + } + compileClass(workDir, sourceFile); + } + + private static void runTest(Path workDir, List jvmArgs) throws Exception { + ArrayList command = new ArrayList<>(); + command.add("-XX:+PrintCompilation"); + command.add("-Xbatch"); + command.addAll(jvmArgs); + command.add("-cp"); + command.add(workDir.toAbsolutePath().toString()); + command.add(HUGE_SWITCH_CLASS_NAME); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(command); + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + analyzer.shouldHaveExitValue(0); + analyzer.shouldContain(" HugeSwitch::shortMethod ("); + analyzer.shouldNotContain(" HugeSwitch::hugeSwitch ("); + } + + public static void main(String[] args) throws Exception { + Path workDir = Paths.get(""); + generateAndCompileClass(workDir); + + runTest(workDir, List.of()); + runTest(workDir, List.of("-XX:-TieredCompilation")); + } +} From fdc11a1569248c9b671b66d547b4616aeb953ecf Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 10 Sep 2025 18:41:42 +0000 Subject: [PATCH 458/471] 8367131: Test com/sun/jdi/ThreadMemoryLeakTest.java fails on 32 bits Reviewed-by: lmesnik, cjplummer, shade --- test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java index 59168a4de7e..5431b8835a2 100644 --- a/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java +++ b/test/jdk/com/sun/jdi/ThreadMemoryLeakTest.java @@ -28,7 +28,7 @@ * * @comment Don't allow -Xcomp or -Xint as they impact memory useage and number of iterations. * Require compressed oops because not doing so increases memory usage. - * @requires (vm.compMode == "Xmixed") & vm.opt.final.UseCompressedOops + * @requires (vm.compMode == "Xmixed") & (vm.bits == 32 | vm.opt.final.UseCompressedOops) * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g ThreadMemoryLeakTest.java * @comment run with -Xmx7m so any leak will quickly produce OOME From 85715e1050fa774c3267dbbe2f749717aeeec8ff Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 10 Sep 2025 19:21:00 +0000 Subject: [PATCH 459/471] 8317269: Store old classes in linked state in AOT cache Reviewed-by: coleenp, matsaave --- src/hotspot/share/cds/aotMetaspace.cpp | 20 +- src/hotspot/share/cds/aotMetaspace.hpp | 1 + src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/cds/cdsConfig.cpp | 30 ++ src/hotspot/share/cds/cdsConfig.hpp | 9 + src/hotspot/share/cds/dumpTimeClassInfo.cpp | 13 +- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 15 +- src/hotspot/share/cds/dynamicArchive.cpp | 6 + .../share/cds/lambdaProxyClassDictionary.cpp | 6 +- src/hotspot/share/cds/runTimeClassInfo.cpp | 10 +- src/hotspot/share/cds/runTimeClassInfo.hpp | 4 +- .../classfile/systemDictionaryShared.cpp | 316 +++++++++++++++--- .../classfile/systemDictionaryShared.hpp | 21 +- src/hotspot/share/oops/instanceKlass.cpp | 14 +- src/hotspot/share/oops/methodData.cpp | 5 +- src/hotspot/share/oops/trainingData.cpp | 9 +- src/hotspot/share/prims/jvm.cpp | 7 + src/hotspot/share/runtime/mutexLocker.cpp | 4 +- test/hotspot/jtreg/TEST.groups | 6 +- .../cds/appcds/aotCache/ExcludedClasses.java | 12 +- .../runtime/cds/appcds/aotCache/OldA.jasm | 38 +++ .../cds/appcds/aotCache/OldClassSupport.java | 162 +++++++++ ...dClassWithExcludedVerifierConstraints.jasm | 50 +++ .../OldClassWithVerifierConstraints.jasm | 50 +++ .../AOTClassLinkingVerification.java | 294 ++++++++++++++++ .../appcds/aotClassLinking/BadNewClass.jasm | 52 +++ .../appcds/aotClassLinking/BadNewClass2.jasm | 52 +++ .../appcds/aotClassLinking/BadNewClass3.jasm | 53 +++ .../appcds/aotClassLinking/BadNewClass4.jasm | 53 +++ .../appcds/aotClassLinking/BadOldClass.jasm | 52 +++ .../appcds/aotClassLinking/BadOldClass2.jasm | 52 +++ .../appcds/aotClassLinking/BadOldClass3.jasm | 53 +++ .../appcds/aotClassLinking/BadOldClass4.jasm | 53 +++ .../aotClassLinking/BulkLoaderTest.java | 2 +- .../appcds/aotClassLinking/GoodOldClass.jasm | 49 +++ 35 files changed, 1485 insertions(+), 90 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index c2d9d0193f5..cca82bed4f1 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -652,6 +652,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& } void VM_PopulateDumpSharedSpace::doit() { + CDSConfig::set_is_at_aot_safepoint(true); + if (!CDSConfig::is_dumping_final_static_archive()) { guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); } @@ -717,6 +719,8 @@ void VM_PopulateDumpSharedSpace::doit() { _map_info->set_serialized_data(serialized_data); _map_info->set_cloned_vtables(CppVtables::vtables_serialized_base()); _map_info->header()->set_class_location_config(cl_config); + + CDSConfig::set_is_at_aot_safepoint(false); } class CollectClassesForLinking : public KlassClosure { @@ -773,12 +777,9 @@ bool AOTMetaspace::may_be_eagerly_linked(InstanceKlass* ik) { return true; } -void AOTMetaspace::link_shared_classes(TRAPS) { - AOTClassLinker::initialize(); - AOTClassInitializer::init_test_class(CHECK); - +void AOTMetaspace::link_all_loaded_classes(JavaThread* current) { while (true) { - ResourceMark rm(THREAD); + ResourceMark rm(current); CollectClassesForLinking collect_classes; bool has_linked = false; const GrowableArray* mirrors = collect_classes.mirrors(); @@ -786,7 +787,7 @@ void AOTMetaspace::link_shared_classes(TRAPS) { OopHandle mirror = mirrors->at(i); InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); if (may_be_eagerly_linked(ik)) { - has_linked |= try_link_class(THREAD, ik); + has_linked |= try_link_class(current, ik); } } @@ -796,6 +797,13 @@ void AOTMetaspace::link_shared_classes(TRAPS) { // Class linking includes verification which may load more classes. // Keep scanning until we have linked no more classes. } +} + +void AOTMetaspace::link_shared_classes(TRAPS) { + AOTClassLinker::initialize(); + AOTClassInitializer::init_test_class(CHECK); + + link_all_loaded_classes(THREAD); // Eargerly resolve all string constants in constant pools { diff --git a/src/hotspot/share/cds/aotMetaspace.hpp b/src/hotspot/share/cds/aotMetaspace.hpp index 6c0ad37dbf7..1803199766d 100644 --- a/src/hotspot/share/cds/aotMetaspace.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -135,6 +135,7 @@ public: } static bool try_link_class(JavaThread* current, InstanceKlass* ik); + static void link_all_loaded_classes(JavaThread* current); static void link_shared_classes(TRAPS) NOT_CDS_RETURN; static bool may_be_eagerly_linked(InstanceKlass* ik) NOT_CDS_RETURN_(false); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 42d575a012f..77f51443bb2 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -937,7 +937,7 @@ void ArchiveBuilder::make_klasses_shareable() { ADD_COUNT(num_enum_klasses); } - if (!ik->can_be_verified_at_dumptime()) { + if (CDSConfig::is_old_class_for_verifier(ik)) { ADD_COUNT(num_old_klasses); old = " old"; } diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 90b802731f0..d3048b9ee7a 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -56,6 +56,7 @@ bool CDSConfig::_has_temp_aot_config_file = false; bool CDSConfig::_old_cds_flags_used = false; bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; +bool CDSConfig::_is_at_aot_safepoint = false; const char* CDSConfig::_default_archive_path = nullptr; const char* CDSConfig::_input_static_archive_path = nullptr; @@ -922,6 +923,35 @@ bool CDSConfig::is_dumping_lambdas_in_legacy_mode() { return !is_dumping_method_handles(); } +bool CDSConfig::is_preserving_verification_constraints() { + // Verification dependencies are classes used in assignability checks by the + // bytecode verifier. In the following example, the verification dependencies + // for X are A and B. + // + // class X { + // A getA() { return new B(); } + // } + // + // With the AOT cache, we can ensure that all the verification dependencies + // (A and B in the above example) are unconditionally loaded during the bootstrap + // of the production run. This means that if a class was successfully verified + // in the assembly phase, all of the verifier's assignability checks will remain + // valid in the production run, so we don't need to verify aot-linked classes again. + + if (is_dumping_preimage_static_archive()) { // writing AOT config + return AOTClassLinking; + } else if (is_dumping_final_static_archive()) { // writing AOT cache + return is_dumping_aot_linked_classes(); + } else { + // For simplicity, we don't support this optimization with the old CDS workflow. + return false; + } +} + +bool CDSConfig::is_old_class_for_verifier(const InstanceKlass* ik) { + return ik->major_version() < 50 /*JAVA_6_VERSION*/; +} + #if INCLUDE_CDS_JAVA_HEAP bool CDSConfig::are_vm_options_incompatible_with_dumping_heap() { return check_options_incompatible_with_dumping_heap() != nullptr; diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index 1fd229ff34f..8361cf052db 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -30,6 +30,7 @@ #include "utilities/macros.hpp" class JavaThread; +class InstanceKlass; class CDSConfig : public AllStatic { #if INCLUDE_CDS @@ -43,6 +44,7 @@ class CDSConfig : public AllStatic { static bool _has_aot_linked_classes; static bool _is_single_command_training; static bool _has_temp_aot_config_file; + static bool _is_at_aot_safepoint; const static char* _default_archive_path; const static char* _input_static_archive_path; @@ -99,6 +101,9 @@ public: static const char* type_of_archive_being_written(); static void prepare_for_dumping(); + static bool is_at_aot_safepoint() { return CDS_ONLY(_is_at_aot_safepoint) NOT_CDS(false); } + static void set_is_at_aot_safepoint(bool value) { CDS_ONLY(_is_at_aot_safepoint = value); } + // --- Basic CDS features // archive(s) in general @@ -161,6 +166,10 @@ public: static bool is_using_aot_linked_classes() NOT_CDS_JAVA_HEAP_RETURN_(false); static void set_has_aot_linked_classes(bool has_aot_linked_classes) NOT_CDS_JAVA_HEAP_RETURN; + // Bytecode verification + static bool is_preserving_verification_constraints(); + static bool is_old_class_for_verifier(const InstanceKlass* ik); + // archive_path // Points to the classes.jsa in $JAVA_HOME (could be input or output) diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 8af762dba4d..0f5773a2729 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -47,7 +47,7 @@ size_t DumpTimeClassInfo::runtime_info_bytesize() const { num_enum_klass_static_fields()); } -void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name, +void DumpTimeClassInfo::add_verification_constraint(Symbol* name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) { if (_verifier_constraints == nullptr) { _verifier_constraints = new (mtClass) GrowableArray(4, mtClass); @@ -73,9 +73,14 @@ void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* na if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm; - log_trace(aot, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d", - k->external_name(), from_name->as_klass_external_name(), - name->as_klass_external_name(), c, vc_array->length(), vcflags_array->length()); + if (from_name != nullptr) { + log_trace(aot, verification)("add verification constraint: %s: %s must be subclass of %s [0x%x]", + _klass->external_name(), from_name->as_klass_external_name(), + name->as_klass_external_name(), c); + } else { + log_trace(aot, verification)("added old verification constraint: %s: %s", _klass->external_name(), + name->as_klass_external_name()); + } } } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 0bc0f8bedda..c2f83b22337 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -88,7 +88,7 @@ class DumpTimeClassInfo: public CHeapObj { Symbol* _from_name; public: DTVerifierConstraint() : _name(nullptr), _from_name(nullptr) {} - DTVerifierConstraint(Symbol* n, Symbol* fn) : _name(n), _from_name(fn) { + DTVerifierConstraint(Symbol* n, Symbol* fn = nullptr) : _name(n), _from_name(fn) { Symbol::maybe_increment_refcount(_name); Symbol::maybe_increment_refcount(_from_name); } @@ -152,8 +152,9 @@ public: DumpTimeClassInfo& operator=(const DumpTimeClassInfo&) = delete; ~DumpTimeClassInfo(); - void add_verification_constraint(InstanceKlass* k, Symbol* name, - Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object); + // For old verifier: only name is saved; all other fields are null/false. + void add_verification_constraint(Symbol* name, + Symbol* from_name = nullptr, bool from_field_is_protected = false, bool from_is_array = false, bool from_is_object = false); void record_linking_constraint(Symbol* name, Handle loader1, Handle loader2); void add_enum_klass_static_field(int archived_heap_root_index); int enum_klass_static_field(int which_field); @@ -175,6 +176,14 @@ public: return array_length_or_zero(_verifier_constraint_flags); } + Symbol* verifier_constraint_name_at(int i) const { + return _verifier_constraints->at(i).name(); + } + + Symbol* verifier_constraint_from_name_at(int i) const { + return _verifier_constraints->at(i).from_name(); + } + int num_loader_constraints() const { return array_length_or_zero(_loader_constraints); } diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index d628a4e991f..58b354b9240 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -110,6 +110,12 @@ public: } void doit() { + CDSConfig::set_is_at_aot_safepoint(true); + doit_inner(); + CDSConfig::set_is_at_aot_safepoint(false); + } + + void doit_inner() { verify_universe("Before CDS dynamic dump"); DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index c8281ef497c..62b1b8c05f1 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -471,12 +471,12 @@ class LambdaProxyClassDictionary::CleanupDumpTimeLambdaProxyClassTable: StackObj // If the caller class and/or nest_host are excluded, the associated lambda proxy // must also be excluded. - bool always_exclude = SystemDictionaryShared::check_for_exclusion(caller_ik, nullptr) || - SystemDictionaryShared::check_for_exclusion(nest_host, nullptr); + bool always_exclude = SystemDictionaryShared::should_be_excluded(caller_ik) || + SystemDictionaryShared::should_be_excluded(nest_host); for (int i = info._proxy_klasses->length() - 1; i >= 0; i--) { InstanceKlass* ik = info._proxy_klasses->at(i); - if (always_exclude || SystemDictionaryShared::check_for_exclusion(ik, nullptr)) { + if (always_exclude || SystemDictionaryShared::should_be_excluded(ik)) { LambdaProxyClassDictionary::reset_registered_lambda_proxy_class(ik); info._proxy_klasses->remove_at(i); } diff --git a/src/hotspot/share/cds/runTimeClassInfo.cpp b/src/hotspot/share/cds/runTimeClassInfo.cpp index d93ef5e9c1d..832b0ce8932 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.cpp +++ b/src/hotspot/share/cds/runTimeClassInfo.cpp @@ -40,12 +40,18 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) { _num_verifier_constraints = info.num_verifier_constraints(); _num_loader_constraints = info.num_loader_constraints(); int i; + + if (CDSConfig::is_preserving_verification_constraints() && CDSConfig::is_dumping_final_static_archive()) { + // The production run doesn't need the verifier constraints, as we can guarantee that all classes checked by + // the verifier during AOT training/assembly phases cannot be replaced in the production run. + _num_verifier_constraints = 0; + } if (_num_verifier_constraints > 0) { RTVerifierConstraint* vf_constraints = verifier_constraints(); char* flags = verifier_constraint_flags(); for (i = 0; i < _num_verifier_constraints; i++) { - vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name()); - vf_constraints[i]._from_name = builder->any_to_offset_u4(info._verifier_constraints->at(i).from_name()); + vf_constraints[i]._name = builder->any_to_offset_u4(info._verifier_constraints->at(i).name()); + vf_constraints[i]._from_name = builder->any_or_null_to_offset_u4(info._verifier_constraints->at(i).from_name()); } for (i = 0; i < _num_verifier_constraints; i++) { flags[i] = info._verifier_constraint_flags->at(i); diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index 29670f5ec51..371924f9065 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -59,7 +59,9 @@ class RunTimeClassInfo { u4 _name; u4 _from_name; Symbol* name() { return ArchiveUtils::offset_to_archived_address(_name); } - Symbol* from_name() { return ArchiveUtils::offset_to_archived_address(_from_name); } + Symbol* from_name() { + return (_from_name == 0) ? nullptr : ArchiveUtils::offset_to_archived_address(_from_name); + } }; struct RTLoaderConstraint { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 45a5dc2328c..eda823704ca 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -204,28 +204,156 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { return info; } -bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { - // We have reached a super type that's already in the base archive. Treat it - // as "not excluded". - return false; - } - - if (info == nullptr) { - info = _dumptime_table->get(k); - assert(info != nullptr, "supertypes of any classes in _dumptime_table must either be shared, or must also be in _dumptime_table"); - } +bool SystemDictionaryShared::should_be_excluded_impl(InstanceKlass* k, DumpTimeClassInfo* info) { + assert_lock_strong(DumpTimeTable_lock); if (!info->has_checked_exclusion()) { - if (check_for_exclusion_impl(k)) { - info->set_excluded(); - } - info->set_has_checked_exclusion(); + check_exclusion_for_self_and_dependencies(k); + assert(info->has_checked_exclusion(), "must be"); } return info->is_excluded(); } +// returns bool and takes a single parameter of Symbol* +// The return value indicates whether we want to keep on iterating or not. +template +void SystemDictionaryShared::iterate_verification_constraint_names(InstanceKlass* k, DumpTimeClassInfo* info, Function func) { + int n = info->num_verifier_constraints(); + bool cont; // continue iterating? + for (int i = 0; i < n; i++) { + cont = func(info->verifier_constraint_name_at(i)); + if (!cont) { + return; // early termination + } + Symbol* from_name = info->verifier_constraint_from_name_at(i); + if (from_name != nullptr) { + cont = func(from_name); + if (!cont) { + return; // early termination + } + } + } +} + +// This is a table of classes that need to be checked for exclusion. +class SystemDictionaryShared::ExclusionCheckCandidates + : public HashTable { + void add_candidate(InstanceKlass* k) { + if (contains(k)) { + return; + } + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { + return; + } + + DumpTimeClassInfo* info = SystemDictionaryShared::get_info_locked(k); + if (info->has_checked_exclusion()) { + // We have check exclusion of k and all of its dependencies, so there's no need to check again. + return; + } + + put(k, info); + + if (!k->is_loaded()) { + // super types are not yet initialized for k. + return; + } + + InstanceKlass* super = k->java_super(); + if (super != nullptr) { + add_candidate(super); + } + + Array* interfaces = k->local_interfaces(); + int len = interfaces->length(); + for (int i = 0; i < len; i++) { + add_candidate(interfaces->at(i)); + } + + InstanceKlass* nest_host = k->nest_host_or_null(); + if (nest_host != nullptr && nest_host != k) { + add_candidate(nest_host); + } + + if (CDSConfig::is_preserving_verification_constraints()) { + SystemDictionaryShared::iterate_verification_constraint_names(k, info, [&] (Symbol* constraint_class_name) { + Klass* constraint_bottom_class = find_verification_constraint_bottom_class(k, constraint_class_name); + if (constraint_bottom_class != nullptr && constraint_bottom_class->is_instance_klass()) { + add_candidate(InstanceKlass::cast(constraint_bottom_class)); + } + return true; // Keep iterating. + }); + } + } + +public: + ExclusionCheckCandidates(InstanceKlass* k) { + add_candidate(k); + } +}; + +// A class X is excluded if check_self_exclusion() returns true for X or any of +// X's "exclusion dependency" classes, which include: +// - ik's super types +// - ik's nest host (if any) +// +// plus, if CDSConfig::is_preserving_verification_constraints()==true: +// - ik's verification constraints. These are the classes used in assignability checks +// when verifying ik's bytecodes. +// +// This method ensure that exclusion check is performed on X and all of its exclusion dependencies. +void SystemDictionaryShared::check_exclusion_for_self_and_dependencies(InstanceKlass* ik) { + assert_lock_strong(DumpTimeTable_lock); + ResourceMark rm; + + // This will recursively find ik and all of its exclusion dependencies that have not yet been checked. + ExclusionCheckCandidates candidates(ik); + + // (1) Check each class to see if it should be excluded due to its own problems + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + if (check_self_exclusion(k)) { + info->set_excluded(); + } + }); + + // (2) Check each class to see if it should be excluded because of problems in a depeendency class + while (true) { + bool found_new_exclusion = false; + + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + if (!info->is_excluded() && check_dependencies_exclusion(k, info)) { + info->set_excluded(); + found_new_exclusion = true; + } + }); + + // Algorithm notes: + // + // The dependencies form a directed graph, possibly cyclic. Class X is excluded + // if it has at least one directed path that reaches class Y, where + // check_self_exclusion(Y) returns true. + // + // Because of the possibility of cycles in the graph, we cannot use simple + // recursion. Otherwise we will either never terminate, or will miss some paths. + // + // Hence, we keep doing a linear scan of the candidates until we stop finding + // new exclusions. + // + // In the worst case, we find one exclusion per iteration of the while loop, + // so the while loop gets executed O(N^2) times. However, in reality we have + // very few exclusions, so in most cases the while loop executes only once, and we + // walk each edge in the dependencies graph exactly once. + if (!found_new_exclusion) { + break; + } + } + candidates.iterate_all([&] (InstanceKlass* k, DumpTimeClassInfo* info) { + // All candidates have been fully checked, so we don't need to check them again. + info->set_has_checked_exclusion(); + }); +} + // Returns true so the caller can do: return warn_excluded("....."); bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { ResourceMark rm; @@ -248,7 +376,8 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { return (info != nullptr) ? info->is_early_klass() : false; } -bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { +bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { + assert_lock_strong(DumpTimeTable_lock); if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() && k->in_aot_cache()) { return false; // Do not exclude: unregistered classes are passed from preimage to final image. @@ -301,9 +430,8 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return warn_excluded(k, "Failed verification"); } else if (CDSConfig::is_dumping_aot_linked_classes()) { // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). - // However, we do not speculatively link old classes, as they are not recorded by - // SystemDictionaryShared::record_linking_constraint(). As a result, such an unlinked - // class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), + // Old classes may not be linked if CDSConfig::is_preserving_verification_constraints()==false. + // An unlinked class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), // causing the JVM to fail at bootstrap. return warn_excluded(k, "Unlinked class not supported by AOTClassLinking"); } else if (CDSConfig::is_dumping_preimage_static_archive()) { @@ -329,10 +457,13 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return true; } - InstanceKlass* super = k->super(); - if (super != nullptr && check_for_exclusion(super, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); + return false; +} + +// Returns true if DumpTimeClassInfo::is_excluded() is true for at least one of k's exclusion dependencies. +bool SystemDictionaryShared::check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { + InstanceKlass* super = k->java_super(); + if (super != nullptr && is_dependency_excluded(k, super, "super")) { return true; } @@ -340,21 +471,87 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { int len = interfaces->length(); for (int i = 0; i < len; i++) { InstanceKlass* intf = interfaces->at(i); - if (check_for_exclusion(intf, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string()); + if (is_dependency_excluded(k, intf, "interface")) { return true; } } InstanceKlass* nest_host = k->nest_host_or_null(); - if (nest_host != nullptr && nest_host != k && check_for_exclusion(nest_host, nullptr)) { - ResourceMark rm; - aot_log_warning(aot)("Skipping %s: nest_host class %s is excluded", k->name()->as_C_string(), nest_host->name()->as_C_string()); + if (nest_host != nullptr && nest_host != k && is_dependency_excluded(k, nest_host, "nest host class")) { return true; } - return false; // false == k should NOT be excluded + if (CDSConfig::is_preserving_verification_constraints()) { + bool excluded = false; + + iterate_verification_constraint_names(k, info, [&] (Symbol* constraint_class_name) { + if (check_verification_constraint_exclusion(k, constraint_class_name)) { + // If one of the verification constraint class has been excluded, the assignability checks + // by the verifier may no longer be valid in the production run. For safety, exclude this class. + excluded = true; + return false; // terminate iteration; k will be excluded + } else { + return true; // keep iterating + } + }); + + if (excluded) { + // At least one verification constraint class has been excluded + return true; + } + } + + return false; +} + +bool SystemDictionaryShared::is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type) { + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(dependency)) { + return false; + } + DumpTimeClassInfo* dependency_info = get_info_locked(dependency); + if (dependency_info->is_excluded()) { + ResourceMark rm; + aot_log_warning(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); + return true; + } + return false; +} + +bool SystemDictionaryShared::check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name) { + Klass* constraint_bottom_class = find_verification_constraint_bottom_class(k, constraint_class_name); + if (constraint_bottom_class == nullptr) { + // We don't have a bottom class (constraint_class_name is a type array), or constraint_class_name + // has not been loaded. The latter case happens when the new verifier was checking + // if constraint_class_name is assignable to an interface, and found the answer without resolving + // constraint_class_name. + // + // Since this class is not even loaded, it surely cannot be excluded. + return false; + } else if (constraint_bottom_class->is_instance_klass()) { + if (is_dependency_excluded(k, InstanceKlass::cast(constraint_bottom_class), "verification constraint")) { + return true; + } + } else { + assert(constraint_bottom_class->is_typeArray_klass(), "must be"); + } + + return false; +} + +Klass* SystemDictionaryShared::find_verification_constraint_bottom_class(InstanceKlass* k, Symbol* constraint_class_name) { + Thread* current = Thread::current(); + Handle loader(current, k->class_loader()); + Klass* constraint_class = SystemDictionary::find_instance_or_array_klass(current, constraint_class_name, loader); + if (constraint_class == nullptr) { + return nullptr; + } + + if (constraint_class->is_objArray_klass()) { + constraint_class = ObjArrayKlass::cast(constraint_class)->bottom_klass(); + } + + precond(constraint_class->is_typeArray_klass() || constraint_class->is_instance_klass()); + return constraint_class; } bool SystemDictionaryShared::is_builtin_loader(ClassLoaderData* loader_data) { @@ -556,7 +753,7 @@ void SystemDictionaryShared::handle_class_unloading(InstanceKlass* klass) { void SystemDictionaryShared::init_dumptime_info_from_preimage(InstanceKlass* k) { init_dumptime_info(k); - copy_verification_constraints_from_preimage(k); + copy_verification_info_from_preimage(k); copy_linking_constraints_from_preimage(k); if (SystemDictionary::is_platform_class_loader(k->class_loader())) { @@ -651,16 +848,21 @@ public: // Returns true if the class should be excluded. This can be called by // AOTConstantPoolResolver before or after we enter the CDS safepoint. // When called before the safepoint, we need to link the class so that -// it can be checked by check_for_exclusion(). +// it can be checked by should_be_excluded_impl(). bool SystemDictionaryShared::should_be_excluded(Klass* k) { assert(CDSConfig::is_dumping_archive(), "sanity"); assert(CDSConfig::current_thread_is_vm_or_dumper(), "sanity"); - if (k->is_objArray_klass()) { - return should_be_excluded(ObjArrayKlass::cast(k)->bottom_klass()); + if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(k)) { + // We have reached a super type that's already in the base archive. Treat it + // as "not excluded". + return false; } - if (!k->is_instance_klass()) { + if (k->is_objArray_klass()) { + return should_be_excluded(ObjArrayKlass::cast(k)->bottom_klass()); + } else if (!k->is_instance_klass()) { + assert(k->is_typeArray_klass(), "must be"); return false; } else { InstanceKlass* ik = InstanceKlass::cast(k); @@ -672,7 +874,7 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (!SafepointSynchronize::is_at_safepoint()) { if (!ik->is_linked()) { - // check_for_exclusion() below doesn't link unlinked classes. We come + // should_be_excluded_impl() below doesn't link unlinked classes. We come // here only when we are trying to aot-link constant pool entries, so // we'd better link the class. JavaThread* THREAD = JavaThread::current(); @@ -681,6 +883,10 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { CLEAR_PENDING_EXCEPTION; return true; // linking failed -- let's exclude it } + + // Also link any classes that were loaded for the verification of ik or its supertypes. + // Otherwise we might miss the verification constraints of those classes. + AOTMetaspace::link_all_loaded_classes(THREAD); } MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); @@ -688,8 +894,17 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (p->is_excluded()) { return true; } - return check_for_exclusion(ik, p); + return should_be_excluded_impl(ik, p); } else { + // When called within the CDS safepoint, the correctness of this function + // relies on the call to AOTMetaspace::link_all_loaded_classes() + // that happened right before we enter the CDS safepoint. + // + // Do not call this function in other types of safepoints. For example, if this + // is called in a GC safepoint, a klass may be improperly excluded because some + // of its verification constraints have not yet been linked. + assert(CDSConfig::is_at_aot_safepoint(), "Do not call this function in any other safepoint"); + // No need to check for is_linked() as all eligible classes should have // already been linked in AOTMetaspace::link_class_for_cds(). // Can't take the lock as we are in safepoint. @@ -697,12 +912,13 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { if (p->is_excluded()) { return true; } - return check_for_exclusion(ik, p); + return should_be_excluded_impl(ik, p); } } } void SystemDictionaryShared::finish_exclusion_checks() { + assert_at_safepoint(); if (CDSConfig::is_dumping_dynamic_archive() || CDSConfig::is_dumping_preimage_static_archive()) { // Do this first -- if a base class is excluded due to duplication, // all of its subclasses will also be excluded. @@ -713,7 +929,7 @@ void SystemDictionaryShared::finish_exclusion_checks() { } _dumptime_table->iterate_all_live_classes([&] (InstanceKlass* k, DumpTimeClassInfo& info) { - SystemDictionaryShared::check_for_exclusion(k, &info); + SystemDictionaryShared::should_be_excluded_impl(k, &info); }); _dumptime_table->update_counts(); @@ -793,7 +1009,7 @@ void SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo bool* skip_assignability_check) { assert(CDSConfig::is_dumping_archive(), "sanity"); DumpTimeClassInfo* info = get_info(k); - info->add_verification_constraint(k, name, from_name, from_field_is_protected, + info->add_verification_constraint(name, from_name, from_field_is_protected, from_is_array, from_is_object); if (CDSConfig::is_dumping_classic_static_archive() && !is_builtin(k)) { @@ -818,6 +1034,15 @@ void SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbo } } +// When the old verifier is verifying the class at dump time, it tries to resolve a +// class with the given . For the verification result to be valid at run time, we must +// ensure that resolves to the exact same Klass as in dump time. +void SystemDictionaryShared::add_old_verification_constraint(Thread* current, InstanceKlass* ik, Symbol* name) { + precond(CDSConfig::is_preserving_verification_constraints()); + DumpTimeClassInfo* info = get_info(ik); + info->add_verification_constraint(name); +} + void SystemDictionaryShared::add_enum_klass_static_field(InstanceKlass* ik, int root_index) { assert(CDSConfig::is_dumping_heap(), "sanity"); DumpTimeClassInfo* info = get_info_locked(ik); @@ -836,6 +1061,13 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); + if (from_name == nullptr) { + // This is for old verifier. No need to check, as we can guarantee that all classes checked by + // the old verifier during AOT training phase cannot be replaced in the asembly phase. + precond(CDSConfig::is_dumping_final_static_archive()); + continue; + } + if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm(THREAD); log_trace(aot, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]", @@ -860,7 +1092,7 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass } } -void SystemDictionaryShared::copy_verification_constraints_from_preimage(InstanceKlass* klass) { +void SystemDictionaryShared::copy_verification_info_from_preimage(InstanceKlass* klass) { assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); DumpTimeClassInfo* dt_info = get_info(klass); RunTimeClassInfo* rt_info = RunTimeClassInfo::get_for(klass); // from preimage @@ -872,7 +1104,7 @@ void SystemDictionaryShared::copy_verification_constraints_from_preimage(Instanc Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); - dt_info->add_verification_constraint(klass, name, from_name, + dt_info->add_verification_constraint(name, from_name, rt_info->from_field_is_protected(i), rt_info->from_is_array(i), rt_info->from_is_object(i)); } } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 30b38a5aa59..baad020cb61 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -146,7 +146,7 @@ class SystemDictionaryShared: public SystemDictionary { }; private: - + class ExclusionCheckCandidates; static DumpTimeSharedClassTable* _dumptime_table; static ArchiveInfo _static_archive; @@ -175,14 +175,27 @@ private: static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin); static bool is_jfr_event_class(InstanceKlass *k); - static bool check_for_exclusion_impl(InstanceKlass* k); + static bool should_be_excluded_impl(InstanceKlass* k, DumpTimeClassInfo* info); + + // exclusion checks + static void check_exclusion_for_self_and_dependencies(InstanceKlass *k); + static bool check_self_exclusion(InstanceKlass* k); + static bool check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); + static bool check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name); + static bool is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type); + static bool is_excluded_verification_constraint(InstanceKlass* k, Symbol* constraint_class_name); + static Klass* find_verification_constraint_bottom_class(InstanceKlass* k, Symbol* constraint_class_name); + static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN; static bool has_been_redefined(InstanceKlass* k); DEBUG_ONLY(static bool _class_loading_may_happen;) - static void copy_verification_constraints_from_preimage(InstanceKlass* klass); + static void copy_verification_info_from_preimage(InstanceKlass* klass); static void copy_linking_constraints_from_preimage(InstanceKlass* klass); + template + static void iterate_verification_constraint_names(InstanceKlass* k, DumpTimeClassInfo* info, Function func); + public: static bool is_early_klass(InstanceKlass* k); // Was k loaded while JvmtiExport::is_early_phase()==true static bool has_archived_enum_objs(InstanceKlass* ik); @@ -239,6 +252,7 @@ public: Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, bool* skip_assignability_check); + static void add_old_verification_constraint(Thread* current, InstanceKlass* k, Symbol* name); static void check_verification_constraints(InstanceKlass* klass, TRAPS) NOT_CDS_RETURN; static void add_enum_klass_static_field(InstanceKlass* ik, int root_index); @@ -258,7 +272,6 @@ public: static DumpTimeSharedClassTable* dumptime_table() { return _dumptime_table; } static bool should_be_excluded(Klass* k); - static bool check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); static void validate_before_archiving(InstanceKlass* k); static bool is_excluded_class(InstanceKlass* k); static void set_excluded(InstanceKlass* k); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 1afc59d8da1..e0ebb92c7ae 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2839,18 +2839,20 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl DEBUG_ONLY(FieldInfoStream::validate_search_table(_constants, _fieldinfo_stream, _fieldinfo_search_table)); } -// Check if a class or any of its supertypes has a version older than 50. -// CDS will not perform verification of old classes during dump time because -// without changing the old verifier, the verification constraint cannot be -// retrieved during dump time. -// Verification of archived old classes will be performed during run time. bool InstanceKlass::can_be_verified_at_dumptime() const { if (AOTMetaspace::in_aot_cache(this)) { // This is a class that was dumped into the base archive, so we know // it was verified at dump time. return true; } - if (major_version() < 50 /*JAVA_6_VERSION*/) { + + if (CDSConfig::is_preserving_verification_constraints()) { + return true; + } + + if (CDSConfig::is_old_class_for_verifier(this)) { + // The old verifier does not save verification constraints, so at run time + // SystemDictionaryShared::check_verification_constraints() will not work for this class. return false; } if (super() != nullptr && !super()->can_be_verified_at_dumptime()) { diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 4c027e0839a..0463d8d9a81 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -323,9 +323,8 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md static bool is_excluded(Klass* k) { #if INCLUDE_CDS - if (SafepointSynchronize::is_at_safepoint() && - CDSConfig::is_dumping_archive() && - CDSConfig::current_thread_is_vm_or_dumper()) { + if (CDSConfig::is_at_aot_safepoint()) { + // Check for CDS exclusion only at CDS safe point. if (k->is_instance_klass() && !InstanceKlass::cast(k)->is_loaded()) { log_debug(aot, training)("Purged %s from MDO: unloaded class", k->name()->as_C_string()); return true; diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 845dc20c0d0..8f906ae3d37 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -554,7 +554,11 @@ void KlassTrainingData::cleanup(Visitor& visitor) { } visitor.visit(this); if (has_holder()) { - bool is_excluded = !holder()->is_loaded() || SystemDictionaryShared::check_for_exclusion(holder(), nullptr); + bool is_excluded = !holder()->is_loaded(); + if (CDSConfig::is_at_aot_safepoint()) { + // Check for AOT exclusion only at AOT safe point. + is_excluded |= SystemDictionaryShared::should_be_excluded(holder()); + } if (is_excluded) { ResourceMark rm; log_debug(aot, training)("Cleanup KTD %s", name()->as_klass_external_name()); @@ -573,7 +577,8 @@ void MethodTrainingData::cleanup(Visitor& visitor) { } visitor.visit(this); if (has_holder()) { - if (SystemDictionaryShared::check_for_exclusion(holder()->method_holder(), nullptr)) { + if (CDSConfig::is_at_aot_safepoint() && SystemDictionaryShared::should_be_excluded(holder()->method_holder())) { + // Check for AOT exclusion only at AOT safe point. log_debug(aot, training)("Cleanup MTD %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); if (_final_profile != nullptr && _final_profile->method() != _holder) { log_warning(aot, training)("Stale MDO for %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 99c8a56c727..0651c173e7b 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -850,6 +850,13 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, log_debug(class, resolve)("%s %s (verification)", from_name, to); } +#if INCLUDE_CDS + if (CDSConfig::is_preserving_verification_constraints() && from_class->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(from_class); + SystemDictionaryShared::add_old_verification_constraint(THREAD, ik, h_name); + } +#endif + return result; JVM_END diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 0c604205939..e0eafbc416b 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -303,11 +303,11 @@ void mutex_init() { #endif MUTEX_DEFN(DumpTimeTable_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(CDSLambda_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(DumpRegion_lock , PaddedMutex , nosafepoint); + MUTEX_DEFL(DumpRegion_lock , PaddedMutex , DumpTimeTable_lock); MUTEX_DEFN(ClassListFile_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(UnregisteredClassesTable_lock , PaddedMutex , nosafepoint-1); MUTEX_DEFN(LambdaFormInvokers_lock , PaddedMutex , safepoint); - MUTEX_DEFN(ScratchObjects_lock , PaddedMutex , nosafepoint-1); // Holds DumpTimeTable_lock + MUTEX_DEFL(ScratchObjects_lock , PaddedMutex , DumpTimeTable_lock); MUTEX_DEFN(FinalImageRecipes_lock , PaddedMutex , nosafepoint); #endif // INCLUDE_CDS MUTEX_DEFN(Bootclasspath_lock , PaddedMutex , nosafepoint); diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index eeb5110b077..3af6548fe33 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -526,6 +526,7 @@ hotspot_aot_classlinking = \ -runtime/cds/appcds/cacheObject/ArchivedIntegerCacheTest.java \ -runtime/cds/appcds/cacheObject/ArchivedModuleCompareTest.java \ -runtime/cds/appcds/CDSandJFR.java \ + -runtime/cds/appcds/LambdaContainsOldInf.java \ -runtime/cds/appcds/customLoader/CustomClassListDump.java \ -runtime/cds/appcds/customLoader/HelloCustom_JFR.java \ -runtime/cds/appcds/customLoader/OldClassAndInf.java \ @@ -533,14 +534,17 @@ hotspot_aot_classlinking = \ -runtime/cds/appcds/customLoader/ParallelTestSingleFP.java \ -runtime/cds/appcds/customLoader/SameNameInTwoLoadersTest.java \ -runtime/cds/appcds/DumpClassListWithLF.java \ - -runtime/cds/appcds/dynamicArchive/ModulePath.java \ + -runtime/cds/appcds/dynamicArchive/LambdaContainsOldInf.java \ -runtime/cds/appcds/dynamicArchive/LambdaCustomLoader.java \ -runtime/cds/appcds/dynamicArchive/LambdaForOldInfInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/LambdaInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/LambdasInTwoArchives.java \ + -runtime/cds/appcds/dynamicArchive/ModulePath.java \ + -runtime/cds/appcds/dynamicArchive/NestHostOldInf.java \ -runtime/cds/appcds/dynamicArchive/OldClassAndInf.java \ -runtime/cds/appcds/dynamicArchive/OldClassInBaseArchive.java \ -runtime/cds/appcds/dynamicArchive/OldClassVerifierTrouble.java \ + -runtime/cds/appcds/dynamicArchive/RedefineCallerClassTest.java \ -runtime/cds/appcds/HelloExtTest.java \ -runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \ -runtime/cds/appcds/javaldr/GCDuringDump.java \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java index f50a2d1f905..9a9524eb2f1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/ExcludedClasses.java @@ -99,7 +99,6 @@ public class ExcludedClasses { if (runMode == RunMode.ASSEMBLY) { out.shouldNotMatch("aot,resolve.*archived field.*TestApp.Foo => TestApp.Foo.ShouldBeExcluded.f:I"); } else if (runMode == RunMode.PRODUCTION) { - out.shouldContain("check_verification_constraint: TestApp$Foo$Taz: TestApp$Foo$ShouldBeExcludedChild must be subclass of TestApp$Foo$ShouldBeExcluded"); out.shouldContain("jdk.jfr.Event source: jrt:/jdk.jfr"); out.shouldMatch("TestApp[$]Foo[$]ShouldBeExcluded source: .*/app.jar"); out.shouldMatch("TestApp[$]Foo[$]ShouldBeExcludedChild source: .*/app.jar"); @@ -259,14 +258,9 @@ class TestApp { static class Taz { static ShouldBeExcluded m() { - // When verifying this method, we need to check the constraint that - // ShouldBeExcluded must be a supertype of ShouldBeExcludedChild. This information - // is checked by SystemDictionaryShared::check_verification_constraints() when the Taz - // class is linked during the production run. - // - // Because ShouldBeExcluded is excluded from the AOT archive, it must be loaded - // dynamically from app.jar inside SystemDictionaryShared::check_verification_constraints(). - // This must happen after the app class loader has been fully restored from the AOT cache. + // Taz should be excluded from the AOT cache because it has a verification constraint that + // "ShouldBeExcludedChild must be a subtype of ShouldBeExcluded", but ShouldBeExcluded is + // excluded from the AOT cache. return new ShouldBeExcludedChild(); } static void hotSpot4() { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm new file mode 100644 index 00000000000..e0362eb0649 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldA.jasm @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class OldA + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java new file mode 100644 index 00000000000..42161b469bf --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Store old classes linked state in AOT cache as long as their verification constraints are not excluded. + * @bug 8317269 + * @requires vm.cds.supports.aot.class.linking + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build OldClass OldA OldClassWithVerifierConstraints OldClassWithExcludedVerifierConstraints + * @build OldClassSupport + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * AppUsesOldClass MyIntf OldClass OldA NewB MyEvent MyEvent2 + * OldClassWithVerifierConstraints + * OldClassWithExcludedVerifierConstraints + * NewClassWithExcludedVerifierConstraints + * @run driver OldClassSupport + */ + +import jdk.jfr.Event; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class OldClassSupport { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "AppUsesOldClass"; + + public static void main(String[] args) throws Exception { + Tester tester = new Tester(); + tester.run(new String[] {"AOT", "--two-step-training"} ); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xlog:aot+class=debug", + "-Xlog:aot+resolve=trace", + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] {"-Xlog:cds+class=debug", mainClass}; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) { + Class[] included = { + OldClass.class, + OldA.class, + NewB.class, + OldClassWithVerifierConstraints.class, + }; + + Class[] excluded = { + OldClassWithExcludedVerifierConstraints.class, + NewClassWithExcludedVerifierConstraints.class, + }; + + + if (runMode == RunMode.TRAINING) { + shouldInclude(out, false, included); + shouldNotInclude(out, excluded); + shouldSkip(out, excluded); + } else if (runMode == RunMode.ASSEMBLY) { + shouldInclude(out, true, included); + shouldNotInclude(out, excluded); + } + } + } + + static void shouldInclude(OutputAnalyzer out, boolean linked, Class[] classes) { + for (Class c : classes) { + out.shouldMatch("aot,class.* = 0x.* app *" + c.getName() + (linked ? " .*aot-linked" : "")); + } + } + + static void shouldNotInclude(OutputAnalyzer out, Class[] classes) { + for (Class c : classes) { + out.shouldNotMatch("aot,class.* = 0x.* app *" + c.getName()); + } + } + + static void shouldSkip(OutputAnalyzer out, Class[] classes) { + for (Class c : classes) { + out.shouldMatch("Skipping " + c.getName() + ": verification constraint .* is excluded"); + } + } +} + +class AppUsesOldClass { + public static void main(String args[]) { + System.out.println("Old Class Instance: " + new OldClass()); + + System.out.println(get_OldA_from_NewB()); + System.out.println(OldClassWithVerifierConstraints.get_OldA_from_NewB()); + System.out.println(OldClassWithExcludedVerifierConstraints.get_Event_from_MyEvent()); + System.out.println(NewClassWithExcludedVerifierConstraints.get_MyEvent_from_MyEvent2()); + System.out.println(new MyEvent()); + + // OldClassWithExcludedVerifierConstraints should still be excluded even it has been used + // in a lambda expression during the training run. + run((OldClassWithExcludedVerifierConstraints x) -> { + System.out.println(x); + }); + } + + static OldA get_OldA_from_NewB() { + return new NewB(); + } + + static void run(MyIntf intf) { + intf.function(new OldClassWithExcludedVerifierConstraints()); + } +} + +interface MyIntf { + public void function(OldClassWithExcludedVerifierConstraints x); +} + +class NewB extends OldA {} + +class MyEvent extends Event {} +class MyEvent2 extends MyEvent {} + +class NewClassWithExcludedVerifierConstraints { + static MyEvent get_MyEvent_from_MyEvent2() { + return new MyEvent2(); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm new file mode 100644 index 00000000000..0c0556bf122 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithExcludedVerifierConstraints.jasm @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This old class has a verification constraint that "MyEvent must be a subtype of Event". However, +// Event and all of its subtypes are excluded from the AOT cache, so this class must also be excluded. + +super public class OldClassWithExcludedVerifierConstraints + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +static Method get_Event_from_MyEvent:"()Ljdk/jfr/Event;" + stack 2 locals 0 +{ + new class MyEvent; + dup; + invokespecial Method MyEvent."":"()V"; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm new file mode 100644 index 00000000000..946c51050a3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassWithVerifierConstraints.jasm @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This old class as a verification constraint that "NewB must be a subtype of OldA". Since both +// OldA and NewB are not excluded, then this class should be cached in aot-linked state. + +super public class OldClassWithVerifierConstraints + version 49:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +static Method get_OldA_from_NewB:"()LOldA;" + stack 2 locals 0 +{ + new class NewB; + dup; + invokespecial Method NewB."":"()V"; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java new file mode 100644 index 00000000000..050f7d28585 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVerification.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8317269 + * @requires vm.cds + * @requires vm.cds.supports.aot.class.linking + * @summary Test for verification of classes that are aot-linked + * @library /test/jdk/lib/testlibrary + * /test/lib + * /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build GoodOldClass + * BadOldClass BadOldClass2 BadOldClass3 BadOldClass4 + * BadNewClass BadNewClass2 BadNewClass3 BadNewClass4 + * @build AOTClassLinkingVerification + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app1.jar + * AOTClassLinkingVerificationApp + * Unlinked UnlinkedSuper + * BadOldClass + * BadOldClass2 + * BadOldClass3 + * BadOldClass4 + * BadNewClass + * BadNewClass2 + * BadNewClass3 + * BadNewClass4 + * GoodOldClass Vehicle Car + * Util + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app2.jar + * Foo NotFoo + * UnlinkedSub + * @run driver AOTClassLinkingVerification + */ + +import java.io.File; +import java.lang.invoke.MethodHandles; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; + +public class AOTClassLinkingVerification { + static final String app1Jar = ClassFileInstaller.getJarPath("app1.jar"); + static final String app2Jar = ClassFileInstaller.getJarPath("app2.jar"); + static final String wbJar = TestCommon.getTestJar("WhiteBox.jar"); + static final String bootAppendWhiteBox = "-Xbootclasspath/a:" + wbJar; + static final String mainClass = AOTClassLinkingVerificationApp.class.getName(); + + static class Tester extends CDSAppTester { + public Tester(String testName) { + super(testName); + } + + @Override + public String[] vmArgs(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return new String[] { + "-XX:+AOTClassLinking", "-Xlog:cds+class=debug", bootAppendWhiteBox, + }; + } else { + return new String[] { + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", bootAppendWhiteBox, + }; + } + } + + @Override + public String classpath(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return app1Jar; + } else { + return app1Jar + File.pathSeparator + app2Jar; + } + } + + @Override + public String[] appCommandLine(RunMode runMode) { + if (runMode == RunMode.TRAINING || + runMode == RunMode.ASSEMBLY) { + return new String[] { + "AOTClassLinkingVerificationApp", app1Jar, "ASSEMBLY" + }; + } else { + return new String[] { + "AOTClassLinkingVerificationApp", app1Jar, "PRODUCTION" + }; + } + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.TRAINING) { + out.shouldContain("Preload Warning: Verification failed for BadNewClass"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass2"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass3"); + out.shouldContain("Preload Warning: Verification failed for BadNewClass4"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass2"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass3"); + out.shouldContain("Preload Warning: Verification failed for BadOldClass4"); + out.shouldContain("Preload Warning: Verification failed for Unlinked"); + } + } + } + + public static void main(String[] args) throws Exception { + // Dump without app2.jar so: + // - Unlinked can be resolved, but UnlinkedSuper UnlinkedSub cannot be resolved, + // so Unlinked cannot be verified at dump time. + // - BadOldClass2 can be resolved, but Foo and NotFoo cannot be resolved, + // so BadOldClass2 cannot be verified at dump time. + // - BadNewClass2 can be resolved, but Foo and NotFoo cannot be resolved, + // so BadNewClass2 cannot be verified at dump time. + Tester t1 = new Tester("verification-aot-linked-classes"); + t1.run("AOT"); + } +} + +class AOTClassLinkingVerificationApp { + static WhiteBox wb = WhiteBox.getWhiteBox(); + static ClassLoader classLoader = AOTClassLinkingVerificationApp.class.getClassLoader(); + static File app1Jar; + static boolean isProduction; + public static void main(String[] args) throws Exception { + app1Jar = new File(args[0]); + isProduction = args[1].equals("PRODUCTION"); + if (isProduction) { + assertNotShared(UnlinkedSub.class); + assertShared(UnlinkedSuper.class); + assertNotShared(Unlinked.class); // failed verification during dump time + assertNotShared(Foo.class); + assertNotShared(NotFoo.class); + } + String s = null; + try { + s = Unlinked.doit(); + } catch (NoClassDefFoundError ncdfe) { + // UnlinkedSub is in app2Jar but only app1Jar is used during training + // and assembly phases. So NoClassDefFoundError is expected during + // during training and assembly phases. + if (isProduction) { + throw ncdfe; + } + } + if (isProduction && !s.equals("heyhey")) { + throw new RuntimeException("Unlinked.doit() returns wrong result: " + s); + } + + // =============================================================================== + + checkSimpleBadClass("BadOldClass"); + + Class cls_BadOldClass2 = Class.forName("BadOldClass2", false, classLoader); + if (isProduction) { + assertNotShared(cls_BadOldClass2); // failed verification during dump time + } + try { + cls_BadOldClass2.newInstance(); + throw new RuntimeException("BadOldClass2 cannot be verified"); + } catch (NoClassDefFoundError ncdfe) { + // BadOldClass2 loads Foo and NotFoo which is in app2Jar which is used + // only in production run. + if (isProduction) { + throw ncdfe; + } + } catch (VerifyError expected) {} + + checkSimpleBadClass("BadOldClass3"); + checkSimpleBadClass("BadOldClass4"); + + // =============================================================================== + + checkSimpleBadClass("BadNewClass"); + + Class cls_BadNewClass2 = Class.forName("BadNewClass2", false, classLoader); + if (isProduction) { + assertNotShared(cls_BadNewClass2); // failed verification during dump time + } + try { + cls_BadNewClass2.newInstance(); + throw new RuntimeException("BadNewClass2 cannot be verified"); + } catch (NoClassDefFoundError ncdfe) { + // BadNewClass2 loads Foo and NotFoo which is in app2Jar which is used + // only in production run. + if (isProduction) { + throw ncdfe; + } + } catch (VerifyError expected) {} + + checkSimpleBadClass("BadNewClass3"); + checkSimpleBadClass("BadNewClass4"); + + // =============================================================================== + + if (isProduction) { + assertAlreadyLoaded("Vehicle"); + assertAlreadyLoaded("Car"); + assertAlreadyLoaded("GoodOldClass"); + + assertShared(GoodOldClass.class); + assertShared(Vehicle.class); + assertShared(Car.class); + } + + GoodOldClass.doit(); // Should not fail + } + + static void checkSimpleBadClass(String className) throws Exception { + Class cls = Class.forName(className, false, classLoader); + if (isProduction) { + assertNotShared(cls); // failed verification during dump time + } + try { + cls.newInstance(); + throw new RuntimeException(className + " should not pass verification"); + } catch (VerifyError expected) {} + } + + static void assertShared(Class c) { + if (!wb.isSharedClass(c)) { + throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be true"); + } + } + + static void assertNotShared(Class c) { + if (wb.isSharedClass(c)) { + throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be false"); + } + } + + static void assertAlreadyLoaded(String className) throws Exception { + byte[] data = Util.getClassFileFromJar(app1Jar, className); + try { + MethodHandles.lookup().defineClass(data); + } catch (LinkageError e) { + if (e.getMessage().contains("duplicate class definition for " + className)) { + return; + } else { + throw e; + } + } + throw new RuntimeException(className + " must have already been loaded"); + } +} + + +class Unlinked { + static String doit() { + UnlinkedSuper sup = new UnlinkedSub(); + return sup.doit(); + } +} + +abstract class UnlinkedSuper { + abstract String doit(); +} + +class UnlinkedSub extends UnlinkedSuper { + String doit() { + return "heyhey"; + } +} + +class Foo {} +class NotFoo {} + +class Vehicle {} +class Car extends Vehicle {} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm new file mode 100644 index 00000000000..cf71d209819 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadNewClass + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return an Object as a String. + * Verifier should fail. + */ +public Method doit:"()Ljava/lang/String;" + stack 2 locals 1 +{ + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_0; + aload_0; + areturn; // tries to return an Object as a String +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm new file mode 100644 index 00000000000..c243d583484 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass2.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadNewClass2 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a NotFoo as a Foo. + * Verifier should fail. + */ +public Method doit:"()LFoo;" + stack 2 locals 1 +{ + new class NotFoo; + dup; + invokespecial Method NotFoo."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a NotFoo as a Foo +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm new file mode 100644 index 00000000000..afce8f76ed8 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass3.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadNewClass3 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[]. + * Verifier should fail. + * + * Note: the arrays must have different number of dimensions, or else + * the new verifier will just check the "bottom" classes. I.e., String and Integer + */ +public Method doit:"()[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm new file mode 100644 index 00000000000..afebe3f1f8e --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadNewClass4.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadNewClass4 + version 52:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[][]. + * Verifier should fail. + * + * Note: the new verifier looks up the Integer and String types, + * not the array types. + */ +public Method doit:"()[[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm new file mode 100644 index 00000000000..adc6a50d4ba --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadOldClass + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return an Object as a String. + * Verifier should fail. + */ +public Method doit:"()Ljava/lang/String;" + stack 2 locals 1 +{ + new class java/lang/Object; + dup; + invokespecial Method java/lang/Object."":"()V"; + astore_0; + aload_0; + areturn; // tries to return an Object as a String +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm new file mode 100644 index 00000000000..1808a019ace --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass2.jasm @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadOldClass2 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a NotFoo as a Foo. + * Verifier should fail. + */ +public Method doit:"()LFoo;" + stack 2 locals 1 +{ + new class NotFoo; + dup; + invokespecial Method NotFoo."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a NotFoo as a Foo +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm new file mode 100644 index 00000000000..6e943cf5afc --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass3.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadOldClass3 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[]. + * Verifier should fail. + * + * Note: the arrays have different number of dimensions. The old verifier + * rejects this immediately without looking up the String/Integer types. + */ +public Method doit:"()[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm new file mode 100644 index 00000000000..56f2a8d299a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BadOldClass4.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class BadOldClass4 + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + /* + * The following method tries to return a String[][] as an Integer[][]. + * Verifier should fail. + * + * Note: the old verifier looks up the Integer and String types, + * not the array types. + */ +public Method doit:"()[[Ljava/lang/Integer;" + stack 2 locals 1 +{ + iconst_1; + iconst_1; + multianewarray class "[[Ljava/lang/String;", 2; + areturn; +} + +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index 0f7707edae3..e1f5f548593 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -147,7 +147,7 @@ public class BulkLoaderTest { @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { if (isAOTWorkflow() && runMode == RunMode.TRAINING) { - out.shouldContain("Skipping BadOldClassA: Unlinked class not supported by AOTConfiguration"); + out.shouldContain("Skipping BadOldClassA: Failed verification"); out.shouldContain("Skipping SimpleCusty: Duplicated unregistered class"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm new file mode 100644 index 00000000000..92a79380d93 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/GoodOldClass.jasm @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +super public class GoodOldClass + version 49:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + +public static Method doit:"()LVehicle;" + stack 2 locals 1 +{ + new class Car; + dup; + invokespecial Method Car."":"()V"; + astore_0; + aload_0; + areturn; // tries to return a Car as a Vehicle +} + +} From 85996572b61e789d7e45bd26b23d233a0a41e158 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 10 Sep 2025 21:23:45 +0000 Subject: [PATCH 460/471] 8365676: javac incorrectly allows calling interface static method via type variable Co-authored-by: Maurizio Cimadamore Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 16 ++++++++++++--- .../generics/typevars/8365676/T8365676.java | 20 +++++++++++++++++++ .../generics/typevars/8365676/T8365676.out | 4 ++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/generics/typevars/8365676/T8365676.java create mode 100644 test/langtools/tools/javac/generics/typevars/8365676/T8365676.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 9f32e7f6186..f780df025bd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4569,9 +4569,19 @@ public class Attr extends JCTree.Visitor { log.error(pos, Errors.TypeVarCantBeDeref); return syms.errSymbol; } else { - Symbol sym2 = (sym.flags() & Flags.PRIVATE) != 0 ? - rs.new AccessError(env, site, sym) : - sym; + // JLS 4.9 specifies the members are derived by inheritance. + // We skip inducing a whole class by filtering members that + // can never be inherited: + Symbol sym2; + if (sym.isPrivate()) { + // Private members + sym2 = rs.new AccessError(env, site, sym); + } else if (sym.owner.isInterface() && sym.kind == MTH && (sym.flags() & STATIC) != 0) { + // Interface static methods + sym2 = rs.new SymbolNotFoundError(ABSENT_MTH); + } else { + sym2 = sym; + } rs.accessBase(sym2, pos, location, site, name, true); return sym; } diff --git a/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java new file mode 100644 index 00000000000..f6b992cb47b --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.java @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8365676 + * @summary Interface static methods should not be inherited by type variables + * @compile/fail/ref=T8365676.out -XDrawDiagnostics T8365676.java + */ + +import java.text.Collator; +import java.util.Comparator; + +class T8365676 { + // T and P should have equivalent members + , P extends Object & Comparator> + void test() { + Comparator.reverseOrder(); + Collator.reverseOrder(); // Fails + P.reverseOrder(); // Fails + T.reverseOrder(); // Should fail + } +} diff --git a/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out new file mode 100644 index 00000000000..214b1640d4a --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/8365676/T8365676.out @@ -0,0 +1,4 @@ +T8365676.java:16:17: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.class, java.text.Collator, null) +T8365676.java:17:10: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.type.variable.bound, java.lang.Object&java.util.Comparator, null) +T8365676.java:18:10: compiler.err.cant.resolve.location.args: kindname.method, reverseOrder, , , (compiler.misc.location: kindname.type.variable.bound, T, null) +3 errors From 7fcce27096605a27ca3b74349d1012bb0bd5963d Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 10 Sep 2025 22:12:04 +0000 Subject: [PATCH 461/471] 8365956: GenShen: Adaptive tenuring threshold algorithm may raise threshold prematurely Reviewed-by: kdnilsen, phh --- .../shenandoahGenerationalHeuristics.cpp | 16 +- .../heuristics/shenandoahGlobalHeuristics.cpp | 7 +- .../heuristics/shenandoahYoungHeuristics.cpp | 34 ++-- .../gc/shenandoah/shenandoahAgeCensus.cpp | 96 +++++++---- .../gc/shenandoah/shenandoahAgeCensus.hpp | 30 +++- .../gc/shenandoah/shenandoahCollectionSet.cpp | 3 +- .../gc/shenandoah/shenandoahGeneration.cpp | 8 +- .../shenandoahGenerationalEvacuationTask.cpp | 12 +- .../shenandoahGenerationalEvacuationTask.hpp | 1 - .../shenandoahGenerationalFullGC.cpp | 5 +- .../shenandoahGenerationalFullGC.hpp | 1 - .../shenandoah/shenandoahGenerationalHeap.cpp | 2 +- .../shenandoah/shenandoahGenerationalHeap.hpp | 1 + .../shenandoahGenerationalHeap.inline.hpp | 37 ++++ .../shenandoah/test_shenandoahAgeCensus.cpp | 159 ++++++++++++++++++ 15 files changed, 318 insertions(+), 94 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp create mode 100644 test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 08fd4599346..dfae9040242 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -28,7 +28,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahEvacInfo.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahTrace.hpp" @@ -65,8 +65,6 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio size_t free = 0; size_t free_regions = 0; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); - // This counts number of humongous regions that we intend to promote in this cycle. size_t humongous_regions_promoted = 0; // This counts number of regular regions that will be promoted in place. @@ -98,12 +96,12 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio bool is_candidate; // This is our candidate for later consideration. if (collection_set->is_preselected(i)) { - assert(region->age() >= tenuring_threshold, "Preselection filter"); + assert(heap->is_tenurable(region), "Preselection filter"); is_candidate = true; preselected_candidates++; // Set garbage value to maximum value to force this into the sorted collection set. garbage = region_size_bytes; - } else if (region->is_young() && (region->age() >= tenuring_threshold)) { + } else if (region->is_young() && heap->is_tenurable(region)) { // Note that for GLOBAL GC, region may be OLD, and OLD regions do not qualify for pre-selection // This region is old enough to be promoted but it was not preselected, either because its garbage is below @@ -142,7 +140,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio immediate_regions++; immediate_garbage += garbage; } else { - if (region->is_young() && region->age() >= tenuring_threshold) { + if (region->is_young() && heap->is_tenurable(region)) { oop obj = cast_to_oop(region->bottom()); size_t humongous_regions = ShenandoahHeapRegion::required_regions(obj->size() * HeapWordSize); humongous_regions_promoted += humongous_regions; @@ -246,10 +244,6 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio size_t ShenandoahGenerationalHeuristics::add_preselected_regions_to_collection_set(ShenandoahCollectionSet* cset, const RegionData* data, size_t size) const { -#ifdef ASSERT - const uint tenuring_threshold = ShenandoahGenerationalHeap::heap()->age_census()->tenuring_threshold(); -#endif - // cur_young_garbage represents the amount of memory to be reclaimed from young-gen. In the case that live objects // are known to be promoted out of young-gen, we count this as cur_young_garbage because this memory is reclaimed // from young-gen and becomes available to serve future young-gen allocation requests. @@ -257,7 +251,7 @@ size_t ShenandoahGenerationalHeuristics::add_preselected_regions_to_collection_s for (size_t idx = 0; idx < size; idx++) { ShenandoahHeapRegion* r = data[idx].get_region(); if (cset->is_preselected(r->index())) { - assert(r->age() >= tenuring_threshold, "Preselected regions must have tenure age"); + assert(ShenandoahGenerationalHeap::heap()->is_tenurable(r), "Preselected regions must have tenure age"); // Entire region will be promoted, This region does not impact young-gen or old-gen evacuation reserve. // This region has been pre-selected and its impact on promotion reserve is already accounted for. diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index 4e12b1d41e8..331bd040575 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -25,7 +25,7 @@ #include "gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahGlobalGeneration.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "utilities/quickSort.hpp" @@ -56,7 +56,6 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti size_t capacity = heap->soft_max_capacity(); size_t garbage_threshold = region_size_bytes * ShenandoahGarbageThreshold / 100; size_t ignore_threshold = region_size_bytes * ShenandoahIgnoreGarbageThreshold / 100; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); size_t young_evac_reserve = heap->young_generation()->get_evacuation_reserve(); size_t old_evac_reserve = heap->old_generation()->get_evacuation_reserve(); @@ -100,7 +99,7 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti ShenandoahHeapRegion* r = data[idx].get_region(); assert(!cset->is_preselected(r->index()), "There should be no preselected regions during GLOBAL GC"); bool add_region = false; - if (r->is_old() || (r->age() >= tenuring_threshold)) { + if (r->is_old() || heap->is_tenurable(r)) { size_t new_cset = old_cur_cset + r->get_live_data_bytes(); if ((r->garbage() > garbage_threshold)) { while ((new_cset > max_old_cset) && (unaffiliated_young_regions > 0)) { @@ -114,7 +113,7 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti old_cur_cset = new_cset; } } else { - assert(r->is_young() && (r->age() < tenuring_threshold), "DeMorgan's law (assuming r->is_affiliated)"); + assert(r->is_young() && !heap->is_tenurable(r), "DeMorgan's law (assuming r->is_affiliated)"); size_t new_cset = young_cur_cset + r->get_live_data_bytes(); size_t region_garbage = r->garbage(); size_t new_garbage = cur_young_garbage + region_garbage; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index fbb165858dc..d236be8c9e6 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -26,7 +26,7 @@ #include "gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahYoungGeneration.hpp" @@ -64,19 +64,18 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection size_t size, size_t actual_free, size_t cur_young_garbage) const { - auto heap = ShenandoahGenerationalHeap::heap(); + const auto heap = ShenandoahGenerationalHeap::heap(); - size_t capacity = heap->soft_max_capacity(); - size_t garbage_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; - size_t ignore_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahIgnoreGarbageThreshold / 100; - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); + const size_t capacity = heap->soft_max_capacity(); + const size_t garbage_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahGarbageThreshold / 100; + const size_t ignore_threshold = ShenandoahHeapRegion::region_size_bytes() * ShenandoahIgnoreGarbageThreshold / 100; // This is young-gen collection or a mixed evacuation. // If this is mixed evacuation, the old-gen candidate regions have already been added. - size_t max_cset = (size_t) (heap->young_generation()->get_evacuation_reserve() / ShenandoahEvacWaste); size_t cur_cset = 0; - size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_cset; - size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; + const size_t max_cset = (size_t) (heap->young_generation()->get_evacuation_reserve() / ShenandoahEvacWaste); + const size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + max_cset; + const size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; log_info(gc, ergo)( @@ -89,11 +88,15 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection if (cset->is_preselected(r->index())) { continue; } - if (r->age() < tenuring_threshold) { - size_t new_cset = cur_cset + r->get_live_data_bytes(); - size_t region_garbage = r->garbage(); - size_t new_garbage = cur_young_garbage + region_garbage; - bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); + + // Note that we do not add tenurable regions if they were not pre-selected. They were not preselected + // because there is insufficient room in old-gen to hold their to-be-promoted live objects or because + // they are to be promoted in place. + if (!heap->is_tenurable(r)) { + const size_t new_cset = cur_cset + r->get_live_data_bytes(); + const size_t region_garbage = r->garbage(); + const size_t new_garbage = cur_young_garbage + region_garbage; + const bool add_regardless = (region_garbage > ignore_threshold) && (new_garbage < min_garbage); assert(r->is_young(), "Only young candidates expected in the data array"); if ((new_cset <= max_cset) && (add_regardless || (region_garbage > garbage_threshold))) { cur_cset = new_cset; @@ -101,9 +104,6 @@ void ShenandoahYoungHeuristics::choose_young_collection_set(ShenandoahCollection cset->add_region(r); } } - // Note that we do not add aged regions if they were not pre-selected. The reason they were not preselected - // is because there is not sufficient room in old-gen to hold their to-be-promoted live objects or because - // they are to be promoted in place. } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 94c98b78f1b..bd66f55bd8f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -27,8 +27,15 @@ #include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" -ShenandoahAgeCensus::ShenandoahAgeCensus() { +ShenandoahAgeCensus::ShenandoahAgeCensus() + : ShenandoahAgeCensus(ShenandoahHeap::heap()->max_workers()) +{ assert(ShenandoahHeap::heap()->mode()->is_generational(), "Only in generational mode"); +} + +ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) + : _max_workers(max_workers) +{ if (ShenandoahGenerationalMinTenuringAge > ShenandoahGenerationalMaxTenuringAge) { vm_exit_during_initialization( err_msg("ShenandoahGenerationalMinTenuringAge=%zu" @@ -39,6 +46,9 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _global_age_table = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_global_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, MAX_SNAPSHOTS, mtGC);) _tenuring_threshold = NEW_C_HEAP_ARRAY(uint, MAX_SNAPSHOTS, mtGC); + CENSUS_NOISE(_skipped = 0); + NOT_PRODUCT(_counted = 0); + NOT_PRODUCT(_total = 0); for (int i = 0; i < MAX_SNAPSHOTS; i++) { // Note that we don't now get perfdata from age_table @@ -48,10 +58,9 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _tenuring_threshold[i] = MAX_COHORTS; } if (ShenandoahGenerationalAdaptiveTenuring && !ShenandoahGenerationalCensusAtEvac) { - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, max_workers, mtGC); + _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { _local_age_table[i] = new AgeTable(false); CENSUS_NOISE(_local_noise[i].clear();) } @@ -61,6 +70,22 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() { _epoch = MAX_SNAPSHOTS - 1; // see update_epoch() } +ShenandoahAgeCensus::~ShenandoahAgeCensus() { + for (uint i = 0; i < MAX_SNAPSHOTS; i++) { + delete _global_age_table[i]; + } + FREE_C_HEAP_ARRAY(AgeTable*, _global_age_table); + FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); + if (_local_age_table) { + for (uint i = 0; i < _max_workers; i++) { + delete _local_age_table[i]; + } + FREE_C_HEAP_ARRAY(AgeTable*, _local_age_table); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); + } +} + CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id) {) NO_CENSUS_NOISE(void ShenandoahAgeCensus::add(uint obj_age, uint region_age, size_t size, uint worker_id) {) if (obj_age <= markWord::max_age) { @@ -131,12 +156,11 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable assert(pv1 == nullptr && pv2 == nullptr, "Error, check caller"); // Seed cohort 0 with population that may have been missed during // regular census. - _global_age_table[_epoch]->add((uint)0, age0_pop); + _global_age_table[_epoch]->add(0u, age0_pop); - size_t max_workers = ShenandoahHeap::heap()->max_workers(); // Merge data from local age tables into the global age table for the epoch, // clearing the local tables. - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { // age stats _global_age_table[_epoch]->merge(_local_age_table[i]); _local_age_table[i]->clear(); // clear for next census @@ -177,8 +201,7 @@ void ShenandoahAgeCensus::reset_local() { assert(_local_age_table == nullptr, "Error"); return; } - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { _local_age_table[i]->clear(); CENSUS_NOISE(_local_noise[i].clear();) } @@ -204,8 +227,7 @@ bool ShenandoahAgeCensus::is_clear_local() { assert(_local_age_table == nullptr, "Error"); return true; } - size_t max_workers = ShenandoahHeap::heap()->max_workers(); - for (uint i = 0; i < max_workers; i++) { + for (uint i = 0; i < _max_workers; i++) { bool clear = _local_age_table[i]->is_clear(); CENSUS_NOISE(clear |= _local_noise[i].is_clear();) if (!clear) { @@ -246,7 +268,7 @@ void ShenandoahAgeCensus::update_tenuring_threshold() { _tenuring_threshold[_epoch] = tt; } print(); - log_trace(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", + log_info(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", (uintx) _tenuring_threshold[_epoch], ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge); } @@ -279,13 +301,14 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { uint upper_bound = ShenandoahGenerationalMaxTenuringAge; const uint prev_tt = previous_tenuring_threshold(); if (ShenandoahGenerationalCensusIgnoreOlderCohorts && prev_tt > 0) { - // We stay below the computed tenuring threshold for the last cycle plus 1, - // ignoring the mortality rates of any older cohorts. - upper_bound = MIN2(upper_bound, prev_tt + 1); + // We stay below the computed tenuring threshold for the last cycle, + // ignoring the mortality rates of any older cohorts (which may see + // higher mortality rates due to promotions). + upper_bound = MIN2(upper_bound, prev_tt); } upper_bound = MIN2(upper_bound, markWord::max_age); - const uint lower_bound = MAX2((uint)ShenandoahGenerationalMinTenuringAge, (uint)1); + const uint lower_bound = MAX2((uint)ShenandoahGenerationalMinTenuringAge, 1u); uint tenuring_threshold = upper_bound; for (uint i = upper_bound; i >= lower_bound; i--) { @@ -303,9 +326,9 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { // cohorts are considered eligible for tenuring when all older // cohorts are. We return the next higher age as the tenuring threshold // so that we do not prematurely promote objects of this age. - assert(tenuring_threshold == i+1 || tenuring_threshold == upper_bound, "Error"); + assert(tenuring_threshold == i + 1 || tenuring_threshold == upper_bound, "Error"); assert(tenuring_threshold >= lower_bound && tenuring_threshold <= upper_bound, "Error"); - return tenuring_threshold; + return i + 1; } // Remember that we passed over this cohort, looking for younger cohorts // showing high mortality. We want to tenure cohorts of this age. @@ -335,6 +358,14 @@ double ShenandoahAgeCensus::mortality_rate(size_t prev_pop, size_t cur_pop) { } void ShenandoahAgeCensus::print() { + + const LogTarget(Debug, gc, age) lt; + if (!lt.is_enabled()) { + return; + } + + LogStream ls(lt); + // Print the population vector for the current epoch, and // for the previous epoch, as well as the computed mortality // ratio for each extant cohort. @@ -350,33 +381,32 @@ void ShenandoahAgeCensus::print() { for (uint i = 1; i < MAX_COHORTS; i++) { const size_t prev_pop = prev_pv->sizes[i-1]; // (i-1) OK because i >= 1 const size_t cur_pop = cur_pv->sizes[i]; - double mr = mortality_rate(prev_pop, cur_pop); + const double mr = mortality_rate(prev_pop, cur_pop); // Suppress printing when everything is zero if (prev_pop + cur_pop > 0) { - log_info(gc, age) - (" - age %3u: prev %10zu bytes, curr %10zu bytes, mortality %.2f ", - i, prev_pop*oopSize, cur_pop*oopSize, mr); + ls.print_cr(" - age %3u: prev %10zu bytes, curr %10zu bytes, mortality %.2f ", + i, prev_pop * oopSize, cur_pop * oopSize, mr); } total += cur_pop; if (i == tt) { // Underline the cohort for tenuring threshold (if < MAX_COHORTS) - log_info(gc, age)("----------------------------------------------------------------------------"); + ls.print_cr("----------------------------------------------------------------------------"); } } - CENSUS_NOISE(_global_noise[cur_epoch].print(total);) + CENSUS_NOISE(_global_noise[cur_epoch].print(ls, total);) } #ifdef SHENANDOAH_CENSUS_NOISE -void ShenandoahNoiseStats::print(size_t total) { +void ShenandoahNoiseStats::print(LogStream& ls, const size_t total) { if (total > 0) { - float f_skipped = (float)skipped/(float)total; - float f_aged = (float)aged/(float)total; - float f_clamped = (float)clamped/(float)total; - float f_young = (float)young/(float)total; - log_info(gc, age)("Skipped: %10zu (%.2f), R-Aged: %10zu (%.2f), " - "Clamped: %10zu (%.2f), R-Young: %10zu (%.2f)", - skipped*oopSize, f_skipped, aged*oopSize, f_aged, - clamped*oopSize, f_clamped, young*oopSize, f_young); + const float f_skipped = (float)skipped/(float)total; + const float f_aged = (float)aged/(float)total; + const float f_clamped = (float)clamped/(float)total; + const float f_young = (float)young/(float)total; + ls.print_cr("Skipped: %10zu (%.2f), R-Aged: %10zu (%.2f), " + "Clamped: %10zu (%.2f), R-Young: %10zu (%.2f)", + skipped*oopSize, f_skipped, aged*oopSize, f_aged, + clamped*oopSize, f_clamped, young*oopSize, f_young); } } #endif // SHENANDOAH_CENSUS_NOISE diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 89c68f7120b..90d188e1fca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -37,6 +37,8 @@ #define CENSUS_NOISE(x) x #define NO_CENSUS_NOISE(x) +class LogStream; + struct ShenandoahNoiseStats { size_t skipped; // Volume of objects skipped size_t aged; // Volume of objects from aged regions @@ -67,7 +69,7 @@ struct ShenandoahNoiseStats { young += other.young; } - void print(size_t total); + void print(LogStream& ls, size_t total); }; #else // SHENANDOAH_CENSUS_NOISE #define CENSUS_NOISE(x) @@ -91,7 +93,7 @@ struct ShenandoahNoiseStats { // // In addition, this class also maintains per worker population vectors into which // census for the current minor GC is accumulated (during marking or, optionally, during -// evacuation). These are cleared after each marking (resectively, evacuation) cycle, +// evacuation). These are cleared after each marking (respectively, evacuation) cycle, // once the per-worker data is consolidated into the appropriate population vector // per minor collection. The _local_age_table is thus C x N, for N GC workers. class ShenandoahAgeCensus: public CHeapObj { @@ -111,10 +113,12 @@ class ShenandoahAgeCensus: public CHeapObj { size_t _total; // net size of objects encountered (counted or skipped) in census #endif - uint _epoch; // Current epoch (modulo max age) - uint *_tenuring_threshold; // An array of the last N tenuring threshold values we + uint _epoch; // Current epoch (modulo max age) + uint* _tenuring_threshold; // An array of the last N tenuring threshold values we // computed. + uint _max_workers; // Maximum number of workers for parallel tasks + // Mortality rate of a cohort, given its population in // previous and current epochs double mortality_rate(size_t prev_pop, size_t cur_pop); @@ -165,11 +169,22 @@ class ShenandoahAgeCensus: public CHeapObj { }; ShenandoahAgeCensus(); + ShenandoahAgeCensus(uint max_workers); + ~ShenandoahAgeCensus(); // Return the local age table (population vector) for worker_id. // Only used in the case of (ShenandoahGenerationalAdaptiveTenuring && !ShenandoahGenerationalCensusAtEvac) - AgeTable* get_local_age_table(uint worker_id) { - return (AgeTable*) _local_age_table[worker_id]; + AgeTable* get_local_age_table(uint worker_id) const { + return _local_age_table[worker_id]; + } + + // Return the most recently computed tenuring threshold. + // Visible for testing. Use is_tenurable for consistent tenuring comparisons. + uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } + + // Return true if this age is at or above the tenuring threshold. + bool is_tenurable(uint age) const { + return age >= tenuring_threshold(); } // Update the local age table for worker_id by size for @@ -201,9 +216,6 @@ class ShenandoahAgeCensus: public CHeapObj { // is 0, because the evacuated objects have all had their ages incremented. void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr); - // Return the most recently computed tenuring threshold - uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } - // Reset the epoch, clearing accumulated census history // Note: this isn't currently used, but reserved for planned // future usage. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp index 25b900f8d77..35faa40af77 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp @@ -27,6 +27,7 @@ #include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" @@ -98,7 +99,7 @@ void ShenandoahCollectionSet::add_region(ShenandoahHeapRegion* r) { if (r->is_young()) { _young_bytes_to_evacuate += live; _young_available_bytes_collected += free; - if (ShenandoahHeap::heap()->mode()->is_generational() && r->age() >= ShenandoahGenerationalHeap::heap()->age_census()->tenuring_threshold()) { + if (ShenandoahHeap::heap()->mode()->is_generational() && ShenandoahGenerationalHeap::heap()->is_tenurable(r)) { _young_bytes_to_promote += live; } } else if (r->is_old()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index f686334d3d5..7b3839dc198 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -28,9 +28,8 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionClosures.hpp" -#include "gc/shenandoah/shenandoahMonitoringSupport.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" @@ -534,7 +533,6 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); - const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); const size_t old_garbage_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahOldGarbageThreshold) / 100; size_t old_consumed = 0; @@ -558,7 +556,7 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { // skip over regions that aren't regular young with some live data continue; } - if (r->age() >= tenuring_threshold) { + if (heap->is_tenurable(r)) { if ((r->garbage() < old_garbage_threshold)) { // This tenure-worthy region has too little garbage, so we do not want to expend the copying effort to // reclaim the garbage; instead this region may be eligible for promotion-in-place to the @@ -613,7 +611,7 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) { // these regions. The likely outcome is that these regions will not be selected for evacuation or promotion // in the current cycle and we will anticipate that they will be promoted in the next cycle. This will cause // us to reserve more old-gen memory so that these objects can be promoted in the subsequent cycle. - if (heap->is_aging_cycle() && (r->age() + 1 == tenuring_threshold)) { + if (heap->is_aging_cycle() && heap->age_census()->is_tenurable(r->age() + 1)) { if (r->garbage() >= old_garbage_threshold) { promo_potential += r->get_live_data_bytes(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 29fd3258b6c..3a0d7926865 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -26,7 +26,7 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp" -#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahGenerationalHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahScanRemembered.inline.hpp" @@ -56,11 +56,9 @@ ShenandoahGenerationalEvacuationTask::ShenandoahGenerationalEvacuationTask(Shena _heap(heap), _regions(iterator), _concurrent(concurrent), - _only_promote_regions(only_promote_regions), - _tenuring_threshold(0) + _only_promote_regions(only_promote_regions) { shenandoah_assert_generational(); - _tenuring_threshold = _heap->age_census()->tenuring_threshold(); } void ShenandoahGenerationalEvacuationTask::work(uint worker_id) { @@ -138,7 +136,7 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() { void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRegion* r) { - if (r->is_young() && r->is_active() && (r->age() >= _tenuring_threshold)) { + if (r->is_young() && r->is_active() && _heap->is_tenurable(r)) { if (r->is_humongous_start()) { // We promote humongous_start regions along with their affiliated continuations during evacuation rather than // doing this work during a safepoint. We cannot put humongous regions into the collection set because that @@ -176,7 +174,7 @@ void ShenandoahGenerationalEvacuationTask::promote_in_place(ShenandoahHeapRegion assert(region->garbage_before_padded_for_promote() < old_garbage_threshold, "Region %zu has too much garbage for promotion", region->index()); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_regular(), "Use different service to promote humongous regions"); - assert(region->age() >= _tenuring_threshold, "Only promote regions that are sufficiently aged"); + assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); assert(region->get_top_before_promote() == tams, "Region %zu has been used for allocations before promotion", region->index()); } @@ -259,7 +257,7 @@ void ShenandoahGenerationalEvacuationTask::promote_humongous(ShenandoahHeapRegio shenandoah_assert_generations_reconciled(); assert(region->is_young(), "Only young regions can be promoted"); assert(region->is_humongous_start(), "Should not promote humongous continuation in isolation"); - assert(region->age() >= _tenuring_threshold, "Only promote regions that are sufficiently aged"); + assert(_heap->is_tenurable(region), "Only promote regions that are sufficiently aged"); assert(marking_context->is_marked(obj), "promoted humongous object should be alive"); const size_t used_bytes = obj->size() * HeapWordSize; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp index abe2fc0110c..0c402d6c90a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.hpp @@ -39,7 +39,6 @@ private: ShenandoahRegionIterator* _regions; bool _concurrent; bool _only_promote_regions; - uint _tenuring_threshold; public: ShenandoahGenerationalEvacuationTask(ShenandoahGenerationalHeap* sh, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index e2e3f0a4677..c4a7408e032 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -193,7 +193,6 @@ ShenandoahPrepareForGenerationalCompactionObjectClosure::ShenandoahPrepareForGen ShenandoahHeapRegion* from_region, uint worker_id) : _preserved_marks(preserved_marks), _heap(ShenandoahGenerationalHeap::heap()), - _tenuring_threshold(0), _empty_regions(empty_regions), _empty_regions_pos(0), _old_to_region(nullptr), @@ -212,8 +211,6 @@ ShenandoahPrepareForGenerationalCompactionObjectClosure::ShenandoahPrepareForGen _young_to_region = from_region; _young_compact_point = from_region->bottom(); } - - _tenuring_threshold = _heap->age_census()->tenuring_threshold(); } void ShenandoahPrepareForGenerationalCompactionObjectClosure::set_from_region(ShenandoahHeapRegion* from_region) { @@ -279,7 +276,7 @@ void ShenandoahPrepareForGenerationalCompactionObjectClosure::do_object(oop p) { bool promote_object = false; if ((_from_affiliation == ShenandoahAffiliation::YOUNG_GENERATION) && - (from_region_age + object_age >= _tenuring_threshold)) { + _heap->age_census()->is_tenurable(from_region_age + object_age)) { if ((_old_to_region != nullptr) && (_old_compact_point + obj_size > _old_to_region->end())) { finish_old_region(); _old_to_region = nullptr; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp index 9240a056105..06080286f22 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.hpp @@ -90,7 +90,6 @@ class ShenandoahPrepareForGenerationalCompactionObjectClosure : public ObjectClo private: PreservedMarks* const _preserved_marks; ShenandoahGenerationalHeap* const _heap; - uint _tenuring_threshold; // _empty_regions is a thread-local list of heap regions that have been completely emptied by this worker thread's // compaction efforts. The worker thread that drives these efforts adds compacted regions to this list if the diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index d05ae713645..0aca8f971e3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -216,7 +216,7 @@ oop ShenandoahGenerationalHeap::evacuate_object(oop p, Thread* thread) { if (mark.has_displaced_mark_helper()) { // We don't want to deal with MT here just to ensure we read the right mark word. // Skip the potential promotion attempt for this one. - } else if (r->age() + mark.age() >= age_census()->tenuring_threshold()) { + } else if (age_census()->is_tenurable(r->age() + mark.age())) { oop result = try_evacuate_object(p, thread, r, OLD_GENERATION); if (result != nullptr) { return result; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index f23e49735e9..6960562b31d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -80,6 +80,7 @@ public: return _age_census; } + inline bool is_tenurable(const ShenandoahHeapRegion* r) const; // Ages regions that haven't been used for allocations in the current cycle. // Resets ages for regions that have been used for allocations. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp new file mode 100644 index 00000000000..8289b48185b --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.inline.hpp @@ -0,0 +1,37 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP + +#include "gc/shenandoah/shenandoahGenerationalHeap.hpp" + +#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" + +inline bool ShenandoahGenerationalHeap::is_tenurable(const ShenandoahHeapRegion* r) const { + return _age_census->is_tenurable(r->age()); +} + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALHEAP_INLINE_HPP diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp new file mode 100644 index 00000000000..c53d0a15554 --- /dev/null +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp @@ -0,0 +1,159 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. 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. + * + * 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. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/shenandoah/shenandoahAgeCensus.hpp" +#include "unittest.hpp" + +class ShenandoahAgeCensusTest : public ::testing::Test { +protected: + static constexpr size_t MinimumPopulationSize = 4*K; + static constexpr size_t InitialPopulationSize = MinimumPopulationSize * 1000; + + size_t _cohorts_count = ShenandoahAgeCensus::MAX_COHORTS; + double _mortality_rates[ShenandoahAgeCensus::MAX_COHORTS]; + size_t _cohort_populations[ShenandoahAgeCensus::MAX_COHORTS]; + + ShenandoahAgeCensusTest() + : _mortality_rates{0.9, 0.7, 0.5, 0.3, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} + { + build_cohort_populations(_mortality_rates, _cohort_populations, _cohorts_count); + } + + static void add_population(ShenandoahAgeCensus& census, const uint age, const size_t population_words) { + CENSUS_NOISE(census.add(age, 0, 0, population_words, 0)); + NO_CENSUS_NOISE(census.add(age, 0, population_words, 0)); + } + + void update(ShenandoahAgeCensus& census, size_t cohorts) const { + for (uint i = 1; i < cohorts; i++) { + add_population(census, i, _cohort_populations[i]); + } + census.update_census(_cohort_populations[0]); + } + + void update(ShenandoahAgeCensus& census) const { + update(census, _cohorts_count); + } + + size_t get_total_population_older_than(const size_t min_cohort_age) const { + size_t total = 0; + for (size_t i = 0; i < _cohorts_count; i++) { + if (i >= min_cohort_age) { + total += _cohort_populations[i]; + } + } + return total; + } + + void promote_all_tenurable(const size_t tenuring_threshold) { + for (size_t i = 0; i < _cohorts_count; i++) { + if (i > tenuring_threshold) { + _cohort_populations[i] = 0; + } + } + } + + static void build_cohort_populations(const double mortality_rates[], size_t cohort_populations[], const size_t cohorts) { + cohort_populations[0] = InitialPopulationSize; + for (size_t i = 1; i < cohorts; i++) { + cohort_populations[i] = cohort_populations[i - 1] * (1.0 - mortality_rates[i - 1]); + } + } +}; + +TEST_F(ShenandoahAgeCensusTest, initialize) { + const ShenandoahAgeCensus census(1); + EXPECT_EQ(census.tenuring_threshold(), ShenandoahAgeCensus::MAX_COHORTS); +} + +TEST_F(ShenandoahAgeCensusTest, ignore_small_populations) { + // Small populations are ignored so we do not return early before reaching the youngest cohort. + ShenandoahAgeCensus census(1); + add_population(census,1, 32); + add_population(census,1, 32); + census.update_census(64); + EXPECT_EQ(1u, census.tenuring_threshold()); +} + +TEST_F(ShenandoahAgeCensusTest, find_high_mortality_rate) { + ShenandoahAgeCensus census(1); + + // Initial threshold, no data + EXPECT_EQ(16u, census.tenuring_threshold()); + + // Provide population data for 1st cohort. Previous epoch has no population data so our + // algorithm skips over all cohorts, leaving tenuring threshold at 1. + update(census, 1); + EXPECT_EQ(1u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 1 is 0.9, we don't want to promote here. Move threshold to 2. + update(census, 2); + EXPECT_EQ(2u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 2 is 0.7, we don't want to promote here. Move threshold to 3. + update(census, 3); + EXPECT_EQ(3u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 3 is 0.5, we don't want to promote here. Move threshold to 4. + update(census, 4); + EXPECT_EQ(4u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 4 is 0.3, we don't want to promote here. Move threshold to 5. + update(census, 5); + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Mortality rate of 1st cohort at age 5 is 0.09, this is less than the mortality rate threshold. It + // is okay to tenure objects older than 5 now. Keep threshold at 5. + update(census, 6); + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Mortality rate at this age is 0. Keep tenuring threshold at 5. + update(census, 7); + EXPECT_EQ(5u, census.tenuring_threshold()); +} + +TEST_F(ShenandoahAgeCensusTest, ignore_mortality_caused_by_promotions) { + ShenandoahAgeCensus census(1); + + // Simulate a sequence of censuses with the same mortality rate. Each one will see a + // mortality rate above the tenuring threshold and raise the tenuring threshold by one. + update(census, 1); + update(census, 2); + update(census, 3); + update(census, 4); + update(census, 5); + + EXPECT_EQ(5u, census.tenuring_threshold()); + + // Simulate the effect of promoting all objects above the tenuring threshold + // out of the young generation. This will look like a very high (100%) mortality + // rate for these cohorts. However, we do _not_ want to raise the threshold in + // this case because these objects haven't really "died", they have just been + // tenured. + promote_all_tenurable(census.tenuring_threshold()); + update(census); + + // We want this to stay at 5 - the mortality in 1st cohort at age 6 was caused by expected promotions. + EXPECT_EQ(5u, census.tenuring_threshold()); +} From 134c3ef41e774b483bcce32ce2fe0ef416017728 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 11 Sep 2025 00:05:02 +0000 Subject: [PATCH 462/471] 8367293: RISC-V: enable vectorapi test for VectorMask.laneIsSet Reviewed-by: fyang, epeter --- .../vectorapi/VectorMaskLaneIsSetTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java index b7f2103c56c..17d483f1b16 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java @@ -69,7 +69,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 6" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testVectorMaskLaneIsSetByte_const() { Asserts.assertEquals(ma[0], mask_b.laneIsSet(0)); Asserts.assertEquals(ma[0], mask_s.laneIsSet(0)); @@ -81,7 +81,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Byte_variable(int i) { return mask_b.laneIsSet(i); } @@ -93,7 +93,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Short_variable(int i) { return mask_s.laneIsSet(i); } @@ -105,7 +105,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Int_variable(int i) { return mask_i.laneIsSet(i); } @@ -117,7 +117,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Long_variable(int i) { return mask_l.laneIsSet(i); } @@ -129,7 +129,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Float_variable(int i) { return mask_f.laneIsSet(i); } @@ -141,7 +141,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Double_variable(int i) { return mask_d.laneIsSet(i); } From eb9e04598db7a70347ada005035644012026f902 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 11 Sep 2025 04:59:07 +0000 Subject: [PATCH 463/471] 8361530: Test javax/swing/GraphicsConfigNotifier/StalePreferredSize.java timed out Reviewed-by: psadhukhan --- .../swing/GraphicsConfigNotifier/StalePreferredSize.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java index 371c6fb43ef..3be7d08870d 100644 --- a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java +++ b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 @@ -66,9 +66,8 @@ import static javax.swing.UIManager.getInstalledLookAndFeels; * It is checked by SwingUtilities.updateComponentTreeUI(), if layout * was correct the call to updateComponentTreeUI() will be no-op. * @compile -encoding utf-8 StalePreferredSize.java - * @run main/othervm/timeout=600 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=1 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=2.25 StalePreferredSize + * @run main/othervm/timeout=420 StalePreferredSize + * @run main/othervm/timeout=420 -Dsun.java2d.uiScale=2.25 StalePreferredSize */ public final class StalePreferredSize { @@ -92,7 +91,7 @@ public final class StalePreferredSize { public static void main(final String[] args) throws Exception { for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { EventQueue.invokeAndWait(() -> setLookAndFeel(laf)); - for (typeFont = 0; typeFont < 3; typeFont++) { + for (typeFont = 0; typeFont < 1; typeFont++) { System.err.println("typeFont = " + typeFont); for (boolean usePopup : new boolean[]{true, false}) { addViaPopup = usePopup; From 4cc75be80e6a89e0ed293e2f8bbb6d0f94189468 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:03:21 +0000 Subject: [PATCH 464/471] 8366702: C2 SuperWord: refactor VTransform vector nodes Reviewed-by: chagedorn, galder --- .../share/opto/superwordVTransformBuilder.cpp | 110 +++++---- .../share/opto/superwordVTransformBuilder.hpp | 4 +- src/hotspot/share/opto/vtransform.cpp | 211 +++++++++--------- src/hotspot/share/opto/vtransform.hpp | 139 ++++++++++-- 4 files changed, 286 insertions(+), 178 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index b31f2eda9c0..dbc96c234a9 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -80,11 +80,13 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (p0->is_Store()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); init_req_with_vector(pack, vtn, MemNode::ValueIn); for (uint k = 0; k < pack->size(); k++) { @@ -93,26 +95,27 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } else if (vtn->isa_ReductionVector() != nullptr) { init_req_with_scalar(p0, vtn, 1); // scalar init init_req_with_vector(pack, vtn, 2); // vector - } else { - assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); - if (VectorNode::is_scalar_rotate(p0) && - p0->in(2)->is_Con() && - Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rotation - } else if (VectorNode::is_roundopD(p0)) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rounding mode - } else if (p0->is_CMove()) { - // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. - set_all_req_with_vectors(pack, vtn); - VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(1)->isa_BoolVector(); - if (vtn_mask_cmp->test()._is_negated) { - vtn->swap_req(2, 3); // swap if test was negated. - } - } else { - set_all_req_with_vectors(pack, vtn); + } else if (VectorNode::is_scalar_rotate(p0) && + p0->in(2)->is_Con() && + Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rotation + } else if (VectorNode::is_roundopD(p0)) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rounding mode + } else if (p0->is_CMove()) { + // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. + init_all_req_with_vectors(pack, vtn); + // Inputs must be permuted from (mask, blend1, blend2) -> (blend1, blend2, mask) + vtn->swap_req(1, 2); + vtn->swap_req(2, 3); + // If the test was negated: (blend1, blend2, mask) -> (blend2, blend1, mask) + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(3)->isa_BoolVector(); + if (vtn_mask_cmp->test()._is_negated) { + vtn->swap_req(1, 2); // swap if test was negated. } + } else { + init_all_req_with_vectors(pack, vtn); } } } @@ -139,51 +142,72 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ init_req_with_scalar(n, vtn, 0); continue; } else { - set_all_req_with_scalars(n, vtn); + init_all_req_with_scalars(n, vtn); } } } // Create a vtnode for each pack. No in/out edges set yet. VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { - uint pack_size = pack->size(); Node* p0 = pack->at(0); - int opc = p0->Opcode(); - VTransformVectorNode* vtn = nullptr; + const VTransformVectorNodeProperties properties = VTransformVectorNodeProperties::make_from_pack(pack, _vloop_analyzer); + const int sopc = properties.scalar_opcode(); + const uint vlen = properties.vector_length(); + const BasicType bt = properties.element_basic_type(); + VTransformVectorNode* vtn = nullptr; if (p0->is_Load()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Load()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type()); } else if (p0->is_Store()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Store()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, properties, vector_p, p0->adr_type()); + } else if (p0->is_Cmp()) { + vtn = new (_vtransform.arena()) VTransformCmpVectorNode(_vtransform, properties); } else if (p0->is_Bool()) { VTransformBoolTest kind = _packset.get_bool_test(pack); - vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, pack_size, kind); + vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, properties, kind); + } else if (p0->is_CMove()) { + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, Op_VectorBlend); } else if (_vloop_analyzer.reductions().is_marked_reduction(p0)) { - vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, pack_size); + vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, properties); } else if (VectorNode::is_muladds2i(p0)) { // A special kind of binary element-wise vector op: the inputs are "ints" a and b, // but reinterpreted as two "shorts" [a0, a1] and [b0, b1]: // v = MulAddS2I(a, b) = a0 * b0 + a1 + b1 assert(p0->req() == 5, "MulAddS2I should have 4 operands"); - vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, pack_size); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, properties, vopc); + } else if (VectorNode::is_convert_opcode(sopc)) { + assert(p0->req() == 2, "convert should have 2 operands"); + BasicType def_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + int vopc = VectorCastNode::opcode(sopc, def_bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_reinterpret_opcode(sopc)) { + assert(p0->req() == 2, "reinterpret should have 2 operands"); + BasicType src_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + vtn = new (_vtransform.arena()) VTransformReinterpretVectorNode(_vtransform, properties, src_bt); + } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(p0, bt)) { + int vopc = VectorNode::opcode(Op_RShiftI, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc)) { + vtn = new (_vtransform.arena()) VTransformElementWiseLongOpWithCastToIntVectorNode(_vtransform, properties); } else { assert(p0->req() == 3 || - p0->is_CMove() || - VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc) || - VectorNode::is_convert_opcode(opc) || - VectorNode::is_reinterpret_opcode(opc) || - VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || - opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, + VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc) || + VectorNode::is_reinterpret_opcode(sopc) || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(sopc) || + sopc == Op_FmaD || + sopc == Op_FmaF || + sopc == Op_FmaHF || + sopc == Op_SignumF || + sopc == Op_SignumD, "pack type must be in this list"); - vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), pack_size); + assert(!VectorNode::is_roundopD(p0) || p0->in(2)->is_Con(), "rounding mode must be constant"); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); } vtn->set_nodes(pack); return vtn; @@ -291,7 +315,7 @@ void SuperWordVTransformBuilder::init_req_with_vector(const Node_List* pack, VTr vtn->init_req(j, req); } -void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_scalars(Node* n, VTransformNode* vtn) { assert(vtn->req() == n->req(), "scalars must have same number of reqs"); for (uint j = 0; j < n->req(); j++) { Node* def = n->in(j); @@ -300,7 +324,7 @@ void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNod } } -void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { Node* p0 = pack->at(0); assert(vtn->req() <= p0->req(), "must have at at most as many reqs"); // Vectors have no ctrl, so ignore it. diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index ea93bb60ffb..6ed8480209a 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -79,8 +79,8 @@ private: VTransformNode* get_vtnode_or_wrap_as_outer(Node* n); void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); - void set_all_req_with_scalars(Node* n, VTransformNode* vtn); - void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); + void init_all_req_with_scalars(Node* n, VTransformNode* vtn); + void init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); }; diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 2f77c1c2e37..8c1210a5a09 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -104,7 +104,7 @@ bool VTransformGraph::schedule() { } #ifndef PRODUCT - if (_trace._verbose) { + if (_trace._info) { print_schedule(); } #endif @@ -158,11 +158,9 @@ void VTransform::apply_speculative_alignment_runtime_checks() { const GrowableArray& vtnodes = _graph.vtnodes(); for (int i = 0; i < vtnodes.length(); i++) { - VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + VTransformMemVectorNode* vtn = vtnodes.at(i)->isa_MemVector(); if (vtn == nullptr) { continue; } - MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); - if (p0 == nullptr) { continue; } - const VPointer& vp = vpointer(p0); + const VPointer& vp = vtn->vpointer(); if (vp.mem_pointer().base().is_object()) { continue; } assert(vp.mem_pointer().base().is_native(), "VPointer base must be object or native"); @@ -720,41 +718,41 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { } VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformReplicateNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformConvI2LNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); Node* n = new ConvI2LNode(val); - register_new_node_from_vectorization(apply_state, n, val); + register_new_node_from_vectorization(apply_state, n); return VTransformApplyResult::make_scalar(n); } @@ -766,11 +764,11 @@ VTransformApplyResult VTransformShiftCountNode::apply(VTransformApplyState& appl // bits in a scalar shift operation. But vector shift does not truncate, so // we must apply the mask now. Node* shift_count_masked = new AndINode(shift_count_in, phase->intcon(_mask)); - register_new_node_from_vectorization(apply_state, shift_count_masked, shift_count_in); + register_new_node_from_vectorization(apply_state, shift_count_masked); // Now that masked value is "boadcast" (some platforms only set the lowest element). VectorNode* vn = VectorNode::shift_count(_shift_opcode, shift_count_masked, _vlen, _element_bt); - register_new_node_from_vectorization(apply_state, vn, shift_count_in); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } @@ -781,77 +779,62 @@ VTransformApplyResult VTransformPopulateIndexNode::apply(VTransformApplyState& a assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); const TypeVect* vt = TypeVect::make(_element_bt, _vlen); VectorNode* vn = new PopulateIndexNode(val, phase->intcon(1), vt); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); - - if (first->is_Cmp()) { - // Cmp + Bool -> VectorMaskCmp - // Handled by Bool / VTransformBoolVectorNode, so we do not generate any nodes here. - return VTransformApplyResult::make_empty(); - } - assert(2 <= req() && req() <= 4, "Must have 1-3 inputs"); - VectorNode* vn = nullptr; + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); Node* in1 = apply_state.transformed_node(in_req(1)); Node* in2 = (req() >= 3) ? apply_state.transformed_node(in_req(2)) : nullptr; - Node* in3 = (req() >= 4) ? apply_state.transformed_node(in_req(3)) : nullptr; - if (first->is_CMove()) { - assert(req() == 4, "three inputs expected: mask, blend1, blend2"); - vn = new VectorBlendNode(/* blend1 */ in2, /* blend2 */ in3, /* mask */ in1); - } else if (VectorNode::is_convert_opcode(opc)) { - assert(first->req() == 2 && req() == 2, "only one input expected"); - int vopc = VectorCastNode::opcode(opc, in1->bottom_type()->is_vect()->element_basic_type()); - vn = VectorCastNode::make(vopc, in1, bt, vlen); - } else if (VectorNode::is_reinterpret_opcode(opc)) { - assert(first->req() == 2 && req() == 2, "only one input expected"); - const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new VectorReinterpretNode(in1, in1->bottom_type()->is_vect(), vt); - } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { - opc = Op_RShiftI; - vn = VectorNode::make(opc, in1, in2, vlen, bt); - } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { - // The scalar operation was a long -> int operation. - // However, the vector operation is long -> long. - VectorNode* long_vn = VectorNode::make(opc, in1, nullptr, vlen, T_LONG); - register_new_node_from_vectorization(apply_state, long_vn, first); - // Cast long -> int, to mimic the scalar long -> int operation. - vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); - } else if (req() == 3 || - VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { - assert(!VectorNode::is_roundopD(first) || in2->is_Con(), "rounding mode must be constant"); - vn = VectorNode::make(opc, in1, in2, vlen, bt); // unary and binary + VectorNode* vn = nullptr; + if (req() <= 3) { + vn = VectorNode::make(_vector_opcode, in1, in2, vt); // unary and binary } else { - assert(req() == 4, "three inputs expected"); - assert(opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, - "element wise operation must be from this list"); - vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary + Node* in3 = apply_state.transformed_node(in_req(3)); + vn = VectorNode::make(_vector_opcode, in1, in2, in3, vt); // ternary } register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformElementWiseLongOpWithCastToIntVectorNode::apply(VTransformApplyState& apply_state) const { + uint vlen = vector_length(); + int sopc = scalar_opcode(); + Node* in1 = apply_state.transformed_node(in_req(1)); + + // The scalar operation was a long -> int operation. + // However, the vector operation is long -> long. + VectorNode* long_vn = VectorNode::make(sopc, in1, nullptr, vlen, T_LONG); + register_new_node_from_vectorization(apply_state, long_vn); + // Cast long -> int, to mimic the scalar long -> int operation. + VectorNode* vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformReinterpretVectorNode::apply(VTransformApplyState& apply_state) const { + const TypeVect* dst_vt = TypeVect::make(element_basic_type(), vector_length()); + const TypeVect* src_vt = TypeVect::make(_src_bt, vector_length()); + assert(VectorNode::is_reinterpret_opcode(scalar_opcode()), "scalar opcode must be reinterpret"); + + Node* in1 = apply_state.transformed_node(in_req(1)); + VectorNode* vn = new VectorReinterpretNode(in1, src_vt, dst_vt); + + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& apply_state) const { - BoolNode* first = nodes().at(0)->as_Bool(); - uint vlen = nodes().length(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); + assert(scalar_opcode() == Op_Bool, ""); // Cmp + Bool -> VectorMaskCmp - VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); - assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), - "bool vtn expects cmp vtn as input"); + VTransformCmpVectorNode* vtn_cmp = in_req(1)->isa_CmpVector(); + assert(vtn_cmp != nullptr, "bool vtn expects cmp vtn as input"); Node* cmp_in1 = apply_state.transformed_node(vtn_cmp->in_req(1)); Node* cmp_in2 = apply_state.transformed_node(vtn_cmp->in_req(2)); @@ -859,35 +842,30 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl PhaseIdealLoop* phase = apply_state.phase(); ConINode* mask_node = phase->intcon((int)mask); - const TypeVect* vt = TypeVect::make(bt, vlen); VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = first->bottom_type()->basic_type(); - Node* init = apply_state.transformed_node(in_req(1)); Node* vec = apply_state.transformed_node(in_req(2)); - ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); + ReductionNode* vn = ReductionNode::make(scalar_opcode(), nullptr, init, vec, element_basic_type()); register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + BasicType bt = element_basic_type(); + LoadNode* first = nodes().at(0)->as_Load(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - int opc = first->Opcode(); - const TypePtr* adr_type = first->adr_type(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); // Set the memory dependency of the LoadVector as early as possible. // Walk up the memory chain, and ignore any StoreVector that provably @@ -902,34 +880,33 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl } } - LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, + LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, control_dependency()); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + StoreNode* first = nodes().at(0)->as_Store(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - int opc = first->Opcode(); - const TypePtr* adr_type = first->adr_type(); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); - StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); + StoreVectorNode* vn = StoreVectorNode::make(sopc, ctrl, mem, adr, _adr_type, value, vlen); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - Node* first = nodes().at(0); - - register_new_node_from_vectorization(apply_state, vn, first); + register_new_node_from_vectorization(apply_state, vn); for (int i = 0; i < _nodes.length(); i++) { Node* n = _nodes.at(i); @@ -937,9 +914,11 @@ void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scal } } -void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const { +void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - phase->register_new_node_with_ctrl_of(vn, old_node); + // Using the cl is sometimes not the most accurate, but still correct. We do not have to be + // perfectly accurate, because we will set major_progress anyway. + phase->register_new_node(vn, apply_state.vloop().cl()); phase->igvn()._worklist.push(vn); VectorNode::trace_new_vector(vn, "AutoVectorization"); } @@ -1050,18 +1029,32 @@ void VTransformPopulateIndexNode::print_spec() const { } void VTransformVectorNode::print_spec() const { - tty->print("%d-pack[", _nodes.length()); - for (int i = 0; i < _nodes.length(); i++) { - Node* n = _nodes.at(i); - if (i > 0) { - tty->print(", "); - } - tty->print("%d %s", n->_idx, n->Name()); - } - tty->print("]"); + tty->print("Properties[orig=[%d %s] sopc=%s vlen=%d element_bt=%s]", + approximate_origin()->_idx, + approximate_origin()->Name(), + NodeClassNames[scalar_opcode()], + vector_length(), + type2name(element_basic_type())); if (is_load_or_store_in_loop()) { tty->print(" "); vpointer().print_on(tty, false); } } + +void VTransformElementWiseVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" vopc=%s", NodeClassNames[_vector_opcode]); +} + +void VTransformReinterpretVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" src_bt=%s", type2name(_src_bt)); +} + +void VTransformBoolVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + const BoolTest bt(_test._mask); + tty->print(" test="); + bt.dump_on(tty); +} #endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 60b0b5d4f9d..9a4e4de01a2 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -26,6 +26,7 @@ #include "opto/node.hpp" #include "opto/vectorization.hpp" +#include "opto/vectornode.hpp" // VTransform: // - Models the transformation of the scalar loop to vectorized loop: @@ -67,6 +68,7 @@ class VTransformCFGNode; class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; +class VTransformCmpVectorNode; class VTransformBoolVectorNode; class VTransformReductionVectorNode; class VTransformMemVectorNode; @@ -90,9 +92,12 @@ public: return VTransformApplyResult(n, 0, 0); } - static VTransformApplyResult make_vector(Node* n, uint vector_length, uint vector_width) { - assert(vector_length > 0 && vector_width > 0, "must have nonzero size"); - return VTransformApplyResult(n, vector_length, vector_width); + static VTransformApplyResult make_vector(VectorNode* vn) { + return VTransformApplyResult(vn, vn->length(), vn->length_in_bytes()); + } + + static VTransformApplyResult make_vector(Node* n, const TypeVect* vt) { + return VTransformApplyResult(n, vt->length(), vt->length_in_bytes()); } static VTransformApplyResult make_empty() { @@ -431,6 +436,7 @@ public: virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } + virtual VTransformCmpVectorNode* isa_CmpVector() { return nullptr; } virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } virtual VTransformReductionVectorNode* isa_ReductionVector() { return nullptr; } virtual VTransformMemVectorNode* isa_MemVector() { return nullptr; } @@ -445,7 +451,7 @@ public: Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const; + void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual const char* name() const = 0;) NOT_PRODUCT(void print() const;) @@ -590,13 +596,52 @@ public: NOT_PRODUCT(virtual void print_spec() const override;) }; -// Base class for all vector vtnodes. +// Bundle the information needed for vector nodes. +class VTransformVectorNodeProperties : public StackObj { +private: + Node* _approximate_origin; // for proper propagation of node notes + const int _scalar_opcode; + const uint _vector_length; + const BasicType _element_basic_type; + + VTransformVectorNodeProperties(Node* approximate_origin, + int scalar_opcode, + uint vector_length, + BasicType element_basic_type) : + _approximate_origin(approximate_origin), + _scalar_opcode(scalar_opcode), + _vector_length(vector_length), + _element_basic_type(element_basic_type) {} + +public: + static VTransformVectorNodeProperties make_from_pack(const Node_List* pack, const VLoopAnalyzer& vloop_analyzer) { + Node* first = pack->at(0); + int opc = first->Opcode(); + int vlen = pack->size(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + return VTransformVectorNodeProperties(first, opc, vlen, bt); + } + + Node* approximate_origin() const { return _approximate_origin; } + int scalar_opcode() const { return _scalar_opcode; } + uint vector_length() const { return _vector_length; } + BasicType element_basic_type() const { return _element_basic_type; } +}; + +// Abstract base class for all vector vtnodes. class VTransformVectorNode : public VTransformNode { private: + const VTransformVectorNodeProperties _properties; +protected: GrowableArray _nodes; public: - VTransformVectorNode(VTransform& vtransform, const uint req, const uint number_of_nodes) : - VTransformNode(vtransform, req), _nodes(vtransform.arena(), number_of_nodes, number_of_nodes, nullptr) {} + VTransformVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties) : + VTransformNode(vtransform, req), + _properties(properties), + _nodes(vtransform.arena(), + properties.vector_length(), + properties.vector_length(), + nullptr) {} void set_nodes(const Node_List* pack) { for (uint k = 0; k < pack->size(); k++) { @@ -604,20 +649,50 @@ public: } } - const GrowableArray& nodes() const { return _nodes; } virtual VTransformVectorNode* isa_Vector() override { return this; } void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual void print_spec() const override;) + +protected: + Node* approximate_origin() const { return _properties.approximate_origin(); } + int scalar_opcode() const { return _properties.scalar_opcode(); } + uint vector_length() const { return _properties.vector_length(); } + BasicType element_basic_type() const { return _properties.element_basic_type(); } }; // Catch all for all element-wise vector operations. class VTransformElementWiseVectorNode : public VTransformVectorNode { +private: + const int _vector_opcode; public: - VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : - VTransformVectorNode(vtransform, req, number_of_nodes) {} + VTransformElementWiseVectorNode(VTransform& vtransform, uint req, const VTransformVectorNodeProperties properties, const int vector_opcode) : + VTransformVectorNode(vtransform, req, properties), _vector_opcode(vector_opcode) {} virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// The scalar operation was a long -> int operation. +// However, the vector operation is long -> long. +// Hence, we vectorize it as: long --long_op--> long --cast--> int +class VTransformElementWiseLongOpWithCastToIntVectorNode : public VTransformVectorNode { +public: + VTransformElementWiseLongOpWithCastToIntVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 2, properties) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseLongOpWithCastToIntVector"; };) +}; + +class VTransformReinterpretVectorNode : public VTransformVectorNode { +private: + const BasicType _src_bt; +public: + VTransformReinterpretVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const BasicType src_bt) : + VTransformVectorNode(vtransform, 2, properties), _src_bt(src_bt) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ReinterpretVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; struct VTransformBoolTest { @@ -628,23 +703,35 @@ struct VTransformBoolTest { _mask(mask), _is_negated(is_negated) {} }; -class VTransformBoolVectorNode : public VTransformElementWiseVectorNode { +// Cmp + Bool -> VectorMaskCmp +// The Bool node takes care of "apply". +class VTransformCmpVectorNode : public VTransformVectorNode { +public: + VTransformCmpVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} + virtual VTransformCmpVectorNode* isa_CmpVector() override { return this; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override { return VTransformApplyResult::make_empty(); } + NOT_PRODUCT(virtual const char* name() const override { return "CmpVector"; };) +}; + +class VTransformBoolVectorNode : public VTransformVectorNode { private: const VTransformBoolTest _test; public: - VTransformBoolVectorNode(VTransform& vtransform, uint number_of_nodes, VTransformBoolTest test) : - VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} + VTransformBoolVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, VTransformBoolTest test) : + VTransformVectorNode(vtransform, 2, properties), _test(test) {} VTransformBoolTest test() const { return _test; } virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; class VTransformReductionVectorNode : public VTransformVectorNode { public: // req = 3 -> [ctrl, scalar init, vector] - VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : - VTransformVectorNode(vtransform, 3, number_of_nodes) {} + VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -653,12 +740,16 @@ public: class VTransformMemVectorNode : public VTransformVectorNode { private: const VPointer _vpointer; // with size of the vector +protected: + const TypePtr* _adr_type; public: - VTransformMemVectorNode(VTransform& vtransform, const uint req, uint number_of_nodes, const VPointer& vpointer) : - VTransformVectorNode(vtransform, req, number_of_nodes), - _vpointer(vpointer) {} + VTransformMemVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformVectorNode(vtransform, req, properties), + _vpointer(vpointer), + _adr_type(adr_type) {} + const GrowableArray& nodes() const { return _nodes; } virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } virtual const VPointer& vpointer() const override { return _vpointer; } @@ -667,8 +758,8 @@ public: class VTransformLoadVectorNode : public VTransformMemVectorNode { public: // req = 3 -> [ctrl, mem, adr] - VTransformLoadVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 3, number_of_nodes, vpointer) {} + VTransformLoadVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type) {} LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } @@ -679,8 +770,8 @@ public: class VTransformStoreVectorNode : public VTransformMemVectorNode { public: // req = 4 -> [ctrl, mem, adr, val] - VTransformStoreVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 4, number_of_nodes, vpointer) {} + VTransformStoreVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 4, properties, vpointer, adr_type) {} virtual VTransformStoreVectorNode* isa_StoreVector() override { return this; } virtual bool is_load_in_loop() const override { return false; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; @@ -703,8 +794,8 @@ void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { callback(scalar->node()); } - VTransformVectorNode* vector = vtn->isa_Vector(); - if (vector != nullptr && vector->nodes().at(0)->is_Mem()) { + VTransformMemVectorNode* vector = vtn->isa_MemVector(); + if (vector != nullptr) { for (int j = 0; j < vector->nodes().length(); j++) { callback(vector->nodes().at(j)->as_Mem()); } From 2826d1702534783023802ac5c8d8ea575558f09f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:05:30 +0000 Subject: [PATCH 465/471] 8367243: Format issues with dist dump debug output in PhaseGVN::dead_loop_check Reviewed-by: thartmann --- src/hotspot/share/opto/phaseX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index a4248cb2b91..00b36d0bf43 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -780,7 +780,7 @@ void PhaseGVN::dead_loop_check( Node *n ) { } } } - if (!no_dead_loop) n->dump_bfs(100,nullptr,"#"); + if (!no_dead_loop) { n->dump_bfs(100, nullptr, ""); } assert(no_dead_loop, "dead loop detected"); } } From 7690a45f77a2da47fa912fe7a2b2faa589f259f0 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 11 Sep 2025 06:55:32 +0000 Subject: [PATCH 466/471] 8366342: Key generator and key pair generator tests skipping, but showing as passed Reviewed-by: weijun --- .../security/pkcs11/KeyGenerator/DESParity.java | 11 ++++++----- .../sun/security/pkcs11/KeyGenerator/TestAES.java | 14 +++++++------- .../security/pkcs11/KeyGenerator/TestChaCha20.java | 7 ++++--- .../pkcs11/KeyGenerator/TestKeyGenerator.java | 2 +- .../pkcs11/KeyPairGenerator/TestDH2048.java | 7 ++++--- .../TestDefaultDHPrivateExpSize.java | 9 ++++----- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java index 59f58ca525e..f9da78df0e2 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 @@ -32,6 +32,8 @@ * @run main/othervm DESParity */ +import jtreg.SkippedException; + import java.security.Provider; import java.util.Random; import javax.crypto.SecretKey; @@ -45,8 +47,7 @@ public class DESParity extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("SecretKeyFactory", "DES") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } Random random = new Random(); SecretKeyFactory kf; @@ -57,7 +58,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DES"); SecretKey key = kf.generateSecret(spec); - if (DESKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DES key not parity adjusted"); } } @@ -68,7 +69,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DESede"); SecretKey key = kf.generateSecret(spec); - if (DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DESede key not parity adjusted"); } } diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java index e74007a65e3..66078be30bd 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. 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 @@ -30,13 +30,14 @@ * @library /test/lib .. * @run main TestAES */ +import jtreg.SkippedException; +import sun.security.util.SecurityProviderConstants; + import java.security.Provider; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import static sun.security.util.SecurityProviderConstants.*; public class TestAES extends PKCS11Test { @@ -53,17 +54,16 @@ public class TestAES extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } // first try w/o setting a key length and check if the generated key // length matches SecretKey key = kg.generateKey(); byte[] keyValue = key.getEncoded(); - if (key.getEncoded().length != getDefAESKeySize() >> 3) { + if (key.getEncoded().length != SecurityProviderConstants.getDefAESKeySize() >> 3) { throw new RuntimeException("Default AES key length should be " + - getDefAESKeySize()); + SecurityProviderConstants.getDefAESKeySize()); } for (int keySize : new int[] { 16, 32, 64, 128, 256, 512, 1024 }) { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java index a21571cd957..0eaab538655 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. 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 @@ -29,6 +29,8 @@ * @library /test/lib .. * @run main/othervm TestChaCha20 */ +import jtreg.SkippedException; + import java.security.Provider; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; @@ -54,8 +56,7 @@ public class TestChaCha20 extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } try { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java index 15d0ee87fe4..50886a7aba3 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. 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 diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java index b05861ff3ae..06a9fa67afe 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. 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 @@ -31,6 +31,8 @@ * @run main/othervm TestDH2048 */ +import jtreg.SkippedException; + import java.security.InvalidParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -50,8 +52,7 @@ public class TestDH2048 extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("KPG for DH not supported, skipping"); - return; + throw new SkippedException("KPG for DH not supported, skipping"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); kpg.initialize(512); diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java index cb93a96fdd2..3f19a59423b 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. 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 @@ -21,12 +21,12 @@ * questions. */ -import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; -import java.security.PrivateKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.interfaces.DHPrivateKey; + +import jtreg.SkippedException; import sun.security.util.SecurityProviderConstants; import sun.security.provider.ParameterCache; @@ -47,8 +47,7 @@ public class TestDefaultDHPrivateExpSize extends PKCS11Test { System.out.println("Testing " + p.getName()); if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("Skip, no support for DH KeyPairGenerator"); - return; + throw new SkippedException("Skip, no support for DH KeyPairGenerator"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); From 8ba0db0de8b79f64cbfa56683f660f888c880182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 11 Sep 2025 07:42:39 +0000 Subject: [PATCH 467/471] 8366951: Test runtime/logging/StressAsyncUL.java is timing out Reviewed-by: ayang, lkorinth, dholmes, syan --- test/hotspot/jtreg/runtime/logging/StressAsyncUL.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index 2967507fa64..479f62d6c30 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -45,12 +45,12 @@ public class StressAsyncUL { } } public static void main(String[] args) throws Exception { - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", InnerClass.class.getName()); // Stress test with a very small buffer. Note: Any valid buffer size must be able to hold a flush token. // Therefore the size of the buffer cannot be zero. - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); } public static class InnerClass { From 0b3a303053d0eb5a98ed3d9df42c659db148b470 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 11 Sep 2025 08:07:25 +0000 Subject: [PATCH 468/471] 8367066: RISC-V: refine register selection in MacroAssembler:: decode_klass_not_null Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 13 +++++-------- src/hotspot/cpu/riscv/riscv.ad | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 1436bc02113..8f136135a89 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3402,6 +3402,8 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) { assert(UseCompressedClassPointers, "should only be used for compressed headers"); + assert_different_registers(dst, tmp); + assert_different_registers(src, tmp); if (CompressedKlassPointers::base() == nullptr) { if (CompressedKlassPointers::shift() != 0) { @@ -3412,18 +3414,13 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register return; } - Register xbase = dst; - if (dst == src) { - xbase = tmp; - } + Register xbase = tmp; - assert_different_registers(src, xbase); mv(xbase, (uintptr_t)CompressedKlassPointers::base()); if (CompressedKlassPointers::shift() != 0) { - Register t = src == dst ? dst : t0; - assert_different_registers(t, xbase); - shadd(dst, src, xbase, t, CompressedKlassPointers::shift()); + // dst = (src << shift) + xbase + shadd(dst, src, xbase, dst /* temporary, dst != xbase */, CompressedKlassPointers::shift()); } else { add(dst, xbase, src); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 0c4dd7b71e2..739a525c9a4 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -8938,7 +8938,7 @@ instruct encodeKlass_not_null(iRegNNoSp dst, iRegP src) %{ instruct decodeKlass_not_null(iRegPNoSp dst, iRegN src, iRegPNoSp tmp) %{ match(Set dst (DecodeNKlass src)); - effect(TEMP tmp); + effect(TEMP_DEF dst, TEMP tmp); ins_cost(ALU_COST); format %{ "decode_klass_not_null $dst, $src\t#@decodeKlass_not_null" %} From 3d679087b0376c221d536780cee387dc2dd8019e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 11 Sep 2025 08:53:09 +0000 Subject: [PATCH 469/471] 8367268: Remove unused os::numa_topology_changed() Reviewed-by: ayang, dholmes --- src/hotspot/os/aix/os_aix.cpp | 4 ---- src/hotspot/os/bsd/os_bsd.cpp | 2 -- src/hotspot/os/linux/os_linux.cpp | 2 -- src/hotspot/os/windows/os_windows.cpp | 1 - src/hotspot/share/runtime/os.hpp | 1 - 5 files changed, 10 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index aa119210f47..2dd60b51119 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1753,10 +1753,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { - return false; -} - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 4f5fed2c8c0..8b75c0dcdd8 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1599,8 +1599,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d133813feb0..9f896d62d4d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2988,8 +2988,6 @@ void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { Linux::numa_tonode_memory(addr, bytes, lgrp_hint); } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { // Return just the number of nodes in which it's possible to allocate memory // (in numa terminology, configured nodes). diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 09d8b542a10..4061ccf9dac 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3794,7 +3794,6 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } size_t os::numa_get_groups_num() { return MAX2(numa_node_list_holder.get_count(), 1); } int os::numa_get_group_id() { return 0; } size_t os::numa_get_leaf_groups(uint *ids, size_t size) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 9db4380fc07..4f6830daa4c 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -540,7 +540,6 @@ class os: AllStatic { static void numa_make_global(char *addr, size_t bytes); static size_t numa_get_groups_num(); static size_t numa_get_leaf_groups(uint *ids, size_t size); - static bool numa_topology_changed(); static int numa_get_group_id(); static int numa_get_group_id_for_address(const void* address); static bool numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count); From 3355a9d3fa3e57d489f716ebc1c885c1391274ea Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 11 Sep 2025 10:43:25 +0000 Subject: [PATCH 470/471] 8285150: Improve tab completion for annotations Reviewed-by: liach --- .../jshell/tool/ConsoleIOContext.java | 19 +- .../jdk/jshell/SourceCodeAnalysisImpl.java | 262 ++++++++++++++++-- .../jdk/jshell/CompletionSuggestionTest.java | 43 +++ .../jdk/jshell/ToolTabSnippetTest.java | 20 ++ 4 files changed, 323 insertions(+), 21 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index 5cf301efac5..1662f81710a 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -394,9 +394,9 @@ class ConsoleIOContext extends IOContext { .reduce(ConsoleIOContext::commonPrefix); String prefix = - prefixOpt.orElse("").substring(cursor - anchor[0]); + prefixOpt.orElse(""); - if (!prefix.isEmpty() && !command) { + if (prefix.length() > cursor - anchor[0] && !command) { //the completion will fill in the prefix, which will invalidate //the documentation, avoid adding documentation tasks into the //todo list: @@ -405,6 +405,7 @@ class ConsoleIOContext extends IOContext { ordinaryCompletion = new OrdinaryCompletionTask(ordinaryCompletionToShow, + anchor[0], prefix, !command && !doc.isEmpty(), hasBoth); @@ -609,15 +610,18 @@ class ConsoleIOContext extends IOContext { private final class OrdinaryCompletionTask implements CompletionTask { private final List toShow; + private final int anchor; private final String prefix; private final boolean cont; private final boolean showSmart; public OrdinaryCompletionTask(List toShow, + int anchor, String prefix, boolean cont, boolean showSmart) { this.toShow = toShow; + this.anchor = anchor; this.prefix = prefix; this.cont = cont; this.showSmart = showSmart; @@ -630,7 +634,14 @@ class ConsoleIOContext extends IOContext { @Override public Result perform(String text, int cursor) throws IOException { - in.putString(prefix); + String existingPrefix = in.getBuffer().substring(anchor, cursor); + + if (prefix.startsWith(existingPrefix)) { + in.putString(prefix.substring(existingPrefix.length())); + } else { + in.getBuffer().backspace(existingPrefix.length()); + in.putString(prefix); + } boolean showItems = toShow.size() > 1 || showSmart; @@ -639,7 +650,7 @@ class ConsoleIOContext extends IOContext { printColumns(toShow); } - if (!prefix.isEmpty()) + if (prefix.length() > existingPrefix.length()) return showItems ? Result.FINISH : Result.SKIP_NOREPAINT; return cont ? Result.CONTINUE : Result.FINISH; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index fffdfd5b33c..045734d9f55 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -38,6 +38,7 @@ import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.NewArrayTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; @@ -111,6 +112,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -310,13 +312,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { default -> proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); }; String[] requiredPrefix = new String[] {identifier}; - return computeSuggestions(codeWrap, cursor, requiredPrefix, anchor).stream() - .filter(s -> s.continuation().startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) + return computeSuggestions(codeWrap, code, cursor, requiredPrefix, anchor).stream() + .filter(s -> filteringText(s).startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) .sorted(Comparator.comparing(Suggestion::continuation)) .toList(); } - private List computeSuggestions(OuterWrap code, int cursor, String[] requiredPrefix, int[] anchor) { + private static String filteringText(Suggestion suggestion) { + return suggestion instanceof SuggestionImpl impl + ? impl.filteringText + : suggestion.continuation(); + } + + private List computeSuggestions(OuterWrap code, String inputCode, int cursor, String[] requiredPrefix, int[] anchor) { return proc.taskFactory.analyze(code, at -> { SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -479,6 +487,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); break; } + if (isAnnotation(tp)) { + if (getAnnotationAttributeNameOrNull(tp.getParentPath(), true) != null) { + //nested annotation + result = completionSuggestionsImpl(inputCode, cursor - 1, anchor); + requiredPrefix[0] = "@" + requiredPrefix[0]; + return result; + } + + Predicate accept = accessibility.and(STATIC_ONLY) + .and(IS_PACKAGE.or(IS_CLASS).or(IS_INTERFACE)); + addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); + break; + } ImportTree it = findImport(tp); if (it != null) { if (it.isModule()) { @@ -512,6 +533,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { case ERRONEOUS: { boolean staticOnly = ReplResolve.isStatic(((JavacScope)scope).getEnv()); Predicate accept = accessibility.and(staticOnly ? STATIC_ONLY : TRUE); + boolean insertPrimitiveTypes = true; if (isClass(tp)) { ClassTree clazz = (ClassTree) tp.getParentPath().getLeaf(); if (clazz.getExtendsClause() == tp.getLeaf()) { @@ -539,20 +561,101 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (var.getType() == tp.getLeaf()) { accept = accept.and(IS_TYPE); } + } else if (tp.getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + AnnotationTree annotation = (AnnotationTree) tp.getParentPath().getLeaf(); + Element annotationType = at.trees().getElement(tp.getParentPath()); + Set present = annotation.getArguments() + .stream() + .filter(expr -> expr.getKind() == Kind.ASSIGNMENT) + .map(expr -> (AssignmentTree) expr) + .map(assign -> assign.getVariable()) + .filter(var -> var.getKind() == Kind.IDENTIFIER) + .map(var -> ((IdentifierTree) var).getName().toString()) + .collect(Collectors.toSet()); + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), el -> !present.contains(el.getSimpleName().toString()), TRUE, _ -> " = ", result); + break; + } else if (getAnnotationAttributeNameOrNull(tp, true) instanceof String attributeName) { + Element annotationType = tp.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION + ? at.trees().getElement(tp.getParentPath().getParentPath()) + : at.trees().getElement(tp.getParentPath().getParentPath().getParentPath()); + if (sp.getEndPosition(topLevel, tp.getParentPath().getLeaf()) == (-1)) { + //synthetic 'value': + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), TRUE, TRUE, _ -> " = ", result); + boolean hasValue = findAnnotationAttributeIfAny(annotationType, "value").isPresent(); + if (!hasValue) { + break; + } + } + Optional ee = findAnnotationAttributeIfAny(annotationType, attributeName); + if (ee.isEmpty()) { + break; + } + TypeMirror relevantAttributeType = ee.orElseThrow().getReturnType(); + if (relevantAttributeType.getKind() == TypeKind.ARRAY) { + relevantAttributeType = ((ArrayType) relevantAttributeType).getComponentType(); + } + if (relevantAttributeType.getKind() == TypeKind.DECLARED && + at.getTypes().asElement(relevantAttributeType) instanceof Element attributeTypeEl) { + if (attributeTypeEl.getKind() == ElementKind.ANNOTATION_TYPE) { + boolean hasAnyAttributes = + ElementFilter.methodsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .anyMatch(attribute -> attribute.getParameters().isEmpty()); + String paren = hasAnyAttributes ? "(" : ""; + String name = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl("@" + name + paren, true)); + break; + } else if (attributeTypeEl.getKind() == ElementKind.ENUM) { + String typeName = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl(typeName, true)); + result.addAll(ElementFilter.fieldsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .filter(e -> e.getKind() == ElementKind.ENUM_CONSTANT) + .map(c -> new SuggestionImpl(scopeContent(at, scope, IDENTITY).contains(c) + ? c.getSimpleName().toString() + : typeName + "." + c.getSimpleName(), c.getSimpleName().toString(), + true)) + .toList()); + break; + } + } + accept = accessibility.and(el -> { + return switch (el.getKind()) { + case PACKAGE, ANNOTATION_TYPE, ENUM, INTERFACE, RECORD, ENUM_CONSTANT -> true; + case CLASS -> !((TypeElement) el).asType().getKind().isPrimitive(); + case FIELD -> isPermittedAnnotationAttributeFieldType(at, el.asType()); + default -> false; + }; + }); + insertPrimitiveTypes = false; } addScopeElements(at, scope, IDENTITY, accept, smartFilter, result); - Tree parent = tp.getParentPath().getLeaf(); - accept = switch (parent.getKind()) { - case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? - IS_VOID.negate() : - TRUE; - case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types - case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; - default -> TRUE; - }; - addElements(primitivesOrVoid(at), accept, smartFilter, result); + if (insertPrimitiveTypes) { + Tree parent = tp.getParentPath().getLeaf(); + accept = switch (parent.getKind()) { + case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? + IS_VOID.negate() : + TRUE; + case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types + case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; + default -> TRUE; + }; + addElements(primitivesOrVoid(at), accept, smartFilter, result); + } + + boolean hasBooleanSmartType = targetTypes != null && + StreamSupport.stream(targetTypes.spliterator(), false) + .anyMatch(tm -> tm.getKind() == TypeKind.BOOLEAN); + if (hasBooleanSmartType) { + result.add(new SuggestionImpl("true", true)); + result.add(new SuggestionImpl("false", true)); + } break; } } @@ -917,6 +1020,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { long start = sp.getStartPosition(topLevel, tree); long end = sp.getEndPosition(topLevel, tree); + if (end == (-1) && tree.getKind() == Kind.ASSIGNMENT && + getCurrentPath() != null && + getCurrentPath().getLeaf().getKind() == Kind.ANNOTATION) { + //the assignment is synthetically generated, take the end pos of the nested tree: + end = sp.getEndPosition(topLevel, ((AssignmentTree) tree).getExpression()); + } if (start <= wrapEndPos && wrapEndPos <= end && (deepest[0] == null || deepest[0].getLeaf() == getCurrentPath().getLeaf())) { deepest[0] = new TreePath(getCurrentPath(), tree); @@ -946,6 +1055,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { ((MethodTree)parent).getThrows().contains(tp.getLeaf()); } + private boolean isAnnotation(TreePath tp) { + Tree parent = tp.getParentPath().getLeaf(); + return parent.getKind() == Kind.ANNOTATION && + ((AnnotationTree)parent).getAnnotationType().equals(tp.getLeaf()); + } + private boolean isClass(TreePath tp) { return tp.getParentPath() != null && CLASS_KINDS.contains(tp.getParentPath().getLeaf().getKind()); @@ -961,6 +1076,39 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { tp.getParentPath().getLeaf().getKind() == Kind.VARIABLE; } + private String getAnnotationAttributeNameOrNull(TreePath tp, boolean acceptArray) { + if (tp.getParentPath() == null) { + return null; + } + if (tp.getParentPath().getLeaf().getKind() == Kind.NEW_ARRAY && + ((NewArrayTree) tp.getParentPath().getLeaf()).getInitializers().contains(tp.getLeaf())) { + if (acceptArray) { + return getAnnotationAttributeNameOrNull(tp.getParentPath(), false); + } else { + return null; + } + } + if (tp.getParentPath().getParentPath() == null || + tp.getParentPath().getLeaf().getKind() != Kind.ASSIGNMENT || + tp.getParentPath().getParentPath().getLeaf().getKind() != Kind.ANNOTATION) { + return null; + } + AssignmentTree assign = (AssignmentTree) tp.getParentPath().getLeaf(); + if (assign.getVariable().getKind() != Kind.IDENTIFIER) { + return null; + } + return ((IdentifierTree) assign.getVariable()).getName().toString(); + } + + private Optional findAnnotationAttributeIfAny(Element annotationType, + String attributeName) { + return ElementFilter.methodsIn(annotationType.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals(attributeName)) + .filter(ee -> ee.getParameters().isEmpty()) + .findAny(); + } + private ImportTree findImport(TreePath tp) { while (tp != null && tp.getLeaf().getKind() != Kind.IMPORT) { tp = tp.getParentPath(); @@ -987,6 +1135,17 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { }; } + private boolean isPermittedAnnotationAttributeFieldType(AnalyzeTask at, TypeMirror type) { + if (type.getKind().isPrimitive()) { + return true; + } + if (type.getKind() == TypeKind.DECLARED) { + Element el = ((DeclaredType) type).asElement(); + return el.getKind() == ElementKind.ENUM || el.equals(at.getElements().getTypeElement("java.lang.String")); + } + return false; + } + private final Predicate TRUE = el -> true; private final Predicate FALSE = TRUE.negate(); private final Predicate IS_STATIC = el -> el.getModifiers().contains(Modifier.STATIC); @@ -1237,7 +1396,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { return new VarSymbol(Flags.PUBLIC | Flags.STATIC | Flags.FINAL, _class, classType, erasedSite.tsym); } - private Iterable scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { + private Collection scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { Iterable scopeIterable = () -> new Iterator() { private Scope currentScope = scope; @Override @@ -1306,11 +1465,54 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { Tree current = forPath.getLeaf(); + if (current.getKind() == Kind.ANNOTATION) { + Element type = at.trees().getElement(forPath); + if (type != null) { + Optional valueAttr = + ElementFilter.methodsIn(type.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals("value")) + .findAny(); + if (valueAttr.isPresent()) { + TypeMirror returnType = valueAttr.orElseThrow().getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + } + } + switch (forPath.getParentPath().getLeaf().getKind()) { + case NEW_ARRAY: + if (getAnnotationAttributeNameOrNull(forPath, true) != null) { + forPath = forPath.getParentPath(); + current = forPath.getLeaf(); + //fall-through + } else { + break; + } case ASSIGNMENT: { AssignmentTree tree = (AssignmentTree) forPath.getParentPath().getLeaf(); - if (tree.getExpression() == current) - return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + if (tree.getExpression() == current) { + if (forPath.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + Element method = at.trees().getElement(new TreePath(forPath.getParentPath(), tree.getVariable())); + if (method != null && method.getKind() == ElementKind.METHOD) { + TypeMirror returnType = ((ExecutableElement) method).getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + return null; + } else { + return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + } + } break; } case VARIABLE: { @@ -1558,7 +1760,8 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { TreePath prevPath = null; while (tp != null && tp.getLeaf().getKind() != Kind.METHOD_INVOCATION && tp.getLeaf().getKind() != Kind.NEW_CLASS && tp.getLeaf().getKind() != Kind.IDENTIFIER && - tp.getLeaf().getKind() != Kind.MEMBER_SELECT) { + tp.getLeaf().getKind() != Kind.MEMBER_SELECT && + tp.getLeaf().getKind() != Kind.ANNOTATION) { prevPath = tp; tp = tp.getParentPath(); } @@ -1611,6 +1814,18 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } elements = Stream.of(el); + } else if (tp.getLeaf().getKind() == Kind.ANNOTATION) { + Element el = at.trees().getElement(tp); + + if (el == null || + el.getKind() != ElementKind.ANNOTATION_TYPE) { + //erroneous state: + return Collections.emptyList(); + } + + elements = ElementFilter.methodsIn(el.getEnclosedElements()) + .stream() + .map(ee -> (Element) ee); } else { return Collections.emptyList(); } @@ -2220,6 +2435,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { private static class SuggestionImpl implements Suggestion { private final String continuation; + private final String filteringText; private final boolean matchesType; /** @@ -2229,7 +2445,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { * @param matchesType does the candidate match the target type */ public SuggestionImpl(String continuation, boolean matchesType) { + this(continuation, continuation, matchesType); + } + + /** + * Create a {@code Suggestion} instance. + * + * @param continuation a candidate continuation of the user's input + * @param filteringText a text that should be used for filtering + * @param matchesType does the candidate match the target type + */ + public SuggestionImpl(String continuation, String filteringText, boolean matchesType) { this.continuation = continuation; + this.filteringText = filteringText; this.matchesType = matchesType; } diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index a710f60aec4..19f7b89a1b3 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -898,4 +898,47 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("p1.|", "p2.", "p3."); } + + @Test + public void testAnnotation() { + assertCompletion("@Deprec|", "Deprecated"); + assertCompletion("@Deprecated(|", "forRemoval = ", "since = "); + assertCompletion("@Deprecated(forRemoval = |", true, "false", "true"); + assertCompletion("@Deprecated(forRemoval = true, |", "since = "); + assertEval("import java.lang.constant.ConstantDescs;"); + assertEval("import static java.lang.constant.ConstantDescs.*;"); + assertEval("@interface Ann1 { public String test(); }"); + assertCompletionIncludesExcludes("@Ann1(test = |", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertEval("@interface Ann2 { public String[] test(); }"); + assertCompletionIncludesExcludes("@Ann2(test = {|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann2(test = {|", true, Set.of("INIT_NAME"), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertEval("@interface Ann3 { public String value(); }"); + assertCompletionIncludesExcludes("@Ann3(|", Set.of("java.", "ConstantDescs", "INIT_NAME", "value = "), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann3(|", true, Set.of("INIT_NAME", "value = "), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertSignature("@Deprecated(|", "boolean Deprecated.forRemoval()", "String Deprecated.since()"); + assertEval("@interface Ann4 { public String[] value(); }"); + assertCompletionIncludesExcludes("@Ann4({|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("value = ")); + assertEval("@interface Ann5 { public Ann4[] value(); }"); + assertCompletion("@Ann5(|", true, "@Ann4(", "value = "); + assertCompletion("@Ann5({|", true, "@Ann4("); + assertCompletion("@Ann5(|", false); + assertCompletion("@Ann5({|", false); + assertCompletion("@Ann5(@|", true, "@Ann4("); + assertCompletion("@Ann5(v|", true, "value = "); + assertEval("@interface Ann6 { public java.lang.annotation.Retention[] value(); }"); + assertCompletion("@Ann6(|", true, "@java.lang.annotation.Retention(", "value = "); + assertEval("@interface Ann7 { }"); //no attributes + assertEval("@interface Ann8 { public Ann7[] value(); }"); + assertCompletion("@Ann8(|", true, "@Ann7", "value = "); + assertEval("enum En { AA, BB, EE; }"); + assertEval("@interface Ann9 { public En[] value(); }"); + assertCompletion("@Ann9(|", true, "En", "En.AA", "En.BB", "En.EE", "value = "); + assertCompletion("@Ann9(A|", true, "En.AA"); + assertCompletion("@Ann9(E|", true, "En", "En.EE"); + assertCompletionIncludesExcludes("@Ann9(En.|", Set.of("AA", "BB", "EE"), Set.of()); + assertEval("@interface AnnA { public java.lang.annotation.RetentionPolicy[] value(); }"); + assertCompletion("@AnnA(C|", true, "java.lang.annotation.RetentionPolicy.CLASS"); + assertEval("import static java.lang.annotation.RetentionPolicy.*;"); + assertCompletion("@AnnA(C|", true, "CLASS"); + } } diff --git a/test/langtools/jdk/jshell/ToolTabSnippetTest.java b/test/langtools/jdk/jshell/ToolTabSnippetTest.java index 39189da8686..968935b0814 100644 --- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java +++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java @@ -344,4 +344,24 @@ public class ToolTabSnippetTest extends UITesting { waitOutput(out, PROMPT + "new InstantiationE"); }); } + + @Test + public void testAnnotation() throws Exception { + doRunTest((inputSink, out) -> { + inputSink.write("@interface Ann1 { public java.lang.annotation.Retention[] value(); }\n"); + waitOutput(out, "\n\\u001B\\[\\?2004h" + PROMPT); + + //-> + inputSink.write("@Ann1(" + TAB); + waitOutput(out, ".*@java.lang.annotation.Retention\\(.*value =.*" + + REDRAW_PROMPT + "@Ann1\\("); + inputSink.write("@" + TAB); + waitOutput(out, "^@java.lang.annotation.Retention\\("); + inputSink.write(TAB); + waitOutput(out, ".*java.lang.annotation.RetentionPolicy.*java.lang.annotation.RetentionPolicy.CLASS.*" + + REDRAW_PROMPT + "@Ann1\\(@java.lang.annotation.Retention\\("); + inputSink.write("CL" + TAB); + waitOutput(out, "CL\\u001B\\[2Djava.lang.annotation.RetentionPolicy.CLASS \\u0008"); + }); + } } From 8735a3d7c0cc38676b8d7f74ce187d29019333c0 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 11 Sep 2025 16:41:34 +0200 Subject: [PATCH 471/471] Adjusting to spec. --- .../com/sun/tools/javac/comp/Flow.java | 54 ++++++++++++++----- .../tools/javac/patterns/Exhaustiveness.java | 8 +-- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 1bf45308fdf..c2ad9deb57d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -60,6 +60,7 @@ import com.sun.tools.javac.resources.CompilerProperties.Fragments; import static com.sun.tools.javac.tree.JCTree.Tag.*; import com.sun.tools.javac.util.JCDiagnostic.Fragment; import java.util.Arrays; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -801,6 +802,7 @@ public class Flow { } } Set patterns = patternSet; + Map> replaces = new IdentityHashMap<>(); Set> seenFallback = new HashSet<>(); boolean useHashes = true; try { @@ -808,8 +810,8 @@ public class Flow { while (repeat) { Set updatedPatterns; updatedPatterns = reduceBindingPatterns(selector.type, patterns); - updatedPatterns = reduceNestedPatterns(updatedPatterns, useHashes); - updatedPatterns = reduceRecordPatterns(updatedPatterns); + updatedPatterns = reduceNestedPatterns(updatedPatterns, replaces, useHashes); + updatedPatterns = reduceRecordPatterns(updatedPatterns, replaces); updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); repeat = !updatedPatterns.equals(patterns); if (checkCovered(selector.type, patterns)) { @@ -1009,6 +1011,7 @@ public class Flow { * as pattern hashes cannot be used to speed up the matching process */ private Set reduceNestedPatterns(Set patterns, + Map> replaces, boolean useHashes) { /* implementation note: * finding a sub-set of patterns that only differ in a single @@ -1060,7 +1063,7 @@ public class Flow { RecordPattern rpOther = candidatesArr[nextCandidate]; if (rpOne.recordType.tsym == rpOther.recordType.tsym) { - for (int i = 0; i < rpOne.nested.length; i++) { + ACCEPT: for (int i = 0; i < rpOne.nested.length; i++) { if (i != mismatchingCandidate) { if (!rpOne.nested[i].equals(rpOther.nested[i])) { if (useHashes) { @@ -1077,9 +1080,26 @@ public class Flow { continue NEXT_PATTERN; } } else if (rpOne.nested[i] instanceof RecordPattern nestedRPOne) { - if (!types.isSubtype(types.erasure(nestedRPOne.recordType()), types.erasure(bpOther.type))) { + boolean foundMatchingReplaced = false; + Set pendingReplacedPatterns = new HashSet<>(replaces.getOrDefault(rpOther.nested[i], Set.of())); + + while (!pendingReplacedPatterns.isEmpty()) { + PatternDescription currentReplaced = pendingReplacedPatterns.iterator().next(); + + pendingReplacedPatterns.remove(currentReplaced); + + if (nestedRPOne.equals(currentReplaced)) { + foundMatchingReplaced = true; + break; + } + + pendingReplacedPatterns.addAll(replaces.getOrDefault(currentReplaced, Set.of())); + } + if (!foundMatchingReplaced) { continue NEXT_PATTERN; } + } else { + continue NEXT_PATTERN; } } } @@ -1089,9 +1109,9 @@ public class Flow { } var nestedPatterns = join.stream().map(rp -> rp.nested[mismatchingCandidateFin]).collect(Collectors.toSet()); - var updatedPatterns = reduceNestedPatterns(nestedPatterns, useHashes); + var updatedPatterns = reduceNestedPatterns(nestedPatterns, replaces, useHashes); - updatedPatterns = reduceRecordPatterns(updatedPatterns); + updatedPatterns = reduceRecordPatterns(updatedPatterns, replaces); updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); updatedPatterns = reduceBindingPatterns(rpOne.fullComponentTypes()[mismatchingCandidateFin], updatedPatterns); @@ -1104,9 +1124,11 @@ public class Flow { PatternDescription[] newNested = Arrays.copyOf(rpOne.nested, rpOne.nested.length); newNested[mismatchingCandidateFin] = nested; - current.add(new RecordPattern(rpOne.recordType(), + RecordPattern nue = new RecordPattern(rpOne.recordType(), rpOne.fullComponentTypes(), - newNested)); + newNested); + current.add(nue); + replaces.put(nue, new HashSet<>(join)); } } } @@ -1128,12 +1150,12 @@ public class Flow { * all the $nestedX pattern cover the given record component, * and replace those with a simple binding pattern over $record. */ - private Set reduceRecordPatterns(Set patterns) { + private Set reduceRecordPatterns(Set patterns, Map> replaces) { var newPatterns = new HashSet(); boolean modified = false; for (PatternDescription pd : patterns) { if (pd instanceof RecordPattern rpOne) { - PatternDescription reducedPattern = reduceRecordPattern(rpOne); + PatternDescription reducedPattern = reduceRecordPattern(rpOne, replaces); if (reducedPattern != rpOne) { newPatterns.add(reducedPattern); modified = true; @@ -1145,7 +1167,7 @@ public class Flow { return modified ? newPatterns : patterns; } - private PatternDescription reduceRecordPattern(PatternDescription pattern) { + private PatternDescription reduceRecordPattern(PatternDescription pattern, Map> replaces) { if (pattern instanceof RecordPattern rpOne) { Type[] componentType = rpOne.fullComponentTypes(); //error recovery, ignore patterns with incorrect number of nested patterns: @@ -1155,7 +1177,7 @@ public class Flow { PatternDescription[] reducedNestedPatterns = null; boolean covered = true; for (int i = 0; i < componentType.length; i++) { - PatternDescription newNested = reduceRecordPattern(rpOne.nested[i]); + PatternDescription newNested = reduceRecordPattern(rpOne.nested[i], replaces); if (newNested != rpOne.nested[i]) { if (reducedNestedPatterns == null) { reducedNestedPatterns = Arrays.copyOf(rpOne.nested, rpOne.nested.length); @@ -1166,9 +1188,13 @@ public class Flow { covered &= checkCovered(componentType[i], List.of(newNested)); } if (covered) { - return new BindingPattern(rpOne.recordType); + PatternDescription pd = new BindingPattern(rpOne.recordType); + replaces.put(pd, Set.of(pattern)); + return pd; } else if (reducedNestedPatterns != null) { - return new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns); + PatternDescription pd = new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns); + replaces.put(pd, Set.of(pattern)); + return pd; } } return pattern; diff --git a/test/langtools/tools/javac/patterns/Exhaustiveness.java b/test/langtools/tools/javac/patterns/Exhaustiveness.java index a0236f323e2..6600f14a07a 100644 --- a/test/langtools/tools/javac/patterns/Exhaustiveness.java +++ b/test/langtools/tools/javac/patterns/Exhaustiveness.java @@ -2222,7 +2222,7 @@ public class Exhaustiveness extends TestRunner { } @Test //JDK-8364991 - public void testX(Path base) throws Exception { + public void testBindingPatternDoesNotStandInPlaceOfRecordPatterns(Path base) throws Exception { doTest(base, new String[0], """ @@ -2232,7 +2232,7 @@ public class Exhaustiveness extends TestRunner { return switch (r) { case Root(R2 _, R2(R1 _)) -> 0; case Root(R2(R1 _), R2(R2 _)) -> 0; - case Root(R2(R2 _), R2 _) -> 0; //the above is functionally equivalent to: Root(R2(R2 _), R2(R2 _)) -> 0; + case Root(R2(R2 _), R2 _) -> 0; }; } sealed interface Base {} @@ -2240,7 +2240,9 @@ public class Exhaustiveness extends TestRunner { record R2(Base b) implements Base {} record Root(R2 b2, R2 b3) {} } - """); + """, + "Test.java:4:16: compiler.err.not.exhaustive", + "1 error"); } private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException {

  • NameDescripionDescriptionDefault valueFormatExample values
    {@code maxSize}Specifies the size, measured in bytes, at which data is kept in disk + * Specifies the size, measured in bytes, at which data is kept in the disk * repository. Only works if * {@code disk=true}, otherwise this parameter is ignored.{@code "0"} (no limit)See {@code Paths#getPath} for format.
    * If this method is invoked from another process, the data is written on the * machine where the target JVM is running. If destination is a relative path, it - * is relative to the working directory where the target JVM was started.}
    {@code "c:\recording\recotding.jfr"},
    + * is relative to the working directory where the target JVM was started.
    {@code "c:\recording\recording.jfr"},
    * {@code "/recordings/recording.jfr"}, {@code "recording.jfr"}
    {@code duration}Sets how long the recording should be runningSpecifies the duration of the recording.{@code "0"} (no limit, continuous){@code "0"} if no limit should be imposed, otherwise a string * representation of a positive {@code Long} followed by an empty space and one @@ -287,7 +288,7 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { *
    NameDescripionDescriptionDefault valueFormatExample values{@code "1.0"}A version number with a major and minor.
    *
    - * To be able to read from a running recording the value must be set
    {@code "1.0"} *
    arm-linux-gnueabihf
    ppc64-linux-gnuppc64le-linux-gnu
    ppc64le-linux-gnuriscv64-linux-gnu
    s390x-linux-gnu