From 2eac490bd22f5488a60e59f93ce54d4babf33c23 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 13 Feb 2025 19:08:03 +0000 Subject: [PATCH 001/587] 8349868: Remove unneeded libjava shared library dependency from jtreg test libNewDirectByteBuffer, libDirectIO and libInheritedChannel Reviewed-by: bpb --- make/test/JtregNativeJdk.gmk | 3 --- 1 file changed, 3 deletions(-) diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index be40e24ba95..60a88ca1c9a 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -56,7 +56,6 @@ BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeCallerAccessTest := java.base:libjvm BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeNullCallerTest := java.base:libjvm BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libstringPlatformChars := java.base:libjava -BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libNewDirectByteBuffer := java.base:libjava BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libGetXSpace := java.base:libjava # Platform specific setup @@ -69,7 +68,6 @@ ifeq ($(call isTargetOs, windows), true) BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeNullCallerTest := /EHsc else - BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libDirectIO := java.base:libjava BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread # java.lang.foreign tests @@ -83,7 +81,6 @@ else BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libImplicitAttach := -pthread BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c ifeq ($(call isTargetOs, linux), true) - BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libInheritedChannel := java.base:libjava BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -ldl endif BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerTest := $(LIBCXX) From a88e2a58bf834081db55c2071d072567ea763354 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 13 Feb 2025 19:35:42 +0000 Subject: [PATCH 002/587] 8349977: JVMCIRuntime::_shared_library_javavm_id should be jlong Reviewed-by: yzheng, never --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciRuntime.cpp | 6 +++--- src/hotspot/share/jvmci/jvmciRuntime.hpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 9bbf4fccae1..f2807dbecd7 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2724,7 +2724,7 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb if (res == JNI_OK) { guarantee(peerJNIEnv != nullptr, "must be"); runtime->init_JavaVM_info(javaVM_info, JVMCI_CHECK_0); - JVMCI_event_1("attached to JavaVM[%d] for JVMCI runtime %d", runtime->get_shared_library_javavm_id(), runtime->id()); + JVMCI_event_1("attached to JavaVM[" JLONG_FORMAT "] for JVMCI runtime %d", runtime->get_shared_library_javavm_id(), runtime->id()); return true; } JVMCI_THROW_MSG_0(InternalError, err_msg("Error %d while attaching %s", res, attach_args.name)); @@ -2757,7 +2757,7 @@ C2V_VMENTRY_PREFIX(jboolean, detachCurrentThread, (JNIEnv* env, jobject c2vm, jb if (res != JNI_OK) { JVMCI_THROW_MSG_0(InternalError, err_msg("Error %d while attaching %s", res, thread->name())); } - JVMCI_event_1("detached from JavaVM[%d] for JVMCI runtime %d", + JVMCI_event_1("detached from JavaVM[" JLONG_FORMAT "] for JVMCI runtime %d", runtime->get_shared_library_javavm_id(), runtime->id()); if (release) { return runtime->detach_thread(thread, "user thread detach"); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 9a2a1de23a5..c88a4390590 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1569,7 +1569,7 @@ bool JVMCIRuntime::destroy_shared_library_javavm() { guarantee(_num_attached_threads == cannot_be_attached, "cannot destroy JavaVM for JVMCI runtime %d with %d attached threads", _id, _num_attached_threads); JavaVM* javaVM; - int javaVM_id = _shared_library_javavm_id; + jlong javaVM_id = _shared_library_javavm_id; { // Exactly one thread can destroy the JavaVM // and release the handle to it. @@ -1588,9 +1588,9 @@ bool JVMCIRuntime::destroy_shared_library_javavm() { result = javaVM->DestroyJavaVM(); } if (result == JNI_OK) { - JVMCI_event_1("destroyed JavaVM[%d]@" PTR_FORMAT " for JVMCI runtime %d", javaVM_id, p2i(javaVM), _id); + JVMCI_event_1("destroyed JavaVM[" JLONG_FORMAT "]@" PTR_FORMAT " for JVMCI runtime %d", javaVM_id, p2i(javaVM), _id); } else { - warning("Non-zero result (%d) when calling JNI_DestroyJavaVM on JavaVM[%d]@" PTR_FORMAT, result, javaVM_id, p2i(javaVM)); + warning("Non-zero result (%d) when calling JNI_DestroyJavaVM on JavaVM[" JLONG_FORMAT "]@" PTR_FORMAT, result, javaVM_id, p2i(javaVM)); } return true; } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index 99738393b5b..884d11f792e 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -183,7 +183,7 @@ class JVMCIRuntime: public CHeapObj { JavaVM* _shared_library_javavm; // Id for _shared_library_javavm. - int _shared_library_javavm_id; + jlong _shared_library_javavm_id; // Position and link in global list of JVMCI shared library runtimes. // The HotSpot heap based runtime will have an id of -1 and the @@ -280,7 +280,7 @@ class JVMCIRuntime: public CHeapObj { bool has_shared_library_javavm() { return _shared_library_javavm != nullptr; } // Gets an ID for the JVMCI shared library JavaVM associated with this runtime. - int get_shared_library_javavm_id() { return _shared_library_javavm_id; } + jlong get_shared_library_javavm_id() { return _shared_library_javavm_id; } // Copies info about the JVMCI shared library JavaVM associated with this // runtime into `info` as follows: From d8fcd43a24a989b71ed30945fda78541c1e42b60 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 13 Feb 2025 20:06:33 +0000 Subject: [PATCH 003/587] 8349927: Waiting for compiler termination delays shutdown for 10+ ms Reviewed-by: kvn, dholmes --- src/hotspot/share/runtime/vmOperations.cpp | 43 ++++++++++++++-------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 7cc8367d6d0..da833150d74 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -500,7 +500,6 @@ int VM_Exit::wait_for_threads_in_native_to_block() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already"); Thread * thr_cur = Thread::current(); - Monitor timer(Mutex::nosafepoint, "VM_ExitTimer_lock"); // Compiler threads need longer wait because they can access VM data directly // while in native. If they are active and some structures being used are @@ -509,12 +508,23 @@ int VM_Exit::wait_for_threads_in_native_to_block() { // data, and they will be stopped during state transition. In theory, we // don't have to wait for user threads to be quiescent, but it's always // better to terminate VM when current thread is the only active thread, so - // wait for user threads too. Numbers are in 10 milliseconds. - int wait_time_per_attempt = 10; // in milliseconds - int max_wait_attempts_user_thread = UserThreadWaitAttemptsAtExit; - int max_wait_attempts_compiler_thread = 1000; // at least 10 seconds + // wait for user threads too. + + // Time per attempt. It is practical to start waiting with 10us delays + // (around scheduling delay / timer slack), and exponentially ramp up + // to 10ms if compiler threads are not responding. + jlong max_wait_time = millis_to_nanos(10); + jlong wait_time = 10000; + + jlong start_time = os::javaTimeNanos(); + + // Deadline for user threads in native code. + // User-settable flag counts "attempts" in 10ms units, to a maximum of 10s. + jlong user_threads_deadline = start_time + (UserThreadWaitAttemptsAtExit * millis_to_nanos(10)); + + // Deadline for compiler threads: at least 10 seconds. + jlong compiler_threads_deadline = start_time + millis_to_nanos(10000); - int attempts = 0; JavaThreadIteratorWithHandle jtiwh; while (true) { int num_active = 0; @@ -543,19 +553,20 @@ int VM_Exit::wait_for_threads_in_native_to_block() { } } + jlong time = os::javaTimeNanos(); + if (num_active == 0) { - return 0; - } else if (attempts >= max_wait_attempts_compiler_thread) { - return num_active; - } else if (num_active_compiler_thread == 0 && - attempts >= max_wait_attempts_user_thread) { - return num_active; + return 0; + } + if (time >= compiler_threads_deadline) { + return num_active; + } + if ((num_active_compiler_thread == 0) && (time >= user_threads_deadline)) { + return num_active; } - attempts++; - - MonitorLocker ml(&timer, Mutex::_no_safepoint_check_flag); - ml.wait(wait_time_per_attempt); + os::naked_short_nanosleep(wait_time); + wait_time = MIN2(max_wait_time, wait_time * 2); } } From 3e7acfac48229441b243a6ac564e719963e4f43d Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 13 Feb 2025 20:57:48 +0000 Subject: [PATCH 004/587] 8349873: StackOverflowError after JDK-8342550 if -Duser.timezone= is set to a deprecated zone id Reviewed-by: joehw, jlu, iris --- .../share/classes/java/util/TimeZone.java | 7 +++--- .../java/util/TimeZone/ThreeLetterZoneID.java | 24 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/util/TimeZone.java b/src/java.base/share/classes/java/util/TimeZone.java index 52d06a858b0..2071ae79b20 100644 --- a/src/java.base/share/classes/java/util/TimeZone.java +++ b/src/java.base/share/classes/java/util/TimeZone.java @@ -47,7 +47,6 @@ import jdk.internal.util.StaticProperty; import sun.util.calendar.ZoneInfo; import sun.util.calendar.ZoneInfoFile; import sun.util.locale.provider.TimeZoneNameUtility; -import sun.util.logging.PlatformLogger; /** * {@code TimeZone} represents a time zone offset, and also figures out daylight @@ -599,9 +598,9 @@ public abstract class TimeZone implements Serializable, Cloneable { private static TimeZone getTimeZone(String ID, boolean fallback) { if (ZoneId.SHORT_IDS.containsKey(ID)) { - PlatformLogger.getLogger(TimeZone.class.getName()) - .warning("Use of the three-letter time zone ID \"%s\" is deprecated and it will be removed in a future release" - .formatted(ID)); + System.err.printf( + "WARNING: Use of the three-letter time zone ID \"%s\" is deprecated and it will be removed in a future release%n", + ID); } TimeZone tz = ZoneInfo.getTimeZone(ID); if (tz == null) { diff --git a/test/jdk/java/util/TimeZone/ThreeLetterZoneID.java b/test/jdk/java/util/TimeZone/ThreeLetterZoneID.java index 5df3ebe5bf0..02b4d89ce2b 100644 --- a/test/jdk/java/util/TimeZone/ThreeLetterZoneID.java +++ b/test/jdk/java/util/TimeZone/ThreeLetterZoneID.java @@ -23,27 +23,37 @@ /* * @test - * @bug 8342550 + * @bug 8342550 8349873 * @summary Three-letter time zone IDs should output a deprecated warning * message. * @library /test/lib * @build jdk.test.lib.process.ProcessTools - * @run main ThreeLetterZoneID + * @run junit ThreeLetterZoneID */ import java.util.TimeZone; import jdk.test.lib.process.ProcessTools; +import org.junit.jupiter.api.Test; + public class ThreeLetterZoneID { - public static void main(String... args) throws Exception { + private static final String WARNING = + "WARNING: Use of the three-letter time zone ID \"PST\" is deprecated and it will be removed in a future release"; + + public static void main(String... args) { if (args.length > 0) { TimeZone.getTimeZone("PST"); } else { - checkWarningMessage(); + TimeZone.getDefault(); } } - public static void checkWarningMessage() throws Exception { - ProcessTools.executeTestJava("ThreeLetterZoneID", "dummy") - .shouldContain("Use of the three-letter time zone ID \"PST\" is deprecated and it will be removed in a future release"); + @Test + public void testExplicitGetTimeZone() throws Exception { + ProcessTools.executeTestJava("ThreeLetterZoneID", "dummy").stderrShouldMatch(WARNING); + } + + @Test + public void testSysProp() throws Exception { + ProcessTools.executeTestJava("-Duser.timezone=PST", "ThreeLetterZoneID").stderrShouldMatch(WARNING); } } From 3741c980b865b7122d07655353657d683923c40d Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 13 Feb 2025 22:25:23 +0000 Subject: [PATCH 005/587] 8349883: Locale.LanguageRange.parse("-") throws ArrayIndexOutOfBoundsException Reviewed-by: naoto --- .../share/classes/java/util/Locale.java | 8 +- test/jdk/java/util/Locale/LRToString.java | 64 ---------------- .../java/util/Locale/LanguageRangeTest.java | 76 +++++++++++++++++-- 3 files changed, 71 insertions(+), 77 deletions(-) delete mode 100644 test/jdk/java/util/Locale/LRToString.java diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 1dd4c2feca7..f6abefb29a7 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -3266,9 +3266,7 @@ public final class Locale implements Cloneable, Serializable { * or greater than {@code MAX_WEIGHT} */ public LanguageRange(String range, double weight) { - if (range == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(range); if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) { throw new IllegalArgumentException("weight=" + weight); } @@ -3278,8 +3276,8 @@ public final class Locale implements Cloneable, Serializable { // Do syntax check. boolean isIllFormed = false; String[] subtags = range.split("-"); - if (isSubtagIllFormed(subtags[0], true) - || range.endsWith("-")) { + if (range.endsWith("-") || + isSubtagIllFormed(subtags[0], true)) { isIllFormed = true; } else { for (int i = 1; i < subtags.length; i++) { diff --git a/test/jdk/java/util/Locale/LRToString.java b/test/jdk/java/util/Locale/LRToString.java deleted file mode 100644 index 229507b71b3..00000000000 --- a/test/jdk/java/util/Locale/LRToString.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2016, 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. - */ - -/* - * @test - * @bug 8026766 - * @summary Confirm that LanguageRange.toString() returns an expected result. - * @run junit LRToString - */ - -import java.util.Locale.LanguageRange; -import java.util.stream.Stream; - -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; - -public class LRToString { - - /** - * This test ensures that the output of LanguageRange.toString() - * returns an expected result, that is, the weight is hidden if it is - * equal to 1.0. - */ - @ParameterizedTest - @MethodSource("ranges") - public void toStringTest(String range, double weight) { - LanguageRange lr = new LanguageRange(range, weight); - String expected = weight == 1.0 - ? range - : range+";q="+weight; - assertEquals(lr.toString(), expected); - } - - private static Stream ranges() { - return Stream.of( - Arguments.of("ja", 1.0), - Arguments.of("de", 0.5), - Arguments.of("fr", 0.0) - ); - } -} diff --git a/test/jdk/java/util/Locale/LanguageRangeTest.java b/test/jdk/java/util/Locale/LanguageRangeTest.java index cb0dd9fda66..d269cb9dc15 100644 --- a/test/jdk/java/util/Locale/LanguageRangeTest.java +++ b/test/jdk/java/util/Locale/LanguageRangeTest.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 @@ -20,21 +20,62 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -/** + +/* * @test - * @bug 8253321 - * @summary test LanguageRange class - * @run testng LanguageRangeTest + * @bug 8026766 8253321 8349883 + * @summary LanguageRange tests: toString(), hashCode()/equals(), checking + * for IAE on ill-formed ranges + * @run junit LanguageRangeTest */ import static java.util.Locale.LanguageRange; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.HashMap; +import java.util.Locale; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -@Test public class LanguageRangeTest { + // 8349883: Test endpoints w/ ill-formed language range fail with IAE + @ParameterizedTest + @MethodSource("illegalRanges") + public void illformedRangeTest(String range) { + // static parses + assertThrows(IllegalArgumentException.class, + () -> Locale.LanguageRange.parse(range)); + assertThrows(IllegalArgumentException.class, + () -> Locale.LanguageRange.parse(range, new HashMap<>())); + // ctors + assertThrows(IllegalArgumentException.class, + () -> new Locale.LanguageRange(range)); + assertThrows(IllegalArgumentException.class, + () -> new Locale.LanguageRange(range, Locale.LanguageRange.MIN_WEIGHT)); + } + + private static Stream illegalRanges() { + return Stream.of( + // 8349883 offending range + "-", + // Other general ill-formed test cases + "-foo", + "foo-", + "foo1", + "foo-123456789", + "*-*-", + "" + ); + } + + // 8253321: Ensure invoking hashCode does not affect equals result @Test public void hashCodeTest() { var range1 = new LanguageRange("en-GB", 0); @@ -45,4 +86,23 @@ public class LanguageRangeTest { range2.hashCode(); assertEquals(range1, range2); } + + // 8026766: toString() should hide weight if equal to MAX_WEIGHT (1.0) + @ParameterizedTest + @MethodSource("ranges") + public void toStringTest(String range, double weight) { + LanguageRange lr = new LanguageRange(range, weight); + String expected = weight == 1.0 + ? range + : range+";q="+weight; + assertEquals(lr.toString(), expected); + } + + private static Stream ranges() { + return Stream.of( + Arguments.of("ja", 1.0), + Arguments.of("de", 0.5), + Arguments.of("fr", 0.0) + ); + } } From ff52859d2ad65b97c56dd19323213a0d07be47ae Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 13 Feb 2025 22:53:30 +0000 Subject: [PATCH 006/587] 8285624: jpackage fails to create exe, msi when Windows OS is in FIPS mode Reviewed-by: almatvee --- .../jdk/jpackage/internal/WixPipeline.java | 6 +- .../jdk/jpackage/internal/WixTool.java | 126 ++++++++++++------ .../jdk/jpackage/internal/WixToolset.java | 13 +- 3 files changed, 97 insertions(+), 48 deletions(-) diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java index d7c1b54a48c..be15b202877 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixPipeline.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 @@ -258,6 +258,10 @@ final class WixPipeline { "-out", wixObj.toString() )); + if (toolset.needFipsParameter()) { + cmdline.add("-fips"); + } + addWixVariblesToCommandLine(wixSource.variables, cmdline); execute(cmdline); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index ee98327b032..e2c84ab8be4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.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 @@ -56,25 +56,45 @@ public enum WixTool { this.minimalVersion = minimalVersion; } - static final class ToolInfo { + interface ToolInfo { + Path path(); + DottedVersion version(); + } - ToolInfo(Path path, String version) { - this.path = path; - this.version = DottedVersion.lazy(version); + interface CandleInfo extends ToolInfo { + boolean fips(); + } + + private record DefaultToolInfo(Path path, DottedVersion version) implements ToolInfo { + DefaultToolInfo { + Objects.requireNonNull(path); + Objects.requireNonNull(version); } - final Path path; - final DottedVersion version; + DefaultToolInfo(Path path, String version) { + this(path, DottedVersion.lazy(version)); + } + } + + private record DefaultCandleInfo(Path path, DottedVersion version, boolean fips) implements CandleInfo { + DefaultCandleInfo { + Objects.requireNonNull(path); + Objects.requireNonNull(version); + } + + DefaultCandleInfo(ToolInfo info, boolean fips) { + this(info.path(), info.version(), fips); + } } static WixToolset createToolset() throws ConfigException { Function, Map> conv = lookupResults -> { return lookupResults.stream().filter(ToolLookupResult::isValid).collect(Collectors. groupingBy(lookupResult -> { - return lookupResult.getInfo().version.toString(); + return lookupResult.info().version().toString(); })).values().stream().filter(sameVersionLookupResults -> { Set sameVersionTools = sameVersionLookupResults.stream().map( - ToolLookupResult::getTool).collect(Collectors.toSet()); + ToolLookupResult::tool).collect(Collectors.toSet()); if (sameVersionTools.equals(Set.of(Candle3)) || sameVersionTools.equals(Set.of( Light3))) { // There is only one tool from WiX v3 toolset of some version available. Discard it. @@ -82,10 +102,10 @@ public enum WixTool { } else { return true; } - }).flatMap(List::stream).collect(Collectors.toMap(ToolLookupResult::getTool, - ToolLookupResult::getInfo, (ToolInfo x, ToolInfo y) -> { + }).flatMap(List::stream).collect(Collectors.toMap(ToolLookupResult::tool, + ToolLookupResult::info, (ToolInfo x, ToolInfo y) -> { return Stream.of(x, y).sorted(Comparator.comparing((ToolInfo toolInfo) -> { - return toolInfo.version.toComponentsString(); + return toolInfo.version().toComponentsString(); }).reversed()).findFirst().get(); })); }; @@ -99,8 +119,8 @@ public enum WixTool { }; var toolsInPath = Stream.of(values()).map(tool -> { - return new ToolLookupResult(tool, null); - }).toList(); + return ToolLookupResult.lookup(tool, Optional.empty()); + }).filter(Optional::isPresent).map(Optional::get).toList(); // Try to build a toolset from tools in the PATH first. var toolset = createToolset.apply(toolsInPath); @@ -111,9 +131,9 @@ public enum WixTool { // Look up for WiX tools in known locations. var toolsInKnownWiXDirs = findWixInstallDirs().stream().map(dir -> { return Stream.of(values()).map(tool -> { - return new ToolLookupResult(tool, dir); + return ToolLookupResult.lookup(tool, Optional.of(dir)); }); - }).flatMap(Function.identity()).toList(); + }).flatMap(Function.identity()).filter(Optional::isPresent).map(Optional::get).toList(); // Build a toolset found in the PATH and in known locations. var allFoundTools = Stream.of(toolsInPath, toolsInKnownWiXDirs).flatMap(List::stream).filter( @@ -128,8 +148,8 @@ public enum WixTool { var toolOldVerErr = allFoundTools.stream().map(lookupResult -> { if (lookupResult.versionTooOld) { return new ConfigException(MessageFormat.format(I18N.getString( - "message.wrong-tool-version"), lookupResult.getInfo().path, - lookupResult.getInfo().version, lookupResult.getTool().minimalVersion), + "message.wrong-tool-version"), lookupResult.info().path(), + lookupResult.info().version(), lookupResult.tool().minimalVersion), I18N.getString("error.no-wix-tools.advice")); } else { return null; @@ -144,11 +164,18 @@ public enum WixTool { } } - private static class ToolLookupResult { + private record ToolLookupResult(WixTool tool, ToolInfo info, boolean versionTooOld) { - ToolLookupResult(WixTool tool, Path lookupDir) { + ToolLookupResult { + Objects.requireNonNull(tool); + Objects.requireNonNull(info); + } - final Path toolPath = Optional.ofNullable(lookupDir).map(p -> p.resolve( + static Optional lookup(WixTool tool, Optional lookupDir) { + Objects.requireNonNull(tool); + Objects.requireNonNull(lookupDir); + + final Path toolPath = lookupDir.map(p -> p.resolve( tool.toolFileName)).orElse(tool.toolFileName); final boolean[] tooOld = new boolean[1]; @@ -165,7 +192,19 @@ public enum WixTool { final Function, String> versionParser; if (Set.of(Candle3, Light3).contains(tool)) { - validator.setCommandLine("/?"); + final String printVersionArg; + if (tool == Candle3) { + // Add '-fips' to make "candle.exe" print help message and return + // 0 exit code instead of returning error exit code and printing + // "error CNDL0308 : The Federal Information Processing Standard (FIPS) appears to be enabled on the machine..." + // error message if FIPS is enabled. + // If FIPS is disabled, passing '-fips' parameter still makes + // "candle.exe" print help message and return 0 exit code. + printVersionArg = "-fips"; + } else { + printVersionArg = "-?"; + } + validator.setCommandLine(printVersionArg); versionParser = output -> { String firstLineOfOutput = output.findFirst().orElse(""); int separatorIdx = firstLineOfOutput.lastIndexOf(' '); @@ -186,36 +225,35 @@ public enum WixTool { return parsedVersion[0]; }); - this.tool = tool; if (validator.validate() == null) { // Tool found - this.versionTooOld = tooOld[0]; - this.info = new ToolInfo(toolPath, parsedVersion[0]); + ToolInfo info = new DefaultToolInfo(toolPath, parsedVersion[0]); + if (tool == Candle3) { + // Detect FIPS mode + var fips = false; + try { + final var exec = Executor.of(toolPath.toString(), "-?").setQuiet(true).saveOutput(true); + final var exitCode = exec.execute(); + if (exitCode != 0 /* 308 */) { + final var output = exec.getOutput(); + if (!output.isEmpty() && output.get(0).contains("error CNDL0308")) { + fips = true; + } + } + } catch (IOException ex) { + Log.verbose(ex); + } + info = new DefaultCandleInfo(info, fips); + } + return Optional.of(new ToolLookupResult(tool, info, tooOld[0])); } else { - this.versionTooOld = false; - this.info = null; + return Optional.empty(); } } - WixTool getTool() { - return tool; - } - - ToolInfo getInfo() { - return info; - } - boolean isValid() { - return info != null && !versionTooOld; + return !versionTooOld; } - - boolean isVersionTooOld() { - return versionTooOld; - } - - private final WixTool tool; - private final ToolInfo info; - private final boolean versionTooOld; } private static Path getSystemDir(String envVar, String knownDir) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java index ab433616f44..046dc5efe4e 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixToolset.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 @@ -60,11 +60,18 @@ final class WixToolset { } Path getToolPath(WixTool tool) { - return tools.get(tool).path; + return tools.get(tool).path(); } DottedVersion getVersion() { - return tools.values().iterator().next().version; + return tools.values().iterator().next().version(); + } + + boolean needFipsParameter() { + return tools.values().stream() + .filter(WixTool.CandleInfo.class::isInstance) + .map(WixTool.CandleInfo.class::cast) + .anyMatch(WixTool.CandleInfo::fips); } static WixToolset create(Set requiredTools, Map allTools) { From 57f4c30fb6be1da57c8fcc742b5c36d842eef397 Mon Sep 17 00:00:00 2001 From: Dmitry Chuyko Date: Fri, 14 Feb 2025 07:54:44 +0000 Subject: [PATCH 007/587] 8347917: AArch64: Enable upper GPR registers in C1 Reviewed-by: aph --- src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp | 15 ++++---- .../cpu/aarch64/c1_FrameMap_aarch64.cpp | 34 +++++++++++++++++-- .../cpu/aarch64/c1_FrameMap_aarch64.hpp | 27 ++++++++++++--- .../cpu/aarch64/c1_LinearScan_aarch64.hpp | 8 ++--- .../cpu/aarch64/c1_Runtime1_aarch64.cpp | 17 ++++++---- src/hotspot/share/c1/c1_Compiler.cpp | 2 +- src/hotspot/share/c1/c1_FrameMap.hpp | 3 +- 7 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp index 9470caae9fe..5f65ef5f043 100644 --- a/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_Defs_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -41,16 +41,17 @@ enum { // registers enum { + pd_nof_available_regs = 32, pd_nof_cpu_regs_frame_map = Register::number_of_registers, // number of GP registers used during code emission pd_nof_fpu_regs_frame_map = FloatRegister::number_of_registers, // number of FP registers used during code emission - pd_nof_caller_save_cpu_regs_frame_map = 19 - 2 /* rscratch1 and rscratch2 */ R18_RESERVED_ONLY(- 1), // number of registers killed by calls + pd_nof_caller_save_cpu_regs_frame_map = pd_nof_available_regs, // number of registers killed by calls pd_nof_caller_save_fpu_regs_frame_map = 32, // number of registers killed by calls - pd_first_callee_saved_reg = 19 - 2 /* rscratch1 and rscratch2 */ R18_RESERVED_ONLY(- 1), - pd_last_callee_saved_reg = 26 - 2 /* rscratch1 and rscratch2 */ R18_RESERVED_ONLY(- 1), + pd_first_callee_saved_reg = pd_nof_available_regs - 1, + pd_last_callee_saved_reg = pd_first_callee_saved_reg - 1, // in fact, no callee saved regs - pd_last_allocatable_cpu_reg = 16 R18_RESERVED_ONLY(- 1), + pd_last_allocatable_cpu_reg = pd_nof_available_regs - 1, pd_nof_cpu_regs_reg_alloc = pd_last_allocatable_cpu_reg + 1, // number of registers that are visible to register allocator @@ -60,9 +61,9 @@ enum { pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of registers visible to linear scan pd_nof_xmm_regs_linearscan = 0, // don't have vector registers pd_first_cpu_reg = 0, - pd_last_cpu_reg = 16 R18_RESERVED_ONLY(- 1), + pd_last_cpu_reg = pd_nof_available_regs - 1, pd_first_byte_reg = 0, - pd_last_byte_reg = 16 R18_RESERVED_ONLY(- 1), + pd_last_byte_reg = pd_last_cpu_reg, pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, pd_last_fpu_reg = pd_first_fpu_reg + 31, diff --git a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp index 051b2ff47c1..9d30092b45a 100644 --- a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp @@ -193,9 +193,26 @@ void FrameMap::initialize() { map_register(i, r25); r25_opr = LIR_OprFact::single_cpu(i); i++; map_register(i, r26); r26_opr = LIR_OprFact::single_cpu(i); i++; - map_register(i, r27); r27_opr = LIR_OprFact::single_cpu(i); i++; // rheapbase + // r27 is allocated conditionally. With compressed oops it holds + // the heapbase value and is not visible to the allocator. + bool preserve_rheapbase = i >= nof_caller_save_cpu_regs(); + if (!preserve_rheapbase) { + map_register(i, r27); r27_opr = LIR_OprFact::single_cpu(i); i++; // rheapbase + } + + if(!PreserveFramePointer) { + map_register(i, r29); r29_opr = LIR_OprFact::single_cpu(i); i++; + } + + // The unallocatable registers are at the end + + if (preserve_rheapbase) { + map_register(i, r27); r27_opr = LIR_OprFact::single_cpu(i); i++; // rheapbase + } map_register(i, r28); r28_opr = LIR_OprFact::single_cpu(i); i++; // rthread - map_register(i, r29); r29_opr = LIR_OprFact::single_cpu(i); i++; // rfp + if(PreserveFramePointer) { + map_register(i, r29); r29_opr = LIR_OprFact::single_cpu(i); i++; // rfp + } map_register(i, r30); r30_opr = LIR_OprFact::single_cpu(i); i++; // lr map_register(i, r31_sp); sp_opr = LIR_OprFact::single_cpu(i); i++; // sp map_register(i, r8); r8_opr = LIR_OprFact::single_cpu(i); i++; // rscratch1 @@ -239,6 +256,19 @@ void FrameMap::initialize() { _caller_save_cpu_regs[16] = r18_opr; #endif + _caller_save_cpu_regs[17 R18_RESERVED_ONLY(-1)] = r19_opr; + _caller_save_cpu_regs[18 R18_RESERVED_ONLY(-1)] = r20_opr; + _caller_save_cpu_regs[19 R18_RESERVED_ONLY(-1)] = r21_opr; + _caller_save_cpu_regs[20 R18_RESERVED_ONLY(-1)] = r22_opr; + _caller_save_cpu_regs[21 R18_RESERVED_ONLY(-1)] = r23_opr; + _caller_save_cpu_regs[22 R18_RESERVED_ONLY(-1)] = r24_opr; + _caller_save_cpu_regs[23 R18_RESERVED_ONLY(-1)] = r25_opr; + _caller_save_cpu_regs[24 R18_RESERVED_ONLY(-1)] = r26_opr; + + if (nof_caller_save_cpu_regs() > 25 R18_RESERVED_ONLY(-1)) { + _caller_save_cpu_regs[25 R18_RESERVED_ONLY(-1)] = r27_opr; + } + for (int i = 0; i < 8; i++) { _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); } diff --git a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.hpp index 3ec3ce1f679..4d783418429 100644 --- a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -140,8 +140,27 @@ static bool is_caller_save_register (LIR_Opr opr) { return true; } static bool is_caller_save_register (Register r) { return true; } - static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; } - static int last_cpu_reg() { return pd_last_cpu_reg; } - static int last_byte_reg() { return pd_last_byte_reg; } + static int adjust_reg_range(int range, bool exclude_fp = true) { + // r27 is not allocatable when compressed oops is on and heapbase is not + // zero, compressed klass pointers doesn't use r27 after JDK-8234794 + if (UseCompressedOops && (CompressedOops::base() != nullptr)) { + range -= 1; + } + + // r29 is not allocatable when PreserveFramePointer is on, + // but fp saving is handled in MacroAssembler::build_frame()/remove_frame() + if (exclude_fp) { + range -= 1; + } + + // rscratch registers r8, r9 + // r28=rthread, r30=lr, r31=sp + // r18 on masOS/Windows + return range - 5 R18_RESERVED_ONLY(-1); + } + + static int nof_caller_save_cpu_regs() { return adjust_reg_range(pd_nof_caller_save_cpu_regs_frame_map); } + static int last_cpu_reg() { return adjust_reg_range(pd_last_cpu_reg, PreserveFramePointer); } + static int last_byte_reg() { return adjust_reg_range(pd_last_byte_reg, PreserveFramePointer); } #endif // CPU_AARCH64_C1_FRAMEMAP_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/c1_LinearScan_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LinearScan_aarch64.hpp index 01a4d27532a..4062adf4154 100644 --- a/src/hotspot/cpu/aarch64/c1_LinearScan_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LinearScan_aarch64.hpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -41,9 +41,9 @@ inline bool LinearScan::requires_adjacent_regs(BasicType type) { inline bool LinearScan::is_caller_save(int assigned_reg) { assert(assigned_reg >= 0 && assigned_reg < nof_regs, "should call this only for registers"); - if (assigned_reg < pd_first_callee_saved_reg) + if (assigned_reg < FrameMap::nof_caller_save_cpu_regs()) return true; - if (assigned_reg > pd_last_callee_saved_reg && assigned_reg < pd_first_callee_saved_fpu_reg) + if (assigned_reg >= pd_first_fpu_reg && assigned_reg < pd_first_callee_saved_fpu_reg) return true; if (assigned_reg > pd_last_callee_saved_fpu_reg && assigned_reg < pd_last_fpu_reg) return true; @@ -66,7 +66,7 @@ inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) { return true; } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || cur->type() == T_ADDRESS || cur->type() == T_METADATA) { _first_reg = pd_first_cpu_reg; - _last_reg = pd_last_allocatable_cpu_reg; + _last_reg = FrameMap::last_cpu_reg(); return true; } return false; diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 7082b4110cd..063918ee20b 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -257,15 +257,18 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); OopMap* oop_map = new OopMap(frame_size_in_slots, 0); - for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { - Register r = as_Register(i); - if (r == rthread || (i <= 18 && i != rscratch1->encoding() && i != rscratch2->encoding())) { - int sp_offset = cpu_reg_save_offsets[i]; - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), - r->as_VMReg()); - } + for (int i = 0; i < FrameMap::nof_caller_save_cpu_regs(); i++) { + LIR_Opr opr = FrameMap::caller_save_cpu_reg_at(i); + Register r = opr->as_register(); + int reg_num = r->encoding(); + int sp_offset = cpu_reg_save_offsets[reg_num]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(cpu_reg_save_offsets[reg_num]), r->as_VMReg()); } + Register r = rthread; + int reg_num = r->encoding(); + oop_map->set_callee_saved(VMRegImpl::stack2reg(cpu_reg_save_offsets[reg_num]), r->as_VMReg()); + if (save_fpu_registers) { for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { FloatRegister r = as_FloatRegister(i); diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index 7d2e6ee75d9..a26320589c4 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -49,8 +49,8 @@ Compiler::Compiler() : AbstractCompiler(compiler_c1) { void Compiler::init_c1_runtime() { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); - Runtime1::initialize(buffer_blob); FrameMap::initialize(); + Runtime1::initialize(buffer_blob); // initialize data structures ValueType::initialize(); GraphBuilder::initialize(); diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index 1fd7dd3edff..dab3aa6e734 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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,6 +32,7 @@ #include "runtime/frame.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "oops/compressedOops.hpp" class ciMethod; class CallingConvention; From fa1bd2344e60163bf247c668b94f98c50c72855a Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Fri, 14 Feb 2025 12:24:36 +0000 Subject: [PATCH 008/587] 8343802: Prevent NULL usage backsliding Reviewed-by: kbarrett --- test/hotspot/jtreg/TEST.groups | 6 +- test/hotspot/jtreg/sources/TestNoNULL.java | 140 +++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/sources/TestNoNULL.java diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index c3bc2351ac8..abbcc90f8c7 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -629,12 +629,16 @@ tier1_serviceability = \ -serviceability/sa/TestJmapCore.java \ -serviceability/sa/TestJmapCoreMetaspace.java +tier1_sources = \ + sources + tier1 = \ :tier1_common \ :tier1_compiler \ :tier1_gc \ :tier1_runtime \ - :tier1_serviceability + :tier1_serviceability \ + :tier1_sources tier2 = \ :hotspot_tier2_runtime \ diff --git a/test/hotspot/jtreg/sources/TestNoNULL.java b/test/hotspot/jtreg/sources/TestNoNULL.java new file mode 100644 index 00000000000..73a415466fe --- /dev/null +++ b/test/hotspot/jtreg/sources/TestNoNULL.java @@ -0,0 +1,140 @@ +/* + * 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 8343802 + * @summary Test prevent NULL backsliding in hotspot code and tests + * @run main TestNoNULL + */ + +import java.io.IOException; +import java.nio.charset.MalformedInputException; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +public class TestNoNULL { + private static final Set excludedSourceFiles = new HashSet<>(); + private static final Set excludedTestFiles = new HashSet<>(); + private static final Set excludedTestExtensions = Set.of(".c", ".java", ".jar", ".class", ".zip"); + private static final Pattern NULL_PATTERN = Pattern.compile("\\bNULL\\b"); + private static Path dir = Paths.get(System.getProperty("test.src")); + private static int errorCount = 0; + + public static void main(String[] args) throws IOException { + int maxIter = 20; + while (maxIter-- > 0 && dir != null && !Files.exists(dir.resolve("src"))) { + dir = dir.getParent(); + } + + if (dir == null) { + throw new RuntimeException("Could not locate the 'src' directory within 20 parent directories."); + } + + Path srcPath = dir.resolve("src").resolve("hotspot"); + Path testPath = dir.resolve("test").resolve("hotspot"); + + initializeExcludedPaths(dir); + + if (Files.exists(srcPath)) { + processFiles(srcPath, excludedSourceFiles, Set.of()); + } + processFiles(testPath, excludedTestFiles, excludedTestExtensions); + + if (errorCount > 0) { + throw new RuntimeException("Test found " + errorCount + " usages of 'NULL' in source files. See errors above."); + } + } + + private static void initializeExcludedPaths(Path rootDir) { + List sourceExclusions = List.of( + "src/hotspot/share/prims/jvmti.xml", + "src/hotspot/share/prims/jvmti.xsl", + "src/hotspot/share/utilities/globalDefinitions_visCPP.hpp" + ); + + List testExclusions = List.of( + "test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/README", + "test/hotspot/jtreg/vmTestbase/nsk/share/jni/README" + ); + + sourceExclusions.forEach(relativePath -> + excludedSourceFiles.add(rootDir.resolve(relativePath).normalize().toString())); + testExclusions.forEach(relativePath -> + excludedTestFiles.add(rootDir.resolve(relativePath).normalize().toString())); + } + + private static void processFiles(Path directory, Set excludedFiles, Set excludedExtensions) throws IOException { + Files.walkFileTree(directory, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + if (isIncluded(file, excludedFiles, excludedExtensions)) { + checkForNull(file); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) { + return FileVisitResult.CONTINUE; + } + }); + } + + private static boolean isIncluded(Path file, Set excludedFiles, Set excludedExtensions) { + String filePath = file.normalize().toString(); + + if (excludedFiles.contains(filePath)) { + return false; + } + + for (String ext : excludedExtensions) { + if (filePath.endsWith(ext)) { + return false; + } + } + + return true; + } + + private static void checkForNull(Path path) { + try { + List lines = Files.readAllLines(path, StandardCharsets.UTF_8); + for (int i = 0; i < lines.size(); i++) { + if (NULL_PATTERN.matcher(lines.get(i)).find()) { + errorCount++; + System.err.printf("Error: 'NULL' found in %s at line %d:%n%s%n", path, i + 1, lines.get(i)); + } + } + } catch (MalformedInputException e) { + System.err.println("Skipping binary file: " + path); + } catch (IOException e) { + System.err.printf("Skipping unreadable file: " + path); + } + } +} From 19c0ce43e258d00d77314d76a361feb2069a5af1 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 14 Feb 2025 12:55:36 +0000 Subject: [PATCH 009/587] 8349751: AIX build failure after upgrade pipewire to 1.3.81 Reviewed-by: mdoerr --- .../unix/native/libpipewire/include/spa/utils/endian.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h b/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h index 2d002d4538c..0a8f62c73ce 100644 --- a/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h +++ b/src/java.desktop/unix/native/libpipewire/include/spa/utils/endian.h @@ -18,6 +18,10 @@ #define bswap_16 _byteswap_ushort #define bswap_32 _byteswap_ulong #define bswap_64 _byteswap_uint64 +#elif defined(AIX) +#include +#define __BIG_ENDIAN BIG_ENDIAN +#define __BYTE_ORDER BIG_ENDIAN #else #include #include From db42a48dc5d49783545757bd34aeead851f9288e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 14 Feb 2025 13:12:30 +0000 Subject: [PATCH 010/587] 8350011: Convert jpackage test lib tests in JUnit format Reviewed-by: almatvee --- .../jpackage/helpers-test/TEST.properties | 9 +++ .../jdk/jpackage/test/AnnotationsTest.java | 55 +++++++------ .../test/DirectoryContentVerifierTest.java | 49 +++++------- .../jdk/jpackage/test/JUnitAdapter.java | 79 +++++++++++++++++++ .../jdk/jpackage/test/JavaAppDescTest.java | 15 +--- .../jdk/jpackage/test/TKitTest.java | 51 +++--------- .../jdk/jpackage/test/TestSuite.java | 63 --------------- .../helpers/jdk/jpackage/test/Main.java | 7 +- .../jdk/jpackage/test/TestBuilder.java | 44 +++++++++-- .../jdk/jpackage/test/TestInstance.java | 12 +-- 10 files changed, 199 insertions(+), 185 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/TEST.properties create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java delete mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java diff --git a/test/jdk/tools/jpackage/helpers-test/TEST.properties b/test/jdk/tools/jpackage/helpers-test/TEST.properties new file mode 100644 index 00000000000..1830ea05443 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/TEST.properties @@ -0,0 +1,9 @@ +JUnit.dirs = . + +lib.dirs = /test/jdk/tools/jpackage/helpers /test/jdk/tools/jpackage/helpers-test + +modules=jdk.jpackage/jdk.jpackage.internal:+open \ + jdk.jpackage/jdk.jpackage.internal.util:+open \ + jdk.jpackage/jdk.jpackage.internal.util.function:+open \ + java.base/jdk.internal.util \ + jdk.jlink/jdk.tools.jlink.internal diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index d439452ffa0..cd7914b917b 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -23,6 +23,9 @@ package jdk.jpackage.test; import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.lang.reflect.Method; import java.nio.file.Path; import java.time.LocalDate; @@ -32,34 +35,34 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; -import static java.util.stream.Collectors.toMap; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Parameters; import jdk.jpackage.test.Annotations.Test; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +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; -/* - * @test - * @summary Test jpackage test library's annotation processor - * @library /test/jdk/tools/jpackage/helpers - * @build jdk.jpackage.test.* - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.AnnotationsTest - */ -public class AnnotationsTest { +public class AnnotationsTest extends JUnitAdapter { - public static void main(String... args) { - runTests(List.of(BasicTest.class, ParameterizedInstanceTest.class)); - for (var os : OperatingSystem.values()) { - try { - TestBuilderConfig.setOperatingSystem(os); - TKit.log("Current operating system: " + os); - runTests(List.of(IfOSTest.class)); - } finally { - TestBuilderConfig.setDefaults(); - } + @ParameterizedTest + @ValueSource(classes = {BasicTest.class, ParameterizedInstanceTest.class}) + public void test(Class clazz, @TempDir Path workDir) { + runTest(clazz, workDir); + } + + @ParameterizedTest + @EnumSource(OperatingSystem.class) + public void testIfOSTest(OperatingSystem os, @TempDir Path workDir) { + try { + TestBuilderConfig.setOperatingSystem(os); + TKit.log("Current operating system: " + os); + runTest(IfOSTest.class, workDir); + } finally { + TestBuilderConfig.setDefaults(); } } @@ -300,22 +303,18 @@ public class AnnotationsTest { }); } - private static void runTests(List> tests) { + private static void runTest(Class test, Path workDir) { ACTUAL_TEST_DESCS.get().clear(); - var expectedTestDescs = tests.stream() - .map(AnnotationsTest::getExpectedTestDescs) - .flatMap(x -> x) + var expectedTestDescs = getExpectedTestDescs(test) // Collect in the map to check for collisions for free .collect(toMap(x -> x, x -> "")) .keySet(); - var args = tests.stream().map(test -> { - return String.format("--jpt-run=%s", test.getName()); - }).toArray(String[]::new); + var args = new String[] { String.format("--jpt-run=%s", test.getName()) }; try { - Main.main(args); + Main.main(TestBuilder.build().workDirRoot(workDir), args); assertRecordedTestDescs(expectedTestDescs); } catch (Throwable t) { t.printStackTrace(System.err); diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java index f7471988051..ea69a525df9 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/DirectoryContentVerifierTest.java @@ -22,7 +22,11 @@ */ package jdk.jpackage.test; -import java.io.IOException; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.CONTAINS; +import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.MATCH; +import static jdk.jpackage.test.TKit.assertAssert; + import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -30,16 +34,12 @@ import java.util.Collection; import java.util.List; import java.util.Set; import java.util.function.BiConsumer; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; -import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.CONTAINS; -import static jdk.jpackage.test.DirectoryContentVerifierTest.AssertType.MATCH; import jdk.jpackage.test.TKit.DirectoryContentVerifier; -import static jdk.jpackage.test.TKit.assertAssert; -public class DirectoryContentVerifierTest { +public class DirectoryContentVerifierTest extends JUnitAdapter { enum AssertType { MATCH(DirectoryContentVerifier::match), @@ -105,7 +105,6 @@ public class DirectoryContentVerifierTest { private boolean success = true; } - @Parameters public static Collection input() { List data = new ArrayList<>(); buildArgs().applyVariantsTo(data); @@ -127,35 +126,23 @@ public class DirectoryContentVerifierTest { return data; } - public DirectoryContentVerifierTest(String[] expectedPaths, String[] actualPaths, - AssertType assertOp, Boolean success) { - this.expectedPaths = conv(expectedPaths); - this.actualPaths = conv(actualPaths); - this.assertOp = assertOp; - this.success = success; - } - @Test - public void test() { - TKit.withTempDirectory("basedir", this::test); - } + @ParameterSupplier("input") + public void test(String[] expectedPaths, String[] actualPaths, AssertType assertOp, Boolean success) { + final var expectedPathsAsSet = conv(expectedPaths); + final var actualPathsAsSet = conv(actualPaths); + TKit.withTempDirectory("basedir", basedir -> { + for (var path : actualPathsAsSet) { + Files.createFile(basedir.resolve(path)); + } - private void test(Path basedir) throws IOException { - for (var path : actualPaths) { - Files.createFile(basedir.resolve(path)); - } + var testee = TKit.assertDirectoryContent(basedir); - var testee = TKit.assertDirectoryContent(basedir); - - assertAssert(success, () -> assertOp.assertFunc.accept(testee, expectedPaths)); + assertAssert(success, () -> assertOp.assertFunc.accept(testee, expectedPathsAsSet)); + }); } private static Set conv(String... paths) { return Stream.of(paths).map(Path::of).collect(toSet()); } - - private final Set expectedPaths; - private final Set actualPaths; - private final AssertType assertOp; - private final boolean success; } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.java new file mode 100644 index 00000000000..7bf1f57a254 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitAdapter.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. + */ +package jdk.jpackage.test; + +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.List; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public class JUnitAdapter { + + JUnitAdapter() { + 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()); + } + } + + @Test + void runJPackageTests(@TempDir Path workDir) throws Throwable { + if (!getClass().equals(JUnitAdapter.class)) { + Main.main(TestBuilder.build().workDirRoot(workDir), new String [] { + "--jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault", + "--jpt-run=" + getClass().getName() + }); + } + } + + static List captureJPackageTestLog(ThrowingRunnable runnable) { + final var buf = new ByteArrayOutputStream(); + try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { + TKit.withExtraLogStream(runnable, ps); + } + + try (final var in = new ByteArrayInputStream(buf.toByteArray()); + final var reader = new InputStreamReader(in, StandardCharsets.UTF_8); + final var bufReader = new BufferedReader(reader)) { + return bufReader.lines().map(line -> { + // Skip timestamp + return line.substring(LOG_MSG_TIMESTAMP_LENGTH); + }).toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); +} 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 a2cde44f009..50f1992f796 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 @@ -26,18 +26,14 @@ import java.nio.file.Path; import java.util.List; import java.util.function.UnaryOperator; import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameters; -public class JavaAppDescTest { - - public JavaAppDescTest(JavaAppDesc expectedAppDesc, JavaAppDesc actualAppDesc) { - this.expectedAppDesc = expectedAppDesc; - this.actualAppDesc = actualAppDesc; - } +public class JavaAppDescTest extends JUnitAdapter { @Test - public void test() { + @ParameterSupplier("input") + public void test(JavaAppDesc expectedAppDesc, JavaAppDesc actualAppDesc) { TKit.assertEquals(expectedAppDesc.toString(), actualAppDesc.toString(), null); TKit.assertTrue(expectedAppDesc.equals(actualAppDesc), null); } @@ -53,7 +49,6 @@ public class JavaAppDescTest { appDesc).classFilePath().toString(), null); } - @Parameters public static List input() { return List.of(new Object[][] { createTestCase("", "hello.jar:Hello"), @@ -93,6 +88,4 @@ public class JavaAppDescTest { return new JavaAppDesc[] {expectedAppDesc, actualAppDesc}; } - private final JavaAppDesc expectedAppDesc; - private final JavaAppDesc actualAppDesc; } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index 98a7d873190..4cddb1eb912 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -22,28 +22,22 @@ */ package jdk.jpackage.test; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; +import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.stream.Stream; -import jdk.jpackage.test.Annotations.Parameters; -import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.internal.util.function.ThrowingRunnable; -import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; -public class TKitTest { +public class TKitTest extends JUnitAdapter { - @Parameters public static Collection assertTestsData() { List data = new ArrayList<>(); @@ -191,12 +185,9 @@ public class TKitTest { } } - public TKitTest(MethodCallConfig methodCall) { - this.methodCall = methodCall; - } - @Test - public void test() { + @ParameterSupplier("assertTestsData") + public void test(MethodCallConfig methodCall) { runAssertWithExpectedLogOutput(() -> { methodCall.method.invoke(null, methodCall.args); }, methodCall.expectFail, methodCall.expectLog); @@ -211,23 +202,11 @@ public class TKitTest { private static void runWithExpectedLogOutput(ThrowingRunnable action, String... expectLogStrings) { - final var buf = new ByteArrayOutputStream(); - try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { - TKit.withExtraLogStream(action, ps); - } finally { - toRunnable(() -> { - var output = new BufferedReader(new InputStreamReader( - new ByteArrayInputStream(buf.toByteArray()), - StandardCharsets.UTF_8)).lines().map(line -> { - // Skip timestamp - return line.substring(LOG_MSG_TIMESTAMP_LENGTH); - }).toList(); - if (output.size() == 1 && expectLogStrings.length == 1) { - TKit.assertEquals(expectLogStrings[0], output.get(0), null); - } else { - TKit.assertStringListEquals(List.of(expectLogStrings), output, null); - } - }).run(); + final var output = JUnitAdapter.captureJPackageTestLog(action); + if (output.size() == 1 && expectLogStrings.length == 1) { + TKit.assertEquals(expectLogStrings[0], output.get(0), null); + } else { + TKit.assertStringListEquals(List.of(expectLogStrings), output, null); } } @@ -237,8 +216,4 @@ public class TKitTest { } return msg; } - - private final MethodCallConfig methodCall; - - private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java deleted file mode 100644 index f9dda851414..00000000000 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 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 jdk.jpackage.test; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -/* - * @test - * @summary Unit tests for jpackage test library - * @library /test/jdk/tools/jpackage/helpers - * @library /test/jdk/tools/jpackage/helpers-test - * @build jdk.jpackage.test.* - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.TestSuite - */ - -public final class TestSuite { - public static void main(String args[]) throws Throwable { - final var pkgName = TestSuite.class.getPackageName(); - final var javaSuffix = ".java"; - final var testSrcNameSuffix = "Test" + javaSuffix; - - final var unitTestDir = TKit.TEST_SRC_ROOT.resolve(Path.of("helpers-test", pkgName.split("\\."))); - - final List runTestArgs = new ArrayList<>(); - runTestArgs.addAll(List.of(args)); - - try (var javaSources = Files.list(unitTestDir)) { - runTestArgs.addAll(javaSources.filter(path -> { - return path.getFileName().toString().endsWith(testSrcNameSuffix); - }).map(path -> { - var filename = path.getFileName().toString(); - return String.join(".", pkgName, filename.substring(0, filename.length() - javaSuffix.length())); - }).map(testClassName -> { - return "--jpt-run=" + testClassName; - }).toList()); - } - - Main.main(runTestArgs.toArray(String[]::new)); - } -} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java index 5919d8361c4..439479a666e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Main.java @@ -38,10 +38,15 @@ import static jdk.jpackage.test.TestBuilder.CMDLINE_ARG_PREFIX; public final class Main { + public static void main(String args[]) throws Throwable { + main(TestBuilder.build(), args); + } + + public static void main(TestBuilder.Builder builder, String args[]) throws Throwable { boolean listTests = false; List tests = new ArrayList<>(); - try (TestBuilder testBuilder = new TestBuilder(tests::add)) { + try (TestBuilder testBuilder = builder.testConsumer(tests::add).create()) { Deque argsAsList = new ArrayDeque<>(List.of(args)); while (!argsAsList.isEmpty()) { var arg = argsAsList.pop(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 195d1ea3936..17c0f131af3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -23,9 +23,13 @@ package jdk.jpackage.test; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.test.TestMethodSupplier.MethodQuery.fromQualifiedMethodName; + import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; @@ -38,14 +42,12 @@ import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.test.Annotations.AfterEach; import jdk.jpackage.test.Annotations.BeforeEach; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.internal.util.function.ThrowingConsumer; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; -import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.test.TestMethodSupplier.InvalidAnnotationException; -import static jdk.jpackage.test.TestMethodSupplier.MethodQuery.fromQualifiedMethodName; final class TestBuilder implements AutoCloseable { @@ -54,8 +56,35 @@ final class TestBuilder implements AutoCloseable { flushTestGroup(); } - TestBuilder(Consumer testConsumer) { + static Builder build() { + return new Builder(); + } + + final static class Builder { + private Builder() { + } + + Builder testConsumer(Consumer v) { + testConsumer = v; + return this; + } + + Builder workDirRoot(Path v) { + workDirRoot = v; + return this; + } + + TestBuilder create() { + return new TestBuilder(testConsumer, workDirRoot); + } + + private Consumer testConsumer; + private Path workDirRoot = Path.of(""); + } + + private TestBuilder(Consumer testConsumer, Path workDirRoot) { this.testMethodSupplier = TestBuilderConfig.getDefault().createTestMethodSupplier(); + this.workDirRoot = Objects.requireNonNull(workDirRoot); argProcessors = Map.of( CMDLINE_ARG_PREFIX + "after-run", arg -> getJavaMethodsFromArg(arg).map( @@ -88,7 +117,7 @@ final class TestBuilder implements AutoCloseable { CMDLINE_ARG_PREFIX + "dry-run", arg -> dryRun = true ); - this.testConsumer = testConsumer; + this.testConsumer = Objects.requireNonNull(testConsumer); clear(); } @@ -188,7 +217,7 @@ final class TestBuilder implements AutoCloseable { } TestInstance test = new TestInstance(testBody, curBeforeActions, - curAfterActions, dryRun); + curAfterActions, dryRun, workDirRoot); if (includedTests == null) { trace(String.format("Create: %s", test.fullName())); } @@ -348,6 +377,7 @@ final class TestBuilder implements AutoCloseable { private final TestMethodSupplier testMethodSupplier; private final Map> argProcessors; private final Consumer testConsumer; + private final Path workDirRoot; private List testGroup; private List> beforeActions; private List> afterActions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java index dd1e46eb09e..ca9523d5760 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestInstance.java @@ -150,7 +150,7 @@ final class TestInstance implements ThrowingRunnable { private String instanceArgs; } - TestInstance(ThrowingRunnable testBody) { + TestInstance(ThrowingRunnable testBody, Path workDirRoot) { assertCount = 0; this.testConstructor = (unused) -> null; this.testBody = (unused) -> testBody.run(); @@ -158,11 +158,11 @@ final class TestInstance implements ThrowingRunnable { this.afterActions = Collections.emptyList(); this.testDesc = TestDesc.createBuilder().get(); this.dryRun = false; - this.workDir = createWorkDirName(testDesc); + this.workDir = workDirRoot.resolve(createWorkDirPath(testDesc)); } TestInstance(MethodCall testBody, List> beforeActions, - List> afterActions, boolean dryRun) { + List> afterActions, boolean dryRun, Path workDirRoot) { assertCount = 0; this.testConstructor = v -> ((MethodCall)v).newInstance(); this.testBody = testBody; @@ -170,7 +170,7 @@ final class TestInstance implements ThrowingRunnable { this.afterActions = afterActions; this.testDesc = testBody.createDescription(); this.dryRun = dryRun; - this.workDir = createWorkDirName(testDesc); + this.workDir = workDirRoot.resolve(createWorkDirPath(testDesc)); } void notifyAssert() { @@ -276,8 +276,8 @@ final class TestInstance implements ThrowingRunnable { return false; } - private static Path createWorkDirName(TestDesc testDesc) { - Path result = Path.of("."); + private static Path createWorkDirPath(TestDesc testDesc) { + Path result = Path.of(""); if (!isCalledByJavatest()) { result = result.resolve(testDesc.clazz.getSimpleName()); } From 742e735d7f6c4ee9ca5a4d290c59d7d6ec1f7635 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 14 Feb 2025 13:53:06 +0000 Subject: [PATCH 011/587] 8349858: Print compilation task before blocking compiler thread for shutdown Reviewed-by: kvn, chagedorn --- src/hotspot/share/compiler/compileBroker.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index c2e2e2d607f..c34d9eb785e 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2074,7 +2074,21 @@ void CompileBroker::maybe_block() { if (PrintCompilation && (Verbose || WizardMode)) tty->print_cr("compiler thread " INTPTR_FORMAT " poll detects block request", p2i(Thread::current())); #endif + // If we are executing a task during the request to block, report the task + // before disappearing. + CompilerThread* thread = CompilerThread::current(); + if (thread != nullptr) { + CompileTask* task = thread->task(); + if (task != nullptr) { + if (PrintCompilation) { + task->print(tty, "blocked"); + } + task->print_ul("blocked"); + } + } + // Go to VM state and block for final VM shutdown safepoint. ThreadInVMfromNative tivfn(JavaThread::current()); + assert(false, "Should never unblock from TIVNM entry"); } } From 9ea81d90175c11460d0efa83f82ceccc4ee2cd3b Mon Sep 17 00:00:00 2001 From: anass baya Date: Fri, 14 Feb 2025 15:19:09 +0000 Subject: [PATCH 012/587] 8349351: Combine Screen Inset Tests into a Single File Reviewed-by: honkar, dnguyen, aivanov --- .../MultiScreenInsetsTest.java | 118 -------------- .../ScreenInsetsTest/ScreenInsetsTest.java | 147 ++++++++---------- 2 files changed, 69 insertions(+), 196 deletions(-) delete mode 100644 test/jdk/java/awt/Multiscreen/MultiScreenInsetsTest/MultiScreenInsetsTest.java diff --git a/test/jdk/java/awt/Multiscreen/MultiScreenInsetsTest/MultiScreenInsetsTest.java b/test/jdk/java/awt/Multiscreen/MultiScreenInsetsTest/MultiScreenInsetsTest.java deleted file mode 100644 index 301d4f2caa3..00000000000 --- a/test/jdk/java/awt/Multiscreen/MultiScreenInsetsTest/MultiScreenInsetsTest.java +++ /dev/null @@ -1,118 +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. - */ - -/* - @test - @key headful - @bug 8020443 6899304 - @summary Test to check if the frame is created on the specified GraphicsDevice - and if getScreenInsets()returns the correct values across multiple monitors. - @library /test/lib - @build jdk.test.lib.Platform jtreg.SkippedException - @run main MultiScreenInsetsTest - */ - -import java.awt.Frame; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Insets; -import java.awt.Rectangle; -import java.awt.Toolkit; - -import jdk.test.lib.Platform; -import jtreg.SkippedException; - -public class MultiScreenInsetsTest { - private static final int SIZE = 100; - // Allow a margin tolerance of 1 pixel due to scaling - private static final int MARGIN_TOLERANCE = 1; - - public static void main(String[] args) throws InterruptedException { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] gds = ge.getScreenDevices(); - if (gds.length < 2) { - throw new SkippedException("It's a multi-screen test... skipping!"); - } - - for (int screen = 0; screen < gds.length; ++screen) { - GraphicsDevice gd = gds[screen]; - GraphicsConfiguration gc = gd.getDefaultConfiguration(); - Rectangle bounds = gc.getBounds(); - Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); - System.out.println("Screen #" + screen); - System.out.println("Screen Bounds: " + bounds); - System.out.println("Insets: " + insets); - - Frame frame = new Frame(gc); - frame.setLocation(bounds.x + (bounds.width - SIZE) / 2, - bounds.y + (bounds.height - SIZE) / 2); - frame.setSize(SIZE, SIZE); - - /* - * On Windows, undecorated maximized frames are placed over the taskbar. - * Use a decorated frame instead. - */ - if (Platform.isWindows()) { - frame.setUndecorated(false); - } else { - frame.setUndecorated(true); - } - - frame.setVisible(true); - - // Maximize Frame to reach the struts - frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); - Thread.sleep(2000); - - Rectangle frameBounds = frame.getBounds(); - System.out.println("Frame bounds: " + frameBounds); - - frame.dispose(); - - /* - * On Windows, the top-left corner of an undecorated maximized frame - * may have negative coordinates (x, y). - * Adjust the frame bounds accordingly. - */ - if (frameBounds.x < bounds.x) { - frameBounds.width -= (bounds.x - frameBounds.x) * 2; - frameBounds.x = bounds.x; - } - if (frameBounds.y < bounds.y) { - frameBounds.height -= (bounds.y - frameBounds.y) * 2; - frameBounds.y = bounds.y; - } - System.out.println("Adjusted Frame bounds: " + frameBounds); - - if (bounds.x + insets.left != frameBounds.x - || bounds.y + insets.top != frameBounds.y - || Math.abs((bounds.width - insets.right - insets.left) - frameBounds.width) > MARGIN_TOLERANCE - || Math.abs((bounds.height - insets.bottom - insets.top) - frameBounds.height) > MARGIN_TOLERANCE) { - throw new RuntimeException("Test FAILED! Wrong screen #" + - screen + " insets: " + insets); - } - } - System.out.println("Test PASSED!"); - } -} diff --git a/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java b/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java index 70ea3e379d7..2cd05b08fc5 100644 --- a/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java +++ b/test/jdk/java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, 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 @@ -22,15 +22,14 @@ */ /* - @test - @key headful - @bug 4737732 - @summary Tests that Toolkit.getScreenInsets() returns correct insets - @author artem.ananiev: area=awt.toplevel - @library ../../regtesthelpers - @build Util - @run main ScreenInsetsTest -*/ + * @test + * @key headful + * @bug 8020443 6899304 4737732 + * @summary Tests that Toolkit.getScreenInsets() returns correct insets + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main ScreenInsetsTest + */ import java.awt.Frame; import java.awt.GraphicsConfiguration; @@ -40,85 +39,77 @@ import java.awt.Insets; import java.awt.Rectangle; import java.awt.Toolkit; -import test.java.awt.regtesthelpers.Util; +import jdk.test.lib.Platform; -public class ScreenInsetsTest -{ - public static void main(String[] args) - { - boolean passed = true; +public class ScreenInsetsTest { + private static final int SIZE = 100; + // Allow a margin tolerance of 1 pixel due to scaling + private static final int MARGIN_TOLERANCE = 1; + public static void main(String[] args) throws InterruptedException { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gds = ge.getScreenDevices(); - for (GraphicsDevice gd : gds) { + + for (int screen = 0; screen < gds.length; ++screen) { + GraphicsDevice gd = gds[screen]; GraphicsConfiguration gc = gd.getDefaultConfiguration(); - Rectangle gcBounds = gc.getBounds(); - Insets gcInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); - int left = gcInsets.left; - int right = gcInsets.right; - int bottom = gcInsets.bottom; - int top = gcInsets.top; - if (left < 0 || right < 0 || bottom < 0 || top < 0) { - throw new RuntimeException("Negative value: " + gcInsets); - } - int maxW = gcBounds.width / 3; - int maxH = gcBounds.height / 3; - if (left > maxW || right > maxW || bottom > maxH || top > maxH) { - throw new RuntimeException("Big value: " + gcInsets); + Rectangle bounds = gc.getBounds(); + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + int workAreaWidth = bounds.width - insets.left - insets.right; + int workAreaHeight = bounds.height - insets.top - insets.bottom; + System.out.println("Screen #" + screen); + System.out.println("Screen Bounds: " + bounds); + System.out.println("Insets: " + insets); + + Frame frame = new Frame(gc); + frame.setLocation(bounds.x + (bounds.width - SIZE) / 2, + bounds.y + (bounds.height - SIZE) / 2); + frame.setSize(SIZE, SIZE); + + /* + * On Windows, undecorated maximized frames are placed over the taskbar. + * Use a decorated frame instead. + */ + if (Platform.isWindows()) { + frame.setUndecorated(false); + } else { + frame.setUndecorated(true); } - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) - { - // this state is used in the test - sorry - continue; + frame.setVisible(true); + + // Maximize Frame to reach the struts + frame.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); + Thread.sleep(2000); + + Rectangle frameBounds = frame.getBounds(); + System.out.println("Frame bounds: " + frameBounds); + + frame.dispose(); + + /* + * On Windows, the top-left corner of an undecorated maximized frame + * may have negative coordinates (x, y). + * Adjust the frame bounds accordingly. + */ + if (frameBounds.x < bounds.x) { + frameBounds.width -= (bounds.x - frameBounds.x) * 2; + frameBounds.x = bounds.x; } - - Frame f = new Frame("Test", gc); - f.setUndecorated(true); - f.setBounds(gcBounds.x + 100, gcBounds.y + 100, 320, 240); - f.setVisible(true); - Util.waitForIdle(null); - - f.setExtendedState(Frame.MAXIMIZED_BOTH); - Util.waitForIdle(null); - - Rectangle fBounds = f.getBounds(); - // workaround: on Windows maximized windows have negative coordinates - if (fBounds.x < gcBounds.x) - { - fBounds.width -= (gcBounds.x - fBounds.x) * 2; // width is decreased - fBounds.x = gcBounds.x; + if (frameBounds.y < bounds.y) { + frameBounds.height -= (bounds.y - frameBounds.y) * 2; + frameBounds.y = bounds.y; } - if (fBounds.y < gcBounds.y) - { - fBounds.height -= (gcBounds.y - fBounds.y) * 2; // height is decreased - fBounds.y = gcBounds.y; - } - Insets expected = new Insets(fBounds.y - gcBounds.y, - fBounds.x - gcBounds.x, - gcBounds.y + gcBounds.height - fBounds.y - fBounds.height, - gcBounds.x + gcBounds.width - fBounds.x - fBounds.width); + System.out.println("Adjusted Frame bounds: " + frameBounds); - // On Windows 10 and up system allows undecorated maximized windows - // to be placed over the taskbar so calculated insets might - // be smaller than reported ones depending on the taskbar position - if (gcInsets.top < expected.top - || gcInsets.bottom < expected.bottom - || gcInsets.left < expected.left - || gcInsets.right < expected.right) - { - passed = false; - System.err.println("Wrong insets for GraphicsConfig: " + gc); - System.err.println("\tExpected: " + expected); - System.err.println("\tActual: " + gcInsets); + if (bounds.x + insets.left != frameBounds.x + || bounds.y + insets.top != frameBounds.y + || Math.abs(workAreaWidth - frameBounds.width) > MARGIN_TOLERANCE + || Math.abs(workAreaHeight - frameBounds.height) > MARGIN_TOLERANCE) { + throw new RuntimeException("Test FAILED! Wrong screen #" + + screen + " insets: " + insets); } - - f.dispose(); - } - - if (!passed) - { - throw new RuntimeException("TEST FAILED: Toolkit.getScreenInsets() returns wrong value for some screens"); } + System.out.println("Test PASSED!"); } } From 0414dcec118fce24037ca1a6b00561c0ce4c6953 Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Fri, 14 Feb 2025 15:28:59 +0000 Subject: [PATCH 013/587] 8349812: (fs) Files.newByteChannel with empty path name and CREATE_NEW throws unexpected exception Reviewed-by: bpb --- .../sun/nio/fs/UnixChannelFactory.java | 4 +-- test/jdk/java/nio/file/Files/SBC.java | 28 +++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java b/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java index dec13180f2f..1e04291d458 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.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 @@ -195,7 +195,7 @@ class UnixChannelFactory { // create flags if (flags.createNew) { - byte[] pathForSysCall = path.asByteArray(); + byte[] pathForSysCall = path.getByteArrayForSysCalls(); // throw exception if file name is "." to avoid confusing error if ((pathForSysCall[pathForSysCall.length-1] == '.') && diff --git a/test/jdk/java/nio/file/Files/SBC.java b/test/jdk/java/nio/file/Files/SBC.java index 7aa04b18462..1e7d463644b 100644 --- a/test/jdk/java/nio/file/Files/SBC.java +++ b/test/jdk/java/nio/file/Files/SBC.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 + * @bug 4313887 8349812 * @summary Unit test for java.nio.file.Files.newByteChannel * @library .. * @modules jdk.unsupported @@ -63,6 +63,7 @@ public class SBC { badCombinations(dir); unsupportedOptions(dir); nullTests(dir); + emptyPathTest(); } finally { TestUtil.removeAll(dir); @@ -424,6 +425,29 @@ public class SBC { } catch (NullPointerException x) { } } + static void emptyPathTest() throws Exception { + try { + Files.newByteChannel(Path.of(""), WRITE, CREATE_NEW); + throw new RuntimeException("FileAlreadyExistsException expected"); + } catch (FileAlreadyExistsException x) { + } catch (AccessDeniedException x) { + /* Thrown on Windows only */ + } + + try { + Files.newByteChannel(Path.of(""), WRITE, CREATE, DELETE_ON_CLOSE); + throw new RuntimeException("FileSystemException expected"); + } catch (FileSystemException x) { } + + try { + Files.newByteChannel(Path.of(""), WRITE, LinkOption.NOFOLLOW_LINKS); + throw new RuntimeException("FileSystemException expected"); + } catch (FileSystemException x) { } + + try (var channel = Files.newByteChannel(Path.of(""), READ, LinkOption.NOFOLLOW_LINKS)) { + } catch(AccessDeniedException x) { /* Thrown on Windows only */ } + } + static void write(WritableByteChannel wbc, String msg) throws IOException { ByteBuffer buf = ByteBuffer.wrap(msg.getBytes()); while (buf.hasRemaining()) From 2a90b90a95da91b71cd90caeafae5adaee621ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=C5=A0ipka?= Date: Fri, 14 Feb 2025 16:18:47 +0000 Subject: [PATCH 014/587] 8346117: Add test annotation Reviewed-by: coffeys --- test/jdk/sun/nio/cs/Test6392804.java | 1 + test/jdk/sun/nio/cs/TestUTF_32.java | 1 + 2 files changed, 2 insertions(+) diff --git a/test/jdk/sun/nio/cs/Test6392804.java b/test/jdk/sun/nio/cs/Test6392804.java index a89c2aa5333..a98428c3e7f 100644 --- a/test/jdk/sun/nio/cs/Test6392804.java +++ b/test/jdk/sun/nio/cs/Test6392804.java @@ -22,6 +22,7 @@ */ /* + @test @bug 6392804 @summary Decoder fails to detect decoding error */ diff --git a/test/jdk/sun/nio/cs/TestUTF_32.java b/test/jdk/sun/nio/cs/TestUTF_32.java index 3179768957e..ba042494fd2 100644 --- a/test/jdk/sun/nio/cs/TestUTF_32.java +++ b/test/jdk/sun/nio/cs/TestUTF_32.java @@ -22,6 +22,7 @@ */ /* + @test @bug 6346419 @summary Check correctness of the UTF-32 and its variant charsets */ From 38322407cd1664115e975c7fd9cb61e40d9557b5 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 14 Feb 2025 16:40:08 +0000 Subject: [PATCH 015/587] 8348594: Shenandoah: Do not penalize for degeneration when not the fault of triggering heuristic Reviewed-by: phh, wkemper --- .../shenandoahAdaptiveHeuristics.cpp | 17 +++++++++-- .../shenandoahAdaptiveHeuristics.hpp | 5 ++++ .../shenandoahAggressiveHeuristics.cpp | 1 + .../shenandoahCompactHeuristics.cpp | 2 ++ .../heuristics/shenandoahHeuristics.cpp | 16 +++++++++- .../heuristics/shenandoahHeuristics.hpp | 29 +++++++++++++++++++ .../shenandoahPassiveHeuristics.cpp | 1 + .../heuristics/shenandoahStaticHeuristics.cpp | 1 + .../heuristics/shenandoahYoungHeuristics.cpp | 5 ++++ .../gc/shenandoah/shenandoahControlThread.cpp | 2 ++ .../share/gc/shenandoah/shenandoahFreeSet.hpp | 1 + .../shenandoah/shenandoahRegulatorThread.cpp | 6 ++++ 12 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 02a363d2392..7a624d4d4a4 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -240,6 +240,10 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { log_debug(gc)("should_start_gc? available: %zu, soft_max_capacity: %zu" ", allocated: %zu", available, capacity, allocated); + if (_start_gc_is_pending) { + return true; + } + // Track allocation rate even if we decide to start a cycle for other reasons. double rate = _allocation_rate.sample(allocated); _last_trigger = OTHER; @@ -249,6 +253,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); + accept_trigger_with_type(OTHER); return true; } @@ -261,6 +266,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { _gc_times_learned + 1, max_learn, byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold)); + accept_trigger_with_type(OTHER); return true; } } @@ -292,7 +298,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom), byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties), byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); - _last_trigger = RATE; + accept_trigger_with_type(RATE); return true; } @@ -303,11 +309,16 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { byte_size_in_proper_unit(rate), proper_unit_for_byte_size(rate), byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom), _spike_threshold_sd); - _last_trigger = SPIKE; + accept_trigger_with_type(SPIKE); return true; } - return ShenandoahHeuristics::should_start_gc(); + if (ShenandoahHeuristics::should_start_gc()) { + _start_gc_is_pending = true; + return true; + } else { + return false; + } } void ShenandoahAdaptiveHeuristics::adjust_last_trigger_parameters(double amount) { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp index 5ee10c6bebf..a47024f3a4b 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp @@ -145,6 +145,11 @@ protected: // this threshold, or we might consider this when dynamically resizing generations // in the generational case. Controlled by global flag ShenandoahMinFreeThreshold. size_t min_free_threshold(); + + inline void accept_trigger_with_type(Trigger trigger_type) { + _last_trigger = trigger_type; + ShenandoahHeuristics::accept_trigger(); + } }; #endif // SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHADAPTIVEHEURISTICS_HPP diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp index 63a4e74fb1d..a833e39631c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp @@ -52,6 +52,7 @@ void ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(Shena bool ShenandoahAggressiveHeuristics::should_start_gc() { log_trigger("Start next cycle immediately"); + accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp index 9d98ff6bf73..9d211314474 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp @@ -61,6 +61,7 @@ bool ShenandoahCompactHeuristics::should_start_gc() { log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold)); + accept_trigger(); return true; } @@ -69,6 +70,7 @@ bool ShenandoahCompactHeuristics::should_start_gc() { log_trigger("Allocated since last cycle (%zu%s) is larger than allocation threshold (%zu%s)", byte_size_in_proper_unit(bytes_allocated), proper_unit_for_byte_size(bytes_allocated), byte_size_in_proper_unit(threshold_bytes_allocated), proper_unit_for_byte_size(threshold_bytes_allocated)); + accept_trigger(); return true; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index fe0d82a72e3..f5bc74b2b1b 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -46,6 +46,9 @@ int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) { } ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) : + _start_gc_is_pending(false), + _declined_trigger_count(0), + _most_recent_declined_trigger_count(0), _space_info(space_info), _region_data(nullptr), _guaranteed_gc_interval(0), @@ -184,10 +187,14 @@ void ShenandoahHeuristics::record_cycle_end() { } bool ShenandoahHeuristics::should_start_gc() { + if (_start_gc_is_pending) { + return true; + } // Perform GC to cleanup metaspace if (has_metaspace_oom()) { // Some of vmTestbase/metaspace tests depend on following line to count GC cycles log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold)); + accept_trigger(); return true; } @@ -196,10 +203,11 @@ bool ShenandoahHeuristics::should_start_gc() { if (last_time_ms > _guaranteed_gc_interval) { log_trigger("Time since last GC (%.0f ms) is larger than guaranteed interval (%zu ms)", last_time_ms, _guaranteed_gc_interval); + accept_trigger(); return true; } } - + decline_trigger(); return false; } @@ -211,6 +219,12 @@ void ShenandoahHeuristics::adjust_penalty(intx step) { assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100, "In range before adjustment: %zd", _gc_time_penalties); + if ((_most_recent_declined_trigger_count <= Penalty_Free_Declinations) && (step > 0)) { + // Don't penalize if heuristics are not responsible for a negative outcome. Allow Penalty_Free_Declinations following + // previous GC for self calibration without penalty. + step = 0; + } + intx new_val = _gc_time_penalties + step; if (new_val < 0) { new_val = 0; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index 8bd5c7775c4..d036a62a32c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -69,6 +69,9 @@ class ShenandoahHeuristics : public CHeapObj { static const intx Degenerated_Penalty = 10; // how much to penalize average GC duration history on Degenerated GC static const intx Full_Penalty = 20; // how much to penalize average GC duration history on Full GC + // How many times can I decline a trigger opportunity without being penalized for excessive idle span before trigger? + static const size_t Penalty_Free_Declinations = 16; + #ifdef ASSERT enum UnionTag { is_uninitialized, is_garbage, is_live_data @@ -78,6 +81,18 @@ class ShenandoahHeuristics : public CHeapObj { protected: static const uint Moving_Average_Samples = 10; // Number of samples to store in moving averages + bool _start_gc_is_pending; // True denotes that GC has been triggered, so no need to trigger again. + size_t _declined_trigger_count; // This counts how many times since previous GC finished that this + // heuristic has answered false to should_start_gc(). + size_t _most_recent_declined_trigger_count; + ; // This represents the value of _declined_trigger_count as captured at the + // moment the most recent GC effort was triggered. In case the most recent + // concurrent GC effort degenerates, the value of this variable allows us to + // differentiate between degeneration because heuristic was overly optimistic + // in delaying the trigger vs. degeneration for other reasons (such as the + // most recent GC triggered "immediately" after previous GC finished, but the + // free headroom has already been depleted). + class RegionData { private: ShenandoahHeapRegion* _region; @@ -167,6 +182,16 @@ protected: void adjust_penalty(intx step); + inline void accept_trigger() { + _most_recent_declined_trigger_count = _declined_trigger_count; + _declined_trigger_count = 0; + _start_gc_is_pending = true; + } + + inline void decline_trigger() { + _declined_trigger_count++; + } + public: ShenandoahHeuristics(ShenandoahSpaceInfo* space_info); virtual ~ShenandoahHeuristics(); @@ -185,6 +210,10 @@ public: virtual bool should_start_gc(); + inline void cancel_trigger_request() { + _start_gc_is_pending = false; + } + virtual bool should_degenerate_cycle(); virtual void record_success_concurrent(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp index a0f209b0d20..b5e9cc433ea 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp @@ -36,6 +36,7 @@ ShenandoahPassiveHeuristics::ShenandoahPassiveHeuristics(ShenandoahSpaceInfo* sp bool ShenandoahPassiveHeuristics::should_start_gc() { // Never do concurrent GCs. + decline_trigger(); return false; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp index 8918d1b3d94..e6f60dc1c83 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp @@ -55,6 +55,7 @@ bool ShenandoahStaticHeuristics::should_start_gc() { log_trigger("Free (%zu%s) is below minimum threshold (%zu%s)", byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), byte_size_in_proper_unit(threshold_available), proper_unit_for_byte_size(threshold_available)); + accept_trigger(); return true; } return ShenandoahHeuristics::should_start_gc(); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index 8e983f62ce1..9f8c6225d23 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -119,6 +119,8 @@ bool ShenandoahYoungHeuristics::should_start_gc() { if (old_generation->is_preparing_for_mark() || old_generation->is_concurrent_mark_in_progress()) { size_t old_time_elapsed = size_t(old_heuristics->elapsed_cycle_time() * 1000); if (old_time_elapsed < ShenandoahMinimumOldTimeMs) { + // Do not decline_trigger() when waiting for minimum quantum of Old-gen marking. It is not at our discretion + // to trigger at this time. return false; } } @@ -140,6 +142,7 @@ bool ShenandoahYoungHeuristics::should_start_gc() { // Detect unsigned arithmetic underflow assert(promo_potential < heap->capacity(), "Sanity"); log_trigger("Expedite promotion of " PROPERFMT, PROPERFMTARGS(promo_potential)); + accept_trigger(); return true; } @@ -150,9 +153,11 @@ bool ShenandoahYoungHeuristics::should_start_gc() { // candidates, but has not completed. There is no point in trying to start the young cycle before the old // cycle completes. log_trigger("Expedite mixed evacuation of %zu regions", mixed_candidates); + accept_trigger(); return true; } + // Don't decline_trigger() here That was done in ShenandoahAdaptiveHeuristics::should_start_gc() return false; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 7208a092682..1ddfb6b7054 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -131,6 +131,8 @@ void ShenandoahControlThread::run_service() { // GC is starting, bump the internal ID update_gc_id(); + heuristics->cancel_trigger_request(); + heap->reset_bytes_allocated_since_gc_start(); MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 45b33e5253b..9f4d1d222b5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -437,6 +437,7 @@ public: inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t available() const { assert(used() <= capacity(), "must use less than capacity"); return capacity() - used(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index 7ed2803f877..a684e8ff228 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -65,6 +65,7 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { if (request_concurrent_gc(GLOBAL)) { // Some of vmTestbase/metaspace tests depend on following line to count GC cycles _global_heuristics->log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold)); + _global_heuristics->cancel_trigger_request(); } } else { if (_young_heuristics->should_start_gc()) { @@ -72,14 +73,17 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { // begins with a 'bootstrap' cycle that will also collect young. if (start_old_cycle()) { log_debug(gc)("Heuristics request for old collection accepted"); + _young_heuristics->cancel_trigger_request(); } else if (request_concurrent_gc(YOUNG)) { log_debug(gc)("Heuristics request for young collection accepted"); + _young_heuristics->cancel_trigger_request(); } } } } else if (mode == ShenandoahGenerationalControlThread::servicing_old) { if (start_young_cycle()) { log_debug(gc)("Heuristics request to interrupt old for young collection accepted"); + _young_heuristics->cancel_trigger_request(); } } @@ -93,8 +97,10 @@ void ShenandoahRegulatorThread::regulate_young_and_global_cycles() { if (_control_thread->gc_mode() == ShenandoahGenerationalControlThread::none) { if (start_global_cycle()) { log_debug(gc)("Heuristics request for global collection accepted."); + _global_heuristics->cancel_trigger_request(); } else if (start_young_cycle()) { log_debug(gc)("Heuristics request for young collection accepted."); + _young_heuristics->cancel_trigger_request(); } } From ba6c96599aac1a6c08cb66c611474f83bbc9b260 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 14 Feb 2025 16:41:26 +0000 Subject: [PATCH 016/587] 8348595: GenShen: Fix generational free-memory no-progress check Reviewed-by: phh, xpeng --- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 2 +- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 3 +++ .../share/gc/shenandoah/shenandoahFullGC.cpp | 2 +- .../share/gc/shenandoah/shenandoahMetrics.cpp | 24 ++++++++++++++++--- .../share/gc/shenandoah/shenandoahMetrics.hpp | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 95d8543f46a..17af519392e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -303,7 +303,7 @@ void ShenandoahDegenGC::op_degenerated() { // Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles, // because that probably means the heap is overloaded and/or fragmented. - if (!metrics.is_good_progress()) { + if (!metrics.is_good_progress(_generation)) { heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc); op_degenerated_futile(); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 9f4d1d222b5..d4754167236 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -435,6 +435,9 @@ public: // Acquire heap lock and log status, assuming heap lock is not acquired by the caller. void log_status_under_lock(); + // Note that capacity is the number of regions that had available memory at most recent rebuild. It is not the + // entire size of the young or global generation. (Regions within the generation that were fully utilized at time of + // rebuild are not counted as part of capacity.) inline size_t capacity() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); } inline size_t used() const { return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index c83de047e97..5f8543ca751 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -119,7 +119,7 @@ void ShenandoahFullGC::op_full(GCCause::Cause cause) { metrics.snap_after(); - if (metrics.is_good_progress()) { + if (metrics.is_good_progress(heap->global_generation())) { heap->notify_gc_progress(); } else { // Nothing to do. Tell the allocation path that we have failed to make diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp index 201bcdc9e39..32386e6aec0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp @@ -43,10 +43,28 @@ void ShenandoahMetricsSnapshot::snap_after() { _ef_after = _heap->free_set()->external_fragmentation(); } -bool ShenandoahMetricsSnapshot::is_good_progress() { +// For degenerated GC, generation is Young in generational mode, Global in non-generational mode. +// For full GC, generation is always Global. +// +// Note that the size of the chosen collection set is proportional to the relevant generation's collection set. +// Note also that the generation size may change following selection of the collection set, as a side effect +// of evacuation. Evacuation may promote objects, causing old to grow and young to shrink. Or this may be a +// mixed evacuation. When old regions are evacuated, this typically allows young to expand. In all of these +// various scenarios, the purpose of asking is_good_progress() is to determine if there is enough memory available +// within young generation to justify making an attempt to perform a concurrent collection. For this reason, we'll +// use the current size of the generation (which may not be different than when the collection set was chosen) to +// assess how much free memory we require in order to consider the most recent GC to have had good progress. + +bool ShenandoahMetricsSnapshot::is_good_progress(ShenandoahGeneration* generation) { // Under the critical threshold? - size_t free_actual = _heap->free_set()->available(); - size_t free_expected = _heap->max_capacity() / 100 * ShenandoahCriticalFreeThreshold; + ShenandoahFreeSet* free_set = _heap->free_set(); + size_t free_actual = free_set->available(); + + // ShenandoahCriticalFreeThreshold is expressed as a percentage. We multiple this percentage by 1/100th + // of the generation capacity to determine whether the available memory within the generation exceeds the + // critical threshold. + size_t free_expected = (generation->max_capacity() / 100) * ShenandoahCriticalFreeThreshold; + bool prog_free = free_actual >= free_expected; log_info(gc, ergo)("%s progress for free space: %zu%s, need %zu%s", prog_free ? "Good" : "Bad", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp index 202d90bb1be..20d8ebfd595 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp @@ -40,7 +40,7 @@ public: void snap_before(); void snap_after(); - bool is_good_progress(); + bool is_good_progress(ShenandoahGeneration *generation); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMETRICS_HPP From b6443f6ff96707f67552df41c01d18c193560223 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 14 Feb 2025 19:40:47 +0000 Subject: [PATCH 017/587] 8348347: Cleanup JavaThread subclass support in SA Reviewed-by: kevinw, sspitsyn --- .../hotspot/runtime/AttachListenerThread.java | 41 ----------------- .../jvm/hotspot/runtime/CompilerThread.java | 17 +++++-- .../runtime/DeoptimizeObjectsALotThread.java | 42 ------------------ ...DedupThread.java => HiddenJavaThread.java} | 10 +++-- .../sun/jvm/hotspot/runtime/JavaThread.java | 20 +-------- .../jvm/hotspot/runtime/JvmtiAgentThread.java | 44 ------------------- .../runtime/MonitorDeflationThread.java | 41 ----------------- .../hotspot/runtime/NotificationThread.java | 37 ---------------- .../jvm/hotspot/runtime/ServiceThread.java | 41 ----------------- .../sun/jvm/hotspot/runtime/Thread.java | 9 ---- .../jvm/hotspot/runtime/ThreadStackTrace.java | 5 +-- .../sun/jvm/hotspot/runtime/Threads.java | 39 ++++++++-------- .../sun/jvm/hotspot/tools/StackTrace.java | 31 +++++++------ .../sun/jvm/hotspot/ui/JavaThreadsPanel.java | 4 +- .../hotspot/utilities/PointerLocation.java | 17 +++---- 15 files changed, 63 insertions(+), 335 deletions(-) delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AttachListenerThread.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeoptimizeObjectsALotThread.java rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/{StringDedupThread.java => HiddenJavaThread.java} (84%) delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NotificationThread.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AttachListenerThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AttachListenerThread.java deleted file mode 100644 index 55d440f79fd..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/AttachListenerThread.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 sun.jvm.hotspot.runtime; - -import java.io.*; - -import sun.jvm.hotspot.debugger.Address; - -public class AttachListenerThread extends JavaThread { - - public AttachListenerThread (Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - - public boolean isAttachListenerThread() { return true; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java index a54ad3f30f6..e5c3ec30887 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -65,8 +65,17 @@ public class CompilerThread extends JavaThread { super(addr); } - public boolean isJavaThread() { return false; } - public boolean isHiddenFromExternalView() { return true; } - public boolean isCompilerThread() { return true; } + @Override + public boolean isHiddenFromExternalView() { + /* + * See JDK-8348317. CompilerThreads are sometimes hidden and sometimes not. They + * are not when JVMCI is enabled and a compiler implemented in java is running + * on the CompilerThread. This is hard for SA to determine, and not something a customer + * is likely to ever run across or care about, so by default all CompilerThreads + * are considered to be hidden. However, we allow this behaviour to be overridden + * in case the user has a need to make the CompilerThreads visible. + */ + return !Boolean.getBoolean("sun.jvm.hotspot.runtime.CompilerThread.visible"); + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeoptimizeObjectsALotThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeoptimizeObjectsALotThread.java deleted file mode 100644 index b79d43948a2..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/DeoptimizeObjectsALotThread.java +++ /dev/null @@ -1,42 +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 sun.jvm.hotspot.runtime; - -import java.io.*; - -import sun.jvm.hotspot.debugger.Address; - -public class DeoptimizeObjectsALotThread extends JavaThread { - - public DeoptimizeObjectsALotThread (Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - public boolean isHiddenFromExternalView() { return true; } - - public boolean isDeoptimizeObjectsALotThread() { return true; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StringDedupThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/HiddenJavaThread.java similarity index 84% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StringDedupThread.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/HiddenJavaThread.java index 3922a2275da..a11aab54bd5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StringDedupThread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/HiddenJavaThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 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 @@ -26,11 +26,13 @@ package sun.jvm.hotspot.runtime; import sun.jvm.hotspot.debugger.Address; -public class StringDedupThread extends JavaThread { - public StringDedupThread(Address addr) { +public class HiddenJavaThread extends JavaThread { + + public HiddenJavaThread(Address addr) { super(addr); } - public boolean isJavaThread() { return false; } + @Override public boolean isHiddenFromExternalView() { return true; } + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java index 0efd1d94ca1..d92f464f0d2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.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 @@ -33,13 +33,6 @@ import sun.jvm.hotspot.utilities.*; import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; -/** This is an abstract class because there are certain OS- and - CPU-specific operations (like the setting and getting of the last - Java frame pointer) which need to be factored out. These - operations are implemented by, for example, - SolarisSPARCJavaThread, and the concrete subclasses are - instantiated by the JavaThreadFactory in the Threads class. */ - public class JavaThread extends Thread { private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null; @@ -58,6 +51,7 @@ public class JavaThread extends Thread { private static CIntegerField monitorOwnerIDField; private static long oopPtrSize; + // For accessing platform dependent functionality private static JavaThreadPDAccess access; // JavaThreadStates read from underlying process @@ -133,16 +127,6 @@ public class JavaThread extends Thread { this.access = access; } - /** NOTE: for convenience, this differs in definition from the underlying VM. - Only "pure" JavaThreads return true; CompilerThreads, - JVMDIDebuggerThreads return false. - FIXME: - consider encapsulating platform-specific functionality in an - object instead of using inheritance (which is the primary reason - we can't traverse CompilerThreads, etc; didn't want to have, for - example, "SolarisSPARCCompilerThread".) */ - public boolean isJavaThread() { return true; } - public boolean isExiting () { return (getTerminated() == EXITING) || isTerminated(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java deleted file mode 100644 index 79d66fb2454..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JvmtiAgentThread.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.runtime; - -import java.io.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; - -/** FIXME: should be in ../prims dir if that directory existed; for - now keep it in runtime dir */ - -public class JvmtiAgentThread extends JavaThread { - public JvmtiAgentThread(Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - - public boolean isJvmtiAgentThread() { return true; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java deleted file mode 100644 index 8bd6492f880..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java +++ /dev/null @@ -1,41 +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. - * - */ - -package sun.jvm.hotspot.runtime; - -import java.io.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; - -public class MonitorDeflationThread extends JavaThread { - public MonitorDeflationThread(Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - public boolean isHiddenFromExternalView() { return true; } - public boolean isMonitorDeflationThread() { return true; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NotificationThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NotificationThread.java deleted file mode 100644 index 2173d4e7191..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/NotificationThread.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.runtime; - - -import sun.jvm.hotspot.debugger.Address; - -public class NotificationThread extends JavaThread { - public NotificationThread(Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java deleted file mode 100644 index d4e28404176..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ServiceThread.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.runtime; - -import java.io.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; - -public class ServiceThread extends JavaThread { - public ServiceThread(Address addr) { - super(addr); - } - - public boolean isJavaThread() { return false; } - public boolean isHiddenFromExternalView() { return true; } - public boolean isServiceThread() { return true; } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java index f9f2f578928..22bc02a06d9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java @@ -80,16 +80,7 @@ public class Thread extends VMObject { } public boolean isVMThread() { return false; } - public boolean isJavaThread() { return false; } - public boolean isCompilerThread() { return false; } - public boolean isCodeCacheSweeperThread() { return false; } public boolean isHiddenFromExternalView() { return false; } - public boolean isJvmtiAgentThread() { return false; } - public boolean isWatcherThread() { return false; } - public boolean isServiceThread() { return false; } - public boolean isMonitorDeflationThread() { return false; } - public boolean isAttachListenerThread() { return false; } - public boolean isDeoptimizeObjectsALotThread() { return false; } /** Memory operations */ public void oopsDo(AddressVisitor oopVisitor) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadStackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadStackTrace.java index 6d3a8109f1b..4053becd916 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadStackTrace.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadStackTrace.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 @@ -46,9 +46,6 @@ public class ThreadStackTrace { } public void dumpStack(int maxDepth) { - if (!thread.isJavaThread()) { - return; - } try { for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { StackFrameInfo frame = new StackFrameInfo(vf); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java index a894380a76f..b6935963de9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -142,21 +142,29 @@ public class Threads { } virtualConstructor = new VirtualConstructor(db); - // Add mappings for all known thread types + + /* + * Add mappings for JavaThread types + */ + virtualConstructor.addMapping("JavaThread", JavaThread.class); + if (!VM.getVM().isCore()) { virtualConstructor.addMapping("CompilerThread", CompilerThread.class); } - virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class); - virtualConstructor.addMapping("ServiceThread", ServiceThread.class); - virtualConstructor.addMapping("MonitorDeflationThread", MonitorDeflationThread.class); - virtualConstructor.addMapping("NotificationThread", NotificationThread.class); - virtualConstructor.addMapping("StringDedupThread", StringDedupThread.class); - virtualConstructor.addMapping("AttachListenerThread", AttachListenerThread.class); - /* Only add DeoptimizeObjectsALotThread if it is actually present in the type database. */ + // These are all the visible JavaThread subclasses that execute java code. + virtualConstructor.addMapping("JvmtiAgentThread", JavaThread.class); + virtualConstructor.addMapping("NotificationThread", JavaThread.class); + virtualConstructor.addMapping("AttachListenerThread", JavaThread.class); + + // These are all the hidden JavaThread subclasses that don't execute java code. + virtualConstructor.addMapping("StringDedupThread", HiddenJavaThread.class); + virtualConstructor.addMapping("ServiceThread", HiddenJavaThread.class); + virtualConstructor.addMapping("MonitorDeflationThread", HiddenJavaThread.class); + // Only add DeoptimizeObjectsALotThread if it is actually present in the type database. if (db.lookupType("DeoptimizeObjectsALotThread", false) != null) { - virtualConstructor.addMapping("DeoptimizeObjectsALotThread", DeoptimizeObjectsALotThread.class); + virtualConstructor.addMapping("DeoptimizeObjectsALotThread", HiddenJavaThread.class); } } @@ -164,17 +172,6 @@ public class Threads { _list = VMObjectFactory.newObject(ThreadsList.class, threadListField.getValue()); } - /** NOTE: this returns objects of type JavaThread or one if its subclasses: - CompilerThread, JvmtiAgentThread, NotificationThread, MonitorDeflationThread, - StringDedupThread, AttachListenerThread, DeoptimizeObjectsALotThread and - ServiceThread. Most operations (fetching the top frame, etc.) are only - allowed to be performed on a "pure" JavaThread. For this reason, - {@link sun.jvm.hotspot.runtime.JavaThread#isJavaThread} has been - changed from the definition in the VM (which returns true for - all of these thread types) to return true for JavaThreads and - false for the seven subclasses. FIXME: should reconsider the - inheritance hierarchy; see {@link - sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */ public JavaThread getJavaThreadAt(int i) { if (i < _list.length()) { return createJavaThreadWrapper(_list.getJavaThreadAddressAt(i)); @@ -258,7 +255,7 @@ public class Threads { List pendingThreads = new ArrayList<>(); for (int i = 0; i < getNumberOfThreads(); i++) { JavaThread thread = getJavaThreadAt(i); - if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) { + if (thread.isHiddenFromExternalView()) { continue; } ObjectMonitor pending = thread.getCurrentPendingMonitor(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java index 2dfdd1ec5a9..266dd852742 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java @@ -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 @@ -73,7 +73,7 @@ public class StackTrace extends Tool { Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { JavaThread cur = threads.getJavaThreadAt(i); - if (cur.isJavaThread()) { + if (!cur.isHiddenFromExternalView()) { cur.printThreadInfoOn(tty); try { int count = 0; @@ -126,20 +126,19 @@ public class StackTrace extends Tool { concLocksPrinter.print(cur); tty.println(); } - } - } - } - catch (AddressException e) { - System.err.println("Error accessing address 0x" + Long.toHexString(e.getAddress())); - e.printStackTrace(); - } - } + } + } + } catch (AddressException e) { + System.err.println("Error accessing address 0x" + Long.toHexString(e.getAddress())); + e.printStackTrace(); + } + } - public static void main(String[] args) { - StackTrace st = new StackTrace(); - st.execute(args); - } + public static void main(String[] args) { + StackTrace st = new StackTrace(); + st.execute(args); + } - private boolean verbose; - private boolean concurrentLocks; + private boolean verbose; + private boolean concurrentLocks; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java index 587cba545a4..3946db8938e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -464,7 +464,7 @@ public class JavaThreadsPanel extends SAPanel implements ActionListener { Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { JavaThread t = threads.getJavaThreadAt(i); - if (t.isJavaThread()) { + if (!t.isHiddenFromExternalView()) { cachedThreads.add(new CachedThread(t)); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java index c3f09bd5e3d..9cfa03bc15c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.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 @@ -86,7 +86,7 @@ public class PointerLocation { boolean inLocalJNIHandleBlock; JNIHandleBlock handleBlock; - sun.jvm.hotspot.runtime.Thread handleThread; + JavaThread handleThread; public PointerLocation(Address addr) { this.addr = addr; @@ -200,7 +200,7 @@ public class PointerLocation { } /** Only valid if isInLocalJNIHandleBlock is true */ - public sun.jvm.hotspot.runtime.Thread getJNIHandleThread() { + public JavaThread getJNIHandleThread() { assert isInLocalJNIHandleBlock(); return handleThread; } @@ -356,14 +356,9 @@ public class PointerLocation { tty.println("In JNI weak global"); } else if (isInLocalJNIHandleBlock()) { tty.print("In thread-local"); - tty.print(" JNI handle block (" + handleBlock.top() + " handle slots present)"); - if (handleThread.isJavaThread()) { - tty.print(" for JavaThread "); - ((JavaThread) handleThread).printThreadIDOn(tty); - tty.println(); - } else { - tty.println(" for a non-Java Thread"); - } + tty.print(" JNI handle block (" + handleBlock.top() + " handle slots present) for JavaThread "); + handleThread.printThreadIDOn(tty); + tty.println(); } else { // This must be last if (Assert.ASSERTS_ENABLED) { From 623453647a8a387b2d8d375cb18b33666abc16ee Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Sat, 15 Feb 2025 07:22:20 +0000 Subject: [PATCH 018/587] 8349915: CTW: Lots of level 3 compiles are done at level 2 after JDK-8348570 Reviewed-by: kvn, chagedorn --- src/hotspot/share/compiler/compilationPolicy.cpp | 5 +++++ src/hotspot/share/compiler/compileTask.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index e28c4511d52..7f2a67f641b 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -633,6 +633,11 @@ CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { task = next_task; continue; } + if (task->compile_reason() == CompileTask::Reason_Whitebox) { + // Whitebox (CTW) tasks do not participate in rate selection and/or any level + // adjustments. Just return them in order. + return task; + } Method* method = task->method(); methodHandle mh(Thread::current(), method); if (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, mh) && !is_old(mh)) { diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 14591a3abdf..04ad7e35a13 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -199,6 +199,8 @@ class CompileTask : public CHeapObj { int comp_level() { return _comp_level;} void set_comp_level(int comp_level) { _comp_level = comp_level;} + CompileReason compile_reason() { return _compile_reason; } + AbstractCompiler* compiler() const; CompileTask* select_for_compilation(); From 5cf11324afdeed0189e0491845a7ffe78c7c1e13 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sat, 15 Feb 2025 14:31:29 +0000 Subject: [PATCH 019/587] 8350098: jpackage test lib erroneously will run methods without @Test annotation as tests Reviewed-by: almatvee --- .../jdk/jpackage/test/AnnotationsTest.java | 39 ++++++++++++++++++- .../jdk/jpackage/test/Annotations.java | 2 +- .../jdk/jpackage/test/TestBuilder.java | 25 +++++------- .../jdk/jpackage/test/TestMethodSupplier.java | 11 ++++-- 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java index cd7914b917b..fdbd30ac7e9 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/AnnotationsTest.java @@ -102,6 +102,12 @@ public class AnnotationsTest extends JUnitAdapter { recordTestCase(v); } + @Test + @ParameterSupplier + public void testDates2(LocalDate v) { + recordTestCase(v); + } + public static Set getExpectedTestDescs() { return Set.of( "().testNoArg()", @@ -115,7 +121,9 @@ public class AnnotationsTest extends JUnitAdapter { "().testDates(2018-05-05)", "().testDates(2018-07-11)", "().testDates(2034-05-05)", - "().testDates(2056-07-11)" + "().testDates(2056-07-11)", + "().testDates2(2028-05-05)", + "().testDates2(2028-07-11)" ); } @@ -125,6 +133,20 @@ public class AnnotationsTest extends JUnitAdapter { { LocalDate.parse("2018-07-11") }, }); } + + public static Collection testDates2() { + return List.of(new Object[][] { + { LocalDate.parse("2028-05-05") }, + { LocalDate.parse("2028-07-11") }, + }); + } + + public static void testDates2(Object unused) { + } + + public int testNoArg(int v) { + return 0; + } } public static class ParameterizedInstanceTest extends TestExecutionRecorder { @@ -313,12 +335,25 @@ public class AnnotationsTest extends JUnitAdapter { var args = new String[] { String.format("--jpt-run=%s", test.getName()) }; + final List log; try { - Main.main(TestBuilder.build().workDirRoot(workDir), args); + log = captureJPackageTestLog(() -> Main.main(TestBuilder.build().workDirRoot(workDir), args)); assertRecordedTestDescs(expectedTestDescs); } catch (Throwable t) { t.printStackTrace(System.err); System.exit(1); + + // Redundant, but needed to suppress "The local variable log may not have been initialized" error. + throw new RuntimeException(t); + } + + final var actualTestCount = Integer.parseInt(log.stream().dropWhile(line -> { + return !(line.startsWith("[==========]") && line.endsWith("tests ran")); + }).findFirst().orElseThrow().split(" ")[1]); + + if (actualTestCount != expectedTestDescs.size()) { + throw new AssertionError(String.format( + "Expected %d executed tests. Actual %d executed tests", expectedTestDescs.size(), actualTestCount)); } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java index ad1e77b4171..4b6072c80b5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Annotations.java @@ -82,7 +82,7 @@ public class Annotations { @Repeatable(ParameterSupplierGroup.class) public @interface ParameterSupplier { - String value(); + String value() default ""; OperatingSystem[] ifOS() default { OperatingSystem.LINUX, diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java index 17c0f131af3..db4810ce5e2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestBuilder.java @@ -249,10 +249,11 @@ final class TestBuilder implements AutoCloseable { .sorted(Comparator.comparing(Method::getName)); } - private Stream cmdLineArgValueToMethodNames(String v) { - List result = new ArrayList<>(); + private Stream getJavaMethodsFromArg(String argValue) { + final List methods = new ArrayList<>(); + String defaultClassName = null; - for (String token : v.split(",")) { + for (String token : argValue.split(",")) { Class testSet = probeClass(token); if (testSet != null) { if (testMethodSupplier.isTestClass(testSet)) { @@ -263,11 +264,9 @@ final class TestBuilder implements AutoCloseable { // from the class with @Test annotation removing name duplicates. // Overloads will be handled at the next phase of processing. defaultClassName = token; - result.addAll(Stream.of(testSet.getMethods()) + methods.addAll(Stream.of(testSet.getMethods()) .filter(m -> m.isAnnotationPresent(Test.class)) .filter(testMethodSupplier::isEnabled) - .map(Method::getName).distinct() - .map(name -> String.join(".", token, name)) .toList()); continue; @@ -283,9 +282,11 @@ final class TestBuilder implements AutoCloseable { } else { qualifiedMethodName = String.join(".", defaultClassName, token); } - result.add(qualifiedMethodName); + methods.addAll(getJavaMethodFromString(qualifiedMethodName)); } - return result.stream(); + + trace(String.format("%s -> %s", argValue, methods)); + return methods.stream(); } private List getJavaMethodFromString(String qualifiedMethodName) { @@ -302,14 +303,6 @@ final class TestBuilder implements AutoCloseable { } } - private Stream getJavaMethodsFromArg(String argValue) { - var methods = cmdLineArgValueToMethodNames(argValue) - .map(this::getJavaMethodFromString) - .flatMap(List::stream).toList(); - trace(String.format("%s -> %s", argValue, methods)); - return methods.stream(); - } - private Stream toMethodCalls(Method method) throws IllegalAccessException, InvocationTargetException, InvalidAnnotationException { return testMethodSupplier.mapToMethodCalls(method).peek(methodCall -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java index 6ba4da0590c..8b92ae7ca46 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java @@ -256,12 +256,17 @@ final class TestMethodSupplier { } final Class execClass = exec.getDeclaringClass(); - final var supplierFuncName = a.value(); + final String supplierFuncName; + if (a.value().isEmpty()) { + supplierFuncName = exec.getName(); + } else { + supplierFuncName = a.value(); + } final MethodQuery methodQuery; - if (!a.value().contains(".")) { + if (!supplierFuncName.contains(".")) { // No class name specified - methodQuery = new MethodQuery(execClass.getName(), a.value()); + methodQuery = new MethodQuery(execClass.getName(), supplierFuncName); } else { methodQuery = MethodQuery.fromQualifiedMethodName(supplierFuncName); } From 7d11418c820b46926a25907766d16083a4b349de Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Sat, 15 Feb 2025 22:40:46 +0000 Subject: [PATCH 020/587] 8350147: Replace example in KEM class with the one from JEP 452 Reviewed-by: weijun --- .../share/classes/javax/crypto/KEM.java | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index 927b36ba25c..0486e48615a 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -65,24 +65,40 @@ import java.util.Objects; * new shared secret and key encapsulation message. *

* - * Example: + * Example operation using a ficticious {@code KEM} algorithm {@code ABC}: * {@snippet lang = java: - * // Receiver side - * var kpg = KeyPairGenerator.getInstance("X25519"); - * var kp = kpg.generateKeyPair(); + * // Receiver side + * KeyPairGenerator g = KeyPairGenerator.getInstance("ABC"); + * KeyPair kp = g.generateKeyPair(); + * publishKey(kp.getPublic()); * - * // Sender side - * var kem1 = KEM.getInstance("DHKEM"); - * var sender = kem1.newEncapsulator(kp.getPublic()); - * var encapsulated = sender.encapsulate(); - * var k1 = encapsulated.key(); + * // Sender side + * KEM senderKEM = KEM.getInstance("ABC"); + * PublicKey receiverPublicKey = retrieveKey(); + * ABCKEMParameterSpec senderSpec = new ABCKEMParameterSpec(args); + * KEM.Encapsulator e = senderKEM.newEncapsulator( + * receiverPublicKey, senderSpec, null); + * KEM.Encapsulated enc = e.encapsulate(); + * SecretKey senderSecret = enc.key(); * - * // Receiver side - * var kem2 = KEM.getInstance("DHKEM"); - * var receiver = kem2.newDecapsulator(kp.getPrivate()); - * var k2 = receiver.decapsulate(encapsulated.encapsulation()); + * sendBytes(enc.encapsulation()); + * sendBytes(enc.params()); * - * assert Arrays.equals(k1.getEncoded(), k2.getEncoded()); + * // Receiver side + * byte[] ciphertext = receiveBytes(); + * byte[] params = receiveBytes(); + * + * KEM receiverKEM = KEM.getInstance("ABC"); + * AlgorithmParameters algParams = + * AlgorithmParameters.getInstance("ABC"); + * algParams.init(params); + * ABCKEMParameterSpec receiverSpec = + * algParams.getParameterSpec(ABCKEMParameterSpec.class); + * KEM.Decapsulator d = + * receiverKEM.newDecapsulator(kp.getPrivate(), receiverSpec); + * SecretKey receiverSecret = d.decapsulate(ciphertext); + * + * // senderSecret and receiverSecret should now be equal. * } * * @since 21 From 2192723734e4edd2d2136637a46e9256c1b15703 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 17 Feb 2025 02:09:25 +0000 Subject: [PATCH 021/587] 8350162: ProblemList compiler/tiered/Level2RecompilationTest.java Reviewed-by: jpai --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index e8656a74f4b..991d0435a91 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,6 +43,8 @@ # :hotspot_compiler +compiler/tiered/Level2RecompilationTest.java 8350159 generic-all + compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all From 5e9d72e2241426c0cf26abadab73e63434d51a4a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 17 Feb 2025 08:02:51 +0000 Subject: [PATCH 022/587] 8350094: Linux gcc 13.2.0 build fails when ubsan is enabled Reviewed-by: mdoerr, prr, kbarrett --- make/autoconf/jdk-options.m4 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index b90f04a89e2..991f57505dc 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -516,10 +516,11 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], OPTIONAL: true) # GCC reports lots of likely false positives for stringop-truncation and format-overflow. + # GCC 13 also for array-bounds and stringop-overflow # Silence them for now. UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment \ $ADDITIONAL_UBSAN_CHECKS" - UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" + UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -Wno-array-bounds -Wno-stringop-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" UBSAN_LDFLAGS="$UBSAN_CHECKS" UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, DESC: [enable UndefinedBehaviorSanitizer], From b1b48286a6cbee8a9f96d739ab437915c573022c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 17 Feb 2025 09:21:49 +0000 Subject: [PATCH 023/587] 8350086: Inline hot Method accessors for faster task selection Reviewed-by: kvn, coleenp, aph, vlivanov --- src/hotspot/share/compiler/compileTask.cpp | 1 + src/hotspot/share/oops/method.cpp | 33 ------------------ src/hotspot/share/oops/method.hpp | 8 ++--- src/hotspot/share/oops/method.inline.hpp | 39 ++++++++++++++++++++++ src/hotspot/share/oops/methodData.cpp | 1 + src/hotspot/share/runtime/java.cpp | 2 +- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index e266a215de1..6668f212b21 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -31,6 +31,7 @@ #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" +#include "oops/method.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index a0f6a901cf7..1a3b908434f 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1919,39 +1919,6 @@ void Method::clear_all_breakpoints() { #endif // INCLUDE_JVMTI -int Method::invocation_count() const { - MethodCounters* mcs = method_counters(); - MethodData* mdo = method_data(); - if (((mcs != nullptr) ? mcs->invocation_counter()->carry() : false) || - ((mdo != nullptr) ? mdo->invocation_counter()->carry() : false)) { - return InvocationCounter::count_limit; - } else { - return ((mcs != nullptr) ? mcs->invocation_counter()->count() : 0) + - ((mdo != nullptr) ? mdo->invocation_counter()->count() : 0); - } -} - -int Method::backedge_count() const { - MethodCounters* mcs = method_counters(); - MethodData* mdo = method_data(); - if (((mcs != nullptr) ? mcs->backedge_counter()->carry() : false) || - ((mdo != nullptr) ? mdo->backedge_counter()->carry() : false)) { - return InvocationCounter::count_limit; - } else { - return ((mcs != nullptr) ? mcs->backedge_counter()->count() : 0) + - ((mdo != nullptr) ? mdo->backedge_counter()->count() : 0); - } -} - -int Method::highest_comp_level() const { - const MethodCounters* mcs = method_counters(); - if (mcs != nullptr) { - return mcs->highest_comp_level(); - } else { - return CompLevel_none; - } -} - int Method::highest_osr_comp_level() const { const MethodCounters* mcs = method_counters(); if (mcs != nullptr) { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 7b13337ecaf..5daa572a46c 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -255,7 +255,7 @@ class Method : public Metadata { void set_deprecated_for_removal() { constMethod()->set_deprecated_for_removal(); } bool deprecated_for_removal() const { return constMethod()->deprecated_for_removal(); } - int highest_comp_level() const; + inline int highest_comp_level() const; void set_highest_comp_level(int level); int highest_osr_comp_level() const; void set_highest_osr_comp_level(int level); @@ -334,8 +334,8 @@ class Method : public Metadata { inline float rate() const; inline void set_rate(float rate); - int invocation_count() const; - int backedge_count() const; + inline int invocation_count() const; + inline int backedge_count() const; bool was_executed_more_than(int n); bool was_never_executed() { return !was_executed_more_than(0); } @@ -344,7 +344,7 @@ class Method : public Metadata { static MethodCounters* build_method_counters(Thread* current, Method* m); - int interpreter_invocation_count() { return invocation_count(); } + inline int interpreter_invocation_count() const; #ifndef PRODUCT int64_t compiled_invocation_count() const { return _compiled_invocation_count;} diff --git a/src/hotspot/share/oops/method.inline.hpp b/src/hotspot/share/oops/method.inline.hpp index f27834de30b..18fca354b6b 100644 --- a/src/hotspot/share/oops/method.inline.hpp +++ b/src/hotspot/share/oops/method.inline.hpp @@ -28,7 +28,9 @@ #include "oops/method.hpp" #include "classfile/vmIntrinsics.hpp" +#include "code/nmethod.inline.hpp" #include "oops/methodCounters.hpp" +#include "oops/methodData.inline.hpp" #include "runtime/atomic.hpp" inline address Method::from_compiled_entry() const { @@ -188,4 +190,41 @@ inline void Method::set_rate(float rate) { } } +inline int Method::invocation_count() const { + MethodCounters* mcs = method_counters(); + MethodData* mdo = method_data(); + if (((mcs != nullptr) ? mcs->invocation_counter()->carry() : false) || + ((mdo != nullptr) ? mdo->invocation_counter()->carry() : false)) { + return InvocationCounter::count_limit; + } else { + return ((mcs != nullptr) ? mcs->invocation_counter()->count() : 0) + + ((mdo != nullptr) ? mdo->invocation_counter()->count() : 0); + } +} + +inline int Method::backedge_count() const { + MethodCounters* mcs = method_counters(); + MethodData* mdo = method_data(); + if (((mcs != nullptr) ? mcs->backedge_counter()->carry() : false) || + ((mdo != nullptr) ? mdo->backedge_counter()->carry() : false)) { + return InvocationCounter::count_limit; + } else { + return ((mcs != nullptr) ? mcs->backedge_counter()->count() : 0) + + ((mdo != nullptr) ? mdo->backedge_counter()->count() : 0); + } +} + +inline int Method::highest_comp_level() const { + const MethodCounters* mcs = method_counters(); + if (mcs != nullptr) { + return mcs->highest_comp_level(); + } else { + return CompLevel_none; + } +} + +inline int Method::interpreter_invocation_count() const { + return invocation_count(); +} + #endif // SHARE_OOPS_METHOD_INLINE_HPP diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 1abc34acc6b..2d366168f08 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -33,6 +33,7 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" +#include "oops/method.inline.hpp" #include "oops/methodData.inline.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/atomic.hpp" diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 46038b1049e..d6dda04e053 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -54,7 +54,7 @@ #include "oops/instanceKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/klassVtable.hpp" -#include "oops/method.hpp" +#include "oops/method.inline.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" From f1258f9e16b063c0fdbdd614ae2dc76c67607654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 17 Feb 2025 09:22:57 +0000 Subject: [PATCH 024/587] 8349755: Fix corner case issues in async UL Reviewed-by: dholmes, aboldtch --- src/hotspot/share/logging/logAsyncWriter.cpp | 82 +++++++++++++++++-- src/hotspot/share/logging/logAsyncWriter.hpp | 9 +- src/hotspot/share/logging/logFileOutput.cpp | 9 +- .../share/logging/logFileStreamOutput.cpp | 8 +- src/hotspot/share/logging/logTag.hpp | 2 + src/hotspot/share/logging/logTagSet.cpp | 9 +- .../jtreg/runtime/logging/AsyncDeathTest.java | 54 ++++++++++++ 7 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index 8360a4af91d..44758958dd3 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -31,18 +31,34 @@ #include "runtime/atomic.hpp" #include "runtime/os.inline.hpp" +DEBUG_ONLY(bool AsyncLogWriter::ignore_recursive_logging = false;) + class AsyncLogWriter::AsyncLogLocker : public StackObj { - public: + static Thread* _holder; +public: + static Thread* current_holder() { return _holder; } AsyncLogLocker() { assert(_instance != nullptr, "AsyncLogWriter::_lock is unavailable"); _instance->_lock.lock(); + _holder = Thread::current_or_null(); } ~AsyncLogLocker() { + assert(_holder == Thread::current_or_null(), "must be"); + _holder = nullptr; _instance->_lock.unlock(); } + + void wait() { + Thread* saved_holder = _holder; + _holder = nullptr; + _instance->_lock.wait(0/* no timeout */); + _holder = saved_holder; + } }; +Thread* AsyncLogWriter::AsyncLogLocker::_holder = nullptr; + // LogDecorator::None applies to 'constant initialization' because of its constexpr constructor. const LogDecorations& AsyncLogWriter::None = LogDecorations(LogLevel::Warning, LogTagSetMapping::tagset(), LogDecorators::None); @@ -84,19 +100,67 @@ void AsyncLogWriter::enqueue_locked(LogFileStreamOutput* output, const LogDecora _lock.notify(); } -void AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg) { +// This function checks for cases where continuing with asynchronous logging may lead to stability issues, such as a deadlock. +// If this returns false then we give up on logging asynchronously and do so synchronously instead. +bool AsyncLogWriter::is_enqueue_allowed() { + AsyncLogWriter* alw = AsyncLogWriter::instance(); + Thread* holding_thread = AsyncLogWriter::AsyncLogLocker::current_holder(); + Thread* this_thread = Thread::current_or_null(); + if (this_thread == nullptr) { + // The current thread is unattached. + return false; + } + + if (holding_thread == this_thread) { + // A thread, while enqueuing a message, has attempted to log something. + // Do not log while holding the Async log lock. + // Try to catch possible occurrences in debug builds. +#ifdef ASSERT + if (!AsyncLogWriter::ignore_recursive_logging) { + ShouldNotReachHere(); + } +#endif // ASSERT + return false; + } + + if (alw == nullptr) { + // There is no AsyncLogWriter instance yet. + return false; + } + + if (this_thread == alw) { + // The async log producer is attempting to log, leading to recursive logging. + return false; + } + + return true; +} + +bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg) { + if (!is_enqueue_allowed()) { + return false; + } + AsyncLogLocker locker; - enqueue_locked(&output, decorations, msg); + DEBUG_ONLY(log_debug(deathtest)("Induce a recursive log for testing (for crashing)");) + DEBUG_ONLY(log_debug(deathtest2)("Induce a recursive log for testing");) + AsyncLogWriter::instance()->enqueue_locked(&output, decorations, msg); + return true; } // LogMessageBuffer consists of a multiple-part/multiple-line message. // The lock here guarantees its integrity. -void AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator) { - AsyncLogLocker locker; - - for (; !msg_iterator.is_at_end(); msg_iterator++) { - enqueue_locked(&output, msg_iterator.decorations(), msg_iterator.message()); +bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator) { + if (!is_enqueue_allowed()) { + return false; } + + // If we get here we know the AsyncLogWriter is initialized. + AsyncLogLocker locker; + for (; !msg_iterator.is_at_end(); msg_iterator++) { + AsyncLogWriter::instance()->enqueue_locked(&output, msg_iterator.decorations(), msg_iterator.message()); + } + return true; } AsyncLogWriter::AsyncLogWriter() @@ -155,7 +219,7 @@ void AsyncLogWriter::run() { AsyncLogLocker locker; while (!_data_available) { - _lock.wait(0/* no timeout */); + locker.wait(); } // Only doing a swap and statistics under the lock to // guarantee that I/O jobs don't block logsites. diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index 4d18e612110..e2c8cb36e07 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -195,9 +195,12 @@ class AsyncLogWriter : public NonJavaThread { ~BufferUpdater(); }; - public: - void enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg); - void enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator); + static bool is_enqueue_allowed(); + +public: + DEBUG_ONLY(static bool ignore_recursive_logging;) + static bool enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg); + static bool enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator); static AsyncLogWriter* instance(); static void initialize(); diff --git a/src/hotspot/share/logging/logFileOutput.cpp b/src/hotspot/share/logging/logFileOutput.cpp index 568708a5961..9d6d19d739e 100644 --- a/src/hotspot/share/logging/logFileOutput.cpp +++ b/src/hotspot/share/logging/logFileOutput.cpp @@ -292,9 +292,7 @@ int LogFileOutput::write(const LogDecorations& decorations, const char* msg) { return 0; } - AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); - if (aio_writer != nullptr) { - aio_writer->enqueue(*this, decorations, msg); + if (AsyncLogWriter::enqueue(*this, decorations, msg)) { return 0; } @@ -306,10 +304,7 @@ int LogFileOutput::write(LogMessageBuffer::Iterator msg_iterator) { // An error has occurred with this output, avoid writing to it. return 0; } - - AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); - if (aio_writer != nullptr) { - aio_writer->enqueue(*this, msg_iterator); + if (AsyncLogWriter::enqueue(*this, msg_iterator)) { return 0; } diff --git a/src/hotspot/share/logging/logFileStreamOutput.cpp b/src/hotspot/share/logging/logFileStreamOutput.cpp index f8bbb28472c..2464bc806c2 100644 --- a/src/hotspot/share/logging/logFileStreamOutput.cpp +++ b/src/hotspot/share/logging/logFileStreamOutput.cpp @@ -173,9 +173,7 @@ int LogFileStreamOutput::write_blocking(const LogDecorations& decorations, const } int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { - AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); - if (aio_writer != nullptr) { - aio_writer->enqueue(*this, decorations, msg); + if (AsyncLogWriter::enqueue(*this, decorations, msg)) { return 0; } @@ -186,9 +184,7 @@ int LogFileStreamOutput::write(const LogDecorations& decorations, const char* ms } int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) { - AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); - if (aio_writer != nullptr) { - aio_writer->enqueue(*this, msg_iterator); + if (AsyncLogWriter::enqueue(*this, msg_iterator)) { return 0; } diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 15ac30d09ab..c3db84930ad 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -68,6 +68,8 @@ class outputStream; LOG_TAG(data) \ LOG_TAG(datacreation) \ LOG_TAG(dcmd) \ + DEBUG_ONLY(LOG_TAG(deathtest)) /* Log Internal death test tag */ \ + DEBUG_ONLY(LOG_TAG(deathtest2)) /* Log Internal death test tag */ \ LOG_TAG(decoder) \ LOG_TAG(defaultmethods) \ LOG_TAG(deoptimization) \ diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index 3cb04a033c6..718627be3a5 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -22,6 +22,7 @@ * */ #include "jvm.h" +#include "logging/logAsyncWriter.hpp" #include "logging/logDecorations.hpp" #include "logging/logFileStreamOutput.hpp" #include "logging/logLevel.hpp" @@ -77,7 +78,13 @@ void LogTagSet::log(LogLevelType level, const char* msg) { // the implied memory order of Atomic::add(). LogOutputList::Iterator it = _output_list.iterator(level); LogDecorations decorations(level, *this, _decorators); - +#ifdef ASSERT + // If we log for tag deathtest2 then we're testing that recursive logging works. + // In this case, do not crash when detecting recursive logging. + if (this->contains(LogTagType::_deathtest2)) { + AsyncLogWriter::ignore_recursive_logging = true; + } +#endif for (; it != _output_list.end(); it++) { (*it)->write(decorations, msg); } diff --git a/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java b/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java new file mode 100644 index 00000000000..2dff887f108 --- /dev/null +++ b/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java @@ -0,0 +1,54 @@ +/* + * 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 8349755 + * @summary Perform recursive logging in async UL on purpose + * @requires vm.flagless + * @requires vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver AsyncDeathTest + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class AsyncDeathTest { + public static void main(String[] args) throws Exception { + // For deathtest we expect the VM to reach ShouldNotReachHere() and die + ProcessBuilder pb = + ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest=debug", "-XX:-CreateCoredumpOnCrash", "--version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldNotContain("Induce a recursive log for testing"); + // For deathtest2 we expect the VM to ignore that recursive logging has been detected and is handled by printing synchronously. + ProcessBuilder pb2 = + ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest2=debug", "--version"); + OutputAnalyzer output2 = new OutputAnalyzer(pb2.start()); + output2.shouldHaveExitValue(0); + output2.shouldContain("Induce a recursive log for testing"); + } +} From 071c8f515537d6030ae7055e309b4f4a6a495bc8 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 17 Feb 2025 11:05:59 +0000 Subject: [PATCH 025/587] 8349909: jdk.internal.jimage.decompressor.ZipDecompressor does not close the Inflater in exceptional cases Reviewed-by: lancea, alanb --- .../jimage/decompressor/ZipDecompressor.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java index f8e9d46a777..b5cba5a17dc 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java +++ b/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.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 @@ -50,15 +50,17 @@ final class ZipDecompressor implements ResourceDecompressor { } byte[] bytesOut = new byte[(int) originalSize]; - Inflater inflater = new Inflater(); - inflater.setInput(bytesIn, offset, bytesIn.length - offset); - int count = 0; - while (!inflater.finished() && count < originalSize) { - count += inflater.inflate(bytesOut, count, bytesOut.length - count); - } + Inflater inflater = new Inflater(); + try { + inflater.setInput(bytesIn, offset, bytesIn.length - offset); - inflater.end(); + while (!inflater.finished() && count < originalSize) { + count += inflater.inflate(bytesOut, count, bytesOut.length - count); + } + } finally { + inflater.end(); + } if (count != originalSize) { throw new IOException("Resource content size mismatch"); From b3a4026c65eb049eb4f3a3cbf52c9f0c9979a256 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Mon, 17 Feb 2025 11:35:07 +0000 Subject: [PATCH 026/587] 8349764: RISC-V: C1: Improve Class.isInstance intrinsic Reviewed-by: fyang, mli --- .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 2 +- src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index e31a1024f76..3868c5ea829 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -1104,7 +1104,7 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { // Intrinsic for Class::isInstance address LIRGenerator::isInstance_entry() { - return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of); + return Runtime1::entry_for(C1StubId::is_instance_of_id); } void LIRGenerator::do_If(If* x) { diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index c076f28be6c..0f1f1dd891c 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -925,6 +925,52 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { } break; + case C1StubId::is_instance_of_id: + { + // Mirror: x10 + // Object: x11 + // Temps: x13, x14, x15, x16, x17 + // Result: x10 + + // Get the Klass* into x16 + Register klass = x16, obj = x11, result = x10; + __ ld(klass, Address(x10, java_lang_Class::klass_offset())); + + Label fail, is_secondary, success; + + __ beqz(klass, fail); // Klass is null + __ beqz(obj, fail); // obj is null + + __ lwu(x13, Address(klass, in_bytes(Klass::super_check_offset_offset()))); + __ mv(x17, in_bytes(Klass::secondary_super_cache_offset())); + __ beq(x13, x17, is_secondary); // Klass is a secondary superclass + + // Klass is a concrete class + __ load_klass(x15, obj); + __ add(x17, x15, x13); + __ ld(x17, Address(x17)); + __ beq(klass, x17, success); + __ mv(result, 0); + __ ret(); + + __ bind(is_secondary); + __ load_klass(obj, obj); + + // This is necessary because I am never in my own secondary_super list. + __ beq(obj, klass, success); + + __ lookup_secondary_supers_table_var(obj, klass, result, x13, x14, x15, x17, &success); + + __ bind(fail); + __ mv(result, 0); + __ ret(); + + __ bind(success); + __ mv(result, 1); + __ ret(); + } + break; + case C1StubId::monitorexit_nofpu_id: save_fpu_registers = false; // fall through From 7f3ecb4d92fdb084ce632cab484cf4578487b090 Mon Sep 17 00:00:00 2001 From: Matthias Ernst Date: Mon, 17 Feb 2025 13:07:23 +0000 Subject: [PATCH 027/587] 8346664: C2: Optimize mask check with constant offset Reviewed-by: epeter, qamai --- src/hotspot/share/opto/mulnode.cpp | 206 ++++++------ src/hotspot/share/opto/mulnode.hpp | 4 +- .../compiler/c2/irTests/TestShiftAndMask.java | 300 +++++++++++++----- .../superword/TestEquivalentInvariants.java | 80 ++++- .../vectorization/TestPopulateIndex.java | 30 +- 5 files changed, 431 insertions(+), 189 deletions(-) diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 58439ce3773..b1a9219e113 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -692,9 +692,11 @@ const Type *AndINode::mul_ring( const Type *t0, const Type *t1 ) const { return and_value(r0, r1); } +static bool AndIL_is_zero_element_under_mask(const PhaseGVN* phase, const Node* expr, const Node* mask, BasicType bt); + const Type* AndINode::Value(PhaseGVN* phase) const { - // patterns similar to (v << 2) & 3 - if (AndIL_shift_and_mask_is_always_zero(phase, in(1), in(2), T_INT, true)) { + if (AndIL_is_zero_element_under_mask(phase, in(1), in(2), T_INT) || + AndIL_is_zero_element_under_mask(phase, in(2), in(1), T_INT)) { return TypeInt::ZERO; } @@ -740,8 +742,8 @@ Node* AndINode::Identity(PhaseGVN* phase) { //------------------------------Ideal------------------------------------------ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) { - // pattern similar to (v1 + (v2 << 2)) & 3 transformed to v1 & 3 - Node* progress = AndIL_add_shift_and_mask(phase, T_INT); + // Simplify (v1 + v2) & mask to v1 & mask or v2 & mask when possible. + Node* progress = AndIL_sum_and_mask(phase, T_INT); if (progress != nullptr) { return progress; } @@ -824,8 +826,8 @@ const Type *AndLNode::mul_ring( const Type *t0, const Type *t1 ) const { } const Type* AndLNode::Value(PhaseGVN* phase) const { - // patterns similar to (v << 2) & 3 - if (AndIL_shift_and_mask_is_always_zero(phase, in(1), in(2), T_LONG, true)) { + if (AndIL_is_zero_element_under_mask(phase, in(1), in(2), T_LONG) || + AndIL_is_zero_element_under_mask(phase, in(2), in(1), T_LONG)) { return TypeLong::ZERO; } @@ -872,8 +874,8 @@ Node* AndLNode::Identity(PhaseGVN* phase) { //------------------------------Ideal------------------------------------------ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // pattern similar to (v1 + (v2 << 2)) & 3 transformed to v1 & 3 - Node* progress = AndIL_add_shift_and_mask(phase, T_LONG); + // Simplify (v1 + v2) & mask to v1 & mask or v2 & mask when possible. + Node* progress = AndIL_sum_and_mask(phase, T_LONG); if (progress != nullptr) { return progress; } @@ -2096,99 +2098,109 @@ const Type* RotateRightNode::Value(PhaseGVN* phase) const { } } -// Given an expression (AndX shift mask) or (AndX mask shift), -// determine if the AndX must always produce zero, because the -// the shift (x< #0 -// (AndL (LShiftL _ #N) #M) => #0 -// (AndL (ConvI2L (LShiftI _ #N)) #M) => #0 -// The M and N values must satisfy ((-1 << N) & M) == 0. -// Because the optimization might work for a non-constant -// mask M, we check the AndX for both operand orders. -bool MulNode::AndIL_shift_and_mask_is_always_zero(PhaseGVN* phase, Node* shift, Node* mask, BasicType bt, bool check_reverse) { - if (mask == nullptr || shift == nullptr) { - return false; +//------------------------------ Sum & Mask ------------------------------ + +// Returns a lower bound on the number of trailing zeros in expr. +static jint AndIL_min_trailing_zeros(const PhaseGVN* phase, const Node* expr, BasicType bt) { + expr = expr->uncast(); + const TypeInteger* type = phase->type(expr)->isa_integer(bt); + if (type == nullptr) { + return 0; } - const TypeInteger* mask_t = phase->type(mask)->isa_integer(bt); - if (mask_t == nullptr || phase->type(shift)->isa_integer(bt) == nullptr) { - return false; + + if (type->is_con()) { + jlong con = type->get_con_as_long(bt); + return con == 0L ? (type2aelembytes(bt) * BitsPerByte) : count_trailing_zeros(con); } - shift = shift->uncast(); - if (shift == nullptr) { - return false; - } - if (phase->type(shift)->isa_integer(bt) == nullptr) { - return false; - } - BasicType shift_bt = bt; - if (bt == T_LONG && shift->Opcode() == Op_ConvI2L) { + + if (expr->Opcode() == Op_ConvI2L) { + expr = expr->in(1)->uncast(); bt = T_INT; - Node* val = shift->in(1); - if (val == nullptr) { - return false; - } - val = val->uncast(); - if (val == nullptr) { - return false; - } - if (val->Opcode() == Op_LShiftI) { - shift_bt = T_INT; - shift = val; - if (phase->type(shift)->isa_integer(bt) == nullptr) { - return false; - } - } - } - if (shift->Opcode() != Op_LShift(shift_bt)) { - if (check_reverse && - (mask->Opcode() == Op_LShift(bt) || - (bt == T_LONG && mask->Opcode() == Op_ConvI2L))) { - // try it the other way around - return AndIL_shift_and_mask_is_always_zero(phase, mask, shift, bt, false); - } - return false; - } - Node* shift2 = shift->in(2); - if (shift2 == nullptr) { - return false; - } - const Type* shift2_t = phase->type(shift2); - if (!shift2_t->isa_int() || !shift2_t->is_int()->is_con()) { - return false; + type = phase->type(expr)->isa_int(); } - jint shift_con = shift2_t->is_int()->get_con() & ((shift_bt == T_INT ? BitsPerJavaInteger : BitsPerJavaLong) - 1); - if ((((jlong)1) << shift_con) > mask_t->hi_as_long() && mask_t->lo_as_long() >= 0) { - return true; + // Pattern: expr = (x << shift) + if (expr->Opcode() == Op_LShift(bt)) { + const TypeInt* shift_t = phase->type(expr->in(2))->isa_int(); + if (shift_t == nullptr || !shift_t->is_con()) { + return 0; + } + // We need to truncate the shift, as it may not have been canonicalized yet. + // T_INT: 0..31 -> shift_mask = 4 * 8 - 1 = 31 + // T_LONG: 0..63 -> shift_mask = 8 * 8 - 1 = 63 + // (JLS: "Shift Operators") + jint shift_mask = type2aelembytes(bt) * BitsPerByte - 1; + return shift_t->get_con() & shift_mask; } - return false; + return 0; } -// Given an expression (AndX (AddX v1 (LShiftX v2 #N)) #M) -// determine if the AndX must always produce (AndX v1 #M), -// because the shift (v2< (AndI v1 #M) -// (AndL (AddI v1 (LShiftL _ #N)) #M) => (AndL v1 #M) -// (AndL (AddL v1 (ConvI2L (LShiftI _ #N))) #M) => (AndL v1 #M) -// The M and N values must satisfy ((-1 << N) & M) == 0. -// Because the optimization might work for a non-constant -// mask M, and because the AddX operands can come in either -// order, we check for every operand order. -Node* MulNode::AndIL_add_shift_and_mask(PhaseGVN* phase, BasicType bt) { +// Checks whether expr is neutral additive element (zero) under mask, +// i.e. whether an expression of the form: +// (AndX (AddX (expr addend) mask) +// (expr + addend) & mask +// is equivalent to +// (AndX addend mask) +// addend & mask +// for any addend. +// (The X in AndX must be I or L, depending on bt). +// +// We check for the sufficient condition when the lowest set bit in expr is higher than +// the highest set bit in mask, i.e.: +// expr: eeeeee0000000000000 +// mask: 000000mmmmmmmmmmmmm +// <--w bits---> +// We do not test for other cases. +// +// Correctness: +// Given "expr" with at least "w" trailing zeros, +// let "mod = 2^w", "suffix_mask = mod - 1" +// +// Since "mask" only has bits set where "suffix_mask" does, we have: +// mask = suffix_mask & mask (SUFFIX_MASK) +// +// And since expr only has bits set above w, and suffix_mask only below: +// expr & suffix_mask == 0 (NO_BIT_OVERLAP) +// +// From unsigned modular arithmetic (with unsigned modulo %), and since mod is +// a power of 2, and we are computing in a ring of powers of 2, we know that +// (x + y) % mod = (x % mod + y) % mod +// (x + y) & suffix_mask = (x & suffix_mask + y) & suffix_mask (MOD_ARITH) +// +// We can now prove the equality: +// (expr + addend) & mask +// = (expr + addend) & suffix_mask & mask (SUFFIX_MASK) +// = (expr & suffix_mask + addend) & suffix_mask & mask (MOD_ARITH) +// = (0 + addend) & suffix_mask & mask (NO_BIT_OVERLAP) +// = addend & mask (SUFFIX_MASK) +// +// Hence, an expr with at least w trailing zeros is a neutral additive element under any mask with bit width w. +static bool AndIL_is_zero_element_under_mask(const PhaseGVN* phase, const Node* expr, const Node* mask, BasicType bt) { + // When the mask is negative, it has the most significant bit set. + const TypeInteger* mask_t = phase->type(mask)->isa_integer(bt); + if (mask_t == nullptr || mask_t->lo_as_long() < 0) { + return false; + } + + // When the mask is constant zero, we defer to MulNode::Value to eliminate the entire AndX operation. + if (mask_t->hi_as_long() == 0) { + assert(mask_t->lo_as_long() == 0, "checked earlier"); + return false; + } + + jint mask_bit_width = BitsPerLong - count_leading_zeros(mask_t->hi_as_long()); + jint expr_trailing_zeros = AndIL_min_trailing_zeros(phase, expr, bt); + return expr_trailing_zeros >= mask_bit_width; +} + +// Reduces the pattern: +// (AndX (AddX add1 add2) mask) +// to +// (AndX add1 mask), if add2 is neutral wrt mask (see above), and vice versa. +Node* MulNode::AndIL_sum_and_mask(PhaseGVN* phase, BasicType bt) { Node* add = in(1); Node* mask = in(2); - if (add == nullptr || mask == nullptr) { - return nullptr; - } int addidx = 0; if (add->Opcode() == Op_Add(bt)) { addidx = 1; @@ -2200,14 +2212,12 @@ Node* MulNode::AndIL_add_shift_and_mask(PhaseGVN* phase, BasicType bt) { if (addidx > 0) { Node* add1 = add->in(1); Node* add2 = add->in(2); - if (add1 != nullptr && add2 != nullptr) { - if (AndIL_shift_and_mask_is_always_zero(phase, add1, mask, bt, false)) { - set_req_X(addidx, add2, phase); - return this; - } else if (AndIL_shift_and_mask_is_always_zero(phase, add2, mask, bt, false)) { - set_req_X(addidx, add1, phase); - return this; - } + if (AndIL_is_zero_element_under_mask(phase, add1, mask, bt)) { + set_req_X(addidx, add2, phase); + return this; + } else if (AndIL_is_zero_element_under_mask(phase, add2, mask, bt)) { + set_req_X(addidx, add1, phase); + return this; } } return nullptr; diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index bb572b9d9a2..65a2cd112ec 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -83,8 +83,8 @@ public: static MulNode* make(Node* in1, Node* in2, BasicType bt); - static bool AndIL_shift_and_mask_is_always_zero(PhaseGVN* phase, Node* shift, Node* mask, BasicType bt, bool check_reverse); - Node* AndIL_add_shift_and_mask(PhaseGVN* phase, BasicType bt); +protected: + Node* AndIL_sum_and_mask(PhaseGVN* phase, BasicType bt); }; //------------------------------MulINode--------------------------------------- diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java index 4396873425a..2cdc6414685 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2021, 2025, Red Hat, 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 @@ -30,7 +30,7 @@ import java.util.Objects; /* * @test - * @bug 8277850 8278949 8285793 + * @bug 8277850 8278949 8285793 8346664 * @summary C2: optimize mask checks in counted loops * @library /test/lib / * @run driver compiler.c2.irTests.TestShiftAndMask @@ -43,11 +43,48 @@ public class TestShiftAndMask { TestFramework.run(); } + // any X << INT_MASK_WIDTH is zero under any INT_MASK + static final int INT_MASK_WIDTH = 1 + RANDOM.nextInt(30); + static final int INT_MAX_MASK = (1 << INT_MASK_WIDTH) - 1; + static final int INT_MASK = 1 + RANDOM.nextInt(INT_MAX_MASK); + static final int INT_MASK2 = 1 + RANDOM.nextInt(INT_MAX_MASK); + static final int INT_ZERO_CONST = RANDOM.nextInt() << INT_MASK_WIDTH; + + static final int INT_RANDOM_CONST = RANDOM.nextInt(); + static final int INT_RANDOM_SHIFT = RANDOM.nextInt(); + static final int INT_RANDOM_MASK = RANDOM.nextInt(); + + // any X << LONG_MASK_WIDTH is zero under any LONG_MASK + static final int LONG_MASK_WIDTH = 1 + RANDOM.nextInt(62); + static final long LONG_MAX_MASK = (1L << LONG_MASK_WIDTH) - 1; + static final long LONG_MASK = 1 + RANDOM.nextLong(LONG_MAX_MASK); + static final long LONG_MASK2 = 1 + RANDOM.nextLong(LONG_MAX_MASK); + static final long LONG_ZERO_CONST = RANDOM.nextLong() << LONG_MASK_WIDTH; + + static final long LONG_RANDOM_CONST = RANDOM.nextLong(); + static final long LONG_RANDOM_SHIFT = RANDOM.nextLong(); + static final long LONG_RANDOM_MASK = RANDOM.nextLong(); + + @Test + public static int intSumAndMask(int i, int j) { + return (j + i << INT_RANDOM_SHIFT + INT_RANDOM_CONST) & INT_RANDOM_MASK; + } + + @Run(test = { "intSumAndMask" }) + public static void checkIntSumAndMask() { + int j = RANDOM.nextInt(); + int i = RANDOM.nextInt(); + int res = intSumAndMask(i, j); + if (res != ((j + i << INT_RANDOM_SHIFT + INT_RANDOM_CONST) & INT_RANDOM_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + } + @Test @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = { IRNode.AND_I, IRNode.LSHIFT_I }) public static int shiftMaskInt(int i) { - return (i << 2) & 3; // transformed to: return 0; + return (i << INT_MASK_WIDTH) & INT_MASK; // transformed to: return 0; } @Check(test = "shiftMaskInt") @@ -57,11 +94,26 @@ public class TestShiftAndMask { } } + @Test + public static long longSumAndMask(long i, long j) { + return (j + i << LONG_RANDOM_SHIFT + LONG_RANDOM_CONST) & LONG_RANDOM_MASK; + } + + @Run(test = { "longSumAndMask" }) + public static void checkLongSumAndMask() { + long j = RANDOM.nextLong(); + long i = RANDOM.nextLong(); + long res = longSumAndMask(i, j); + if (res != ((j + i << LONG_RANDOM_SHIFT + LONG_RANDOM_CONST) & LONG_RANDOM_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + } + @Test @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) public static long shiftMaskLong(long i) { - return (i << 2) & 3; // transformed to: return 0; + return (i << LONG_MASK_WIDTH) & LONG_MASK; // transformed to: return 0; } @@ -81,11 +133,11 @@ public class TestShiftAndMask { int mask; if (flag) { barrier = 42; - mask = 3; + mask = INT_MASK; } else { - mask = 1; + mask = INT_MASK2; } - return mask & (i << 2); // transformed to: return 0; + return mask & (i << INT_MASK_WIDTH); // transformed to: return 0; } @Check(test = "shiftNonConstMaskInt") @@ -102,11 +154,11 @@ public class TestShiftAndMask { long mask; if (flag) { barrier = 42; - mask = 3; + mask = LONG_MASK; } else { - mask = 1; + mask = LONG_MASK2; } - return mask & (i << 2); // transformed to: return 0; + return mask & (i << LONG_MASK_WIDTH); // transformed to: return 0; } @Check(test = "shiftNonConstMaskLong") @@ -120,7 +172,7 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_I, "1" }) @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) public static int addShiftMaskInt(int i, int j) { - return (j + (i << 2)) & 3; // transformed to: return j & 3; + return (j + (i << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftMaskInt") @@ -128,11 +180,42 @@ public class TestShiftAndMask { int i = RANDOM.nextInt(); int j = RANDOM.nextInt(); int res = addShiftMaskInt(i, j); - if (res != (j & 3)) { + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } } + @Test + @IR(counts = { IRNode.AND_I, "1" }) + @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) + public static int addShiftPlusConstMaskInt(int i, int j) { + return (j + ((i + INT_RANDOM_CONST) << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return j & INT_MASK; + } + + @Run(test = "addShiftPlusConstMaskInt") + public static void addShiftPlusConstMaskInt_runner() { + int i = RANDOM.nextInt(); + int j = RANDOM.nextInt(); + int res = addShiftPlusConstMaskInt(i, j); + if (res != (j & INT_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(counts = { IRNode.ADD_I, "2", IRNode.LSHIFT_I, "1" }) + public static int addShiftPlusConstDisjointMaskInt(int i, int j) { + return (j + ((i + 5) << 2)) & 32; // NOT transformed even though (5<<2) & 32 == 0 + } + + @Test + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" }) + public static int addShiftPlusConstOverlyLargeShift(int i, int j) { + return (j + i << 129) & 32; // NOT transformed, only lower 5 bits of shift count. + } + @Test @IR(counts = { IRNode.AND_I, "1" }) @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) @@ -140,11 +223,11 @@ public class TestShiftAndMask { int mask; if (flag) { barrier = 42; - mask = 3; + mask = INT_MASK; } else { - mask = 1; + mask = INT_MASK2; } - return mask & (j + (i << 2)); // transformed to: return j & mask; + return mask & (j + (i << INT_MASK_WIDTH)); // transformed to: return j & mask; } @Run(test = "addSshiftNonConstMaskInt") @@ -152,11 +235,38 @@ public class TestShiftAndMask { int i = RANDOM.nextInt(); int j = RANDOM.nextInt(); int res = addSshiftNonConstMaskInt(i, j, true); - if (res != (j & 3)) { + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } res = addSshiftNonConstMaskInt(i, j, false); - if (res != (j & 1)) { + if (res != (j & INT_MASK2)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_I, "1" }) + @IR(failOn = { IRNode.ADD_I }) + public static int addConstNonConstMaskInt(int j, boolean flag) { + int mask; + if (flag) { + barrier = 42; + mask = INT_MASK; + } else { + mask = INT_MASK2; + } + return mask & (j + INT_ZERO_CONST); // transformed to: return j & mask; + } + + @Run(test = "addConstNonConstMaskInt") + public static void addConstNonConstMaskInt_runner() { + int j = RANDOM.nextInt(); + int res = addConstNonConstMaskInt(j, true); + if (res != (j & INT_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + res = addConstNonConstMaskInt(j, false); + if (res != (j & INT_MASK2)) { throw new RuntimeException("incorrect result: " + res); } } @@ -165,7 +275,7 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) public static long addShiftMaskLong(long i, long j) { - return (j + (i << 2)) & 3; // transformed to: return j & 3; + return (j + (i << LONG_MASK_WIDTH)) & LONG_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftMaskLong") @@ -173,7 +283,24 @@ public class TestShiftAndMask { long i = RANDOM.nextLong(); long j = RANDOM.nextLong(); long res = addShiftMaskLong(i, j); - if (res != (j & 3)) { + if (res != (j & LONG_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) + public static long addShiftPlusConstMaskLong(long i, long j) { + return (j + ((i + LONG_RANDOM_CONST) << LONG_MASK_WIDTH)) & LONG_MASK; // transformed to: return j & LONG_MASK; + } + + @Run(test = "addShiftPlusConstMaskLong") + public static void addShiftPlusConstMaskLong_runner() { + long i = RANDOM.nextLong(); + long j = RANDOM.nextLong(); + long res = addShiftPlusConstMaskLong(i, j); + if (res != (j & LONG_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -182,14 +309,14 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) public static long addSshiftNonConstMaskLong(long i, long j, boolean flag) { - int mask; + long mask; if (flag) { barrier = 42; - mask = 3; + mask = LONG_MASK; } else { - mask = 1; + mask = LONG_MASK2; } - return mask & (j + (i << 2)); // transformed to: return j & mask; + return mask & (j + (i << LONG_MASK_WIDTH)); // transformed to: return j & mask } @Run(test = "addSshiftNonConstMaskLong") @@ -197,11 +324,38 @@ public class TestShiftAndMask { long i = RANDOM.nextLong(); long j = RANDOM.nextLong(); long res = addSshiftNonConstMaskLong(i, j, true); - if (res != (j & 3)) { + if (res != (j & LONG_MASK)) { throw new RuntimeException("incorrect result: " + res); } res = addSshiftNonConstMaskLong(i, j, false); - if (res != (j & 1)) { + if (res != (j & LONG_MASK2)) { + throw new RuntimeException("incorrect result: " + res); + } + } + + @Test + @IR(counts = { IRNode.AND_L, "1" }) + @IR(failOn = { IRNode.ADD_L }) + public static long addConstNonConstMaskLong(long j, boolean flag) { + long mask; + if (flag) { + barrier = 42; + mask = LONG_MASK; + } else { + mask = LONG_MASK2; + } + return mask & (j + LONG_ZERO_CONST); // transformed to: return j & mask; + } + + @Run(test = "addConstNonConstMaskLong") + public static void addConstNonConstMaskLong_runner() { + long j = RANDOM.nextLong(); + long res = addConstNonConstMaskLong(j, true); + if (res != (j & LONG_MASK)) { + throw new RuntimeException("incorrect result: " + res); + } + res = addConstNonConstMaskLong(j, false); + if (res != (j & LONG_MASK2)) { throw new RuntimeException("incorrect result: " + res); } } @@ -210,7 +364,7 @@ public class TestShiftAndMask { @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_I, IRNode.ADD_I, IRNode.LSHIFT_I }) public static int addShiftMaskInt2(int i, int j) { - return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; + return ((j << INT_MASK_WIDTH) + (i << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return 0; } @Check(test = "addShiftMaskInt2") @@ -224,7 +378,7 @@ public class TestShiftAndMask { @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_L }) public static long addShiftMaskLong2(long i, long j) { - return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; + return ((j << INT_MASK_WIDTH) + (i << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return 0; } @Check(test = "addShiftMaskLong2") @@ -239,9 +393,9 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_I, "1" }) @IR(failOn = { IRNode.ADD_I, IRNode.LSHIFT_I }) public static int addShiftMaskInt3(int i, long j) { - int add1 = (i << 2); + int add1 = (i << INT_MASK_WIDTH); int add2 = (int)j; - return (add1 + add2) & 3; // transformed to: return j & 3; + return (add1 + add2) & INT_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftMaskInt3") @@ -249,7 +403,7 @@ public class TestShiftAndMask { int i = RANDOM.nextInt(); int j = RANDOM.nextInt(); int res = addShiftMaskInt3(i, j); - if (res != (j & 3)) { + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -258,9 +412,9 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_L }) public static long addShiftMaskLong3(long i, float j) { - long add1 = (i << 2); + long add1 = (i << LONG_MASK_WIDTH); long add2 = (long)j; - return (add1 + add2) & 3; // transformed to: return j & 3; + return (add1 + add2) & LONG_MASK; // transformed to: return j & LONG_MASK; } @Run(test = "addShiftMaskLong3") @@ -268,7 +422,7 @@ public class TestShiftAndMask { long i = RANDOM.nextLong(); float j = RANDOM.nextFloat(); long res = addShiftMaskLong3(i, j); - if (res != (((long)j) & 3)) { + if (res != (((long) j) & LONG_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -277,7 +431,7 @@ public class TestShiftAndMask { @Arguments(values = {Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long shiftConvMask(int i) { - return ((long)(i << 2)) & 3; // transformed to: return 0; + return ((long) (i << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return 0; } @Check(test = "shiftConvMask") @@ -294,11 +448,11 @@ public class TestShiftAndMask { long mask; if (flag) { barrier = 42; - mask = 3; + mask = INT_MASK; } else { - mask = 1; + mask = INT_MASK2; } - return mask & ((long)(i << 2)); // transformed to: return 0; + return mask & ((long) (i << INT_MASK_WIDTH)); // transformed to: return 0; } @Check(test = "shiftNotConstConvMask") @@ -312,7 +466,7 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long addShiftConvMask(int i, long j) { - return (j + (i << 2)) & 3; // transformed to: return j & 3; + return (j + (i << INT_MASK_WIDTH)) & INT_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftConvMask") @@ -320,7 +474,7 @@ public class TestShiftAndMask { int i = RANDOM.nextInt(); long j = RANDOM.nextLong(); long res = addShiftConvMask(i, j); - if (res != (j & 3)) { + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -329,7 +483,7 @@ public class TestShiftAndMask { @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long addShiftConvMask2(int i, int j) { - return (((long)(j << 2)) + ((long)(i << 2))) & 3; // transformed to: return 0; + return (((long) (j << INT_MASK_WIDTH)) + ((long) (i << INT_MASK_WIDTH))) & INT_MASK; // transformed to: return 0; } @Check(test = "addShiftConvMask2") @@ -342,13 +496,13 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_I }) public static int shiftMaskIntCheckIndex(int i, int length) { - return Objects.checkIndex(i << 2, length) & 3; // transformed to: return 0; + return Objects.checkIndex(i << INT_MASK_WIDTH, length) & INT_MASK; // transformed to: return 0; } @Run(test = "shiftMaskIntCheckIndex") public static void shiftMaskIntCheckIndex_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - int res = shiftMaskIntCheckIndex(i, (i << 2) + 1); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + int res = shiftMaskIntCheckIndex(i, (i << INT_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } @@ -357,13 +511,13 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_L }) public static long shiftMaskLongCheckIndex(long i, long length) { - return Objects.checkIndex(i << 2, length) & 3; // transformed to: return 0; + return Objects.checkIndex(i << LONG_MASK_WIDTH, length) & LONG_MASK; // transformed to: return 0; } @Run(test = "shiftMaskLongCheckIndex") public static void shiftMaskLongCheckIndex_runner() { - long i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - long res = shiftMaskLongCheckIndex(i, (i << 2) + 1); + long i = RANDOM.nextLong((Long.MAX_VALUE - 1) >> LONG_MASK_WIDTH); + long res = shiftMaskLongCheckIndex(i, (i << LONG_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } @@ -373,15 +527,15 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_I, "1" }) @IR(failOn = { IRNode.ADD_I }) public static int addShiftMaskIntCheckIndex(int i, int j, int length) { - return (j + Objects.checkIndex(i << 2, length)) & 3; // transformed to: return j & 3; + return (j + Objects.checkIndex(i << INT_MASK_WIDTH, length)) & INT_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftMaskIntCheckIndex") public static void addShiftMaskIntCheckIndex_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); int j = RANDOM.nextInt(); - int res = addShiftMaskIntCheckIndex(i, j, (i << 2) + 1); - if (res != (j & 3)) { + int res = addShiftMaskIntCheckIndex(i, j, (i << INT_MASK_WIDTH) + 1); + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -390,15 +544,15 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L }) public static long addShiftMaskLongCheckIndex(long i, long j, long length) { - return (j + Objects.checkIndex(i << 2, length)) & 3; // transformed to: return j & 3; + return (j + Objects.checkIndex(i << LONG_MASK_WIDTH, length)) & LONG_MASK; // transformed to: return j & LONG_MASK; } @Run(test = "addShiftMaskLongCheckIndex") public static void addShiftMaskLongCheckIndex_runner() { - long i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); + long i = RANDOM.nextLong((Long.MAX_VALUE - 1) >> LONG_MASK_WIDTH); long j = RANDOM.nextLong(); - long res = addShiftMaskLongCheckIndex(i, j, (i << 2) + 1); - if (res != (j & 3)) { + long res = addShiftMaskLongCheckIndex(i, j, (i << LONG_MASK_WIDTH) + 1); + if (res != (j & LONG_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -406,15 +560,15 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_I, IRNode.ADD_I }) public static int addShiftMaskIntCheckIndex2(int i, int j, int length) { - return (Objects.checkIndex(j << 2, length) + Objects.checkIndex(i << 2, length)) & 3; // transformed to: return 0; + return (Objects.checkIndex(j << INT_MASK_WIDTH, length) + Objects.checkIndex(i << INT_MASK_WIDTH, length)) & INT_MASK; // transformed to: return 0; } @Run(test = "addShiftMaskIntCheckIndex2") public static void addShiftMaskIntCheckIndex2_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - int j = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - int res = addShiftMaskIntCheckIndex2(i, j, (Integer.max(i, j) << 2) + 1); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + int j = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + int res = addShiftMaskIntCheckIndex2(i, j, (Integer.max(i, j) << INT_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } @@ -423,14 +577,14 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_L, IRNode.ADD_L }) public static long addShiftMaskLongCheckIndex2(long i, long j, long length) { - return (Objects.checkIndex(j << 2, length) + Objects.checkIndex(i << 2, length)) & 3; // transformed to: return 0; + return (Objects.checkIndex(j << LONG_MASK_WIDTH, length) + Objects.checkIndex(i << LONG_MASK_WIDTH, length)) & LONG_MASK; // transformed to: return 0; } @Run(test = "addShiftMaskLongCheckIndex2") public static void addShiftMaskLongCheckIndex2_runner() { - long i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - long j = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - long res = addShiftMaskLongCheckIndex2(i, j, (Long.max(i, j) << 2) + 1); + long i = RANDOM.nextLong((Long.MAX_VALUE - 1) >> LONG_MASK_WIDTH); + long j = RANDOM.nextLong((Long.MAX_VALUE - 1) >> LONG_MASK_WIDTH); + long res = addShiftMaskLongCheckIndex2(i, j, (Long.max(i, j) << LONG_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } @@ -439,13 +593,13 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_L, IRNode.CONV_I2L }) public static long shiftConvMaskCheckIndex(int i, int length) { - return ((long)Objects.checkIndex(i << 2, length)) & 3; // transformed to: return 0; + return ((long) Objects.checkIndex(i << INT_MASK_WIDTH, length)) & INT_MASK; // transformed to: return 0; } @Run(test = "shiftConvMaskCheckIndex") public static void shiftConvMaskCheckIndex_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - long res = shiftConvMaskCheckIndex(i, (i << 2) + 1); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + long res = shiftConvMaskCheckIndex(i, (i << INT_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } @@ -455,15 +609,15 @@ public class TestShiftAndMask { @IR(counts = { IRNode.AND_L, "1" }) @IR(failOn = { IRNode.ADD_L, IRNode.CONV_I2L }) public static long addShiftConvMaskCheckIndex(int i, long j, int length) { - return (j + Objects.checkIndex(i << 2, length)) & 3; // transformed to: return j & 3; + return (j + Objects.checkIndex(i << INT_MASK_WIDTH, length)) & INT_MASK; // transformed to: return j & INT_MASK; } @Run(test = "addShiftConvMaskCheckIndex") public static void addShiftConvMaskCheckIndex_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); long j = RANDOM.nextLong(); - long res = addShiftConvMaskCheckIndex(i, j, (i << 2) + 1); - if (res != (j & 3)) { + long res = addShiftConvMaskCheckIndex(i, j, (i << INT_MASK_WIDTH) + 1); + if (res != (j & INT_MASK)) { throw new RuntimeException("incorrect result: " + res); } } @@ -471,14 +625,14 @@ public class TestShiftAndMask { @Test @IR(failOn = { IRNode.AND_L, IRNode.ADD_L }) public static long addShiftConvMaskCheckIndex2(int i, int j, int length) { - return (((long)Objects.checkIndex(j << 2, length)) + ((long)Objects.checkIndex(i << 2, length))) & 3; // transformed to: return 0; + return (((long) Objects.checkIndex(j << INT_MASK_WIDTH, length)) + ((long) Objects.checkIndex(i << INT_MASK_WIDTH, length))) & INT_MASK; // transformed to: return 0; } @Run(test = "addShiftConvMaskCheckIndex2") public static void addShiftConvMaskCheckIndex2_runner() { - int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - int j = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> 2); - long res = addShiftConvMaskCheckIndex2(i, j, (Integer.max(i, j) << 2) + 1); + int i = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + int j = RANDOM.nextInt((Integer.MAX_VALUE - 1) >> INT_MASK_WIDTH); + long res = addShiftConvMaskCheckIndex2(i, j, (Integer.max(i, j) << INT_MASK_WIDTH) + 1); if (res != 0) { throw new RuntimeException("incorrect result: " + res); } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index a9b158f1c09..09b087bee54 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java @@ -173,9 +173,13 @@ public class TestEquivalentInvariants { return testMemorySegmentIInvarL3e(data, 1, 2, 3, RANGE-200); }); tests.put("testMemorySegmentIInvarL3f", () -> { - MemorySegment data = MemorySegment.ofArray(aI.clone()); + MemorySegment data = MemorySegment.ofArray(aL.clone()); return testMemorySegmentIInvarL3f(data, 1, 2, 3, RANGE-200); }); + tests.put("testMemorySegmentIInvarL3g", () -> { + MemorySegment data = MemorySegment.ofArray(aI.clone()); + return testMemorySegmentIInvarL3g(data, 1, 2, 3, RANGE-200); + }); tests.put("testMemorySegmentLInvarL3a", () -> { MemorySegment data = MemorySegment.ofArray(aL.clone()); return testMemorySegmentLInvarL3a(data, 1, 2, 3, RANGE-200); @@ -246,6 +250,7 @@ public class TestEquivalentInvariants { "testMemorySegmentIInvarL3d3", "testMemorySegmentIInvarL3e", "testMemorySegmentIInvarL3f", + "testMemorySegmentIInvarL3g", "testMemorySegmentLInvarL3a", "testMemorySegmentLInvarL3b", "testMemorySegmentLInvarL3c", @@ -681,12 +686,17 @@ public class TestEquivalentInvariants { } @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - // Would be nice if it vectorized. - // Fails because of control flow. Somehow the "offsetPlain" check (checks for alignment) is not folded away. + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. static Object[] testMemorySegmentIInvarL3d(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); long i2 = (long)(invar2 + invar3 - invar1); // equivalent @@ -700,12 +710,17 @@ public class TestEquivalentInvariants { } @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - // Would be nice if it vectorized. - // Fails because of control flow. Somehow the "offsetPlain" check (checks for alignment) is not folded away. + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. static Object[] testMemorySegmentIInvarL3d2(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); for (int i = 0; i < size; i+=2) { @@ -735,6 +750,31 @@ public class TestEquivalentInvariants { return new Object[]{ m }; } + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. + static Object[] testMemorySegmentIInvarL3e(MemorySegment m, int invar1, int invar2, int invar3, int size) { + long i1 = (long)(-invar1 + invar2 + invar3); + long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent + for (int i = 0; i < size; i+=2) { + int v0 = m.getAtIndex(ValueLayout.JAVA_INT, i + i1 + 0); + int v1 = m.getAtIndex(ValueLayout.JAVA_INT, i + i2 + 1); + m.setAtIndex(ValueLayout.JAVA_INT, i + i1 + 0, v0 + 1); + m.setAtIndex(ValueLayout.JAVA_INT, i + i2 + 1, v1 + 1); + } + return new Object[]{ m }; + } + + // Same as testMemorySegmentIInvarL3e, but with long[] input. @Test @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", IRNode.STORE_VECTOR, "= 0"}, @@ -743,7 +783,7 @@ public class TestEquivalentInvariants { // Should never vectorize, since i1 and i2 are not guaranteed to be adjacent // invar2 + invar3 could overflow, and the address be valid with and without overflow. // So both addresses are valid, and not adjacent. - static Object[] testMemorySegmentIInvarL3e(MemorySegment m, int invar1, int invar2, int invar3, int size) { + static Object[] testMemorySegmentIInvarL3f(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent for (int i = 0; i < size; i+=2) { @@ -762,7 +802,7 @@ public class TestEquivalentInvariants { applyIfPlatform = {"64-bit", "true"}, applyIf = {"AlignVector", "false"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - static Object[] testMemorySegmentIInvarL3f(MemorySegment m, long invar1, long invar2, long invar3, int size) { + static Object[] testMemorySegmentIInvarL3g(MemorySegment m, long invar1, long invar2, long invar3, int size) { long i1 = -invar1 + invar2 + invar3; long i2 = invar2 + invar3 - invar1; // equivalent for (int i = 0; i < size; i++) { @@ -825,12 +865,17 @@ public class TestEquivalentInvariants { } @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_L, "= 0", IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - // Would be nice if it vectorized. - // Fails because of control flow. Somehow the "offsetPlain" check (checks for alignment) is not folded away. + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. static Object[] testMemorySegmentLInvarL3d(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); long i2 = (long)(invar2 + invar3 - invar1); // equivalent @@ -844,12 +889,17 @@ public class TestEquivalentInvariants { } @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_L, "= 0", IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - // Would be nice if it vectorized. - // Fails because of control flow. Somehow the "offsetPlain" check (checks for alignment) is not folded away. + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. static Object[] testMemorySegmentLInvarL3d2(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); for (int i = 0; i < size; i+=2) { @@ -880,11 +930,17 @@ public class TestEquivalentInvariants { } @Test + @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "false"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) @IR(counts = {IRNode.LOAD_VECTOR_L, "= 0", IRNode.STORE_VECTOR, "= 0"}, applyIfPlatform = {"64-bit", "true"}, + applyIf = {"AlignVector", "true"}, applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) - // FAILS: should be ok to vectorize, but does not. Investigate in JDK-8331659. + // With AlignVector (strict alignment requirements): we cannot prove that the invariants are alignable -> no vectorization. static Object[] testMemorySegmentLInvarL3e(MemorySegment m, int invar1, int invar2, int invar3, int size) { long i1 = (long)(-invar1 + invar2 + invar3); long i2 = (long)(invar2 + invar3) - (long)(invar1); // not equivalent diff --git a/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java b/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java index e23accd27b0..afe733bad4b 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestPopulateIndex.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 @@ -78,17 +78,17 @@ public class TestPopulateIndex { } @Test - @IR(counts = {IRNode.POPULATE_INDEX, "> 0"}) + // Does not vectorize, possibly because the OrI is pushed through the Phi, see also JDK-8348096. public void exprWithIndex1() { for (int i = 0; i < count; i++) { - dst[i] = src[i] * (i & 7); + dst[i] = src[i] * (i | 7); } checkResultExprWithIndex1(); } public void checkResultExprWithIndex1() { for (int i = 0; i < count; i++) { - int expected = src[i] * (i & 7); + int expected = src[i] * (i | 7); if (dst[i] != expected) { throw new RuntimeException("Invalid result: dst[" + i + "] = " + dst[i] + " != " + expected); } @@ -112,4 +112,26 @@ public class TestPopulateIndex { } } } + + @Test + // Does not vectorize: due to sum-under-mask optimization. + // (i+0) & 7, (i+1) & 7 ... (i+8) & 7 .... -> PopulateIndex + // becomes + // (i+0) & 7, (i+1) & 7 ... (i+0) & 7 .... -> pattern broken + // See JDK-8349128. + public void exprWithIndex3() { + for (int i = 0; i < count; i++) { + dst[i] = src[i] * (i & 7); + } + checkResultExprWithIndex3(); + } + + public void checkResultExprWithIndex3() { + for (int i = 0; i < count; i++) { + int expected = src[i] * (i & 7); + if (dst[i] != expected) { + throw new RuntimeException("Invalid result: dst[" + i + "] = " + dst[i] + " != " + expected); + } + } + } } From 2bd8f026dbd449e810dc6ce96cd9235e5cb51a9b Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 17 Feb 2025 13:12:02 +0000 Subject: [PATCH 028/587] 8342524: Use latch in AbstractButton/bug6298940.java instead of delay Reviewed-by: azvegint, kizune, dnguyen, achung --- .../swing/AbstractButton/bug6298940.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 test/jdk/javax/swing/AbstractButton/bug6298940.java diff --git a/test/jdk/javax/swing/AbstractButton/bug6298940.java b/test/jdk/javax/swing/AbstractButton/bug6298940.java new file mode 100644 index 00000000000..c2857c68ae3 --- /dev/null +++ b/test/jdk/javax/swing/AbstractButton/bug6298940.java @@ -0,0 +1,93 @@ +/* + * 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 + * 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 6298940 + * @key headful + * @summary Tests that mnemonic keystroke fires an action + * @library /javax/swing/regtesthelpers + * @build Util + * @run main bug6298940 + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; + +import javax.swing.ButtonModel; +import javax.swing.DefaultButtonModel; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import static java.util.concurrent.TimeUnit.SECONDS; + +public final class bug6298940 { + private static JFrame frame; + + private static final CountDownLatch actionEvent = new CountDownLatch(1); + + private static void createAndShowGUI() { + ButtonModel model = new DefaultButtonModel(); + model.addActionListener(event -> { + System.out.println("ActionEvent"); + actionEvent.countDown(); + }); + model.setMnemonic('T'); + + JButton button = new JButton("Test"); + button.setModel(model); + + frame = new JFrame("bug6298940"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(button); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + SwingUtilities.invokeAndWait(bug6298940::createAndShowGUI); + + robot.waitForIdle(); + robot.delay(500); + + Util.hitMnemonics(robot, KeyEvent.VK_T); + + try { + if (!actionEvent.await(1, SECONDS)) { + throw new RuntimeException("Mnemonic didn't fire an action"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} From 906358d3a14ce755fec771f0a6bb856b3a8f3297 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 17 Feb 2025 13:13:15 +0000 Subject: [PATCH 029/587] 8294155: Exception thrown before awaitAndCheck hangs PassFailJFrame Reviewed-by: serb, azvegint, kizune --- .../java/awt/regtesthelpers/PassFailJFrame.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 95d925d7b3d..5f559ea47c3 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -1787,8 +1787,20 @@ public final class PassFailJFrame { public PassFailJFrame build() throws InterruptedException, InvocationTargetException { - validate(); - return new PassFailJFrame(this); + try { + validate(); + return new PassFailJFrame(this); + } catch (final Throwable t) { + // Dispose of all the windows, including those that may not + // be registered with PassFailJFrame to allow AWT to shut down + try { + invokeOnEDT(() -> Arrays.stream(Window.getWindows()) + .forEach(Window::dispose)); + } catch (Throwable edt) { + t.addSuppressed(edt); + } + throw t; + } } /** From 650d0d954ea8e20e31f17d459993d5edecf08a4c Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 17 Feb 2025 13:13:42 +0000 Subject: [PATCH 030/587] 8348865: JButton/bug4796987.java never runs because Windows XP is unavailable Reviewed-by: tr, abhiscxk, serb --- .../swing/JButton/4796987/bug4796987.java | 106 +++++++++++------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/test/jdk/javax/swing/JButton/4796987/bug4796987.java b/test/jdk/javax/swing/JButton/4796987/bug4796987.java index 62d11fc18c0..bfa6ef8d129 100644 --- a/test/jdk/javax/swing/JButton/4796987/bug4796987.java +++ b/test/jdk/javax/swing/JButton/4796987/bug4796987.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, 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,67 +26,91 @@ * @bug 4796987 * @key headful * @requires (os.family == "windows") - * @summary XP Only: JButton.setBorderPainted() does not work with XP L&F - * @author Alexander Scherbatiy + * @summary Verify JButton.setBorderPainted(false) removes border + * for Windows visual styles (Windows XP and later) * @library ../../regtesthelpers - * @library /test/lib - * @modules java.desktop/com.sun.java.swing.plaf.windows - * java.desktop/sun.awt - * @build jdk.test.lib.OSVersion jdk.test.lib.Platform * @build Util * @run main bug4796987 */ -import jdk.test.lib.Platform; -import jdk.test.lib.OSVersion; -import java.awt.*; -import javax.swing.*; -import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; public class bug4796987 { private static JButton button1; private static JButton button2; private static JFrame frame; + private static JPanel panel; public static void main(String[] args) throws Exception { try { - if (Platform.isWindows() - && OSVersion.current().equals(OSVersion.WINDOWS_XP)) { - UIManager.setLookAndFeel(new WindowsLookAndFeel()); - testButtonBorder(); - } + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + testButtonBorder(); } finally { - if (frame != null) SwingUtilities.invokeAndWait(() -> frame.dispose()); + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } private static void testButtonBorder() throws Exception { Robot robot = new Robot(); - robot.setAutoDelay(50); - - SwingUtilities.invokeAndWait(new Runnable() { - - public void run() { - createAndShowGUI(); - } - }); + SwingUtilities.invokeAndWait(bug4796987::createAndShowGUI); robot.waitForIdle(); - Thread.sleep(500); + robot.delay(500); - Point p1 = Util.getCenterPoint(button1); - Point p2 = Util.getCenterPoint(button2); + // Hover over button1 + Point b1Center = Util.getCenterPoint(button1); + robot.mouseMove(b1Center.x, b1Center.y); + robot.waitForIdle(); - Color color = robot.getPixelColor(p1.x, p2.x); - for (int dx = p1.x; dx < p2.x - p1.x; dx++) { - robot.mouseMove(p1.x + dx, p1.y); - if (!color.equals(robot.getPixelColor(p1.x + dx, p1.y))) { + Rectangle panelBounds = Util.invokeOnEDT(() -> + new Rectangle(panel.getLocationOnScreen(), + panel.getSize())); + BufferedImage image = robot.createScreenCapture(panelBounds); + + final Point p1 = Util.invokeOnEDT(() -> getCenterPoint(button1)); + final Point p2 = Util.invokeOnEDT(() -> getCenterPoint(button2)); + + final int color = image.getRGB(p1.x, p1.y); + for (int dx = 0; p1.x + dx < p2.x; dx++) { + if (color != image.getRGB(p1.x + dx, p1.y)) { + System.err.println("Wrong color at " + (p1.x + dx) + ", " + p1.y + + " - expected " + Integer.toHexString(color)); + saveImage(image); throw new RuntimeException("Button has border and background!"); } } } + /** + * {@return the center point of a button relative to its parent} + * @param button the button to calculate the center point + */ + private static Point getCenterPoint(JButton button) { + Point location = button.getLocation(); + Dimension size = button.getSize(); + location.translate(size.width / 2, size.height / 2); + return location; + } + private static JButton getButton() { JButton button = new JButton(); button.setBorderPainted(false); @@ -95,18 +119,24 @@ public class bug4796987 { } private static void createAndShowGUI() { - frame = new JFrame("Test"); + frame = new JFrame("bug4796987"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 200); - JButton button = new JButton(); - button.setBorder(null); - - JPanel panel = new JPanel(new BorderLayout(50, 50)); + panel = new JPanel(new BorderLayout(50, 50)); panel.add(getButton(), BorderLayout.CENTER); panel.add(button1 = getButton(), BorderLayout.WEST); panel.add(button2 = getButton(), BorderLayout.EAST); frame.getContentPane().add(panel); + frame.setLocationRelativeTo(null); frame.setVisible(true); } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("frame.png")); + } catch (IOException ignored) { + } + } } From 8b2aa51b0c36a993e46fea7a4b61788dd101d606 Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Mon, 17 Feb 2025 13:28:34 +0000 Subject: [PATCH 031/587] 8349780: AIX os::get_summary_cpu_info support Power 11 Reviewed-by: stuefe, amitkumar --- src/hotspot/os/aix/os_aix.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 9222104c6d6..bebd1f1a8c1 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -164,6 +164,12 @@ extern "C" int getargs(procsinfo*, int, char*, int); #ifndef PV_10_Compat #define PV_10_Compat 0x508000 /* Power PC 10 */ #endif +#ifndef PV_11 + #define PV_11 0x600000 /* Power PC 11 */ +#endif +#ifndef PV_11_Compat + #define PV_11_Compat 0x608000 /* Power PC 11 */ +#endif static address resolve_function_descriptor_to_code_pointer(address p); @@ -1219,6 +1225,9 @@ void os::print_memory_info(outputStream* st) { void os::get_summary_cpu_info(char* buf, size_t buflen) { // read _system_configuration.version switch (_system_configuration.version) { + case PV_11: + strncpy(buf, "Power PC 11", buflen); + break; case PV_10: strncpy(buf, "Power PC 10", buflen); break; @@ -1264,6 +1273,9 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { case PV_10_Compat: strncpy(buf, "PV_10_Compat", buflen); break; + case PV_11_Compat: + strncpy(buf, "PV_11_Compat", buflen); + break; default: strncpy(buf, "unknown", buflen); } From 3f0c1370269db978072814c2170fc3987efade85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 17 Feb 2025 15:31:18 +0000 Subject: [PATCH 032/587] 8347123: Add missing @serial tags to other modules Reviewed-by: prr, nbenalla, alanb --- .../classes/java/awt/datatransfer/DataFlavor.java | 5 ++++- .../classes/javax/management/ImmutableDescriptor.java | 6 +++--- .../classes/javax/management/MBeanPermission.java | 2 +- .../classes/javax/management/remote/JMXServiceURL.java | 10 +++++----- .../javax/management/remote/NotificationResult.java | 5 ++++- .../share/classes/javax/script/ScriptException.java | 5 ++++- .../javax/security/auth/kerberos/KerberosTicket.java | 4 ++-- .../share/classes/javax/smartcardio/ATR.java | 3 ++- .../classes/javax/sql/rowset/serial/SerialBlob.java | 4 ++-- .../classes/javax/sql/rowset/serial/SerialClob.java | 4 ++-- .../javax/sql/rowset/serial/SerialJavaObject.java | 6 +++--- .../classes/javax/sql/rowset/serial/SerialRef.java | 6 +++--- .../javax/sql/rowset/spi/SyncProviderException.java | 4 ++-- .../share/classes/java/sql/SQLClientInfoException.java | 4 ++-- .../share/classes/javax/sql/StatementEvent.java | 6 +++--- .../javax/xml/crypto/URIReferenceException.java | 4 ++-- .../share/classes/javax/xml/namespace/QName.java | 6 +++--- .../javax/xml/parsers/FactoryConfigurationError.java | 4 ++-- .../javax/xml/stream/FactoryConfigurationError.java | 4 ++-- .../classes/javax/xml/stream/XMLStreamException.java | 6 +++++- .../javax/xml/transform/TransformerException.java | 6 +++--- .../TransformerFactoryConfigurationError.java | 4 ++-- .../share/classes/org/w3c/dom/DOMException.java | 4 ++++ .../classes/org/w3c/dom/events/EventException.java | 3 +++ .../share/classes/org/w3c/dom/ls/LSException.java | 3 +++ .../classes/org/w3c/dom/ranges/RangeException.java | 3 +++ .../sun/tools/attach/AgentInitializationException.java | 3 ++- .../share/classes/jdk/dynalink/beans/StaticClass.java | 4 ++-- .../share/classes/jdk/incubator/vector/Float16.java | 1 + .../classes/com/sun/jdi/ClassNotLoadedException.java | 3 ++- .../share/classes/com/sun/jdi/InternalException.java | 3 ++- .../share/classes/com/sun/jdi/InvocationException.java | 3 ++- .../connect/IllegalConnectorArgumentsException.java | 3 ++- .../classes/com/sun/jdi/connect/VMStartException.java | 3 ++- .../share/classes/jdk/jshell/EvalException.java | 3 ++- .../jdk/jshell/UnresolvedReferenceException.java | 3 ++- .../share/classes/jdk/jshell/spi/ExecutionControl.java | 7 ++++++- .../classes/jdk/jshell/spi/SPIResolutionException.java | 3 ++- .../classes/org/w3c/dom/xpath/XPathException.java | 3 +++ 39 files changed, 104 insertions(+), 59 deletions(-) diff --git a/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java b/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java index 3a18834a567..cfb89118ff7 100644 --- a/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.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 @@ -1286,6 +1286,9 @@ public class DataFlavor implements Externalizable, Cloneable { /** * Serializes this {@code DataFlavor}. + * + * @serialData The {@code mimeType} field with the {@code humanPresentableName} parameter set, + * followed by the {@code representationClass} field */ public synchronized void writeExternal(ObjectOutput os) throws IOException { if (mimeType != null) { diff --git a/src/java.management/share/classes/javax/management/ImmutableDescriptor.java b/src/java.management/share/classes/javax/management/ImmutableDescriptor.java index c151f423215..c9044b68ed2 100644 --- a/src/java.management/share/classes/javax/management/ImmutableDescriptor.java +++ b/src/java.management/share/classes/javax/management/ImmutableDescriptor.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 @@ -42,13 +42,13 @@ public class ImmutableDescriptor implements Descriptor { private static final long serialVersionUID = 8853308591080540165L; /** - * The names of the fields in this ImmutableDescriptor with their + * @serial The names of the fields in this ImmutableDescriptor with their * original case. The names must be in alphabetical order as determined * by {@link String#CASE_INSENSITIVE_ORDER}. */ private final String[] names; /** - * The values of the fields in this ImmutableDescriptor. The + * @serial The values of the fields in this ImmutableDescriptor. The * elements in this array match the corresponding elements in the * {@code names} array. */ diff --git a/src/java.management/share/classes/javax/management/MBeanPermission.java b/src/java.management/share/classes/javax/management/MBeanPermission.java index abc3cdda7a8..b26df6edada 100644 --- a/src/java.management/share/classes/javax/management/MBeanPermission.java +++ b/src/java.management/share/classes/javax/management/MBeanPermission.java @@ -222,7 +222,7 @@ public class MBeanPermission extends Permission { UnregisterMBean; /** - * The actions string. + * @serial The actions string. */ private String actions; diff --git a/src/java.management/share/classes/javax/management/remote/JMXServiceURL.java b/src/java.management/share/classes/javax/management/remote/JMXServiceURL.java index 61dfeaffeae..b6c2860b9cd 100644 --- a/src/java.management/share/classes/javax/management/remote/JMXServiceURL.java +++ b/src/java.management/share/classes/javax/management/remote/JMXServiceURL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, 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 @@ -758,22 +758,22 @@ public class JMXServiceURL implements Serializable { } /** - * The value returned by {@link #getProtocol()}. + * @serial The value returned by {@link #getProtocol()}. */ private String protocol; /** - * The value returned by {@link #getHost()}. + * @serial The value returned by {@link #getHost()}. */ private String host; /** - * The value returned by {@link #getPort()}. + * @serial The value returned by {@link #getPort()}. */ private int port; /** - * The value returned by {@link #getURLPath()}. + * @serial The value returned by {@link #getURLPath()}. */ private String urlPath; diff --git a/src/java.management/share/classes/javax/management/remote/NotificationResult.java b/src/java.management/share/classes/javax/management/remote/NotificationResult.java index 4dedcc348fc..7c147cfc3dc 100644 --- a/src/java.management/share/classes/javax/management/remote/NotificationResult.java +++ b/src/java.management/share/classes/javax/management/remote/NotificationResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, 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 @@ -148,8 +148,11 @@ public class NotificationResult implements Serializable { } } + /** @serial */ private long earliestSequenceNumber; + /** @serial */ private long nextSequenceNumber; + /** @serial */ private TargetedNotification[] targetedNotifications; private static void validate(TargetedNotification[] targetedNotifications, diff --git a/src/java.scripting/share/classes/javax/script/ScriptException.java b/src/java.scripting/share/classes/javax/script/ScriptException.java index f10ead75510..1037ccde27f 100644 --- a/src/java.scripting/share/classes/javax/script/ScriptException.java +++ b/src/java.scripting/share/classes/javax/script/ScriptException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, 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,8 +38,11 @@ public class ScriptException extends Exception { private static final long serialVersionUID = 8265071037049225001L; + /** @serial */ private final String fileName; + /** @serial */ private final int lineNumber; + /** @serial */ private final int columnNumber; /** diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java index d82337c3e2e..333a6ec0a8e 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.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 @@ -187,7 +187,7 @@ public class KerberosTicket implements Destroyable, Refreshable, private InetAddress[] clientAddresses; /** - * Evidence ticket if proxy_impersonator. This field can be accessed + * @serial Evidence ticket if proxy_impersonator. This field can be accessed * by KerberosSecrets. It's serialized. */ KerberosTicket proxy = null; diff --git a/src/java.smartcardio/share/classes/javax/smartcardio/ATR.java b/src/java.smartcardio/share/classes/javax/smartcardio/ATR.java index 49537c394e5..6038d8ded92 100644 --- a/src/java.smartcardio/share/classes/javax/smartcardio/ATR.java +++ b/src/java.smartcardio/share/classes/javax/smartcardio/ATR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, 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 @@ -46,6 +46,7 @@ public final class ATR implements java.io.Serializable { private static final long serialVersionUID = 6695383790847736493L; + /** @serial */ private byte[] atr; private transient int startHistorical, nHistorical; diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialBlob.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialBlob.java index 34474deb593..9d499ab03b7 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialBlob.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -70,7 +70,7 @@ public class SerialBlob implements Blob, Serializable, Cloneable { private byte[] buf; /** - * The internal representation of the Blob object on which this + * @serial The internal representation of the Blob object on which this * SerialBlob object is based. */ @SuppressWarnings("serial") // Not statically typed as Serializable; checked in writeObject diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialClob.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialClob.java index b64001a0a91..51ae1d8f336 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialClob.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialClob.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 @@ -65,7 +65,7 @@ public class SerialClob implements Clob, Serializable, Cloneable { private char buf[]; /** - * Internal Clob representation if SerialClob is initialized with a + * @serial Internal Clob representation if SerialClob is initialized with a * Clob. Null if SerialClob is initialized with a char[]. */ @SuppressWarnings("serial") // Not statically typed as Serializable; checked in writeObject diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java index 154c95bc1c4..9486c325278 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.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 @@ -56,7 +56,7 @@ import javax.sql.rowset.RowSetWarning; public class SerialJavaObject implements Serializable, Cloneable { /** - * Placeholder for object to be serialized. + * @serial Placeholder for object to be serialized. */ @SuppressWarnings("serial") // Not statically typed as Serializable private Object obj; @@ -139,7 +139,7 @@ public class SerialJavaObject implements Serializable, Cloneable { static final long serialVersionUID = -1465795139032831023L; /** - * A container for the warnings issued on this SerialJavaObject + * @serial A container for the warnings issued on this SerialJavaObject * object. When there are multiple warnings, each warning is chained to the * previous warning. */ diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialRef.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialRef.java index f31df04e914..4e8bbc9ea0a 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialRef.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, 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 @@ -54,13 +54,13 @@ public class SerialRef implements Ref, Serializable, Cloneable { private String baseTypeName; /** - * This will store the type Ref as an Object. + * @serial This will store the type Ref as an Object. */ @SuppressWarnings("serial") // Not statically typed as Serializable private Object object; /** - * Private copy of the Ref reference. + * @serial Private copy of the Ref reference. */ @SuppressWarnings("serial") // Not statically typed as Serializable; checked in writeObject private Ref reference; diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncProviderException.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncProviderException.java index 694d6b56314..b1dd9f7e761 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncProviderException.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncProviderException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, 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 @@ -66,7 +66,7 @@ import javax.sql.rowset.*; public class SyncProviderException extends java.sql.SQLException { /** - * The instance of javax.sql.rowset.spi.SyncResolver that + * @serial The instance of javax.sql.rowset.spi.SyncResolver that * this SyncProviderException object will return when its * getSyncResolver method is called. */ diff --git a/src/java.sql/share/classes/java/sql/SQLClientInfoException.java b/src/java.sql/share/classes/java/sql/SQLClientInfoException.java index 59a479b8056..fdffd2fc931 100644 --- a/src/java.sql/share/classes/java/sql/SQLClientInfoException.java +++ b/src/java.sql/share/classes/java/sql/SQLClientInfoException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, 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 @@ -48,7 +48,7 @@ import java.util.Map; public class SQLClientInfoException extends SQLException { /** - * A {@code Map} containing the client info properties that could not be set. + * @serial A {@code Map} containing the client info properties that could not be set. */ @SuppressWarnings("serial") // Not statically typed as Serializable private Map failedProperties; diff --git a/src/java.sql/share/classes/javax/sql/StatementEvent.java b/src/java.sql/share/classes/javax/sql/StatementEvent.java index 6588bebfd40..68b0ebeb5e9 100644 --- a/src/java.sql/share/classes/javax/sql/StatementEvent.java +++ b/src/java.sql/share/classes/javax/sql/StatementEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, 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 @@ -44,12 +44,12 @@ public class StatementEvent extends EventObject { static final long serialVersionUID = -8089573731826608315L; /** - * The {@code SQLException} the driver is about to throw to the application. + * @serial The {@code SQLException} the driver is about to throw to the application. */ private SQLException exception; /** - * The {@code PreparedStatement} that is being closed or is invalid. + * @serial The {@code PreparedStatement} that is being closed or is invalid. */ @SuppressWarnings("serial") // Not statically typed as Serializable private PreparedStatement statement; diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java index df56fd3105a..766d10ee0a6 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.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 @@ -58,7 +58,7 @@ public class URIReferenceException extends Exception { private Throwable cause; /** - * The {@code URIReference} that was being dereferenced + * @serial The {@code URIReference} that was being dereferenced * when the exception was thrown, or {@code null} if not specified. */ @SuppressWarnings("serial") // Type of field is not Serializable diff --git a/src/java.xml/share/classes/javax/xml/namespace/QName.java b/src/java.xml/share/classes/javax/xml/namespace/QName.java index aaab6ae5333..8fb3e15d2bd 100644 --- a/src/java.xml/share/classes/javax/xml/namespace/QName.java +++ b/src/java.xml/share/classes/javax/xml/namespace/QName.java @@ -70,17 +70,17 @@ public class QName implements Serializable { private static final long serialVersionUID = -9120448754896609940L; /** - *

Namespace URI of this QName.

+ * @serial

Namespace URI of this QName.

*/ private final String namespaceURI; /** - *

local part of this QName.

+ * @serial

local part of this QName.

*/ private final String localPart; /** - *

prefix of this QName.

+ * @serial

prefix of this QName.

*/ private final String prefix; diff --git a/src/java.xml/share/classes/javax/xml/parsers/FactoryConfigurationError.java b/src/java.xml/share/classes/javax/xml/parsers/FactoryConfigurationError.java index 67a0152e761..cc17030c3a4 100644 --- a/src/java.xml/share/classes/javax/xml/parsers/FactoryConfigurationError.java +++ b/src/java.xml/share/classes/javax/xml/parsers/FactoryConfigurationError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, 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 @@ -39,7 +39,7 @@ public class FactoryConfigurationError extends Error { private static final long serialVersionUID = -827108682472263355L; /** - *Exception that represents the error. + * @serial Exception that represents the error. */ private Exception exception; diff --git a/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java b/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java index e882914b622..9a479a150c4 100644 --- a/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.java +++ b/src/java.xml/share/classes/javax/xml/stream/FactoryConfigurationError.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 @@ -37,7 +37,7 @@ public class FactoryConfigurationError extends Error { private static final long serialVersionUID = -2994412584589975744L; /** - * The nested exception. + * @serial The nested exception. */ Exception nested; diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java index a6bac73e528..e529e8a839c 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, 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 @@ -39,11 +39,15 @@ public class XMLStreamException extends Exception { /** * The nested exception. + * + * @serial */ protected Throwable nested; /** * The location of the error. + * + * @serial */ @SuppressWarnings("serial") // Type of field is not Serializable protected Location location; diff --git a/src/java.xml/share/classes/javax/xml/transform/TransformerException.java b/src/java.xml/share/classes/javax/xml/transform/TransformerException.java index 2e01dc00361..292486f4d5d 100644 --- a/src/java.xml/share/classes/javax/xml/transform/TransformerException.java +++ b/src/java.xml/share/classes/javax/xml/transform/TransformerException.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 @@ -44,7 +44,7 @@ public class TransformerException extends Exception { private static final long serialVersionUID = 975798773772956428L; - /** Field locator specifies where the error occurred */ + /** @serial Field locator specifies where the error occurred */ @SuppressWarnings("serial") // Type of field is not Serializable SourceLocator locator; @@ -68,7 +68,7 @@ public class TransformerException extends Exception { this.locator = location; } - /** Field containedException specifies a wrapped exception. May be null. */ + /** @serial Field containedException specifies a wrapped exception. May be null. */ Throwable containedException; /** diff --git a/src/java.xml/share/classes/javax/xml/transform/TransformerFactoryConfigurationError.java b/src/java.xml/share/classes/javax/xml/transform/TransformerFactoryConfigurationError.java index 3eda99138af..a620abfdd4a 100644 --- a/src/java.xml/share/classes/javax/xml/transform/TransformerFactoryConfigurationError.java +++ b/src/java.xml/share/classes/javax/xml/transform/TransformerFactoryConfigurationError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, 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 @@ -37,7 +37,7 @@ public class TransformerFactoryConfigurationError extends Error { private static final long serialVersionUID = -6527718720676281516L; /** - * Exception for the + * @serial Exception for the * TransformerFactoryConfigurationError. */ private Exception exception; diff --git a/src/java.xml/share/classes/org/w3c/dom/DOMException.java b/src/java.xml/share/classes/org/w3c/dom/DOMException.java index b49351ba621..10a4fd35a91 100644 --- a/src/java.xml/share/classes/org/w3c/dom/DOMException.java +++ b/src/java.xml/share/classes/org/w3c/dom/DOMException.java @@ -66,6 +66,10 @@ public class DOMException extends RuntimeException { super(message); this.code = code; } + + /** + * @serial + */ public short code; // ExceptionCode /** diff --git a/src/java.xml/share/classes/org/w3c/dom/events/EventException.java b/src/java.xml/share/classes/org/w3c/dom/events/EventException.java index 53bb3480754..778019b09de 100644 --- a/src/java.xml/share/classes/org/w3c/dom/events/EventException.java +++ b/src/java.xml/share/classes/org/w3c/dom/events/EventException.java @@ -54,6 +54,9 @@ public class EventException extends RuntimeException { super(message); this.code = code; } + /** + * @serial + */ public short code; // EventExceptionCode /** diff --git a/src/java.xml/share/classes/org/w3c/dom/ls/LSException.java b/src/java.xml/share/classes/org/w3c/dom/ls/LSException.java index 61ec756ed91..80f439a8020 100644 --- a/src/java.xml/share/classes/org/w3c/dom/ls/LSException.java +++ b/src/java.xml/share/classes/org/w3c/dom/ls/LSException.java @@ -64,6 +64,9 @@ public class LSException extends RuntimeException { super(message); this.code = code; } + /** + * @serial + */ public short code; // LSExceptionCode /** diff --git a/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java b/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java index 46a4eb5d9b6..41534ae94ba 100644 --- a/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java +++ b/src/java.xml/share/classes/org/w3c/dom/ranges/RangeException.java @@ -54,6 +54,9 @@ public class RangeException extends RuntimeException { super(message); this.code = code; } + /** + * @serial + */ public short code; // RangeExceptionCode /** diff --git a/src/jdk.attach/share/classes/com/sun/tools/attach/AgentInitializationException.java b/src/jdk.attach/share/classes/com/sun/tools/attach/AgentInitializationException.java index 520355c1d8b..4bf5c907280 100644 --- a/src/jdk.attach/share/classes/com/sun/tools/attach/AgentInitializationException.java +++ b/src/jdk.attach/share/classes/com/sun/tools/attach/AgentInitializationException.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 @@ -47,6 +47,7 @@ public class AgentInitializationException extends Exception { /** use serialVersionUID for interoperability */ static final long serialVersionUID = -1508756333332806353L; + /** @serial */ private int returnValue; /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java index f8c6a95b2d1..3aa2dabdc59 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.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 @@ -115,7 +115,7 @@ public final class StaticClass implements Serializable { private static final long serialVersionUID = 1L; /** - * The runtime {@code Class} object whose static members this + * @serial The runtime {@code Class} object whose static members this * {@code StaticClass} represents. */ private final Class clazz; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java index f918878324d..fce71e4589e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java @@ -101,6 +101,7 @@ import jdk.internal.vm.vector.Float16Math; public final class Float16 extends Number implements Comparable { + /** @serial */ private final short value; private static final long serialVersionUID = 16; // May not be needed when a value class? diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ClassNotLoadedException.java b/src/jdk.jdi/share/classes/com/sun/jdi/ClassNotLoadedException.java index 51cfac7e943..07135eb8458 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ClassNotLoadedException.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ClassNotLoadedException.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 @@ -71,6 +71,7 @@ public class ClassNotLoadedException extends Exception { private static final long serialVersionUID = -6242978768444298722L; + /** @serial */ private String className; public ClassNotLoadedException(String className) { diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/InternalException.java b/src/jdk.jdi/share/classes/com/sun/jdi/InternalException.java index ab7373b3574..2161812a4bf 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/InternalException.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/InternalException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, 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 @@ -36,6 +36,7 @@ public class InternalException extends RuntimeException { private static final long serialVersionUID = -9171606393104480607L; + /** @serial */ private int errorCode; public InternalException() { diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/InvocationException.java b/src/jdk.jdi/share/classes/com/sun/jdi/InvocationException.java index ecc1142990a..f13537d9ed9 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/InvocationException.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/InvocationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, 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 @@ -36,6 +36,7 @@ public class InvocationException extends Exception { private static final long serialVersionUID = 6066780907971918568L; + /** @serial */ @SuppressWarnings("serial") // Not statically typed as Serializable ObjectReference exception; diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/connect/IllegalConnectorArgumentsException.java b/src/jdk.jdi/share/classes/com/sun/jdi/connect/IllegalConnectorArgumentsException.java index 6a0dba81a04..dccf43a1bae 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/connect/IllegalConnectorArgumentsException.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/connect/IllegalConnectorArgumentsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, 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 @@ -40,6 +40,7 @@ public class IllegalConnectorArgumentsException extends Exception { private static final long serialVersionUID = -3042212603611350941L; + /** @serial */ @SuppressWarnings("serial") // Conditionally serializable List names; diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/connect/VMStartException.java b/src/jdk.jdi/share/classes/com/sun/jdi/connect/VMStartException.java index 45850a197f4..43ffcda25b3 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/connect/VMStartException.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/connect/VMStartException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, 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 @@ -38,6 +38,7 @@ public class VMStartException extends Exception { private static final long serialVersionUID = 6408644824640801020L; + /** @serial */ @SuppressWarnings("serial") // Not statically typed as Serializable Process process; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java b/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java index 01721db3fa6..783368f221b 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/EvalException.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 @@ -43,6 +43,7 @@ package jdk.jshell; */ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class EvalException extends JShellException { + /** @serial */ private final String exceptionClass; EvalException(String message, String exceptionClass, diff --git a/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java b/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java index 44c33e6a074..ab60ca36f2e 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.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 @@ -42,6 +42,7 @@ package jdk.jshell; @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class UnresolvedReferenceException extends JShellException { + /** @serial */ final DeclarationSnippet snippet; UnresolvedReferenceException(DeclarationSnippet snippet, StackTraceElement[] stackElements) { diff --git a/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java index 13514a1c5cf..830a354bebb 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.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 @@ -302,7 +302,9 @@ public interface ExecutionControl extends AutoCloseable { public static final class ClassBytecodes implements Serializable { private static final long serialVersionUID = 0xC1A55B47EC0DE5L; + /** @serial */ private final String name; + /** @serial */ private final byte[] bytecodes; /** @@ -389,6 +391,7 @@ public interface ExecutionControl extends AutoCloseable { private static final long serialVersionUID = 1L; + /** @serial */ private final boolean[] installed; public ClassInstallException(String message, boolean[] installed) { @@ -426,6 +429,7 @@ public interface ExecutionControl extends AutoCloseable { private static final long serialVersionUID = 1L; + /** @serial */ private final String causeExceptionClass; @SuppressWarnings("this-escape") @@ -459,6 +463,7 @@ public interface ExecutionControl extends AutoCloseable { private static final long serialVersionUID = 1L; + /** @serial */ private final int id; /** diff --git a/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java b/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java index c9199ab7495..60ba33beac4 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.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 @@ -39,6 +39,7 @@ package jdk.jshell.spi; @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class SPIResolutionException extends RuntimeException { + /** @serial */ private final int id; /** diff --git a/src/jdk.xml.dom/share/classes/org/w3c/dom/xpath/XPathException.java b/src/jdk.xml.dom/share/classes/org/w3c/dom/xpath/XPathException.java index e686e06b2a4..30b85cbcdb0 100644 --- a/src/jdk.xml.dom/share/classes/org/w3c/dom/xpath/XPathException.java +++ b/src/jdk.xml.dom/share/classes/org/w3c/dom/xpath/XPathException.java @@ -62,6 +62,9 @@ public class XPathException extends RuntimeException { super(message); this.code = code; } + /** + * @serial + */ public short code; // XPathExceptionCode /** From 8ec589390f7dc67dd883a1efddb8da32790f6591 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 17 Feb 2025 19:34:29 +0000 Subject: [PATCH 033/587] 8346781: [JVMCI] Limit ServiceLoader to class initializers Reviewed-by: never, yzheng --- .../classes/jdk/vm/ci/hotspot/Cleaner.java | 4 +- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 53 ++++------- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 2 +- .../vm/ci/services/JVMCIServiceLocator.java | 28 ++---- .../classes/jdk/vm/ci/services/Services.java | 89 ------------------- .../events/JvmciShutdownEventListener.java | 12 +-- .../jvmci/events/JvmciShutdownEventTest.java | 8 +- 7 files changed, 40 insertions(+), 156 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java index b6f4395f055..87760efb8a0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java @@ -36,7 +36,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; * referenced by this might be referenced by {@link ResolvedJavaType} which is kept alive by a * {@link WeakReference} so we need equivalent reference strength. */ -abstract class Cleaner extends WeakReference { +public abstract class Cleaner extends WeakReference { /** * Head of linked list of cleaners. @@ -107,7 +107,7 @@ abstract class Cleaner extends WeakReference { /** * Remove the cleaners whose referents have become weakly reachable. */ - static void clean() { + public static void clean() { Cleaner c = (Cleaner) queue.poll(); boolean oopHandleCleared = false; while (c != null) { 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 bc221c46717..0943b0f8162 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 @@ -23,7 +23,6 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.common.InitTimer.timer; -import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import java.io.IOException; @@ -453,33 +452,26 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { } } - private static HotSpotJVMCIBackendFactory findFactory(String architecture) { - Iterable factories = getHotSpotJVMCIBackendFactories(); - assert factories != null : "sanity"; - for (HotSpotJVMCIBackendFactory factory : factories) { - if (factory.getArchitecture().equalsIgnoreCase(architecture)) { - return factory; + /** + * The backend factory for the JVMCI shared library. + */ + private static final HotSpotJVMCIBackendFactory backendFactory; + static { + String arch = HotSpotVMConfig.getHostArchitectureName(); + HotSpotJVMCIBackendFactory selected = null; + for (HotSpotJVMCIBackendFactory factory : ServiceLoader.load(HotSpotJVMCIBackendFactory.class)) { + if (factory.getArchitecture().equalsIgnoreCase(arch)) { + if (selected != null) { + throw new JVMCIError("Multiple factories available for %s: %s and %s", + arch, selected, factory); + } + selected = factory; } } - - throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); - } - - private static volatile List cachedHotSpotJVMCIBackendFactories; - - @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this") - private static Iterable getHotSpotJVMCIBackendFactories() { - if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) { - return cachedHotSpotJVMCIBackendFactories; + if (selected == null) { + throw new JVMCIError("No JVMCI runtime available for the %s architecture", arch); } - Iterable result = ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader()); - if (IS_BUILDING_NATIVE_IMAGE) { - cachedHotSpotJVMCIBackendFactories = new ArrayList<>(); - for (HotSpotJVMCIBackendFactory factory : result) { - cachedHotSpotJVMCIBackendFactories.add(factory); - } - } - return result; + backendFactory = selected; } /** @@ -587,15 +579,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { // Initialize the Option values. Option.parse(this); - String hostArchitecture = config.getHostArchitectureName(); - - HotSpotJVMCIBackendFactory factory; - try (InitTimer t = timer("find factory:", hostArchitecture)) { - factory = findFactory(hostArchitecture); - } - - try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { - hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); + try (InitTimer t = timer("create JVMCI backend:", backendFactory.getArchitecture())) { + hostBackend = registerBackend(backendFactory.createJVMCIBackend(this, null)); } compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(this); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 5d5956a667c..e93b98042b6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -55,7 +55,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { * Gets the host architecture name for the purpose of finding the corresponding * {@linkplain HotSpotJVMCIBackendFactory backend}. */ - String getHostArchitectureName() { + static String getHostArchitectureName() { Architecture arch = Architecture.current(); switch (arch) { case X64: return "amd64"; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java index c155c9c8613..265b8c24f3e 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java @@ -22,8 +22,6 @@ */ package jdk.vm.ci.services; -import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; - import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; @@ -71,24 +69,12 @@ public abstract class JVMCIServiceLocator { */ protected abstract S getProvider(Class service); - private static volatile List cachedLocators; - - private static Iterable getJVMCIServiceLocators() { - Iterable result = cachedLocators; - if (result != null) { - return result; - } - result = ServiceLoader.load(JVMCIServiceLocator.class, ClassLoader.getSystemClassLoader()); - if (IS_BUILDING_NATIVE_IMAGE) { - ArrayList l = new ArrayList<>(); - for (JVMCIServiceLocator locator : result) { - l.add(locator); - } - l.trimToSize(); - cachedLocators = l; - return l; - } - return result; + /** + * The available set of locators. + */ + private static final List locators = new ArrayList<>(); + static { + ServiceLoader.load(JVMCIServiceLocator.class).forEach(locators::add); } /** @@ -106,7 +92,7 @@ public abstract class JVMCIServiceLocator { sm.checkPermission(new JVMCIPermission()); } List providers = new ArrayList<>(); - for (JVMCIServiceLocator access : getJVMCIServiceLocators()) { + for (JVMCIServiceLocator access : locators) { S provider = access.getProvider(service); if (provider != null) { providers.add(provider); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java index d4171002247..d16a788eb14 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java @@ -22,13 +22,10 @@ */ package jdk.vm.ci.services; -import java.util.ArrayList; -import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.ServiceLoader; import java.util.Set; import java.util.function.Consumer; import java.util.function.Supplier; @@ -44,13 +41,6 @@ import jdk.internal.util.OperatingSystem; */ public final class Services { - /** - * Guards code that should be run when building an JVMCI shared library but should be excluded - * from (being compiled into) the library. Such code must be directly guarded by an {@code if} - * statement on this field - the guard cannot be behind a method call. - */ - public static final boolean IS_BUILDING_NATIVE_IMAGE = Boolean.parseBoolean(VM.getSavedProperty("jdk.vm.ci.services.aot")); - /** * Guards code that should only be run in a JVMCI shared library. Such code must be directly * guarded by an {@code if} statement on this field - the guard cannot be behind a method call. @@ -131,34 +121,6 @@ public final class Services { } } - private static final Map, List> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; - - @SuppressWarnings("unchecked") - private static Iterable load0(Class service) { - if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) { - List list = servicesCache.get(service); - if (list != null) { - return (Iterable) list; - } - if (IS_IN_NATIVE_IMAGE) { - throw new InternalError(String.format("No %s providers found when building native image", service.getName())); - } - } - - Iterable providers = ServiceLoader.load(service, ClassLoader.getSystemClassLoader()); - if (IS_BUILDING_NATIVE_IMAGE) { - synchronized (servicesCache) { - ArrayList providersList = new ArrayList<>(); - for (S provider : providers) { - providersList.add(provider); - } - servicesCache.put(service, providersList); - providers = providersList; - } - } - return providers; - } - /** * Opens all JVMCI packages to {@code otherModule}. */ @@ -175,57 +137,6 @@ public final class Services { } } - /** - * Gets an {@link Iterable} of the JVMCI providers available for a given service. - * - * @throws SecurityException if a security manager is present and it denies - * {@link RuntimePermission}("jvmci") - */ - public static Iterable load(Class service) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new JVMCIPermission()); - } - return load0(service); - } - - /** - * Gets the JVMCI provider for a given service for which at most one provider must be available. - * - * @param service the service whose provider is being requested - * @param required specifies if an {@link InternalError} should be thrown if no provider of - * {@code service} is available - * @throws SecurityException if a security manager is present and it denies - * {@link RuntimePermission}("jvmci") - */ - public static S loadSingle(Class service, boolean required) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new JVMCIPermission()); - } - Iterable providers = load0(service); - - S singleProvider = null; - for (S provider : providers) { - if (singleProvider != null) { - throw new InternalError(String.format("Multiple %s providers found: %s, %s", service.getName(), singleProvider.getClass().getName(), provider.getClass().getName())); - } - singleProvider = provider; - } - if (singleProvider == null && required) { - String javaHome = Services.getSavedProperty("java.home"); - String vmName = Services.getSavedProperty("java.vm.name"); - Formatter errorMessage = new Formatter(); - errorMessage.format("The VM does not expose required service %s.%n", service.getName()); - errorMessage.format("Currently used Java home directory is %s.%n", javaHome); - errorMessage.format("Currently used VM configuration is: %s", vmName); - throw new UnsupportedOperationException(errorMessage.toString()); - } - return singleProvider; - } - /** * Creates a thread-local variable that notifies {@code onThreadTermination} when a thread * terminates and it has been initialized in the terminating thread (even if it was initialized diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java b/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java index 1d855aeb4e5..59066126d87 100644 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java @@ -31,11 +31,13 @@ public class JvmciShutdownEventListener extends JVMCIServiceLocator implements H public static final String MESSAGE = "Shutdown notified"; public static final String GOT_INTERNAL_ERROR = "Got internal error"; - public static void main(String args[]) { - try { - HotSpotJVMCIRuntime.runtime(); // let's trigger that lazy jvmci init - } catch (Error e) { - System.out.println(GOT_INTERNAL_ERROR); + public static class Main { + public static void main(String args[]) { + try { + HotSpotJVMCIRuntime.runtime(); // let's trigger that lazy jvmci init + } catch (Error e) { + System.out.println(GOT_INTERNAL_ERROR); + } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventTest.java b/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventTest.java index 0242f548cca..0f0d34bf2d8 100644 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventTest.java @@ -53,11 +53,11 @@ import jdk.test.lib.process.ExitCode; import jdk.test.lib.cli.CommandLineOptionTest; public class JvmciShutdownEventTest { - private final static String[] MESSAGE = new String[]{ + private final static String[] MESSAGE = { JvmciShutdownEventListener.MESSAGE }; - private final static String[] ERROR_MESSAGE = new String[]{ + private final static String[] ERROR_MESSAGE = { JvmciShutdownEventListener.GOT_INTERNAL_ERROR }; @@ -68,7 +68,7 @@ public class JvmciShutdownEventTest { "Unexpected output with +EnableJVMCI", ExitCode.OK, addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "-XX:-UseJVMCICompiler", "-Xbootclasspath/a:.", - JvmciShutdownEventListener.class.getName() + JvmciShutdownEventListener.Main.class.getName() ); CommandLineOptionTest.verifyJVMStartup(ERROR_MESSAGE, MESSAGE, @@ -76,7 +76,7 @@ public class JvmciShutdownEventTest { "Unexpected output with -EnableJVMCI", ExitCode.OK, addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", "-XX:-EnableJVMCI", "-XX:-UseJVMCICompiler", "-Xbootclasspath/a:.", - JvmciShutdownEventListener.class.getName() + JvmciShutdownEventListener.Main.class.getName() ); } } From 8df804005ed772936fd77a4c0335a5620f909570 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Tue, 18 Feb 2025 00:19:46 +0000 Subject: [PATCH 034/587] 8350093: RISC-V: java/math/BigInteger/LargeValueExceptions.java timeout with COH Reviewed-by: mli, fjiang --- .../cpu/riscv/macroAssembler_riscv.cpp | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b7d1f869f98..4276595ffcc 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5484,21 +5484,31 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi const Register jdx = tmp1; if (AvoidUnalignedAccesses) { - // Check if x and y are both 8-byte aligned. - orr(t0, xlen, ylen); - test_bit(t0, t0, 0); - beqz(t0, L_multiply_64_x_64_loop); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_INT); + assert((base_offset % (UseCompactObjectHeaders ? 4 : + (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + + if ((base_offset % 8) == 0) { + // multiply_64_x_64_loop emits 8-byte load/store to access two elements + // at a time from int arrays x and y. When base_offset is 8 bytes, these + // accesses are naturally aligned if both xlen and ylen are even numbers. + orr(t0, xlen, ylen); + test_bit(t0, t0, 0); + beqz(t0, L_multiply_64_x_64_loop); + } + + Label L_second_loop_unaligned, L_third_loop, L_third_loop_exit; multiply_32_x_32_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); shadd(t0, xstart, z, t0, LogBytesPerInt); sw(carry, Address(t0, 0)); - Label L_second_loop_unaligned; bind(L_second_loop_unaligned); mv(carry, zr); mv(jdx, ylen); subiw(xstart, xstart, 1); bltz(xstart, L_done); + subi(sp, sp, 2 * wordSize); sd(z, Address(sp, 0)); sd(zr, Address(sp, wordSize)); @@ -5506,7 +5516,6 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi addi(z, t0, 4); shadd(t0, xstart, x, t0, LogBytesPerInt); lwu(product, Address(t0, 0)); - Label L_third_loop, L_third_loop_exit; blez(jdx, L_third_loop_exit); From 3353f8e0875165adbc8ee764a4c8d8817a87cd88 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 18 Feb 2025 07:51:45 +0000 Subject: [PATCH 035/587] 8349652: Rewire nmethod oop load barriers Reviewed-by: kvn, aboldtch --- src/hotspot/share/code/nmethod.cpp | 8 ++++-- .../share/gc/shared/barrierSetNMethod.cpp | 8 ++++++ .../share/gc/shared/barrierSetNMethod.hpp | 4 +++ src/hotspot/share/gc/z/zBarrierSet.inline.hpp | 6 +---- src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 8 ++++++ src/hotspot/share/gc/z/zBarrierSetNMethod.hpp | 3 +++ src/hotspot/share/gc/z/zNMethod.cpp | 24 ++++++++++------- src/hotspot/share/gc/z/zNMethod.hpp | 6 ++++- src/hotspot/share/oops/access.hpp | 6 ----- src/hotspot/share/oops/accessDecorators.hpp | 26 +++++++++---------- 10 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 283970afa69..e454d8f3f68 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -2143,14 +2143,18 @@ oop nmethod::oop_at(int index) const { if (index == 0) { return nullptr; } - return NMethodAccess::oop_load(oop_addr_at(index)); + + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + return bs_nm->oop_load_no_keepalive(this, index); } oop nmethod::oop_at_phantom(int index) const { if (index == 0) { return nullptr; } - return NMethodAccess::oop_load(oop_addr_at(index)); + + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + return bs_nm->oop_load_phantom(this, index); } // diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 4b81f321be3..c5d8a7e5401 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -212,3 +212,11 @@ bool BarrierSetNMethod::nmethod_osr_entry_barrier(nmethod* nm) { OrderAccess::cross_modify_fence(); return result; } + +oop BarrierSetNMethod::oop_load_no_keepalive(const nmethod* nm, int index) { + return NativeAccess::oop_load(nm->oop_addr_at(index)); +} + +oop BarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { + return NativeAccess::oop_load(nm->oop_addr_at(index)); +} diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp index d003abe9bbe..756dc43b3f1 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_SHARED_BARRIERSETNMETHOD_HPP #include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/sizes.hpp" @@ -57,6 +58,9 @@ public: void arm_all_nmethods(); + virtual oop oop_load_no_keepalive(const nmethod* nm, int index); + virtual oop oop_load_phantom(const nmethod* nm, int index); + #if INCLUDE_JVMCI bool verify_barrier(nmethod* nm, FormatBuffer<>& msg); #endif diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index 174cdfd9e90..f7baf85efbf 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -473,11 +473,7 @@ template inline oop ZBarrierSet::AccessBarrier::oop_load_not_in_heap(oop* p) { verify_decorators_absent(); - if (HasDecorator::value) { - return ZNMethod::load_oop(p, decorators); - } else { - return oop_load_not_in_heap((zpointer*)p); - } + return oop_load_not_in_heap((zpointer*)p); } template diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index cdb17018756..0d6be2b789f 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -97,3 +97,11 @@ int* ZBarrierSetNMethod::disarmed_guard_value_address() const { ByteSize ZBarrierSetNMethod::thread_disarmed_guard_value_offset() const { return ZThreadLocalData::nmethod_disarmed_offset(); } + +oop ZBarrierSetNMethod::oop_load_no_keepalive(const nmethod* nm, int index) { + return ZNMethod::oop_load_no_keepalive(nm, index); +} + +oop ZBarrierSetNMethod::oop_load_phantom(const nmethod* nm, int index) { + return ZNMethod::oop_load_phantom(nm, index); +} diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp index ed9f06672e7..780d3772123 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp @@ -36,6 +36,9 @@ protected: public: virtual ByteSize thread_disarmed_guard_value_offset() const; virtual int* disarmed_guard_value_address() const; + + virtual oop oop_load_no_keepalive(const nmethod* nm, int index); + virtual oop oop_load_phantom(const nmethod* nm, int index); }; #endif // SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index 26f2ab96946..4ae440ea231 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -305,26 +305,32 @@ uintptr_t ZNMethod::color(nmethod* nm) { return (uintptr_t)bs_nm->guard_value(nm); } -oop ZNMethod::load_oop(oop* p, DecoratorSet decorators) { - assert((decorators & ON_WEAK_OOP_REF) == 0, - "nmethod oops have phantom strength, not weak"); - nmethod* const nm = CodeCache::find_nmethod((void*)p); - assert(nm != nullptr, "did not find nmethod"); +oop ZNMethod::oop_load_no_keepalive(const nmethod* nm, int index) { + return oop_load(nm, index, false /* keep_alive */); +} + +oop ZNMethod::oop_load_phantom(const nmethod* nm, int index) { + return oop_load(nm, index, true /* keep_alive */); +} + +oop ZNMethod::oop_load(const nmethod* const_nm, int index, bool keep_alive) { + // The rest of the code is not ready to handle const nmethod, so cast it away + // until we are more consistent with our const corectness. + nmethod* nm = const_cast(const_nm); + if (!is_armed(nm)) { // If the nmethod entry barrier isn't armed, then it has been applied // already. The implication is that the contents of the memory location // is already a valid oop, and the barrier would have kept it alive if // necessary. Therefore, no action is required, and we are allowed to // simply read the oop. - return *p; + return *nm->oop_addr_at(index); } - const bool keep_alive = (decorators & ON_PHANTOM_OOP_REF) != 0 && - (decorators & AS_NO_KEEPALIVE) == 0; ZLocker locker(ZNMethod::lock_for_nmethod(nm)); // Make a local root - zaddress_unsafe obj = *ZUncoloredRoot::cast(p); + zaddress_unsafe obj = *ZUncoloredRoot::cast(nm->oop_addr_at(index)); if (keep_alive) { ZUncoloredRoot::process(&obj, ZNMethod::color(nm)); diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp index 2c92e1f5efb..5d797f3fd55 100644 --- a/src/hotspot/share/gc/z/zNMethod.hpp +++ b/src/hotspot/share/gc/z/zNMethod.hpp @@ -42,6 +42,8 @@ private: static void log_unregister(const nmethod* nm); static void log_purge(const nmethod* nm); + static oop oop_load(const nmethod* nm, int index, bool keep_alive); + public: static void register_nmethod(nmethod* nm); static void unregister_nmethod(nmethod* nm); @@ -69,7 +71,9 @@ public: static void purge(); static uintptr_t color(nmethod* nm); - static oop load_oop(oop* p, DecoratorSet decorators); + + static oop oop_load_no_keepalive(const nmethod* nm, int index); + static oop oop_load_phantom(const nmethod* nm, int index); }; #endif // SHARE_GC_Z_ZNMETHOD_HPP diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp index 34393462d03..917627f445e 100644 --- a/src/hotspot/share/oops/access.hpp +++ b/src/hotspot/share/oops/access.hpp @@ -284,11 +284,6 @@ class HeapAccess: public Access {}; template class NativeAccess: public Access {}; -// Helper for performing accesses in nmethods. These accesses -// may resolve an accessor on a GC barrier set. -template -class NMethodAccess: public Access {}; - // Helper for array access. template class ArrayAccess: public HeapAccess { @@ -366,7 +361,6 @@ void Access::verify_decorators() { const DecoratorSet location_decorators = decorators & IN_DECORATOR_MASK; STATIC_ASSERT(location_decorators == 0 || ( // make sure location decorators are disjoint if set (location_decorators ^ IN_NATIVE) == 0 || - (location_decorators ^ IN_NMETHOD) == 0 || (location_decorators ^ IN_HEAP) == 0 )); } diff --git a/src/hotspot/share/oops/accessDecorators.hpp b/src/hotspot/share/oops/accessDecorators.hpp index fc5860d6487..3d89b5c4334 100644 --- a/src/hotspot/share/oops/accessDecorators.hpp +++ b/src/hotspot/share/oops/accessDecorators.hpp @@ -173,11 +173,9 @@ const DecoratorSet ON_DECORATOR_MASK = ON_STRONG_OOP_REF | ON_WEAK_OOP_REF | // * IN_HEAP: The access is performed in the heap. Many barriers such as card marking will // be omitted if this decorator is not set. // * IN_NATIVE: The access is performed in an off-heap data structure. -// * IN_NMETHOD: The access is performed inside of an nmethod. const DecoratorSet IN_HEAP = UCONST64(1) << 18; const DecoratorSet IN_NATIVE = UCONST64(1) << 19; -const DecoratorSet IN_NMETHOD = UCONST64(1) << 20; -const DecoratorSet IN_DECORATOR_MASK = IN_HEAP | IN_NATIVE | IN_NMETHOD; +const DecoratorSet IN_DECORATOR_MASK = IN_HEAP | IN_NATIVE; // == Boolean Flag Decorators == // * IS_ARRAY: The access is performed on a heap allocated array. This is sometimes a special case @@ -185,9 +183,9 @@ const DecoratorSet IN_DECORATOR_MASK = IN_HEAP | IN_NATIVE | IN_NMETHOD; // * IS_DEST_UNINITIALIZED: This property can be important to e.g. SATB barriers by // marking that the previous value is uninitialized nonsense rather than a real value. // * IS_NOT_NULL: This property can make certain barriers faster such as compressing oops. -const DecoratorSet IS_ARRAY = UCONST64(1) << 21; -const DecoratorSet IS_DEST_UNINITIALIZED = UCONST64(1) << 22; -const DecoratorSet IS_NOT_NULL = UCONST64(1) << 23; +const DecoratorSet IS_ARRAY = UCONST64(1) << 20; +const DecoratorSet IS_DEST_UNINITIALIZED = UCONST64(1) << 21; +const DecoratorSet IS_NOT_NULL = UCONST64(1) << 22; // == Arraycopy Decorators == // * ARRAYCOPY_CHECKCAST: This property means that the class of the objects in source @@ -199,11 +197,11 @@ const DecoratorSet IS_NOT_NULL = UCONST64(1) << 23; // * ARRAYCOPY_ARRAYOF: The copy is in the arrayof form. // * ARRAYCOPY_ATOMIC: The accesses have to be atomic over the size of its elements. // * ARRAYCOPY_ALIGNED: The accesses have to be aligned on a HeapWord. -const DecoratorSet ARRAYCOPY_CHECKCAST = UCONST64(1) << 24; -const DecoratorSet ARRAYCOPY_DISJOINT = UCONST64(1) << 25; -const DecoratorSet ARRAYCOPY_ARRAYOF = UCONST64(1) << 26; -const DecoratorSet ARRAYCOPY_ATOMIC = UCONST64(1) << 27; -const DecoratorSet ARRAYCOPY_ALIGNED = UCONST64(1) << 28; +const DecoratorSet ARRAYCOPY_CHECKCAST = UCONST64(1) << 23; +const DecoratorSet ARRAYCOPY_DISJOINT = UCONST64(1) << 24; +const DecoratorSet ARRAYCOPY_ARRAYOF = UCONST64(1) << 25; +const DecoratorSet ARRAYCOPY_ATOMIC = UCONST64(1) << 26; +const DecoratorSet ARRAYCOPY_ALIGNED = UCONST64(1) << 27; const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT | ARRAYCOPY_DISJOINT | ARRAYCOPY_ARRAYOF | ARRAYCOPY_ATOMIC | ARRAYCOPY_ALIGNED; @@ -212,11 +210,11 @@ const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYC // * ACCESS_READ: Indicate that the resolved object is accessed read-only. This allows the GC // backend to use weaker and more efficient barriers. // * ACCESS_WRITE: Indicate that the resolved object is used for write access. -const DecoratorSet ACCESS_READ = UCONST64(1) << 29; -const DecoratorSet ACCESS_WRITE = UCONST64(1) << 30; +const DecoratorSet ACCESS_READ = UCONST64(1) << 28; +const DecoratorSet ACCESS_WRITE = UCONST64(1) << 29; // Keep track of the last decorator. -const DecoratorSet DECORATOR_LAST = UCONST64(1) << 30; +const DecoratorSet DECORATOR_LAST = UCONST64(1) << 29; namespace AccessInternal { // This class adds implied decorators that follow according to decorator rules. From 013fda1dad22d7aca3ee24c11dc42cb3885b5323 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 18 Feb 2025 08:43:21 +0000 Subject: [PATCH 036/587] 8348172: C2: Remove unused local variables in filter_helper() methods Reviewed-by: kvn, haosun, chagedorn --- src/hotspot/share/opto/type.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index db6070428ce..b56e3739a9d 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -4019,8 +4019,6 @@ intptr_t TypeOopPtr::get_con() const { const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculative) const { const Type* ft = join_helper(kills, include_speculative); - const TypeInstPtr* ftip = ft->isa_instptr(); - const TypeInstPtr* ktip = kills->isa_instptr(); if (ft->empty()) { return Type::TOP; // Canonical empty value @@ -5853,8 +5851,6 @@ const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculat // logic here mirrors the one from TypeOopPtr::filter. See comments // there. const Type* ft = join_helper(kills, include_speculative); - const TypeKlassPtr* ftkp = ft->isa_instklassptr(); - const TypeKlassPtr* ktkp = kills->isa_instklassptr(); if (ft->empty()) { return Type::TOP; // Canonical empty value From ff05d9795322fee6def559bd6776de42b96c27dc Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 18 Feb 2025 09:25:24 +0000 Subject: [PATCH 037/587] 8349180: Remove redundant initialization in ciField constructor Reviewed-by: chagedorn --- src/hotspot/share/ci/ciField.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 44d7fa37960..cbe0cadbc93 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -102,8 +102,6 @@ ciField::ciField(ciInstanceKlass* klass, int index, Bytecodes::Code bc) : _type = ciType::make(field_type); } - _name = (ciSymbol*)ciEnv::current(THREAD)->get_symbol(name); - // Get the field's declared holder. // // Note: we actually create a ciInstanceKlass for this klass, From 160db5f0f000f8471f71e0725da862d57db28c8a Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 18 Feb 2025 09:56:38 +0000 Subject: [PATCH 038/587] 8340110: Ubsan: verifier.cpp:2043:19: runtime error: shift exponent 100 is too large for 32-bit type 'int' Reviewed-by: dholmes, jsjolen --- src/hotspot/share/classfile/verifier.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 95e5f55c172..1e9bdcc682d 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2037,7 +2037,8 @@ void ClassVerifier::verify_cp_type( verify_cp_index(bci, cp, index, CHECK_VERIFY(this)); unsigned int tag = cp->tag_at(index).value(); - if ((types & (1 << tag)) == 0) { + // tags up to JVM_CONSTANT_ExternalMax are verifiable and valid for shift op + if (tag > JVM_CONSTANT_ExternalMax || (types & (1 << tag)) == 0) { verify_error(ErrorContext::bad_cp_index(bci, index), "Illegal type at constant pool entry %d in class %s", index, cp->pool_holder()->external_name()); From d7baae3ee92bbc94e380703f173a4d4a9de75e29 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 18 Feb 2025 09:56:49 +0000 Subject: [PATCH 039/587] 8350178: Incorrect comment after JDK-8345580 Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/node.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index a2ea0b4939f..2e52c12e4e8 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved. + * Copyright (c) 2024, 2025, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -337,11 +337,9 @@ protected: void out_grow( uint len ); public: - // Each Node is assigned a unique small/dense number. This number is used + // Each Node is assigned a unique small/dense number. This number is used // to index into auxiliary arrays of data and bit vectors. - // The field _idx is declared constant to defend against inadvertent assignments, - // since it is used by clients as a naked field. However, the field's value can be - // changed using the set_idx() method. + // The value of _idx can be changed using the set_idx() method. // // The PhaseRenumberLive phase renumbers nodes based on liveness information. // Therefore, it updates the value of the _idx field. The parse-time _idx is From 8193e0d53ac806d6974e2aacc7b7476aeb52a5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Tue, 18 Feb 2025 10:23:35 +0000 Subject: [PATCH 040/587] 8346280: C2: implement late barrier elision for G1 Reviewed-by: tschatzl, aboldtch, mdoerr --- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 57 +++ src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp | 6 +- .../share/gc/shared/c2/barrierSetC2.cpp | 256 ++++++++++++ .../share/gc/shared/c2/barrierSetC2.hpp | 10 +- .../gc/shared/c2/cardTableBarrierSetC2.cpp | 2 +- .../gc/shared/c2/cardTableBarrierSetC2.hpp | 2 +- src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 269 +------------ src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp | 4 +- .../gcbarriers/TestG1BarrierGeneration.java | 375 +++++++++++++++++- 9 files changed, 693 insertions(+), 288 deletions(-) diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 7999efe54bf..71fd3ec6610 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -529,8 +529,65 @@ int G1BarrierSetC2::get_store_barrier(C2Access& access) const { return barriers; } +void G1BarrierSetC2::elide_dominated_barrier(MachNode* mach) const { + uint8_t barrier_data = mach->barrier_data(); + barrier_data &= ~G1C2BarrierPre; + if (CardTableBarrierSetC2::use_ReduceInitialCardMarks()) { + barrier_data &= ~G1C2BarrierPost; + barrier_data &= ~G1C2BarrierPostNotNull; + } + mach->set_barrier_data(barrier_data); +} + +void G1BarrierSetC2::analyze_dominating_barriers() const { + ResourceMark rm; + PhaseCFG* const cfg = Compile::current()->cfg(); + + // Find allocations and memory accesses (stores and atomic operations), and + // track them in lists. + Node_List accesses; + Node_List allocations; + for (uint i = 0; i < cfg->number_of_blocks(); ++i) { + const Block* const block = cfg->get_block(i); + for (uint j = 0; j < block->number_of_nodes(); ++j) { + Node* const node = block->get_node(j); + if (node->is_Phi()) { + if (BarrierSetC2::is_allocation(node)) { + allocations.push(node); + } + continue; + } else if (!node->is_Mach()) { + continue; + } + + MachNode* const mach = node->as_Mach(); + switch (mach->ideal_Opcode()) { + case Op_StoreP: + case Op_StoreN: + case Op_CompareAndExchangeP: + case Op_CompareAndSwapP: + case Op_GetAndSetP: + case Op_CompareAndExchangeN: + case Op_CompareAndSwapN: + case Op_GetAndSetN: + if (mach->barrier_data() != 0) { + accesses.push(mach); + } + break; + default: + break; + } + } + } + + // Find dominating allocations for each memory access (store or atomic + // operation) and elide barriers if there is no safepoint poll in between. + elide_dominated_barriers(accesses, allocations); +} + void G1BarrierSetC2::late_barrier_analysis() const { compute_liveness_at_stubs(); + analyze_dominating_barriers(); } void G1BarrierSetC2::emit_stubs(CodeBuffer& cb) const { diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp index 81e67df29ce..5f85714d889 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp @@ -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 @@ -86,6 +86,9 @@ public: }; class G1BarrierSetC2: public CardTableBarrierSetC2 { +private: + void analyze_dominating_barriers() const; + protected: bool g1_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, @@ -117,6 +120,7 @@ public: ArrayCopyNode* ac) const; virtual void* create_barrier_state(Arena* comp_arena) const; virtual void emit_stubs(CodeBuffer& cb) const; + virtual void elide_dominated_barrier(MachNode* mach) const; virtual void late_barrier_analysis() const; #ifndef PRODUCT diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 3d59e972925..b0082b6444d 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -896,6 +896,262 @@ void BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac #undef XTOP +static bool block_has_safepoint(const Block* block, uint from, uint to) { + for (uint i = from; i < to; i++) { + if (block->get_node(i)->is_MachSafePoint()) { + // Safepoint found + return true; + } + } + + // Safepoint not found + return false; +} + +static bool block_has_safepoint(const Block* block) { + return block_has_safepoint(block, 0, block->number_of_nodes()); +} + +static uint block_index(const Block* block, const Node* node) { + for (uint j = 0; j < block->number_of_nodes(); ++j) { + if (block->get_node(j) == node) { + return j; + } + } + ShouldNotReachHere(); + return 0; +} + +// Look through various node aliases +static const Node* look_through_node(const Node* node) { + while (node != nullptr) { + const Node* new_node = node; + if (node->is_Mach()) { + const MachNode* const node_mach = node->as_Mach(); + if (node_mach->ideal_Opcode() == Op_CheckCastPP) { + new_node = node->in(1); + } + if (node_mach->is_SpillCopy()) { + new_node = node->in(1); + } + } + if (new_node == node || new_node == nullptr) { + break; + } else { + node = new_node; + } + } + + return node; +} + +// Whether the given offset is undefined. +static bool is_undefined(intptr_t offset) { + return offset == Type::OffsetTop; +} + +// Whether the given offset is unknown. +static bool is_unknown(intptr_t offset) { + return offset == Type::OffsetBot; +} + +// Whether the given offset is concrete (defined and compile-time known). +static bool is_concrete(intptr_t offset) { + return !is_undefined(offset) && !is_unknown(offset); +} + +// Compute base + offset components of the memory address accessed by mach. +// Return a node representing the base address, or null if the base cannot be +// found or the offset is undefined or a concrete negative value. If a non-null +// base is returned, the offset is a concrete, nonnegative value or unknown. +static const Node* get_base_and_offset(const MachNode* mach, intptr_t& offset) { + const TypePtr* adr_type = nullptr; + offset = 0; + const Node* base = mach->get_base_and_disp(offset, adr_type); + + if (base == nullptr || base == NodeSentinel) { + return nullptr; + } + + if (offset == 0 && base->is_Mach() && base->as_Mach()->ideal_Opcode() == Op_AddP) { + // The memory address is computed by 'base' and fed to 'mach' via an + // indirect memory operand (indicated by offset == 0). The ultimate base and + // offset can be fetched directly from the inputs and Ideal type of 'base'. + const TypeOopPtr* oopptr = base->bottom_type()->isa_oopptr(); + if (oopptr == nullptr) return nullptr; + offset = oopptr->offset(); + // Even if 'base' is not an Ideal AddP node anymore, Matcher::ReduceInst() + // guarantees that the base address is still available at the same slot. + base = base->in(AddPNode::Base); + assert(base != nullptr, ""); + } + + if (is_undefined(offset) || (is_concrete(offset) && offset < 0)) { + return nullptr; + } + + return look_through_node(base); +} + +// Whether a phi node corresponds to an array allocation. +// This test is incomplete: in some edge cases, it might return false even +// though the node does correspond to an array allocation. +static bool is_array_allocation(const Node* phi) { + precond(phi->is_Phi()); + // Check whether phi has a successor cast (CheckCastPP) to Java array pointer, + // possibly below spill copies and other cast nodes. Limit the exploration to + // a single path from the phi node consisting of these node types. + const Node* current = phi; + while (true) { + const Node* next = nullptr; + for (DUIterator_Fast imax, i = current->fast_outs(imax); i < imax; i++) { + if (!current->fast_out(i)->isa_Mach()) { + continue; + } + const MachNode* succ = current->fast_out(i)->as_Mach(); + if (succ->ideal_Opcode() == Op_CheckCastPP) { + if (succ->get_ptr_type()->isa_aryptr()) { + // Cast to Java array pointer: phi corresponds to an array allocation. + return true; + } + // Other cast: record as candidate for further exploration. + next = succ; + } else if (succ->is_SpillCopy() && next == nullptr) { + // Spill copy, and no better candidate found: record as candidate. + next = succ; + } + } + if (next == nullptr) { + // No evidence found that phi corresponds to an array allocation, and no + // candidates available to continue exploring. + return false; + } + // Continue exploring from the best candidate found. + current = next; + } + ShouldNotReachHere(); +} + +bool BarrierSetC2::is_allocation(const Node* node) { + assert(node->is_Phi(), "expected phi node"); + if (node->req() != 3) { + return false; + } + const Node* const fast_node = node->in(2); + if (!fast_node->is_Mach()) { + return false; + } + const MachNode* const fast_mach = fast_node->as_Mach(); + if (fast_mach->ideal_Opcode() != Op_LoadP) { + return false; + } + intptr_t offset; + const Node* const base = get_base_and_offset(fast_mach, offset); + if (base == nullptr || !base->is_Mach() || !is_concrete(offset)) { + return false; + } + const MachNode* const base_mach = base->as_Mach(); + if (base_mach->ideal_Opcode() != Op_ThreadLocal) { + return false; + } + return offset == in_bytes(Thread::tlab_top_offset()); +} + +void BarrierSetC2::elide_dominated_barriers(Node_List& accesses, Node_List& access_dominators) const { + Compile* const C = Compile::current(); + PhaseCFG* const cfg = C->cfg(); + + for (uint i = 0; i < accesses.size(); i++) { + MachNode* const access = accesses.at(i)->as_Mach(); + intptr_t access_offset; + const Node* const access_obj = get_base_and_offset(access, access_offset); + Block* const access_block = cfg->get_block_for_node(access); + const uint access_index = block_index(access_block, access); + + if (access_obj == nullptr) { + // No information available + continue; + } + + for (uint j = 0; j < access_dominators.size(); j++) { + const Node* const mem = access_dominators.at(j); + if (mem->is_Phi()) { + assert(is_allocation(mem), "expected allocation phi node"); + if (mem != access_obj) { + continue; + } + if (is_unknown(access_offset) && !is_array_allocation(mem)) { + // The accessed address has an unknown offset, but the allocated + // object cannot be determined to be an array. Avoid eliding in this + // case, to be on the safe side. + continue; + } + assert((is_concrete(access_offset) && access_offset >= 0) || (is_unknown(access_offset) && is_array_allocation(mem)), + "candidate allocation-dominated access offsets must be either concrete and nonnegative, or unknown (for array allocations only)"); + } else { + // Access node + const MachNode* const mem_mach = mem->as_Mach(); + intptr_t mem_offset; + const Node* const mem_obj = get_base_and_offset(mem_mach, mem_offset); + + if (mem_obj == nullptr || + !is_concrete(access_offset) || + !is_concrete(mem_offset)) { + // No information available + continue; + } + + if (mem_obj != access_obj || mem_offset != access_offset) { + // Not the same addresses, not a candidate + continue; + } + assert(is_concrete(access_offset) && access_offset >= 0, + "candidate non-allocation-dominated access offsets must be concrete and nonnegative"); + } + + Block* mem_block = cfg->get_block_for_node(mem); + const uint mem_index = block_index(mem_block, mem); + + if (access_block == mem_block) { + // Earlier accesses in the same block + if (mem_index < access_index && !block_has_safepoint(mem_block, mem_index + 1, access_index)) { + elide_dominated_barrier(access); + } + } else if (mem_block->dominates(access_block)) { + // Dominating block? Look around for safepoints + ResourceMark rm; + Block_List stack; + VectorSet visited; + stack.push(access_block); + bool safepoint_found = block_has_safepoint(access_block); + while (!safepoint_found && stack.size() > 0) { + const Block* const block = stack.pop(); + if (visited.test_set(block->_pre_order)) { + continue; + } + if (block_has_safepoint(block)) { + safepoint_found = true; + break; + } + if (block == mem_block) { + continue; + } + + // Push predecessor blocks + for (uint p = 1; p < block->num_preds(); ++p) { + Block* const pred = cfg->get_block_for_node(block->pred(p)); + stack.push(pred); + } + } + + if (!safepoint_found) { + elide_dominated_barrier(access); + } + } + } + } +} + void BarrierSetC2::compute_liveness_at_stubs() const { ResourceMark rm; Compile* const C = Compile::current(); diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index a78fd434ad9..7b9cb985cff 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -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 @@ -364,6 +364,14 @@ public: virtual bool matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const { return false; }; virtual bool matcher_is_store_load_barrier(Node* x, uint xop) const { return false; } + // Whether the given phi node joins OOPs from fast and slow allocation paths. + static bool is_allocation(const Node* node); + // Elide GC barriers from a Mach node according to elide_dominated_barriers(). + virtual void elide_dominated_barrier(MachNode* mach) const { } + // Elide GC barriers from instructions in 'accesses' if they are dominated by + // instructions in 'access_dominators' (according to elide_mach_barrier()) and + // there is no safepoint poll in between. + void elide_dominated_barriers(Node_List& accesses, Node_List& access_dominators) const; virtual void late_barrier_analysis() const { } virtual void compute_liveness_at_stubs() const; virtual int estimate_stub_size() const { return 0; } diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 870e351db66..7df210d9fb6 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -120,7 +120,7 @@ void CardTableBarrierSetC2::post_barrier(GraphKit* kit, kit->final_sync(ideal); } -bool CardTableBarrierSetC2::use_ReduceInitialCardMarks() const { +bool CardTableBarrierSetC2::use_ReduceInitialCardMarks() { return ReduceInitialCardMarks; } diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp index a380ec4a484..1263030a8b5 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp @@ -41,7 +41,7 @@ public: virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const; virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, bool is_clone_instance, ArrayCopyPhase phase) const; - bool use_ReduceInitialCardMarks() const; + static bool use_ReduceInitialCardMarks(); }; #endif // SHARE_GC_SHARED_C2_CARDTABLEBARRIERSETC2_HPP diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index 311ea2871f7..650918e2d30 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -28,7 +28,6 @@ #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zBarrierSetRuntime.hpp" #include "opto/arraycopynode.hpp" -#include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/compile.hpp" #include "opto/graphKit.hpp" @@ -38,7 +37,6 @@ #include "opto/node.hpp" #include "opto/output.hpp" #include "opto/regalloc.hpp" -#include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" #include "utilities/debug.hpp" @@ -475,269 +473,10 @@ void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* a #undef XTOP -// == Dominating barrier elision == - -static bool block_has_safepoint(const Block* block, uint from, uint to) { - for (uint i = from; i < to; i++) { - if (block->get_node(i)->is_MachSafePoint()) { - // Safepoint found - return true; - } - } - - // Safepoint not found - return false; -} - -static bool block_has_safepoint(const Block* block) { - return block_has_safepoint(block, 0, block->number_of_nodes()); -} - -static uint block_index(const Block* block, const Node* node) { - for (uint j = 0; j < block->number_of_nodes(); ++j) { - if (block->get_node(j) == node) { - return j; - } - } - ShouldNotReachHere(); - return 0; -} - -// Look through various node aliases -static const Node* look_through_node(const Node* node) { - while (node != nullptr) { - const Node* new_node = node; - if (node->is_Mach()) { - const MachNode* const node_mach = node->as_Mach(); - if (node_mach->ideal_Opcode() == Op_CheckCastPP) { - new_node = node->in(1); - } - if (node_mach->is_SpillCopy()) { - new_node = node->in(1); - } - } - if (new_node == node || new_node == nullptr) { - break; - } else { - node = new_node; - } - } - - return node; -} - -// Whether the given offset is undefined. -static bool is_undefined(intptr_t offset) { - return offset == Type::OffsetTop; -} - -// Whether the given offset is unknown. -static bool is_unknown(intptr_t offset) { - return offset == Type::OffsetBot; -} - -// Whether the given offset is concrete (defined and compile-time known). -static bool is_concrete(intptr_t offset) { - return !is_undefined(offset) && !is_unknown(offset); -} - -// Compute base + offset components of the memory address accessed by mach. -// Return a node representing the base address, or null if the base cannot be -// found or the offset is undefined or a concrete negative value. If a non-null -// base is returned, the offset is a concrete, nonnegative value or unknown. -static const Node* get_base_and_offset(const MachNode* mach, intptr_t& offset) { - const TypePtr* adr_type = nullptr; - offset = 0; - const Node* base = mach->get_base_and_disp(offset, adr_type); - - if (base == nullptr || base == NodeSentinel) { - return nullptr; - } - - if (offset == 0 && base->is_Mach() && base->as_Mach()->ideal_Opcode() == Op_AddP) { - // The memory address is computed by 'base' and fed to 'mach' via an - // indirect memory operand (indicated by offset == 0). The ultimate base and - // offset can be fetched directly from the inputs and Ideal type of 'base'. - const TypeOopPtr* oopptr = base->bottom_type()->isa_oopptr(); - if (oopptr == nullptr) return nullptr; - offset = oopptr->offset(); - // Even if 'base' is not an Ideal AddP node anymore, Matcher::ReduceInst() - // guarantees that the base address is still available at the same slot. - base = base->in(AddPNode::Base); - assert(base != nullptr, ""); - } - - if (is_undefined(offset) || (is_concrete(offset) && offset < 0)) { - return nullptr; - } - - return look_through_node(base); -} - -// Whether a phi node corresponds to an array allocation. -// This test is incomplete: in some edge cases, it might return false even -// though the node does correspond to an array allocation. -static bool is_array_allocation(const Node* phi) { - precond(phi->is_Phi()); - // Check whether phi has a successor cast (CheckCastPP) to Java array pointer, - // possibly below spill copies and other cast nodes. Limit the exploration to - // a single path from the phi node consisting of these node types. - const Node* current = phi; - while (true) { - const Node* next = nullptr; - for (DUIterator_Fast imax, i = current->fast_outs(imax); i < imax; i++) { - if (!current->fast_out(i)->isa_Mach()) { - continue; - } - const MachNode* succ = current->fast_out(i)->as_Mach(); - if (succ->ideal_Opcode() == Op_CheckCastPP) { - if (succ->get_ptr_type()->isa_aryptr()) { - // Cast to Java array pointer: phi corresponds to an array allocation. - return true; - } - // Other cast: record as candidate for further exploration. - next = succ; - } else if (succ->is_SpillCopy() && next == nullptr) { - // Spill copy, and no better candidate found: record as candidate. - next = succ; - } - } - if (next == nullptr) { - // No evidence found that phi corresponds to an array allocation, and no - // candidates available to continue exploring. - return false; - } - // Continue exploring from the best candidate found. - current = next; - } - ShouldNotReachHere(); -} - -// Match the phi node that connects a TLAB allocation fast path with its slowpath -static bool is_allocation(const Node* node) { - if (node->req() != 3) { - return false; - } - const Node* const fast_node = node->in(2); - if (!fast_node->is_Mach()) { - return false; - } - const MachNode* const fast_mach = fast_node->as_Mach(); - if (fast_mach->ideal_Opcode() != Op_LoadP) { - return false; - } - const TypePtr* const adr_type = nullptr; - intptr_t offset; - const Node* const base = get_base_and_offset(fast_mach, offset); - if (base == nullptr || !base->is_Mach() || !is_concrete(offset)) { - return false; - } - const MachNode* const base_mach = base->as_Mach(); - if (base_mach->ideal_Opcode() != Op_ThreadLocal) { - return false; - } - return offset == in_bytes(Thread::tlab_top_offset()); -} - -static void elide_mach_barrier(MachNode* mach) { +void ZBarrierSetC2::elide_dominated_barrier(MachNode* mach) const { mach->set_barrier_data(ZBarrierElided); } -void ZBarrierSetC2::analyze_dominating_barriers_impl(Node_List& accesses, Node_List& access_dominators) const { - Compile* const C = Compile::current(); - PhaseCFG* const cfg = C->cfg(); - - for (uint i = 0; i < accesses.size(); i++) { - MachNode* const access = accesses.at(i)->as_Mach(); - intptr_t access_offset; - const Node* const access_obj = get_base_and_offset(access, access_offset); - Block* const access_block = cfg->get_block_for_node(access); - const uint access_index = block_index(access_block, access); - - if (access_obj == nullptr) { - // No information available - continue; - } - - for (uint j = 0; j < access_dominators.size(); j++) { - const Node* const mem = access_dominators.at(j); - if (mem->is_Phi()) { - // Allocation node - if (mem != access_obj) { - continue; - } - if (is_unknown(access_offset) && !is_array_allocation(mem)) { - // The accessed address has an unknown offset, but the allocated - // object cannot be determined to be an array. Avoid eliding in this - // case, to be on the safe side. - continue; - } - assert((is_concrete(access_offset) && access_offset >= 0) || (is_unknown(access_offset) && is_array_allocation(mem)), - "candidate allocation-dominated access offsets must be either concrete and nonnegative, or unknown (for array allocations only)"); - } else { - // Access node - const MachNode* const mem_mach = mem->as_Mach(); - intptr_t mem_offset; - const Node* const mem_obj = get_base_and_offset(mem_mach, mem_offset); - - if (mem_obj == nullptr || - !is_concrete(access_offset) || - !is_concrete(mem_offset)) { - // No information available - continue; - } - - if (mem_obj != access_obj || mem_offset != access_offset) { - // Not the same addresses, not a candidate - continue; - } - assert(is_concrete(access_offset) && access_offset >= 0, - "candidate non-allocation-dominated access offsets must be concrete and nonnegative"); - } - - Block* mem_block = cfg->get_block_for_node(mem); - const uint mem_index = block_index(mem_block, mem); - - if (access_block == mem_block) { - // Earlier accesses in the same block - if (mem_index < access_index && !block_has_safepoint(mem_block, mem_index + 1, access_index)) { - elide_mach_barrier(access); - } - } else if (mem_block->dominates(access_block)) { - // Dominating block? Look around for safepoints - ResourceMark rm; - Block_List stack; - VectorSet visited; - stack.push(access_block); - bool safepoint_found = block_has_safepoint(access_block); - while (!safepoint_found && stack.size() > 0) { - const Block* const block = stack.pop(); - if (visited.test_set(block->_pre_order)) { - continue; - } - if (block_has_safepoint(block)) { - safepoint_found = true; - break; - } - if (block == mem_block) { - continue; - } - - // Push predecessor blocks - for (uint p = 1; p < block->num_preds(); ++p) { - Block* const pred = cfg->get_block_for_node(block->pred(p)); - stack.push(pred); - } - } - - if (!safepoint_found) { - elide_mach_barrier(access); - } - } - } - } -} - void ZBarrierSetC2::analyze_dominating_barriers() const { ResourceMark rm; Compile* const C = Compile::current(); @@ -807,9 +546,9 @@ void ZBarrierSetC2::analyze_dominating_barriers() const { } // Step 2 - Find dominating accesses or allocations for each access - analyze_dominating_barriers_impl(loads, load_dominators); - analyze_dominating_barriers_impl(stores, store_dominators); - analyze_dominating_barriers_impl(atomics, atomic_dominators); + elide_dominated_barriers(loads, load_dominators); + elide_dominated_barriers(stores, store_dominators); + elide_dominated_barriers(atomics, atomic_dominators); } void ZBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp index 2aa4d0daa85..370a543f381 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.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 @@ -99,7 +99,6 @@ public: class ZBarrierSetC2 : public BarrierSetC2 { private: - void analyze_dominating_barriers_impl(Node_List& accesses, Node_List& access_dominators) const; void analyze_dominating_barriers() const; protected: @@ -128,6 +127,7 @@ public: virtual void clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const; + virtual void elide_dominated_barrier(MachNode* mach) const; virtual void late_barrier_analysis() const; virtual int estimate_stub_size() const; virtual void emit_stubs(CodeBuffer& cb) const; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java index 36ad0bf84a4..a9df0019ab1 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.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 @@ -47,6 +47,7 @@ public class TestG1BarrierGeneration { static final String POST_ONLY_NOT_NULL = "post notnull"; static final String PRE_AND_POST = "pre post"; static final String PRE_AND_POST_NOT_NULL = "pre post notnull"; + static final String ANY = ".*"; static class Outer { Object f; @@ -90,6 +91,9 @@ public class TestG1BarrierGeneration { } } + @DontInline + static void nonInlinedMethod() {} + public static void main(String[] args) { TestFramework framework = new TestFramework(); Scenario[] scenarios = new Scenario[2*2]; @@ -194,10 +198,11 @@ public class TestG1BarrierGeneration { counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_P}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) public static Outer testStoreOnNewObject(Object o1) { Outer o = new Outer(); @@ -222,10 +227,11 @@ public class TestG1BarrierGeneration { counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_P}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) public static Outer testStoreNotNullOnNewObject(Object o1) { if (o1.hashCode() == 42) { @@ -244,10 +250,11 @@ public class TestG1BarrierGeneration { counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_P}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) public static Outer testStoreOnNewObjectInTwoPaths(Object o1, boolean c) { Outer o; @@ -261,6 +268,63 @@ public class TestG1BarrierGeneration { return o; } + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreConditionallyOnNewObject(Object o1, boolean c) { + Outer o = new Outer(); + if (c) { + o.f = o1; + } + return o; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObjectAfterException(Object o1, boolean c) throws Exception { + Outer o = new Outer(); + if (c) { + throw new Exception(""); + } + o.f = o1; + return o; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObjectAfterCall(Object o1) { + Outer o = new Outer(); + nonInlinedMethod(); + o.f = o1; + return o; + } + @Run(test = {"testStore", "testStoreNull", "testStoreObfuscatedNull", @@ -270,7 +334,10 @@ public class TestG1BarrierGeneration { "testStoreOnNewObject", "testStoreNullOnNewObject", "testStoreNotNullOnNewObject", - "testStoreOnNewObjectInTwoPaths"}) + "testStoreOnNewObjectInTwoPaths", + "testStoreConditionallyOnNewObject", + "testStoreOnNewObjectAfterException", + "testStoreOnNewObjectAfterCall"}) public void runStoreTests() { { Outer o = new Outer(); @@ -328,6 +395,24 @@ public class TestG1BarrierGeneration { Outer o = testStoreOnNewObjectInTwoPaths(o1, ThreadLocalRandom.current().nextBoolean()); Asserts.assertEquals(o1, o.f); } + { + Object o1 = new Object(); + boolean c = ThreadLocalRandom.current().nextBoolean(); + Outer o = testStoreConditionallyOnNewObject(o1, c); + Asserts.assertTrue(o.f == (c ? o1 : null)); + } + { + Object o1 = new Object(); + boolean c = ThreadLocalRandom.current().nextBoolean(); + try { + Outer o = testStoreOnNewObjectAfterException(o1, c); + } catch (Exception e) {} + } + { + Object o1 = new Object(); + Outer o = testStoreOnNewObjectAfterCall(o1); + Asserts.assertEquals(o1, o.f); + } } @Test @@ -379,25 +464,91 @@ public class TestG1BarrierGeneration { } @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_P}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) - public static Object[] testStoreOnNewArray(Object o1) { + public static Object[] testStoreOnNewArrayAtKnownIndex(Object o1) { Object[] a = new Object[10]; - // The index needs to be concrete for C2 to detect that it is safe to - // remove the pre-barrier. a[4] = o1; return a; } + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + public static Object[] testStoreOnNewArrayAtUnknownIndex(Object o1, int index) { + Object[] a = new Object[10]; + a[index] = o1; + return a; + } + + @Test + @IR(failOn = IRNode.SAFEPOINT) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + public static Object[] testStoreAllOnNewSmallArray(Object o1) { + Object[] a = new Object[64]; + for (int i = 0; i < a.length; i++) { + a[i] = o1; + } + return a; + } + + @Test + @IR(counts = {IRNode.SAFEPOINT, "1"}) + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static Object[] testStoreAllOnNewLargeArray(Object o1) { + Object[] a = new Object[1024]; + for (int i = 0; i < a.length; i++) { + a[i] = o1; + } + return a; + } + @Run(test = {"testArrayStore", "testArrayStoreNull", "testArrayStoreNotNull", "testArrayStoreTwice", - "testStoreOnNewArray"}) + "testStoreOnNewArrayAtKnownIndex", + "testStoreOnNewArrayAtUnknownIndex", + "testStoreAllOnNewSmallArray", + "testStoreAllOnNewLargeArray"}) public void runArrayStoreTests() { { Object[] a = new Object[10]; @@ -426,9 +577,28 @@ public class TestG1BarrierGeneration { } { Object o1 = new Object(); - Object[] a = testStoreOnNewArray(o1); + Object[] a = testStoreOnNewArrayAtKnownIndex(o1); Asserts.assertEquals(o1, a[4]); } + { + Object o1 = new Object(); + Object[] a = testStoreOnNewArrayAtUnknownIndex(o1, 5); + Asserts.assertEquals(o1, a[5]); + } + { + Object o1 = new Object(); + Object[] a = testStoreAllOnNewSmallArray(o1); + for (int i = 0; i < a.length; i++) { + Asserts.assertEquals(o1, a[i]); + } + } + { + Object o1 = new Object(); + Object[] a = testStoreAllOnNewLargeArray(o1); + for (int i = 0; i < a.length; i++) { + Asserts.assertEquals(o1, a[i]); + } + } } @Test @@ -442,7 +612,9 @@ public class TestG1BarrierGeneration { @Test @IR(applyIf = {"ReduceInitialCardMarks", "true"}, - failOn = {IRNode.G1_STORE_P, IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + failOn = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, ANY, + IRNode.G1_STORE_N_WITH_BARRIER_FLAG, ANY, + IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, ANY}, phase = CompilePhase.FINAL_CODE) @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "false"}, counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"}, @@ -565,9 +737,139 @@ public class TestG1BarrierGeneration { return fVarHandle.getAndSet(o, newVal); } + // IR checks are disabled for s390 because barriers are not elided (to be investigated). + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + applyIfPlatform = {"s390", "false"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + applyIfPlatform = {"s390", "false"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + applyIfPlatform = {"s390", "false"}, + failOn = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + applyIfPlatform = {"s390", "false"}, + failOn = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + static Object testCompareAndExchangeOnNewObject(Object oldVal, Object newVal) { + Outer o = new Outer(); + o.f = oldVal; + return fVarHandle.compareAndExchange(o, oldVal, newVal); + } + + // IR checks are disabled for s390 when OOPs compression is disabled + // because barriers are not elided in this configuration (to be investigated). + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + applyIfPlatform = {"s390", "false"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + applyIfPlatform = {"s390", "false"}, + failOn = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + static boolean testCompareAndSwapOnNewObject(Object oldVal, Object newVal) { + Outer o = new Outer(); + o.f = oldVal; + return fVarHandle.compareAndSet(o, oldVal, newVal); + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSetOnNewObject(Object oldVal, Object newVal) { + Outer o = new Outer(); + o.f = oldVal; + return fVarHandle.getAndSet(o, newVal); + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSetConditionallyOnNewObject(Object oldVal, Object newVal, boolean c) { + Outer o = new Outer(); + o.f = oldVal; + if (c) { + return fVarHandle.getAndSet(o, newVal); + } + return oldVal; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, ANY}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSetOnNewObjectAfterException(Object oldVal, Object newVal, boolean c) throws Exception { + Outer o = new Outer(); + if (c) { + throw new Exception(""); + } + o.f = oldVal; + return fVarHandle.getAndSet(o, newVal); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSetOnNewObjectAfterCall(Object oldVal, Object newVal) { + Outer o = new Outer(); + nonInlinedMethod(); + o.f = oldVal; + return fVarHandle.getAndSet(o, newVal); + } + @Run(test = {"testCompareAndExchange", "testCompareAndSwap", - "testGetAndSet"}) + "testGetAndSet", + "testCompareAndExchangeOnNewObject", + "testCompareAndSwapOnNewObject", + "testGetAndSetOnNewObject", + "testGetAndSetConditionallyOnNewObject", + "testGetAndSetOnNewObjectAfterException", + "testGetAndSetOnNewObjectAfterCall"}) public void runAtomicTests() { { Outer o = new Outer(); @@ -596,6 +898,45 @@ public class TestG1BarrierGeneration { Asserts.assertEquals(oldVal, oldVal2); Asserts.assertEquals(o.f, newVal); } + { + Object oldVal = new Object(); + Object newVal = new Object(); + Object oldVal2 = testCompareAndExchangeOnNewObject(oldVal, newVal); + Asserts.assertEquals(oldVal, oldVal2); + } + { + Object oldVal = new Object(); + Object newVal = new Object(); + boolean b = testCompareAndSwapOnNewObject(oldVal, newVal); + Asserts.assertTrue(b); + } + { + Object oldVal = new Object(); + Object newVal = new Object(); + Object oldVal2 = testGetAndSetOnNewObject(oldVal, newVal); + Asserts.assertEquals(oldVal, oldVal2); + } + { + Object oldVal = new Object(); + Object newVal = new Object(); + boolean c = ThreadLocalRandom.current().nextBoolean(); + Object oldVal2 = testGetAndSetConditionallyOnNewObject(oldVal, newVal, c); + Asserts.assertEquals(oldVal, oldVal2); + } + { + Object oldVal = new Object(); + Object newVal = new Object(); + boolean c = ThreadLocalRandom.current().nextBoolean(); + try { + Object oldVal2 = testGetAndSetOnNewObjectAfterException(oldVal, newVal, c); + } catch (Exception e) {} + } + { + Object oldVal = new Object(); + Object newVal = new Object(); + Object oldVal2 = testGetAndSetOnNewObjectAfterCall(oldVal, newVal); + Asserts.assertEquals(oldVal, oldVal2); + } } @Test From 885be2efa6b1359a7c7ab36882e19a7eaba77fb3 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 18 Feb 2025 10:24:51 +0000 Subject: [PATCH 041/587] 8349908: RISC-V: C2 SelectFromTwoVector Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/riscv_v.ad | 37 +++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 4b30a911152..7be169ef709 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -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, 2023, Arm Limited. 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. @@ -109,6 +109,13 @@ source %{ if (!UseRVV) { return false; } + switch (opcode) { + case Op_SelectFromTwoVector: + // There is no masked version of selectFrom two vector, i.e. selectFrom(av, bv, mask) in vector API. + return false; + default: + break; + } return match_rule_supported_vector(opcode, vlen, bt); } @@ -4425,6 +4432,34 @@ instruct vmask_reinterpret_diff_esize(vRegMask dst, vRegMask_V0 src, vReg tmp) % ins_pipe(pipe_slow); %} +// ------------------------------ Vector selectFrom ----------------------------- + +instruct select_from_two_vectors(vReg dst, vReg src1, vReg src2, vReg index, vRegMask_V0 v0, vReg tmp) %{ + match(Set dst (SelectFromTwoVector (Binary index src1) src2)); + effect(TEMP_DEF dst, TEMP v0, TEMP tmp); + format %{ "select_from_two_vectors $dst, $src1, $src2, $index" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($index$$reg)); + bool use_imm = __ is_simm5(Matcher::vector_length(this) - 1); + if (use_imm) { + __ vmsgtu_vi(v0, as_VectorRegister($index$$reg), Matcher::vector_length(this) - 1); + __ vadd_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($index$$reg), + -Matcher::vector_length(this), Assembler::v0_t); + } else { + __ mv(t0, Matcher::vector_length(this) - 1); + __ vmsgtu_vx(v0, as_VectorRegister($index$$reg), t0); + __ mv(t0, -Matcher::vector_length(this)); + __ vadd_vx(as_VectorRegister($tmp$$reg), as_VectorRegister($index$$reg), t0, Assembler::v0_t); + } + __ vrgather_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector rearrange ----------------------------- instruct rearrange(vReg dst, vReg src, vReg shuffle) %{ From e1d0a9c832ef3e92faaed7f290ff56c0ed8a9d94 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 18 Feb 2025 13:20:05 +0000 Subject: [PATCH 042/587] 8350202: Tune for Power10 CPUs on Linux ppc64le Reviewed-by: mdoerr --- make/autoconf/flags-cflags.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 61645cda6dd..1674d10fa91 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -719,7 +719,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], elif test "x$FLAGS_CPU" = xppc64le; then # Little endian machine uses ELFv2 ABI. # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2 -mcpu=power8 -mtune=power8" + $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2 -mcpu=power8 -mtune=power10" fi elif test "x$FLAGS_CPU" = xs390x; then $1_CFLAGS_CPU="-mbackchain -march=z10" @@ -740,7 +740,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], if test "x$FLAGS_CPU" = xppc64le; then # Little endian machine uses ELFv2 ABI. # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2 -mcpu=power8 -mtune=power8" + $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2 -mcpu=power8 -mtune=power10" fi fi if test "x$OPENJDK_TARGET_OS" = xaix; then From 62d93f2a2222a044ac4aa409efd69e776f0d43da Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 18 Feb 2025 20:06:05 +0000 Subject: [PATCH 043/587] 8346050: Update BuildTestLib.gmk to build whole testlibrary Reviewed-by: weijun, ihse --- make/test/BuildTestLib.gmk | 10 +++++++++- test/lib/jdk/test/lib/security/CertUtils.java | 6 ++++-- test/lib/jdk/test/lib/security/FixedSecureRandom.java | 4 +++- test/lib/jdk/test/lib/security/SeededSecureRandom.java | 4 +++- test/lib/jdk/test/lib/security/XMLUtils.java | 3 ++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk index 3dc00aeff87..54b4b306cb8 100644 --- a/make/test/BuildTestLib.gmk +++ b/make/test/BuildTestLib.gmk @@ -52,10 +52,14 @@ $(eval $(call SetupJavaCompilation, BUILD_WB_JAR, \ TARGETS += $(BUILD_WB_JAR) +ifeq ($(call isTargetOs, linux), false) + BUILD_TEST_LIB_JAR_EXCLUDES := jdk/test/lib/containers +endif + $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ SRC := $(TEST_LIB_SOURCE_DIR), \ - EXCLUDES := jdk/test/lib/containers jdk/test/lib/security, \ + EXCLUDES := $(BUILD_TEST_LIB_JAR_EXCLUDES), \ BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \ HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \ JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \ @@ -64,6 +68,10 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \ --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \ --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED \ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.platform=ALL-UNNAMED \ + --add-exports java.base/sun.security.pkcs=ALL-UNNAMED \ + --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED \ + --add-exports java.base/sun.security.x509=ALL-UNNAMED \ --enable-preview, \ )) diff --git a/test/lib/jdk/test/lib/security/CertUtils.java b/test/lib/jdk/test/lib/security/CertUtils.java index c52d98c2572..e5bd3169c0b 100644 --- a/test/lib/jdk/test/lib/security/CertUtils.java +++ b/test/lib/jdk/test/lib/security/CertUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -21,7 +21,7 @@ * questions. */ -/** +/* * * @author Sean Mullan * @author Steve Hanna @@ -645,7 +645,9 @@ public class CertUtils { * This class is useful for overriding one or more methods of an * X509Certificate for testing purposes. */ + @SuppressWarnings("deprecation") public static class ForwardingX509Certificate extends X509Certificate { + private static final long serialVersionUID = -8453912214640985478L; private final X509Certificate cert; public ForwardingX509Certificate(X509Certificate cert) { this.cert = cert; diff --git a/test/lib/jdk/test/lib/security/FixedSecureRandom.java b/test/lib/jdk/test/lib/security/FixedSecureRandom.java index cfe8ccc212f..d6a08730b0e 100644 --- a/test/lib/jdk/test/lib/security/FixedSecureRandom.java +++ b/test/lib/jdk/test/lib/security/FixedSecureRandom.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 @@ -37,6 +37,8 @@ import java.security.SecureRandom; /// bytes are exhausted. public class FixedSecureRandom extends SecureRandom { + private static final long serialVersionUID = -8753752741562231543L; + private byte[] buffer; private int offset; diff --git a/test/lib/jdk/test/lib/security/SeededSecureRandom.java b/test/lib/jdk/test/lib/security/SeededSecureRandom.java index 305a91c41d2..d56af1aee14 100644 --- a/test/lib/jdk/test/lib/security/SeededSecureRandom.java +++ b/test/lib/jdk/test/lib/security/SeededSecureRandom.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 @@ -35,6 +35,8 @@ import java.util.Random; */ public class SeededSecureRandom extends SecureRandom { + private static final long serialVersionUID = 4657031557630518194L; + private final Random rnd; public static long seed() { diff --git a/test/lib/jdk/test/lib/security/XMLUtils.java b/test/lib/jdk/test/lib/security/XMLUtils.java index efc8f6d5449..e70a30d9b3d 100644 --- a/test/lib/jdk/test/lib/security/XMLUtils.java +++ b/test/lib/jdk/test/lib/security/XMLUtils.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 @@ -559,6 +559,7 @@ public class XMLUtils { /** * Adds a new rule to "jdk.xml.dsig.secureValidationPolicy" */ + @SuppressWarnings("dangling-doc-comments") public static void addPolicy(String rule) { String value = Security.getProperty("jdk.xml.dsig.secureValidationPolicy"); value = rule + "," + value; From 46d4a601e04f90b11d4ccc97a49f4e7010b4fd83 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 18 Feb 2025 20:08:08 +0000 Subject: [PATCH 044/587] 8349088: De-virtualize Codeblob and nmethod Co-authored-by: Stefan Karlsson Co-authored-by: Chris Plummer Reviewed-by: cjplummer, aboldtch, dlong --- src/hotspot/share/code/codeBlob.cpp | 140 +++++++++++------ src/hotspot/share/code/codeBlob.hpp | 148 ++++++++++++------ src/hotspot/share/code/dependencyContext.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 23 ++- src/hotspot/share/code/nmethod.hpp | 32 ++-- src/hotspot/share/runtime/vmStructs.cpp | 19 +++ .../classes/sun/jvm/hotspot/c1/Runtime1.java | 4 +- .../sun/jvm/hotspot/code/AdapterBlob.java | 6 +- .../sun/jvm/hotspot/code/BufferBlob.java | 6 +- .../sun/jvm/hotspot/code/CodeBlob.java | 87 ++++++++-- .../sun/jvm/hotspot/code/CodeCache.java | 92 +++-------- .../jvm/hotspot/code/DeoptimizationBlob.java | 6 +- .../sun/jvm/hotspot/code/ExceptionBlob.java | 6 +- .../code/MethodHandlesAdapterBlob.java | 6 +- .../classes/sun/jvm/hotspot/code/NMethod.java | 3 +- .../sun/jvm/hotspot/code/RuntimeStub.java | 6 +- .../sun/jvm/hotspot/code/SafepointBlob.java | 6 +- .../sun/jvm/hotspot/code/SingletonBlob.java | 4 +- .../jvm/hotspot/code/UncommonTrapBlob.java | 6 +- .../sun/jvm/hotspot/code/UpcallStub.java | 6 +- .../sun/jvm/hotspot/code/VtableBlob.java | 6 +- .../sun/jvm/hotspot/memory/CodeHeap.java | 4 +- .../classes/sun/jvm/hotspot/tools/PStack.java | 26 +-- 23 files changed, 377 insertions(+), 267 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index c033bff6ff7..3ed00a08e40 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -53,6 +53,53 @@ #include "c1/c1_Runtime1.hpp" #endif +#include + +// Virtual methods are not allowed in code blobs to simplify caching compiled code. +// Check all "leaf" subclasses of CodeBlob class. + +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in nmethod"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +#ifdef COMPILER2 +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +#endif + +// Add proxy vtables. +// We need only few for now - they are used only from prints. +const nmethod::Vptr nmethod::_vptr; +const BufferBlob::Vptr BufferBlob::_vptr; +const RuntimeStub::Vptr RuntimeStub::_vptr; +const SingletonBlob::Vptr SingletonBlob::_vptr; +const DeoptimizationBlob::Vptr DeoptimizationBlob::_vptr; +const UpcallStub::Vptr UpcallStub::_vptr; + +const CodeBlob::Vptr* CodeBlob::vptr() const { + constexpr const CodeBlob::Vptr* array[(size_t)CodeBlobKind::Number_Of_Kinds] = { + nullptr/* None */, + &nmethod::_vptr, + &BufferBlob::_vptr, + &AdapterBlob::_vptr, + &VtableBlob::_vptr, + &MethodHandlesAdapterBlob::_vptr, + &RuntimeStub::_vptr, + &DeoptimizationBlob::_vptr, + &SafepointBlob::_vptr, +#ifdef COMPILER2 + &ExceptionBlob::_vptr, + &UncommonTrapBlob::_vptr, +#endif + &UpcallStub::_vptr + }; + + return array[(size_t)_kind]; +} unsigned int CodeBlob::align_code_offset(int offset) { // align the size to CodeEntryAlignment @@ -386,7 +433,7 @@ RuntimeStub::RuntimeStub( OopMapSet* oop_maps, bool caller_must_gc_arguments ) -: RuntimeBlob(name, CodeBlobKind::Runtime_Stub, cb, size, sizeof(RuntimeStub), +: RuntimeBlob(name, CodeBlobKind::RuntimeStub, cb, size, sizeof(RuntimeStub), frame_complete, frame_size, oop_maps, caller_must_gc_arguments) { } @@ -482,18 +529,18 @@ DeoptimizationBlob* DeoptimizationBlob::create( return blob; } +#ifdef COMPILER2 //---------------------------------------------------------------------------------------------------- // Implementation of UncommonTrapBlob -#ifdef COMPILER2 UncommonTrapBlob::UncommonTrapBlob( CodeBuffer* cb, int size, OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("UncommonTrapBlob", CodeBlobKind::Uncommon_Trap, cb, +: SingletonBlob("UncommonTrapBlob", CodeBlobKind::UncommonTrap, cb, size, sizeof(UncommonTrapBlob), frame_size, oop_maps) {} @@ -516,14 +563,9 @@ UncommonTrapBlob* UncommonTrapBlob::create( return blob; } - -#endif // COMPILER2 - - //---------------------------------------------------------------------------------------------------- // Implementation of ExceptionBlob -#ifdef COMPILER2 ExceptionBlob::ExceptionBlob( CodeBuffer* cb, int size, @@ -553,10 +595,8 @@ ExceptionBlob* ExceptionBlob::create( return blob; } - #endif // COMPILER2 - //---------------------------------------------------------------------------------------------------- // Implementation of SafepointBlob @@ -644,17 +684,45 @@ void UpcallStub::free(UpcallStub* blob) { //---------------------------------------------------------------------------------------------------- // Verification and printing +void CodeBlob::verify() { + if (is_nmethod()) { + as_nmethod()->verify(); + } +} + void CodeBlob::print_on(outputStream* st) const { - st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", p2i(this)); - st->print_cr("Framesize: %d", _frame_size); + vptr()->print_on(this, st); } void CodeBlob::print() const { print_on(tty); } void CodeBlob::print_value_on(outputStream* st) const { + vptr()->print_value_on(this, st); +} + +void CodeBlob::print_on_impl(outputStream* st) const { + st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", p2i(this)); + st->print_cr("Framesize: %d", _frame_size); +} + +void CodeBlob::print_value_on_impl(outputStream* st) const { st->print_cr("[CodeBlob]"); } +void CodeBlob::print_block_comment(outputStream* stream, address block_begin) const { +#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) + if (is_nmethod()) { + as_nmethod()->print_nmethod_labels(stream, block_begin); + } +#endif + +#ifndef PRODUCT + ptrdiff_t offset = block_begin - code_begin(); + assert(offset >= 0, "Expecting non-negative offset!"); + _asm_remarks.print(uint(offset), stream); +#endif + } + void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const { if (is_buffer_blob() || is_adapter_blob() || is_vtable_blob() || is_method_handles_adapter_blob()) { // the interpreter is generated into a buffer blob @@ -708,7 +776,7 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const // verbose is only ever true when called from findpc in debug.cpp nm->print_nmethod(true); } else { - nm->print(st); + nm->print_on(st); } return; } @@ -716,61 +784,45 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const print_on(st); } -void BufferBlob::verify() { - // unimplemented +void BufferBlob::print_on_impl(outputStream* st) const { + RuntimeBlob::print_on_impl(st); + print_value_on_impl(st); } -void BufferBlob::print_on(outputStream* st) const { - RuntimeBlob::print_on(st); - print_value_on(st); -} - -void BufferBlob::print_value_on(outputStream* st) const { +void BufferBlob::print_value_on_impl(outputStream* st) const { st->print_cr("BufferBlob (" INTPTR_FORMAT ") used for %s", p2i(this), name()); } -void RuntimeStub::verify() { - // unimplemented -} - -void RuntimeStub::print_on(outputStream* st) const { +void RuntimeStub::print_on_impl(outputStream* st) const { ttyLocker ttyl; - RuntimeBlob::print_on(st); + RuntimeBlob::print_on_impl(st); st->print("Runtime Stub (" INTPTR_FORMAT "): ", p2i(this)); st->print_cr("%s", name()); Disassembler::decode((RuntimeBlob*)this, st); } -void RuntimeStub::print_value_on(outputStream* st) const { +void RuntimeStub::print_value_on_impl(outputStream* st) const { st->print("RuntimeStub (" INTPTR_FORMAT "): ", p2i(this)); st->print("%s", name()); } -void SingletonBlob::verify() { - // unimplemented -} - -void SingletonBlob::print_on(outputStream* st) const { +void SingletonBlob::print_on_impl(outputStream* st) const { ttyLocker ttyl; - RuntimeBlob::print_on(st); + RuntimeBlob::print_on_impl(st); st->print_cr("%s", name()); Disassembler::decode((RuntimeBlob*)this, st); } -void SingletonBlob::print_value_on(outputStream* st) const { +void SingletonBlob::print_value_on_impl(outputStream* st) const { st->print_cr("%s", name()); } -void DeoptimizationBlob::print_value_on(outputStream* st) const { +void DeoptimizationBlob::print_value_on_impl(outputStream* st) const { st->print_cr("Deoptimization (frame not available)"); } -void UpcallStub::verify() { - // unimplemented -} - -void UpcallStub::print_on(outputStream* st) const { - RuntimeBlob::print_on(st); - print_value_on(st); +void UpcallStub::print_on_impl(outputStream* st) const { + RuntimeBlob::print_on_impl(st); + print_value_on_impl(st); st->print_cr("Frame data offset: %d", (int) _frame_data_offset); oop recv = JNIHandles::resolve(_receiver); st->print("Receiver MH="); @@ -778,6 +830,6 @@ void UpcallStub::print_on(outputStream* st) const { Disassembler::decode((RuntimeBlob*)this, st); } -void UpcallStub::print_value_on(outputStream* st) const { +void UpcallStub::print_value_on_impl(outputStream* st) const { st->print_cr("UpcallStub (" INTPTR_FORMAT ") used for %s", p2i(this), name()); } diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 63294d71892..fd9a96a2a6b 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.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 @@ -61,8 +61,8 @@ enum class CodeBlobType { // RuntimeStub : Call to VM runtime methods // SingletonBlob : Super-class for all blobs that exist in only one instance // DeoptimizationBlob : Used for deoptimization -// ExceptionBlob : Used for stack unrolling // SafepointBlob : Used to handle illegal instruction exceptions +// ExceptionBlob : Used for stack unrolling // UncommonTrapBlob : Used to handle uncommon traps // UpcallStub : Used for upcalls from native code // @@ -80,12 +80,14 @@ enum class CodeBlobKind : u1 { Buffer, Adapter, Vtable, - MH_Adapter, - Runtime_Stub, + MHAdapter, + RuntimeStub, Deoptimization, - Exception, Safepoint, - Uncommon_Trap, +#ifdef COMPILER2 + Exception, + UncommonTrap, +#endif Upcall, Number_Of_Kinds }; @@ -128,6 +130,17 @@ protected: DbgStrings _dbg_strings; #endif + void print_on_impl(outputStream* st) const; + void print_value_on_impl(outputStream* st) const; + + class Vptr { + public: + virtual void print_on(const CodeBlob* instance, outputStream* st) const = 0; + virtual void print_value_on(const CodeBlob* instance, outputStream* st) const = 0; + }; + + const Vptr* vptr() const; + CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, uint16_t header_size, int16_t frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments); @@ -138,7 +151,7 @@ protected: public: - virtual ~CodeBlob() { + ~CodeBlob() { assert(_oop_maps == nullptr, "Not flushed"); } @@ -152,20 +165,25 @@ public: // Typing bool is_nmethod() const { return _kind == CodeBlobKind::Nmethod; } bool is_buffer_blob() const { return _kind == CodeBlobKind::Buffer; } - bool is_runtime_stub() const { return _kind == CodeBlobKind::Runtime_Stub; } + bool is_runtime_stub() const { return _kind == CodeBlobKind::RuntimeStub; } bool is_deoptimization_stub() const { return _kind == CodeBlobKind::Deoptimization; } - bool is_uncommon_trap_stub() const { return _kind == CodeBlobKind::Uncommon_Trap; } +#ifdef COMPILER2 + bool is_uncommon_trap_stub() const { return _kind == CodeBlobKind::UncommonTrap; } bool is_exception_stub() const { return _kind == CodeBlobKind::Exception; } +#else + bool is_uncommon_trap_stub() const { return false; } + bool is_exception_stub() const { return false; } +#endif bool is_safepoint_stub() const { return _kind == CodeBlobKind::Safepoint; } bool is_adapter_blob() const { return _kind == CodeBlobKind::Adapter; } bool is_vtable_blob() const { return _kind == CodeBlobKind::Vtable; } - bool is_method_handles_adapter_blob() const { return _kind == CodeBlobKind::MH_Adapter; } + bool is_method_handles_adapter_blob() const { return _kind == CodeBlobKind::MHAdapter; } bool is_upcall_stub() const { return _kind == CodeBlobKind::Upcall; } // Casting - nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : nullptr; } - nmethod* as_nmethod() { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } - CodeBlob* as_codeblob_or_null() const { return (CodeBlob*) this; } + nmethod* as_nmethod_or_null() const { return is_nmethod() ? (nmethod*) this : nullptr; } + nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } + CodeBlob* as_codeblob() const { return (CodeBlob*) this; } UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; } RuntimeStub* as_runtime_stub() const { assert(is_runtime_stub(), "must be runtime blob"); return (RuntimeStub*) this; } @@ -233,21 +251,16 @@ public: void set_name(const char* name) { _name = name; } // Debugging - virtual void verify() = 0; - virtual void print() const; - virtual void print_on(outputStream* st) const; - virtual void print_value_on(outputStream* st) const; + void verify(); + void print() const; + void print_on(outputStream* st) const; + void print_value_on(outputStream* st) const; + void dump_for_addr(address addr, outputStream* st, bool verbose) const; void print_code_on(outputStream* st); // Print to stream, any comments associated with offset. - virtual void print_block_comment(outputStream* stream, address block_begin) const { -#ifndef PRODUCT - ptrdiff_t offset = block_begin - code_begin(); - assert(offset >= 0, "Expecting non-negative offset!"); - _asm_remarks.print(uint(offset), stream); -#endif - } + void print_block_comment(outputStream* stream, address block_begin) const; #ifndef PRODUCT AsmRemarks &asm_remarks() { return _asm_remarks; } @@ -290,6 +303,9 @@ class RuntimeBlob : public CodeBlob { // Deal with Disassembler, VTune, Forte, JvmtiExport, MemoryService. static void trace_new_stub(RuntimeBlob* blob, const char* name1, const char* name2 = ""); + + class Vptr : public CodeBlob::Vptr { + }; }; class WhiteBox; @@ -318,11 +334,19 @@ class BufferBlob: public RuntimeBlob { static void free(BufferBlob* buf); - // Verification support - void verify() override; + void print_on_impl(outputStream* st) const; + void print_value_on_impl(outputStream* st) const; - void print_on(outputStream* st) const override; - void print_value_on(outputStream* st) const override; + class Vptr : public RuntimeBlob::Vptr { + void print_on(const CodeBlob* instance, outputStream* st) const override { + ((const BufferBlob*)instance)->print_on_impl(st); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + ((const BufferBlob*)instance)->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; @@ -355,7 +379,7 @@ public: class MethodHandlesAdapterBlob: public BufferBlob { private: - MethodHandlesAdapterBlob(int size): BufferBlob("MethodHandles adapters", CodeBlobKind::MH_Adapter, size) {} + MethodHandlesAdapterBlob(int size): BufferBlob("MethodHandles adapters", CodeBlobKind::MHAdapter, size) {} public: // Creation @@ -396,13 +420,21 @@ class RuntimeStub: public RuntimeBlob { static void free(RuntimeStub* stub) { RuntimeBlob::free(stub); } - address entry_point() const { return code_begin(); } + address entry_point() const { return code_begin(); } - // Verification support - void verify() override; + void print_on_impl(outputStream* st) const; + void print_value_on_impl(outputStream* st) const; - void print_on(outputStream* st) const override; - void print_value_on(outputStream* st) const override; + class Vptr : public RuntimeBlob::Vptr { + void print_on(const CodeBlob* instance, outputStream* st) const override { + instance->as_runtime_stub()->print_on_impl(st); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + instance->as_runtime_stub()->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; @@ -430,11 +462,19 @@ class SingletonBlob: public RuntimeBlob { address entry_point() { return code_begin(); } - // Verification support - void verify() override; // does nothing + void print_on_impl(outputStream* st) const; + void print_value_on_impl(outputStream* st) const; - void print_on(outputStream* st) const override; - void print_value_on(outputStream* st) const override; + class Vptr : public RuntimeBlob::Vptr { + void print_on(const CodeBlob* instance, outputStream* st) const override { + ((const SingletonBlob*)instance)->print_on_impl(st); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + ((const SingletonBlob*)instance)->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; @@ -479,9 +519,6 @@ class DeoptimizationBlob: public SingletonBlob { int frame_size ); - // Printing - void print_value_on(outputStream* st) const override; - address unpack() const { return code_begin() + _unpack_offset; } address unpack_with_exception() const { return code_begin() + _unpack_with_exception; } address unpack_with_reexecution() const { return code_begin() + _unpack_with_reexecution; } @@ -511,6 +548,16 @@ class DeoptimizationBlob: public SingletonBlob { } address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } #endif // INCLUDE_JVMCI + + void print_value_on_impl(outputStream* st) const; + + class Vptr : public SingletonBlob::Vptr { + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + ((const DeoptimizationBlob*)instance)->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; @@ -623,13 +670,22 @@ class UpcallStub: public RuntimeBlob { JavaFrameAnchor* jfa_for_frame(const frame& frame) const; - // GC/Verification support + // GC support void oops_do(OopClosure* f, const frame& frame); - void verify() override; - // Misc. - void print_on(outputStream* st) const override; - void print_value_on(outputStream* st) const override; + void print_on_impl(outputStream* st) const; + void print_value_on_impl(outputStream* st) const; + + class Vptr : public RuntimeBlob::Vptr { + void print_on(const CodeBlob* instance, outputStream* st) const override { + instance->as_upcall_stub()->print_on_impl(st); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + instance->as_upcall_stub()->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; #endif // SHARE_CODE_CODEBLOB_HPP diff --git a/src/hotspot/share/code/dependencyContext.cpp b/src/hotspot/share/code/dependencyContext.cpp index f64b6e15c1a..2b3253030c5 100644 --- a/src/hotspot/share/code/dependencyContext.cpp +++ b/src/hotspot/share/code/dependencyContext.cpp @@ -218,7 +218,7 @@ void DependencyContext::print_dependent_nmethods(bool verbose) { nmethod* nm = b->get_nmethod(); tty->print("[%d] { ", idx++); if (!verbose) { - nm->print_on(tty, "nmethod"); + nm->print_on_with_msg(tty, "nmethod"); tty->print_cr(" } "); } else { nm->print(); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index e454d8f3f68..4f72c193d7f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1619,7 +1619,7 @@ void nmethod::log_new_nmethod() const { // Print out more verbose output usually for a newly created nmethod. -void nmethod::print_on(outputStream* st, const char* msg) const { +void nmethod::print_on_with_msg(outputStream* st, const char* msg) const { if (st != nullptr) { ttyLocker ttyl; if (WizardMode) { @@ -1971,7 +1971,7 @@ void nmethod::log_state_change() const { CompileTask::print_ul(this, "made not entrant"); if (PrintCompilation) { - print_on(tty, "made not entrant"); + print_on_with_msg(tty, "made not entrant"); } } @@ -3033,12 +3033,7 @@ void nmethod::verify_scopes() { // ----------------------------------------------------------------------------- // Printing operations -void nmethod::print() const { - ttyLocker ttyl; // keep the following output all in one block - print(tty); -} - -void nmethod::print(outputStream* st) const { +void nmethod::print_on_impl(outputStream* st) const { ResourceMark rm; st->print("Compiled method "); @@ -3053,7 +3048,7 @@ void nmethod::print(outputStream* st) const { st->print("(n/a) "); } - print_on(st, nullptr); + print_on_with_msg(st, nullptr); if (WizardMode) { st->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this)); @@ -3404,7 +3399,7 @@ void nmethod::decode2(outputStream* ost) const { #endif st->cr(); - this->print(st); + this->print_on(st); st->cr(); #if defined(SUPPORT_ASSEMBLY) @@ -3953,12 +3948,12 @@ address nmethod::call_instruction_address(address pc) const { return nullptr; } +void nmethod::print_value_on_impl(outputStream* st) const { + st->print_cr("nmethod"); #if defined(SUPPORT_DATA_STRUCTS) -void nmethod::print_value_on(outputStream* st) const { - st->print("nmethod"); - print_on(st, nullptr); -} + print_on_with_msg(st, nullptr); #endif +} #ifndef PRODUCT diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 095c0ba4a26..39bf18547d8 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.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 @@ -900,7 +900,7 @@ public: void post_compiled_method_load_event(JvmtiThreadState* state = nullptr); // verify operations - void verify() override; + void verify(); void verify_scopes(); void verify_interrupt_point(address interrupt_point, bool is_inline_cache); @@ -912,9 +912,9 @@ public: void decode(outputStream* st) const { decode2(st); } // just delegate here. // printing support - void print() const override; - void print(outputStream* st) const; + void print_on_impl(outputStream* st) const; void print_code(); + void print_value_on_impl(outputStream* st) const; #if defined(SUPPORT_DATA_STRUCTS) // print output in opt build for disassembler library @@ -922,7 +922,6 @@ public: void print_pcs_on(outputStream* st); void print_scopes() { print_scopes_on(tty); } void print_scopes_on(outputStream* st) PRODUCT_RETURN; - void print_value_on(outputStream* st) const override; void print_handler_table(); void print_nul_chk_table(); void print_recorded_oop(int log_n, int index); @@ -941,9 +940,7 @@ public: void maybe_print_nmethod(const DirectiveSet* directive); void print_nmethod(bool print_code); - // need to re-define this from CodeBlob else the overload hides it - void print_on(outputStream* st) const override { CodeBlob::print_on(st); } - void print_on(outputStream* st, const char* msg) const; + void print_on_with_msg(outputStream* st, const char* msg) const; // Logging void log_identity(xmlStream* log) const; @@ -951,13 +948,6 @@ public: void log_state_change() const; // Prints block-level comments, including nmethod specific block labels: - void print_block_comment(outputStream* stream, address block_begin) const override { -#if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) - print_nmethod_labels(stream, block_begin); - CodeBlob::print_block_comment(stream, block_begin); -#endif - } - void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const; const char* nmethod_section_label(address pos) const; @@ -995,6 +985,18 @@ public: void make_deoptimized(); void finalize_relocations(); + + class Vptr : public CodeBlob::Vptr { + void print_on(const CodeBlob* instance, outputStream* st) const override { + ttyLocker ttyl; + instance->as_nmethod()->print_on_impl(st); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { + instance->as_nmethod()->print_value_on_impl(st); + } + }; + + static const Vptr _vptr; }; #endif // SHARE_CODE_NMETHOD_HPP diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index ac6a6682beb..1c776f7b8e2 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -549,6 +549,7 @@ \ nonstatic_field(CodeBlob, _name, const char*) \ nonstatic_field(CodeBlob, _size, int) \ + nonstatic_field(CodeBlob, _kind, CodeBlobKind) \ nonstatic_field(CodeBlob, _header_size, u2) \ nonstatic_field(CodeBlob, _relocation_size, int) \ nonstatic_field(CodeBlob, _content_offset, int) \ @@ -1916,6 +1917,7 @@ \ declare_integer_type(CompLevel) \ declare_integer_type(ByteSize) \ + declare_integer_type(CodeBlobKind) \ JVMTI_ONLY(declare_toplevel_type(BreakpointInfo)) \ JVMTI_ONLY(declare_toplevel_type(BreakpointInfo*)) \ declare_toplevel_type(CodeBlob*) \ @@ -2373,6 +2375,23 @@ declare_constant(CompLevel_full_profile) \ declare_constant(CompLevel_full_optimization) \ \ + /****************/ \ + /* CodeBlobKind */ \ + /****************/ \ + \ + declare_constant(CodeBlobKind::Nmethod) \ + declare_constant(CodeBlobKind::Buffer) \ + declare_constant(CodeBlobKind::Adapter) \ + declare_constant(CodeBlobKind::Vtable) \ + declare_constant(CodeBlobKind::MHAdapter) \ + declare_constant(CodeBlobKind::RuntimeStub) \ + declare_constant(CodeBlobKind::Deoptimization) \ + declare_constant(CodeBlobKind::Safepoint) \ + COMPILER2_PRESENT(declare_constant(CodeBlobKind::Exception)) \ + COMPILER2_PRESENT(declare_constant(CodeBlobKind::UncommonTrap)) \ + declare_constant(CodeBlobKind::Upcall) \ + declare_constant(CodeBlobKind::Number_Of_Kinds) \ + \ /***************/ \ /* OopMapValue */ \ /***************/ \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java index b7bcc87e933..b26e42ebfdf 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -62,6 +62,6 @@ public class Runtime1 { /** FIXME: consider making argument "type-safe" in Java port */ public CodeBlob blobFor(int id) { Address blobAddr = blobsField.getStaticFieldAddress().getAddressAt(id * VM.getVM().getAddressSize()); - return VM.getVM().getCodeCache().createCodeBlobWrapper(blobAddr); + return VM.getVM().getCodeCache().createCodeBlobWrapper(blobAddr, blobAddr); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java index eefc2ed808a..8fa69a2686c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.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 @@ -50,10 +50,6 @@ public class AdapterBlob extends RuntimeBlob { super(addr); } - public boolean isAdapterBlob() { - return true; - } - public String getName() { return "AdapterBlob: " + super.getName(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java index 97fc59d25e1..8f2ed2aa601 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -49,8 +49,4 @@ public class BufferBlob extends RuntimeBlob { public BufferBlob(Address addr) { super(addr); } - - public boolean isBufferBlob() { - return true; - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java index 90e4b5b98b4..326600d79f4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.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 @@ -43,6 +43,7 @@ import sun.jvm.hotspot.utilities.Observer; public class CodeBlob extends VMObject { private static AddressField nameField; private static CIntegerField sizeField; + private static CIntegerField kindField; private static CIntegerField relocationSizeField; private static CIntField headerSizeField; private static CIntegerField contentOffsetField; @@ -52,6 +53,22 @@ public class CodeBlob extends VMObject { private static CIntegerField frameSizeField; private static AddressField oopMapsField; + // Kinds of Codeblob + private static int NMethodKind; + private static int BufferKind; + private static int AdapterKind; + private static int VtableKind; + private static int MHAdapterKind; + private static int RuntimeStubKind; + private static int DeoptimizationKind; + private static int ExceptionKind; + private static int SafepointKind; + private static int UncommonTrapKind; + private static int UpcallKind; + private static int NumberOfKinds; + + private static Class[] wrapperClasses; + public CodeBlob(Address addr) { super(addr); } @@ -63,6 +80,7 @@ public class CodeBlob extends VMObject { nameField = type.getAddressField("_name"); sizeField = type.getCIntegerField("_size"); + kindField = type.getCIntegerField("_kind"); relocationSizeField = type.getCIntegerField("_relocation_size"); headerSizeField = new CIntField(type.getCIntegerField("_header_size"), 0); contentOffsetField = type.getCIntegerField("_content_offset"); @@ -76,6 +94,40 @@ public class CodeBlob extends VMObject { matcherInterpreterFramePointerReg = db.lookupIntConstant("Matcher::interpreter_frame_pointer_reg").intValue(); } + + NMethodKind = db.lookupIntConstant("CodeBlobKind::Nmethod").intValue(); + BufferKind = db.lookupIntConstant("CodeBlobKind::Buffer").intValue(); + AdapterKind = db.lookupIntConstant("CodeBlobKind::Adapter").intValue(); + VtableKind = db.lookupIntConstant("CodeBlobKind::Vtable").intValue(); + MHAdapterKind = db.lookupIntConstant("CodeBlobKind::MHAdapter").intValue(); + RuntimeStubKind = db.lookupIntConstant("CodeBlobKind::RuntimeStub").intValue(); + DeoptimizationKind = db.lookupIntConstant("CodeBlobKind::Deoptimization").intValue(); + SafepointKind = db.lookupIntConstant("CodeBlobKind::Safepoint").intValue(); + UpcallKind = db.lookupIntConstant("CodeBlobKind::Upcall").intValue(); + NumberOfKinds = db.lookupIntConstant("CodeBlobKind::Number_Of_Kinds").intValue(); + if (VM.getVM().isServerCompiler()) { + ExceptionKind = db.lookupIntConstant("CodeBlobKind::Exception").intValue(); + UncommonTrapKind = db.lookupIntConstant("CodeBlobKind::UncommonTrap").intValue(); + } else { + // Set invalid value to not match default. + ExceptionKind = NumberOfKinds + 1; + UncommonTrapKind = NumberOfKinds + 1; + } + + wrapperClasses = new Class[NumberOfKinds]; + wrapperClasses[NMethodKind] = NMethod.class; + wrapperClasses[BufferKind] = BufferBlob.class; + wrapperClasses[AdapterKind] = AdapterBlob.class; + wrapperClasses[VtableKind] = VtableBlob.class; + wrapperClasses[MHAdapterKind] = MethodHandlesAdapterBlob.class; + wrapperClasses[RuntimeStubKind] = RuntimeStub.class; + wrapperClasses[DeoptimizationKind] = DeoptimizationBlob.class; + wrapperClasses[SafepointKind] = SafepointBlob.class; + wrapperClasses[UpcallKind] = UpcallStub.class; + if (VM.getVM().isServerCompiler()) { + wrapperClasses[ExceptionKind] = ExceptionBlob.class; + wrapperClasses[UncommonTrapKind] = UncommonTrapBlob.class; + } } static { @@ -86,6 +138,11 @@ public class CodeBlob extends VMObject { }); } + public static Class getClassFor(Address addr) { + CodeBlob cb = new CodeBlob(addr); + return wrapperClasses[cb.getKind()]; + } + public Address headerBegin() { return getAddress(); } public Address headerEnd() { return getAddress().addOffsetTo(getHeaderSize()); } @@ -124,6 +181,10 @@ public class CodeBlob extends VMObject { return CStringUtilities.getString(nameField.getValue(addr)); } + public int getKind() { + return (int) kindField.getValue(addr); + } + /** OopMap for frame; can return null if none available */ public ImmutableOopMapSet getOopMaps() { Address value = oopMapsField.getValue(addr); @@ -135,27 +196,29 @@ public class CodeBlob extends VMObject { // Typing - public boolean isBufferBlob() { return false; } + public boolean isBufferBlob() { return getKind() == BufferKind; } - public boolean isCompiled() { return false; } + public boolean isNMethod() { return getKind() == NMethodKind; } - public boolean isNMethod() { return false; } + public boolean isRuntimeStub() { return getKind() == RuntimeStubKind; } - public boolean isRuntimeStub() { return false; } + public boolean isUpcallStub() { return getKind() == UpcallKind; } - public boolean isUpcallStub() { return false; } + public boolean isDeoptimizationBlob() { return getKind() == DeoptimizationKind; } - public boolean isDeoptimizationStub() { return false; } + public boolean isUncommonTrapBlob() { return getKind() == UncommonTrapKind; } - public boolean isUncommonTrapStub() { return false; } + public boolean isExceptionBlob() { return getKind() == ExceptionKind; } - public boolean isExceptionStub() { return false; } + public boolean isSafepointBlob() { return getKind() == SafepointKind; } - public boolean isSafepointStub() { return false; } + public boolean isAdapterBlob() { return getKind() == AdapterKind; } - public boolean isAdapterBlob() { return false; } + public boolean isMHAdapterBlob() { return getKind() == MHAdapterKind; } - // Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod() + public boolean isVtableBlob() { return getKind() == VtableKind; } + + // Fine grain nmethod support: isNMethod() == isJavaMethod() || isNativeMethod() || isOSRMethod() public boolean isJavaMethod() { return false; } public boolean isNativeMethod() { return false; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java index e2eac930e02..73135a873e5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.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 @@ -35,7 +35,6 @@ import sun.jvm.hotspot.utilities.Observer; public class CodeCache { private static GrowableArray heapArray; - private static VirtualConstructor virtualConstructor; static { VM.registerVMInitializedObserver(new Observer() { @@ -51,22 +50,6 @@ public class CodeCache { // Get array of CodeHeaps AddressField heapsField = type.getAddressField("_heaps"); heapArray = GrowableArray.create(heapsField.getValue(), new StaticBaseConstructor<>(CodeHeap.class)); - - virtualConstructor = new VirtualConstructor(db); - // Add mappings for all possible CodeBlob subclasses - virtualConstructor.addMapping("BufferBlob", BufferBlob.class); - virtualConstructor.addMapping("nmethod", NMethod.class); - virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class); - virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class); - virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class); - virtualConstructor.addMapping("VtableBlob", VtableBlob.class); - virtualConstructor.addMapping("UpcallStub", UpcallStub.class); - virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); - virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); - if (VM.getVM().isServerCompiler()) { - virtualConstructor.addMapping("ExceptionBlob", ExceptionBlob.class); - virtualConstructor.addMapping("UncommonTrapBlob", UncommonTrapBlob.class); - } } public boolean contains(Address p) { @@ -80,8 +63,8 @@ public class CodeCache { /** When VM.getVM().isDebugging() returns true, this behaves like findBlobUnsafe */ - public CodeBlob findBlob(Address start) { - CodeBlob result = findBlobUnsafe(start); + public CodeBlob findBlob(Address addr) { + CodeBlob result = findBlobUnsafe(addr); if (result == null) return null; if (VM.getVM().isDebugging()) { return result; @@ -91,11 +74,10 @@ public class CodeCache { return result; } - public CodeBlob findBlobUnsafe(Address start) { - CodeBlob result = null; + public CodeBlob findBlobUnsafe(Address addr) { CodeHeap containing_heap = null; for (int i = 0; i < heapArray.length(); ++i) { - if (heapArray.at(i).contains(start)) { + if (heapArray.at(i).contains(addr)) { containing_heap = heapArray.at(i); break; } @@ -104,76 +86,52 @@ public class CodeCache { return null; } - try { - result = (CodeBlob) virtualConstructor.instantiateWrapperFor(containing_heap.findStart(start)); - } - catch (WrongTypeException wte) { - Address cbAddr = null; - try { - cbAddr = containing_heap.findStart(start); - } - catch (Exception findEx) { - findEx.printStackTrace(); - } + Address cbStart = containing_heap.findStart(addr); + if (cbStart == null) return null; + return createCodeBlobWrapper(cbStart, addr); + } + + // cbStart - address of a code blob + // addr - address inside of a code blob + public CodeBlob createCodeBlobWrapper(Address cbStart, Address addr) { + Class cbClass = CodeBlob.getClassFor(cbStart); + if (cbClass == null) { String message = "Couldn't deduce type of CodeBlob "; - if (cbAddr != null) { - message = message + "@" + cbAddr + " "; - } - message = message + "for PC=" + start; + message = message + "@" + cbStart + " "; + message = message + "for PC=" + addr; - throw new RuntimeException(message, wte); + throw new RuntimeException(message); } - if (result == null) return null; + CodeBlob result = (CodeBlob) VMObjectFactory.newObject(cbClass, cbStart); if (Assert.ASSERTS_ENABLED) { // The pointer to the HeapBlock that contains this blob is outside of the blob, // but it shouldn't be an error to find a blob based on the pointer to the HeapBlock. // The heap block header is padded out to an 8-byte boundary. See heap.hpp. The // simplest way to compute the header size is just 2 * addressSize. - Assert.that(result.blobContains(start) || - result.blobContains(start.addOffsetTo(2 * VM.getVM().getAddressSize())), + Assert.that(result.blobContains(addr) || + result.blobContains(addr.addOffsetTo(2 * VM.getVM().getAddressSize())), "found wrong CodeBlob"); } return result; } - public NMethod findNMethod(Address start) { - CodeBlob cb = findBlob(start); + public NMethod findNMethod(Address addr) { + CodeBlob cb = findBlob(addr); if (Assert.ASSERTS_ENABLED) { Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod"); } return (NMethod) cb; } - public NMethod findNMethodUnsafe(Address start) { - CodeBlob cb = findBlobUnsafe(start); + public NMethod findNMethodUnsafe(Address addr) { + CodeBlob cb = findBlobUnsafe(addr); if (Assert.ASSERTS_ENABLED) { Assert.that(cb == null || cb.isNMethod(), "did not find an nmethod"); } return (NMethod) cb; } - /** Routine for instantiating appropriately-typed wrapper for a - CodeBlob. Used by CodeCache, Runtime1, etc. */ - public CodeBlob createCodeBlobWrapper(Address codeBlobAddr) { - try { - return (CodeBlob) virtualConstructor.instantiateWrapperFor(codeBlobAddr); - } - catch (Exception e) { - String message = "Unable to deduce type of CodeBlob from address " + codeBlobAddr + - " (expected type nmethod, RuntimeStub, VtableBlob, "; - if (VM.getVM().isClientCompiler()) { - message = message + " or "; - } - message = message + "SafepointBlob"; - if (VM.getVM().isServerCompiler()) { - message = message + ", DeoptimizationBlob, or ExceptionBlob"; - } - message = message + ")"; - throw new RuntimeException(message); - } - } - public void iterate(CodeCacheVisitor visitor) { visitor.prologue(lowBound(), highBound()); for (int i = 0; i < heapArray.length(); ++i) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java index d6686e1bb96..51a5184ca85 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -49,8 +49,4 @@ public class DeoptimizationBlob extends SingletonBlob { public DeoptimizationBlob(Address addr) { super(addr); } - - public boolean isDeoptimizationStub() { - return true; - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java index 6ce32c03b65..30025a41866 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -52,8 +52,4 @@ public class ExceptionBlob extends SingletonBlob { public ExceptionBlob(Address addr) { super(addr); } - - public boolean isExceptionStub() { - return true; - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java index fa3cc84f179..53c9593d0b8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.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 @@ -50,10 +50,6 @@ public class MethodHandlesAdapterBlob extends AdapterBlob { super(addr); } - public boolean isMethodHandlesAdapterBlob() { - return true; - } - public String getName() { return "MethodHandlesAdapterBlob: " + super.getName(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index 8eacd1a8a86..8cd2342750d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.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 @@ -117,7 +117,6 @@ public class NMethod extends CodeBlob { } // Type info - public boolean isNMethod() { return true; } public boolean isJavaMethod() { return !getMethod().isNative(); } public boolean isNativeMethod() { return getMethod().isNative(); } public boolean isOSRMethod() { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java index 10568701a43..f51dcd76516 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -53,10 +53,6 @@ public class RuntimeStub extends RuntimeBlob { super(addr); } - public boolean isRuntimeStub() { - return true; - } - public boolean callerMustGCArguments() { return callerMustGCArgumentsField.getValue(addr) != 0; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java index 70d6f1a3c5f..3f3ba79ff9f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -51,8 +51,4 @@ public class SafepointBlob extends SingletonBlob { public SafepointBlob(Address addr) { super(addr); } - - public boolean isSafepointStub() { - return true; - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java index 7957fba1d92..5a80b957e1d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -49,6 +49,4 @@ public class SingletonBlob extends RuntimeBlob { public SingletonBlob(Address addr) { super(addr); } - - public boolean isSingletonBlob() { return true; } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java index b7fa1d25821..077e49b5fe6 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -51,8 +51,4 @@ public class UncommonTrapBlob extends SingletonBlob { public UncommonTrapBlob(Address addr) { super(addr); } - - public boolean isUncommonTrapStub() { - return true; - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java index 4e324ba38e4..eeb5821bb60 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.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 @@ -85,10 +85,6 @@ public class UpcallStub extends RuntimeBlob { return lastJavaPCField.getValue(getJavaFrameAnchor(frame)); } - public boolean isUpcallStub() { - return true; - } - public static class FrameData extends VMObject { private static AddressField jfaField; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java index e992cfe7787..a193d5ff340 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.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. * Copyright (c) 2020, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -33,10 +33,6 @@ public class VtableBlob extends BufferBlob { super(addr); } - public boolean isVtableBlob() { - return true; - } - public String getName() { return "VtableBlob: " + super.getName(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java index 4b188ac2b5a..5df4050a6a9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/CodeHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, 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 @@ -108,7 +108,7 @@ public class CodeHeap extends VMObject { while (ptr != null && ptr.lessThan(end())) { try { // Use findStart to get a pointer inside blob other findBlob asserts - CodeBlob blob = cache.createCodeBlobWrapper(findStart(ptr)); + CodeBlob blob = cache.createCodeBlobWrapper(findStart(ptr), ptr); if (blob != null) { visitor.visit(blob); if (blob == lastBlob) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 2f48c75eb78..945dd6bcc49 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.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 @@ -162,16 +162,24 @@ public class PStack extends Tool { } } else if (cb.isBufferBlob()) { out.println(""); + } else if (cb.isAdapterBlob()) { + out.println(""); + } else if (cb.isVtableBlob()) { + out.println(""); + } else if (cb.isMHAdapterBlob()) { + out.println(""); } else if (cb.isRuntimeStub()) { out.println(""); - } else if (cb.isDeoptimizationStub()) { - out.println(""); - } else if (cb.isUncommonTrapStub()) { - out.println(""); - } else if (cb.isExceptionStub()) { - out.println(""); - } else if (cb.isSafepointStub()) { - out.println(""); + } else if (cb.isUpcallStub()) { + out.println(""); + } else if (cb.isDeoptimizationBlob()) { + out.println(""); + } else if (cb.isUncommonTrapBlob()) { + out.println(""); + } else if (cb.isExceptionBlob()) { + out.println(""); + } else if (cb.isSafepointBlob()) { + out.println(""); } else { out.println(""); } From f2b4e12afe67086a2ae08081fd545e5ce4d731fd Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 18 Feb 2025 20:18:08 +0000 Subject: [PATCH 045/587] 8350263: JvmciNotifyBootstrapFinishedEventTest intermittently times out Reviewed-by: yzheng, never --- .../TestUncaughtErrorInCompileMethod.config | 2 +- .../TestUncaughtErrorInCompileMethod.java | 52 ++++++++++--------- ...mciNotifyBootstrapFinishedEventTest.config | 2 +- ...JvmciNotifyBootstrapFinishedEventTest.java | 31 ++++++----- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.config b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.config index 521c27977f2..f54fcb0b8dc 100644 --- a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.config +++ b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.config @@ -1 +1 @@ -compiler.jvmci.TestUncaughtErrorInCompileMethod +compiler.jvmci.TestUncaughtErrorInCompileMethod$Locator diff --git a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java index 511e0c4b98c..49eae648bfc 100644 --- a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java @@ -56,7 +56,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -public class TestUncaughtErrorInCompileMethod extends JVMCIServiceLocator { +public class TestUncaughtErrorInCompileMethod { static volatile boolean compilerCreationErrorOccurred; @@ -86,6 +86,7 @@ public class TestUncaughtErrorInCompileMethod extends JVMCIServiceLocator { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:+UnlockExperimentalVMOptions", "-XX:+UseJVMCICompiler", "-Djvmci.Compiler=ErrorCompiler", + "-XX:-UseJVMCINativeLibrary", "-XX:-TieredCompilation", "-XX:+PrintCompilation", "--add-exports=jdk.internal.vm.ci/jdk.vm.ci.services=ALL-UNNAMED", @@ -124,7 +125,7 @@ public class TestUncaughtErrorInCompileMethod extends JVMCIServiceLocator { // Check that hs-err contains the stack trace of the fatal exception (sample shown above) String[] stackTraceSubstrings = { - "at compiler.jvmci.TestUncaughtErrorInCompileMethod$1.createCompiler(TestUncaughtErrorInCompileMethod.java", + "at compiler.jvmci.TestUncaughtErrorInCompileMethod$Locator$1.createCompiler(TestUncaughtErrorInCompileMethod.java", "at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.compileMethod(HotSpotJVMCIRuntime.java" }; for (String expect : stackTraceSubstrings) { @@ -172,31 +173,34 @@ public class TestUncaughtErrorInCompileMethod extends JVMCIServiceLocator { } } - @Override - public S getProvider(Class service) { - if (service == JVMCICompilerFactory.class) { - return service.cast(new JVMCICompilerFactory() { - final AtomicInteger counter = new AtomicInteger(); - @Override - public String getCompilerName() { - return "ErrorCompiler"; - } + public static class Locator extends JVMCIServiceLocator { - @Override - public JVMCICompiler createCompiler(JVMCIRuntime runtime) { - int attempt = counter.incrementAndGet(); - CompilerCreationError e = new CompilerCreationError(attempt); - e.printStackTrace(); - if (attempt >= 10) { - // Delay notifying the loop in main so that compilation failures - // have time to be reported by -XX:+PrintCompilation. - compilerCreationErrorOccurred = true; + @Override + public S getProvider(Class service) { + if (service == JVMCICompilerFactory.class) { + return service.cast(new JVMCICompilerFactory() { + final AtomicInteger counter = new AtomicInteger(); + @Override + public String getCompilerName() { + return "ErrorCompiler"; } - throw e; - } - }); + + @Override + public JVMCICompiler createCompiler(JVMCIRuntime runtime) { + int attempt = counter.incrementAndGet(); + CompilerCreationError e = new CompilerCreationError(attempt); + e.printStackTrace(); + if (attempt >= 10) { + // Delay notifying the loop in main so that compilation failures + // have time to be reported by -XX:+PrintCompilation. + compilerCreationErrorOccurred = true; + } + throw e; + } + }); + } + return null; } - return null; } /** diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.config b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.config index 19cd01ec1e1..709b87f94ef 100644 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.config +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.config @@ -1,2 +1,2 @@ -compiler.jvmci.events.JvmciNotifyBootstrapFinishedEventTest +compiler.jvmci.events.JvmciNotifyBootstrapFinishedEventTest$Locator compiler.jvmci.common.JVMCIHelpers diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java index 6230dda8802..8d3b5fcce5b 100644 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyBootstrapFinishedEventTest.java @@ -62,29 +62,34 @@ import jdk.test.lib.Asserts; import jdk.vm.ci.services.JVMCIServiceLocator; import jdk.vm.ci.hotspot.HotSpotVMEventListener; -public class JvmciNotifyBootstrapFinishedEventTest extends JVMCIServiceLocator implements HotSpotVMEventListener { +public class JvmciNotifyBootstrapFinishedEventTest { private static final boolean BOOTSTRAP = Boolean .getBoolean("compiler.jvmci.events.JvmciNotifyBootstrapFinishedEventTest.bootstrap"); - private static volatile int gotBoostrapNotification = 0; + private static volatile int gotBootstrapNotification = 0; public static void main(String args[]) { if (BOOTSTRAP) { - Asserts.assertEQ(gotBoostrapNotification, 1, "Did not receive expected number of bootstrap events"); + Asserts.assertEQ(gotBootstrapNotification, 1, "Did not receive expected number of bootstrap events"); } else { - Asserts.assertEQ(gotBoostrapNotification, 0, "Got unexpected bootstrap event"); + Asserts.assertEQ(gotBootstrapNotification, 0, "Got unexpected bootstrap event"); } } - @Override - public S getProvider(Class service) { - if (service == HotSpotVMEventListener.class) { - return service.cast(this); + public static class Locator extends JVMCIServiceLocator implements HotSpotVMEventListener { + public Locator() { + Thread.dumpStack(); + } + @Override + public S getProvider(Class service) { + if (service == HotSpotVMEventListener.class) { + return service.cast(this); + } + return null; } - return null; - } - @Override - public void notifyBootstrapFinished() { - gotBoostrapNotification++; + @Override + public void notifyBootstrapFinished() { + gotBootstrapNotification++; + } } } From 2d03bd007895b139b027947852c8b5ad8eab49b6 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 18 Feb 2025 20:58:04 +0000 Subject: [PATCH 046/587] 8350280: The JDK-8346050 testlibrary changes break the build Reviewed-by: dholmes --- make/test/BuildTestLib.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk index 54b4b306cb8..dc5e0a9bd64 100644 --- a/make/test/BuildTestLib.gmk +++ b/make/test/BuildTestLib.gmk @@ -70,6 +70,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \ --add-exports java.base/jdk.internal.platform=ALL-UNNAMED \ --add-exports java.base/sun.security.pkcs=ALL-UNNAMED \ + --add-exports java.base/sun.security.provider.certpath=ALL-UNNAMED \ --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED \ --add-exports java.base/sun.security.x509=ALL-UNNAMED \ --enable-preview, \ From 04659a40736610164855ac161120e63fcd46fe31 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 19 Feb 2025 01:30:16 +0000 Subject: [PATCH 047/587] 8350197: [UBSAN] Node::dump_idx reported float-cast-overflow Reviewed-by: chagedorn --- src/hotspot/share/opto/loopnode.cpp | 2 +- src/hotspot/share/opto/node.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 3329d4dadc6..ed2db13421f 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -6831,7 +6831,7 @@ void PhaseIdealLoop::get_idoms(Node* n, const uint count, Unique_Node_List& idom void PhaseIdealLoop::dump_idoms_in_reverse(const Node* n, const Node_List& idom_list) const { Node* next; uint padding = 3; - uint node_index_padding_width = static_cast(log10(static_cast(C->unique()))) + 1; + uint node_index_padding_width = (C->unique() == 0 ? 0 : static_cast(log10(static_cast(C->unique())))) + 1; for (int i = idom_list.size() - 1; i >= 0; i--) { if (i == 9 || i == 99) { padding++; diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 0c185c682b3..0e2957ac66e 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved. + * Copyright (c) 2024, 2025, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2425,9 +2425,9 @@ void Node::dump_idx(bool align, outputStream* st, DumpConfig* dc) const { bool is_new = C->node_arena()->contains(this); if (align) { // print prefix empty spaces$ // +1 for leading digit, +1 for "o" - uint max_width = static_cast(log10(static_cast(C->unique()))) + 2; + uint max_width = (C->unique() == 0 ? 0 : static_cast(log10(static_cast(C->unique())))) + 2; // +1 for leading digit, maybe +1 for "o" - uint width = static_cast(log10(static_cast(_idx))) + 1 + (is_new ? 0 : 1); + uint width = (_idx == 0 ? 0 : static_cast(log10(static_cast(_idx)))) + 1 + (is_new ? 0 : 1); while (max_width > width) { st->print(" "); width++; From 4de92a40d0750a2e6f72eb675d900f1129718d39 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 19 Feb 2025 02:19:27 +0000 Subject: [PATCH 048/587] 8350224: Test javax/swing/JComboBox/TestComboBoxComponentRendering.java fails in ubuntu 23.x and later Reviewed-by: aivanov, azvegint --- test/jdk/ProblemList.txt | 4 ---- .../javax/swing/JComboBox/TestComboBoxComponentRendering.java | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 2c63cd43d25..c6e62a55962 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -695,10 +695,6 @@ sanity/client/SwingSet/src/ToolTipDemoTest.java 8293001 linux-all sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java 8265770 macosx-all sanity/client/SwingSet/src/EditorPaneDemoTest.java 8212240 linux-x64 -# jdk_swing Ubuntu 23.04 specific - -javax/swing/JComboBox/TestComboBoxComponentRendering.java 8309734 linux-all - # This test fails on macOS 14 javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all diff --git a/test/jdk/javax/swing/JComboBox/TestComboBoxComponentRendering.java b/test/jdk/javax/swing/JComboBox/TestComboBoxComponentRendering.java index 0e176a911a3..da914314670 100644 --- a/test/jdk/javax/swing/JComboBox/TestComboBoxComponentRendering.java +++ b/test/jdk/javax/swing/JComboBox/TestComboBoxComponentRendering.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 @@ -33,6 +33,7 @@ import java.awt.Color; import java.awt.Component; import java.awt.image.BufferedImage; +import java.awt.Font; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; @@ -137,6 +138,7 @@ class ComboBoxCustomRenderer extends JLabel implements ListCellRenderer { public ComboBoxCustomRenderer() { + setFont(new Font("SansSerif", Font.BOLD, 32)); setOpaque(true); setHorizontalAlignment(CENTER); setVerticalAlignment(CENTER); From 9042aa82a890b0f0348ac8127dbd3268f2620346 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 19 Feb 2025 06:38:39 +0000 Subject: [PATCH 049/587] 8339238: Update to use jtreg 7.5.1 Reviewed-by: erikj, jpai, rriggs, iris --- make/autoconf/lib-tests.m4 | 4 ++-- make/conf/github-actions.conf | 4 ++-- make/conf/jib-profiles.js | 4 ++-- test/docs/TEST.ROOT | 4 ++-- test/hotspot/jtreg/TEST.ROOT | 2 +- test/jaxp/TEST.ROOT | 2 +- test/jdk/TEST.ROOT | 2 +- test/langtools/TEST.ROOT | 2 +- test/lib-test/TEST.ROOT | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index afb94030808..d2a4fcbb191 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -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,7 +28,7 @@ ################################################################################ # Minimum supported versions -JTREG_MINIMUM_VERSION=7.4 +JTREG_MINIMUM_VERSION=7.5.1 GTEST_MINIMUM_VERSION=1.14.0 ################################################################################ diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index a6b383daa8f..c34c90ef76e 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -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 @@ -26,7 +26,7 @@ # Versions and download locations for dependencies used by GitHub Actions (GHA) GTEST_VERSION=1.14.0 -JTREG_VERSION=7.4+1 +JTREG_VERSION=7.5.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_linux-x64_bin.tar.gz diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 9f04fce2ca6..397e75968e4 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1186,9 +1186,9 @@ var getJibProfilesDependencies = function (input, common) { jtreg: { server: "jpg", product: "jtreg", - version: "7.4", + version: "7.5.1", build_number: "1", - file: "bundles/jtreg-7.4+1.zip", + file: "bundles/jtreg-7.5.1+1.zip", environment_name: "JT_HOME", environment_path: input.get("jtreg", "home_path") + "/bin", configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"), diff --git a/test/docs/TEST.ROOT b/test/docs/TEST.ROOT index af2e5896779..9be915dd4ff 100644 --- a/test/docs/TEST.ROOT +++ b/test/docs/TEST.ROOT @@ -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 @@ -38,7 +38,7 @@ groups=TEST.groups # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Use new module options useNewOptions=true diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index eacf856075c..ac4321e6839 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -95,7 +95,7 @@ requires.properties= \ jlink.packagedModules # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../../ notation to reach them diff --git a/test/jaxp/TEST.ROOT b/test/jaxp/TEST.ROOT index 8098695b80e..7a457d87b69 100644 --- a/test/jaxp/TEST.ROOT +++ b/test/jaxp/TEST.ROOT @@ -23,7 +23,7 @@ modules=java.xml groups=TEST.groups # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index db48d501707..3b0b824b36f 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -114,7 +114,7 @@ requires.properties= \ jlink.packagedModules # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index d816d5b096b..c6c79ac81df 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -15,7 +15,7 @@ keys=intermittent randomness needs-src needs-src-jdk_javadoc groups=TEST.groups # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Use new module options useNewOptions=true diff --git a/test/lib-test/TEST.ROOT b/test/lib-test/TEST.ROOT index 27576a2d040..5908b50cb17 100644 --- a/test/lib-test/TEST.ROOT +++ b/test/lib-test/TEST.ROOT @@ -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 @@ -29,7 +29,7 @@ keys=randomness # Minimum jtreg version -requiredVersion=7.4+1 +requiredVersion=7.5.1+1 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them From 0ef1c40991e703592fc79325bda1a6d2fc6caf4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Wed, 19 Feb 2025 09:17:27 +0000 Subject: [PATCH 050/587] 8350006: IGV: show memory slices as type information Reviewed-by: dlunden, chagedorn, dfenacci --- src/hotspot/share/opto/idealGraphPrinter.cpp | 25 +++++++++++++++++++ src/hotspot/share/opto/idealGraphPrinter.hpp | 4 +-- .../servercompiler/filters/showTypes.filter | 17 +++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 6a28074f4d9..f6ec1a72506 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -542,6 +542,31 @@ void IdealGraphPrinter::visit_node(Node* n, bool edges) { assert(s2.size() < sizeof(buffer), "size in range"); print_prop("dump_spec", buffer); + const TypePtr* adr_type = node->adr_type(); + if (adr_type != nullptr && C->have_alias_type(adr_type)) { + Compile::AliasType* at = C->alias_type(adr_type); + if (at != nullptr) { + print_prop("alias_index", at->index()); + // The value of at->field(), if present, is already dumped in the + // "source"/"destination" properties. + const Type* element = at->element(); + if (element != nullptr) { + stringStream element_stream; + element->dump_on(&element_stream); + print_prop("alias_element", element_stream.freeze()); + } + if (at->is_rewritable()) { + print_prop("alias_is_rewritable", "true"); + } + if (at->is_volatile()) { + print_prop("alias_is_volatile", "true"); + } + if (at->general_index() != at->index()) { + print_prop("alias_general_index", at->general_index()); + } + } + } + if (node->is_block_proj()) { print_prop("is_block_proj", "true"); } diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 042ac694843..aab35c7a908 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -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 @@ -98,7 +98,7 @@ class IdealGraphPrinter : public CHeapObj { outputStream *_output; ciMethod *_current_method; int _depth; - char buffer[512]; + char buffer[2048]; bool _should_send_method; PhaseChaitin* _chaitin; bool _traverse_outs; diff --git a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showTypes.filter b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showTypes.filter index 16360d78c18..a50729080a8 100644 --- a/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showTypes.filter +++ b/src/utils/IdealGraphVisualizer/ServerCompiler/src/main/resources/com/sun/hotspot/igv/servercompiler/filters/showTypes.filter @@ -44,8 +44,16 @@ function simplifyType(type) { } // Merge a possibly existing extra label, bottom type, and phase type into a -// new, single extra label. -function mergeAndAppendTypeInfo(extra_label, bottom_type, phase_type) { +// new, single extra label. For memory nodes, add an extra label with the memory +// slice, extracted from the dump_spec field. +function mergeAndAppendTypeInfo(extra_label, bottom_type, phase_type, category, dump_spec) { + new_extra_label = extra_label == null ? "" : (extra_label + " "); + if (category == "memory") { + m = /idx=([^\s]+);/.exec(dump_spec); + if (m != null) { + return new_extra_label + "mem: " + m[1]; + } + } if (phase_type == null && bottom_type == null) { return extra_label; } @@ -62,11 +70,10 @@ function mergeAndAppendTypeInfo(extra_label, bottom_type, phase_type) { type += "B: "; type += simplifyType(bottom_type); } - new_extra_label = extra_label == null ? "" : (extra_label + " "); return new_extra_label + type; } editProperty(not(or([matches("bottom_type", "bottom"), matches("bottom_type", "abIO")])), - ["extra_label", "bottom_type", "phase_type"], "extra_label", - function(propertyValues) {return mergeAndAppendTypeInfo(propertyValues[0], propertyValues[1], propertyValues[2]);}); + ["extra_label", "bottom_type", "phase_type", "category", "dump_spec"], "extra_label", + function(propertyValues) {return mergeAndAppendTypeInfo(propertyValues[0], propertyValues[1], propertyValues[2], propertyValues[3], propertyValues[4]);}); From d13fd5738f8a3d4b4009c2e15cfd967332d97bbd Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 19 Feb 2025 11:02:14 +0000 Subject: [PATCH 051/587] 8350211: CTW: Attempt to preload all classes in constant pool Reviewed-by: vlivanov, chagedorn --- .../ctw/src/sun/hotspot/tools/ctw/Compiler.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java index de804b3d2c8..b8f2919e594 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java @@ -122,17 +122,16 @@ public class Compiler { private static void preloadClasses(String className, long id, ConstantPool constantPool) { - try { - for (int i = 0, n = constantPool.getSize(); i < n; ++i) { - try { + for (int i = 0, n = constantPool.getSize(); i < n; ++i) { + try { + if (constantPool.getTagAt(i) == ConstantPool.Tag.CLASS) { constantPool.getClassAt(i); - } catch (IllegalArgumentException ignore) { } + } catch (Throwable t) { + CompileTheWorld.OUT.println(String.format("[%d]\t%s\tWARNING preloading failed : %s", + id, className, t)); + t.printStackTrace(CompileTheWorld.ERR); } - } catch (Throwable t) { - CompileTheWorld.OUT.println(String.format("[%d]\t%s\tWARNING preloading failed : %s", - id, className, t)); - t.printStackTrace(CompileTheWorld.ERR); } } From 79db2d4186eb2af827295581464be8602ac95f98 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 19 Feb 2025 11:33:57 +0000 Subject: [PATCH 052/587] 8350159: compiler/tiered/Level2RecompilationTest.java fails after JDK-8349915 Reviewed-by: kvn, chagedorn --- src/hotspot/share/compiler/compilationPolicy.cpp | 6 +++--- test/hotspot/jtreg/ProblemList.txt | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 7f2a67f641b..82061d92daa 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -633,9 +633,9 @@ CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { task = next_task; continue; } - if (task->compile_reason() == CompileTask::Reason_Whitebox) { - // Whitebox (CTW) tasks do not participate in rate selection and/or any level - // adjustments. Just return them in order. + if (task->is_blocking() && task->compile_reason() == CompileTask::Reason_Whitebox) { + // CTW tasks, submitted as blocking Whitebox requests, do not participate in rate + // selection and/or any level adjustments. Just return them in order. return task; } Method* method = task->method(); diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 991d0435a91..e8656a74f4b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,8 +43,6 @@ # :hotspot_compiler -compiler/tiered/Level2RecompilationTest.java 8350159 generic-all - compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all From 2353f3e2f18ccaa972ee7a292d5a45035c647881 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 19 Feb 2025 11:35:00 +0000 Subject: [PATCH 053/587] 8350210: CTW: Use stackless exceptions Reviewed-by: kvn, chagedorn --- .../testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index c909d34eae8..573b70faabe 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -305,6 +305,8 @@ public class CtwRunner { // Expand the optimization scope by disallowing most traps. "-XX:PerMethodTrapLimit=0", "-XX:PerMethodSpecTrapLimit=0", + // Do not pay extra stack trace generation cost for normally thrown exceptions + "-XX:-StackTraceInThrowable", "-XX:+IgnoreUnrecognizedVMOptions", // Do not pay extra zapping cost for explicit GC invocations "-XX:-ZapUnusedHeapArea", From 59810ad745b28f50d287fa8db650c3f1924791d9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 19 Feb 2025 12:14:04 +0000 Subject: [PATCH 054/587] 8350201: Out of bounds access on Linux aarch64 in os::print_register_info Reviewed-by: dholmes, mdoerr --- src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp | 2 +- src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp | 2 +- src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 720c732327e..3d11bfe037a 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -447,7 +447,7 @@ void os::print_context(outputStream *st, const void *context) { } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = 32 /* r0-r32 */ + 3 /* pc, lr, sp */; + const int register_count = 32 /* r0-r31 */ + 3 /* pc, lr, sp */; int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); if (context == nullptr || n == register_count) { diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 171b40e414e..7728c62682c 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -354,7 +354,7 @@ void os::print_context(outputStream *st, const void *context) { } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = 32 /* r0-r31 */; + const int register_count = 31 /* r0-r30 */; int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); if (context == nullptr || n == register_count) { diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 11ac1b01784..81fede02956 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -467,7 +467,7 @@ void os::print_context(outputStream *st, const void *context) { } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = 32 /* r0-r32 */ + 3 /* pc, lr, ctr */; + const int register_count = 32 /* r0-r31 */ + 3 /* pc, lr, ctr */; int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); if (context == nullptr || n == register_count) { From 014701a09b23d21f57edb5b085820532804475bd Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 19 Feb 2025 12:22:51 +0000 Subject: [PATCH 055/587] 8350260: Improve HTML instruction formatting in PassFailJFrame Reviewed-by: kizune, azvegint, abhiscxk --- test/jdk/java/awt/regtesthelpers/PassFailJFrame.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 5f559ea47c3..5b825bb4c37 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -633,6 +633,8 @@ public final class PassFailJFrame { ? configureHTML(instructions, rows, columns) : configurePlainText(instructions, rows, columns); text.setEditable(false); + text.setBorder(createTextBorder()); + text.setCaretPosition(0); JPanel textPanel = new JPanel(new BorderLayout()); textPanel.setBorder(createEmptyBorder(GAP, 0, GAP, 0)); @@ -687,7 +689,6 @@ public final class PassFailJFrame { JTextArea text = new JTextArea(instructions, rows, columns); text.setLineWrap(true); text.setWrapStyleWord(true); - text.setBorder(createTextBorder()); return text; } @@ -701,10 +702,10 @@ public final class PassFailJFrame { HTMLEditorKit kit = (HTMLEditorKit) text.getEditorKit(); StyleSheet styles = kit.getStyleSheet(); - // Reduce the default margins - styles.addRule("ol, ul { margin-left-ltr: 20; margin-left-rtl: 20 }"); - // Make the size of code blocks the same as other text - styles.addRule("code { font-size: inherit }"); + // 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 }"); return text; } From 577ff98a6733a99ea49510f15d631beff39c34a5 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Wed, 19 Feb 2025 13:18:20 +0000 Subject: [PATCH 056/587] 8347946: Add API note that caller should validate/trust signers to the getCertificates and getCodeSigners methods of JarEntry and JarURLConnection Reviewed-by: lancea, jpai --- .../classes/java/net/JarURLConnection.java | 20 ++++++++++++++++--- .../share/classes/java/util/jar/JarEntry.java | 20 ++++++++++++++++++- .../share/classes/java/util/jar/JarFile.java | 4 ++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/net/JarURLConnection.java b/src/java.base/share/classes/java/net/JarURLConnection.java index 2c2734b08d7..160b7e8de64 100644 --- a/src/java.base/share/classes/java/net/JarURLConnection.java +++ b/src/java.base/share/classes/java/net/JarURLConnection.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 @@ -301,9 +301,23 @@ public abstract class JarURLConnection extends URLConnection { * can only be called once * the connection has been completely verified by reading * from the input stream until the end of the stream has been - * reached. Otherwise, this method will return {@code null} + * reached. Otherwise, this method will return {@code null}. * - * @return the Certificate object for this connection if the URL + *

The returned certificate array comprises all the signer certificates + * that were used to verify this entry. Each signer certificate is + * followed by its supporting certificate chain (which may be empty). + * Each signer certificate and its supporting certificate chain are ordered + * bottom-to-top (i.e., with the signer certificate first and the (root) + * certificate authority last). + * + * @apiNote + * The verification process does not include validating or establishing + * trust in the code signers. A caller should perform additional checks, + * such as using a {@link java.security.cert.CertPathValidator} to + * validate each signer's certificate chain, and determining whether + * to trust the entry signed by the signers. + * + * @return the Certificate objects for this connection if the URL * for it points to a JAR file entry, null otherwise. * * @throws IOException if getting the JAR entry causes an diff --git a/src/java.base/share/classes/java/util/jar/JarEntry.java b/src/java.base/share/classes/java/util/jar/JarEntry.java index 5e1d687e6c6..ff0750a3342 100644 --- a/src/java.base/share/classes/java/util/jar/JarEntry.java +++ b/src/java.base/share/classes/java/util/jar/JarEntry.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 @@ -97,6 +97,9 @@ public class JarEntry extends ZipEntry { * from the entry input stream until the end of the stream has been * reached. Otherwise, this method will return {@code null}. * + *

It is recommended to use the {@link getCodeSigners} method instead, + * which returns an array of {@code CodeSigner}s. + * *

The returned certificate array comprises all the signer certificates * that were used to verify this entry. Each signer certificate is * followed by its supporting certificate chain (which may be empty). @@ -104,8 +107,16 @@ public class JarEntry extends ZipEntry { * bottom-to-top (i.e., with the signer certificate first and the (root) * certificate authority last). * + * @apiNote + * The verification process does not include validating or establishing + * trust in the code signers. A caller should perform additional checks, + * such as using a {@link java.security.cert.CertPathValidator} to + * validate each signer's certificate chain, and determining whether + * to trust the entry signed by the signers. + * * @return the {@code Certificate} objects for this entry, or * {@code null} if none. + * */ public Certificate[] getCertificates() { return certs == null ? null : certs.clone(); @@ -121,6 +132,13 @@ public class JarEntry extends ZipEntry { *

The returned array comprises all the code signers that have signed * this entry. * + * @apiNote + * The verification process does not include validating or establishing + * trust in the code signers. A caller should perform additional checks, + * such as using a {@link java.security.cert.CertPathValidator} to + * validate each signer's certificate chain, and determining whether + * to trust the entry signed by the signers. + * * @return the {@code CodeSigner} objects for this entry, or * {@code null} if none. * diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index 7b64e3cdd04..e7725c8636f 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.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 @@ -93,7 +93,7 @@ import java.util.zip.ZipFile; * multi-release jar file, the content of a versioned entry is verified against * its own signature and {@link JarEntry#getCodeSigners()} returns its own signers. * - * Please note that the verification process does not include validating the + *

Please note that the verification process does not include validating the * signer's certificate. A caller should inspect the return value of * {@link JarEntry#getCodeSigners()} to further determine if the signature * can be trusted. From c6e47fd5812997e3428249be1c77c60e7b05a5df Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 19 Feb 2025 14:15:16 +0000 Subject: [PATCH 057/587] 8348171: Refactor GenerationCounters and its subclasses Co-authored-by: Thomas Schatzl Reviewed-by: gli, tschatzl, zgu --- .../gc/epsilon/epsilonMonitoringSupport.cpp | 4 +- .../gc/epsilon/epsilonMonitoringSupport.hpp | 4 +- .../share/gc/g1/g1MonitoringSupport.cpp | 8 +-- .../share/gc/g1/g1MonitoringSupport.hpp | 6 +- .../gc/parallel/psGenerationCounters.cpp | 66 ------------------- .../gc/parallel/psGenerationCounters.hpp | 51 -------------- src/hotspot/share/gc/parallel/psOldGen.cpp | 8 +-- src/hotspot/share/gc/parallel/psOldGen.hpp | 3 +- src/hotspot/share/gc/parallel/psYoungGen.cpp | 6 +- src/hotspot/share/gc/parallel/psYoungGen.hpp | 3 +- .../share/gc/serial/defNewGeneration.cpp | 4 +- .../share/gc/serial/tenuredGeneration.cpp | 4 +- .../share/gc/shared/generationCounters.cpp | 31 ++------- .../share/gc/shared/generationCounters.hpp | 25 +------ .../shenandoahMonitoringSupport.cpp | 6 +- .../shenandoahMonitoringSupport.hpp | 7 +- src/hotspot/share/gc/z/zServiceability.cpp | 2 +- 17 files changed, 42 insertions(+), 196 deletions(-) delete mode 100644 src/hotspot/share/gc/parallel/psGenerationCounters.cpp delete mode 100644 src/hotspot/share/gc/parallel/psGenerationCounters.hpp diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 55f15fb473d..540ede9dd83 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -90,8 +90,8 @@ public: _heap(heap) {}; - virtual void update_all() { - _current_size->set_value(_heap->capacity()); + void update_all() { + GenerationCounters::update_all(_heap->capacity()); } }; diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp index 73cfc943612..67a60d92778 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.hpp @@ -27,13 +27,13 @@ #include "memory/allocation.hpp" -class GenerationCounters; +class EpsilonGenerationCounters; class EpsilonSpaceCounters; class EpsilonHeap; class EpsilonMonitoringSupport : public CHeapObj { private: - GenerationCounters* _heap_counters; + EpsilonGenerationCounters* _heap_counters; EpsilonSpaceCounters* _space_counters; public: diff --git a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp index e018515a051..03bd1840206 100644 --- a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp +++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp @@ -60,9 +60,9 @@ public: } } - virtual void update_all() { + void update_all() { size_t committed = _monitoring_support->young_gen_committed(); - _current_size->set_value(committed); + GenerationCounters::update_all(committed); } }; @@ -81,9 +81,9 @@ public: } } - virtual void update_all() { + void update_all() { size_t committed = _monitoring_support->old_gen_committed(); - _current_size->set_value(committed); + GenerationCounters::update_all(committed); } }; diff --git a/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp b/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp index 1f62b53d97c..f22581ad9b1 100644 --- a/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp +++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp @@ -33,6 +33,8 @@ class CollectorCounters; class G1CollectedHeap; +class G1OldGenerationCounters; +class G1YoungGenerationCounters; class HSpaceCounters; class MemoryPool; @@ -146,10 +148,10 @@ class G1MonitoringSupport : public CHeapObj { // young collection set counters. The _eden_counters, // _from_counters, and _to_counters are associated with // this "generational" counter. - GenerationCounters* _young_gen_counters; + G1YoungGenerationCounters* _young_gen_counters; // old collection set counters. The _old_space_counters // below are associated with this "generational" counter. - GenerationCounters* _old_gen_counters; + G1OldGenerationCounters* _old_gen_counters; // Counters for the capacity and used for // the whole heap HSpaceCounters* _old_space_counters; diff --git a/src/hotspot/share/gc/parallel/psGenerationCounters.cpp b/src/hotspot/share/gc/parallel/psGenerationCounters.cpp deleted file mode 100644 index 8792df7cf27..00000000000 --- a/src/hotspot/share/gc/parallel/psGenerationCounters.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -/* - * 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 - * 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/parallel/psGenerationCounters.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" - -PSGenerationCounters::PSGenerationCounters(const char* name, - int ordinal, int spaces, - size_t min_capacity, - size_t max_capacity, - PSVirtualSpace* v): - _ps_virtual_space(v) { - - if (UsePerfData) { - - EXCEPTION_MARK; - ResourceMark rm; - - const char* cns = PerfDataManager::name_space("generation", ordinal); - - _name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtGC); - strcpy(_name_space, cns); - - const char* cname = PerfDataManager::counter_name(_name_space, "name"); - PerfDataManager::create_string_constant(SUN_GC, cname, name, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "spaces"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, - spaces, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "minCapacity"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes, - min_capacity, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "maxCapacity"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes, - max_capacity, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "capacity"); - _current_size = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, _ps_virtual_space->committed_size(), CHECK); - } -} diff --git a/src/hotspot/share/gc/parallel/psGenerationCounters.hpp b/src/hotspot/share/gc/parallel/psGenerationCounters.hpp deleted file mode 100644 index 60385965feb..00000000000 --- a/src/hotspot/share/gc/parallel/psGenerationCounters.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2004, 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. - * - */ - -#ifndef SHARE_GC_PARALLEL_PSGENERATIONCOUNTERS_HPP -#define SHARE_GC_PARALLEL_PSGENERATIONCOUNTERS_HPP - -#include "gc/parallel/psVirtualspace.hpp" -#include "gc/shared/generationCounters.hpp" -#include "runtime/perfData.hpp" - -// A PSGenerationCounter is a holder class for performance counters -// that track a generation - -class PSGenerationCounters: public GenerationCounters { - friend class VMStructs; - - private: - PSVirtualSpace* _ps_virtual_space; - - public: - PSGenerationCounters(const char* name, int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, PSVirtualSpace* v); - - void update_all() { - assert(_virtual_space == nullptr, "Only one should be in use"); - _current_size->set_value(_ps_virtual_space->committed_size()); - } -}; - -#endif // SHARE_GC_PARALLEL_PSGENERATIONCOUNTERS_HPP diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index ab74d3468e1..8eadc833ac7 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -113,8 +113,8 @@ void PSOldGen::initialize_work(const char* perf_data_name, int level) { void PSOldGen::initialize_performance_counters(const char* perf_data_name, int level) { // Generation Counters, generation 'level', 1 subspace - _gen_counters = new PSGenerationCounters(perf_data_name, level, 1, min_gen_size(), - max_gen_size(), virtual_space()); + _gen_counters = new GenerationCounters(perf_data_name, level, 1, min_gen_size(), + max_gen_size(), virtual_space()->committed_size()); _space_counters = new SpaceCounters(perf_data_name, 0, virtual_space()->reserved_size(), _object_space, _gen_counters); @@ -243,7 +243,7 @@ bool PSOldGen::expand_by(size_t bytes) { post_resize(); if (UsePerfData) { _space_counters->update_capacity(); - _gen_counters->update_all(); + _gen_counters->update_all(_virtual_space->committed_size()); } } @@ -379,7 +379,7 @@ void PSOldGen::print_on(outputStream* st) const { void PSOldGen::update_counters() { if (UsePerfData) { _space_counters->update_all(); - _gen_counters->update_all(); + _gen_counters->update_all(_virtual_space->committed_size()); } } diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index c2ae50bfcf8..138b2a5b30c 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -27,7 +27,6 @@ #include "gc/parallel/mutableSpace.hpp" #include "gc/parallel/objectStartArray.hpp" -#include "gc/parallel/psGenerationCounters.hpp" #include "gc/parallel/psVirtualspace.hpp" #include "gc/parallel/spaceCounters.hpp" #include "runtime/mutexLocker.hpp" @@ -43,7 +42,7 @@ class PSOldGen : public CHeapObj { MutableSpace* _object_space; // Where all the objects live // Performance Counters - PSGenerationCounters* _gen_counters; + GenerationCounters* _gen_counters; SpaceCounters* _space_counters; // Sizing information, in bytes, set in constructor diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 82b946201d2..309b293e5ac 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -91,8 +91,8 @@ void PSYoungGen::initialize_work() { _to_space = new MutableSpace(virtual_space()->alignment()); // Generation Counters - generation 0, 3 subspaces - _gen_counters = new PSGenerationCounters("new", 0, 3, min_gen_size(), - max_gen_size(), virtual_space()); + _gen_counters = new GenerationCounters("new", 0, 3, min_gen_size(), + max_gen_size(), virtual_space()->committed_size()); // Compute maximum space sizes for performance counters size_t alignment = SpaceAlignment; @@ -809,7 +809,7 @@ void PSYoungGen::update_counters() { _eden_counters->update_all(); _from_counters->update_all(); _to_counters->update_all(); - _gen_counters->update_all(); + _gen_counters->update_all(_virtual_space->committed_size()); } } diff --git a/src/hotspot/share/gc/parallel/psYoungGen.hpp b/src/hotspot/share/gc/parallel/psYoungGen.hpp index e6e73b8aee2..5140ea08bd1 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.hpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.hpp @@ -27,7 +27,6 @@ #include "gc/parallel/mutableSpace.hpp" #include "gc/parallel/objectStartArray.hpp" -#include "gc/parallel/psGenerationCounters.hpp" #include "gc/parallel/psVirtualspace.hpp" #include "gc/parallel/spaceCounters.hpp" @@ -51,7 +50,7 @@ class PSYoungGen : public CHeapObj { const size_t _max_gen_size; // Performance counters - PSGenerationCounters* _gen_counters; + GenerationCounters* _gen_counters; SpaceCounters* _eden_counters; SpaceCounters* _from_counters; SpaceCounters* _to_counters; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index f637eb62a00..c5c1b67d5cf 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -250,7 +250,7 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, // Generation counters -- generation 0, 3 subspaces _gen_counters = new GenerationCounters("new", 0, 3, - min_size, max_size, &_virtual_space); + min_size, max_size, _virtual_space.committed_size()); _gc_counters = new CollectorCounters(policy, 0); _eden_counters = new CSpaceCounters("eden", 0, _max_eden_size, _eden_space, @@ -826,7 +826,7 @@ void DefNewGeneration::update_counters() { _eden_counters->update_all(); _from_counters->update_all(); _to_counters->update_all(); - _gen_counters->update_all(); + _gen_counters->update_all(_virtual_space.committed_size()); } } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index e3b7eef478a..c793f138de0 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -329,7 +329,7 @@ TenuredGeneration::TenuredGeneration(ReservedSpace rs, const char* gen_name = "old"; // Generation Counters -- generation 1, 1 subspace _gen_counters = new GenerationCounters(gen_name, 1, 1, - min_byte_size, max_byte_size, &_virtual_space); + min_byte_size, max_byte_size, _virtual_space.committed_size()); _gc_counters = new CollectorCounters("Serial full collection pauses", 1); @@ -371,7 +371,7 @@ void TenuredGeneration::update_promote_stats() { void TenuredGeneration::update_counters() { if (UsePerfData) { _space_counters->update_all(); - _gen_counters->update_all(); + _gen_counters->update_all(_virtual_space.committed_size()); } } diff --git a/src/hotspot/share/gc/shared/generationCounters.cpp b/src/hotspot/share/gc/shared/generationCounters.cpp index a8e5889dd8e..4af7b412aea 100644 --- a/src/hotspot/share/gc/shared/generationCounters.cpp +++ b/src/hotspot/share/gc/shared/generationCounters.cpp @@ -28,9 +28,10 @@ #include "memory/virtualspace.hpp" #include "runtime/perfData.hpp" -void GenerationCounters::initialize(const char* name, int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, - size_t curr_capacity) { +GenerationCounters::GenerationCounters(const char* name, + int ordinal, int spaces, + size_t min_capacity, size_t max_capacity, + size_t curr_capacity) { if (UsePerfData) { EXCEPTION_MARK; ResourceMark rm; @@ -62,29 +63,11 @@ void GenerationCounters::initialize(const char* name, int ordinal, int spaces, } } -GenerationCounters::GenerationCounters(const char* name, - int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, - VirtualSpace* v) - : _virtual_space(v) { - assert(v != nullptr, "don't call this constructor if v == nullptr"); - initialize(name, ordinal, spaces, - min_capacity, max_capacity, v->committed_size()); -} - -GenerationCounters::GenerationCounters(const char* name, - int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, - size_t curr_capacity) - : _virtual_space(nullptr) { - initialize(name, ordinal, spaces, min_capacity, max_capacity, curr_capacity); -} - GenerationCounters::~GenerationCounters() { FREE_C_HEAP_ARRAY(char, _name_space); } -void GenerationCounters::update_all() { - assert(_virtual_space != nullptr, "otherwise, override this method"); - _current_size->set_value(_virtual_space->committed_size()); +void GenerationCounters::update_all(size_t curr_capacity) { + _current_size->set_value(curr_capacity); } + diff --git a/src/hotspot/share/gc/shared/generationCounters.hpp b/src/hotspot/share/gc/shared/generationCounters.hpp index 603d9850a73..50672ab5d74 100644 --- a/src/hotspot/share/gc/shared/generationCounters.hpp +++ b/src/hotspot/share/gc/shared/generationCounters.hpp @@ -28,22 +28,13 @@ #include "memory/allocation.hpp" #include "runtime/perfDataTypes.hpp" -class VirtualSpace; - // A GenerationCounter is a holder class for performance counters // that track a generation class GenerationCounters: public CHeapObj { friend class VMStructs; -private: - void initialize(const char* name, int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, - size_t curr_capacity); - - protected: PerfVariable* _current_size; - VirtualSpace* _virtual_space; // Constant PerfData types don't need to retain a reference. // However, it's a good idea to document them here. @@ -54,27 +45,15 @@ private: char* _name_space; - // This constructor is only meant for use with the PSGenerationCounters - // constructor. The need for such an constructor should be eliminated - // when VirtualSpace and PSVirtualSpace are unified. - GenerationCounters() - : _current_size(nullptr), _virtual_space(nullptr), _name_space(nullptr) {} - - // This constructor is used for subclasses that do not have a space - // associated with them (e.g, in G1). + public: GenerationCounters(const char* name, int ordinal, int spaces, size_t min_capacity, size_t max_capacity, size_t curr_capacity); - public: - GenerationCounters(const char* name, int ordinal, int spaces, - size_t min_capacity, size_t max_capacity, VirtualSpace* v); - ~GenerationCounters(); - virtual void update_all(); + void update_all(size_t curr_capacity); const char* name_space() const { return _name_space; } - }; #endif // SHARE_GC_SHARED_GENERATIONCOUNTERS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp index 77d586dd90b..31265addda8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp @@ -36,7 +36,7 @@ public: ShenandoahYoungGenerationCounters() : GenerationCounters("Young", 0, 0, 0, (size_t)0, (size_t)0) {}; - void update_all() override { + void update_all() { // no update } }; @@ -50,8 +50,8 @@ public: _heap(heap) {}; - void update_all() override { - _current_size->set_value(_heap->capacity()); + void update_all() { + GenerationCounters::update_all(_heap->capacity()); } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.hpp index 2d90f887707..c58c91e1622 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.hpp @@ -29,12 +29,13 @@ #include "memory/allocation.hpp" #include "runtime/task.hpp" -class GenerationCounters; class HSpaceCounters; class ShenandoahHeap; class CollectorCounters; class ShenandoahHeapRegionCounters; class ShenandoahMonitoringSupport; +class ShenandoahGenerationCounters; +class ShenandoahYoungGenerationCounters; class ShenandoahPeriodicCountersUpdateTask : public PeriodicTask { private: @@ -60,8 +61,8 @@ private: CollectorCounters* _partial_counters; CollectorCounters* _full_counters; - GenerationCounters* _young_counters; - GenerationCounters* _heap_counters; + ShenandoahYoungGenerationCounters* _young_counters; + ShenandoahGenerationCounters* _heap_counters; HSpaceCounters* _space_counters; diff --git a/src/hotspot/share/gc/z/zServiceability.cpp b/src/hotspot/share/gc/z/zServiceability.cpp index f2a7ad2dc1a..076d310ff71 100644 --- a/src/hotspot/share/gc/z/zServiceability.cpp +++ b/src/hotspot/share/gc/z/zServiceability.cpp @@ -66,7 +66,7 @@ public: curr_capacity) {} void update_capacity(size_t capacity) { - _current_size->set_value(capacity); + update_all(capacity); } }; From efbad00c4d7931177ccc5e9bce3b30dfbac94010 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 19 Feb 2025 14:27:33 +0000 Subject: [PATCH 058/587] 8349688: G1: Wrong initial optional region index when selecting candidates from retained regions Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 19056245152..075951ab07c 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -383,6 +383,8 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) uint num_initial_groups = 0; uint num_optional_regions = 0; + assert(_optional_groups.num_regions() == 0, "Optional regions should not already be selected"); + double predicted_initial_time_ms = 0.0; double predicted_optional_time_ms = 0.0; @@ -483,7 +485,8 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) { uint num_initial_regions = 0; - uint num_optional_regions = 0; + uint prev_num_optional_regions = _optional_groups.num_regions(); + uint num_optional_regions = prev_num_optional_regions; uint num_expensive_regions = 0; uint num_pinned_regions = 0; @@ -576,10 +579,13 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) groups_to_abandon.clear(true /* uninstall_group_cardset */); + assert(num_optional_regions >= prev_num_optional_regions, "Sanity"); + uint selected_optional_regions = num_optional_regions - prev_num_optional_regions; + log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " "time remaining: %1.2fms optional time remaining %1.2fms", - num_initial_regions, num_optional_regions, num_pinned_regions, + num_initial_regions, selected_optional_regions, num_pinned_regions, predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); } From 70a6c0b7ac952eebdffa1d64399cd0ee1efec1f6 Mon Sep 17 00:00:00 2001 From: konanki sreenath Date: Wed, 19 Feb 2025 16:47:54 +0000 Subject: [PATCH 059/587] 8346094: Harden X509CertImpl.getExtensionValue for NPE cases Reviewed-by: coffeys, weijun --- .../sun/security/x509/X509CertImpl.java | 71 ++----- .../HostnameChecker/TestHostnameChecker.java | 5 +- .../x509/X509CertImpl/CertExtensions.java | 201 ++++++++++++++++++ 3 files changed, 220 insertions(+), 57 deletions(-) create mode 100644 test/jdk/sun/security/x509/X509CertImpl/CertExtensions.java diff --git a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java index 656e4c168fb..0f4388fb07b 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -120,7 +120,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { */ public X509CertImpl(X509CertInfo info, AlgorithmId algId, byte[] signature, byte[] signedCert) { - this.info = info; + this.info = Objects.requireNonNull(info); this.algId = algId; this.signature = signature; this.signedCert = Objects.requireNonNull(signedCert); @@ -553,7 +553,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * before this function may be called. */ public String toString() { - if (info == null || algId == null || signature == null) + if (algId == null || signature == null) return ""; HexDumpEncoder encoder = new HexDumpEncoder(); @@ -570,8 +570,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the publickey. */ public PublicKey getPublicKey() { - if (info == null) - return null; return info.getKey().getKey(); } @@ -581,8 +579,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the version number, i.e. 1, 2 or 3. */ public int getVersion() { - if (info == null) - return -1; try { int vers = info.getVersion().getVersion(); return vers + 1; @@ -609,8 +605,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the serial number. */ public SerialNumber getSerialNumberObject() { - if (info == null) - return null; return info.getSerialNumber().getSerial(); } @@ -622,8 +616,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { */ @SuppressWarnings("deprecation") public Principal getSubjectDN() { - if (info == null) - return null; return info.getSubject(); } @@ -633,9 +625,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * also aware of X509CertImpl mutability. */ public X500Principal getSubjectX500Principal() { - if (info == null) { - return null; - } try { return info.getSubject().asX500Principal(); } catch (Exception e) { @@ -650,8 +639,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { */ @SuppressWarnings("deprecation") public Principal getIssuerDN() { - if (info == null) - return null; return info.getIssuer(); } @@ -661,9 +648,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * also aware of X509CertImpl mutability. */ public X500Principal getIssuerX500Principal() { - if (info == null) { - return null; - } try { return info.getIssuer().asX500Principal(); } catch (Exception e) { @@ -677,8 +661,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the start date of the validity period. */ public Date getNotBefore() { - if (info == null) - return null; return info.getValidity().getNotBefore(); } @@ -688,8 +670,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the end date of the validity period. */ public Date getNotAfter() { - if (info == null) - return null; return info.getValidity().getNotAfter(); } @@ -702,10 +682,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @exception CertificateEncodingException if an encoding error occurs. */ public byte[] getTBSCertificate() throws CertificateEncodingException { - if (info != null) { - return info.getEncodedInfo(); - } else - throw new CertificateEncodingException("Uninitialized certificate"); + return info.getEncodedInfo(); } /** @@ -766,8 +743,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the Issuer Unique Identity. */ public boolean[] getIssuerUniqueID() { - if (info == null) - return null; UniqueIdentity id = info.getIssuerUniqueId(); if (id == null) return null; @@ -781,8 +756,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * @return the Subject Unique Identity. */ public boolean[] getSubjectUniqueID() { - if (info == null) - return null; UniqueIdentity id = info.getSubjectUniqueId(); if (id == null) return null; @@ -935,8 +908,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * not supported, otherwise return false. */ public boolean hasUnsupportedCriticalExtension() { - if (info == null) - return false; CertificateExtensions exts = info.getExtensions(); if (exts == null) return false; @@ -952,9 +923,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * certificate that are marked critical. */ public Set getCriticalExtensionOIDs() { - if (info == null) { - return null; - } try { CertificateExtensions exts = info.getExtensions(); if (exts == null) { @@ -981,9 +949,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * certificate that are NOT marked critical. */ public Set getNonCriticalExtensionOIDs() { - if (info == null) { - return null; - } try { CertificateExtensions exts = info.getExtensions(); if (exts == null) { @@ -1010,9 +975,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * extension */ public Extension getExtension(ObjectIdentifier oid) { - if (info == null) { - return null; - } CertificateExtensions extensions = info.getExtensions(); if (extensions != null) { Extension ex = extensions.getExtension(oid.toString()); @@ -1031,9 +993,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { } public Extension getUnparseableExtension(ObjectIdentifier oid) { - if (info == null) { - return null; - } CertificateExtensions extensions = info.getExtensions(); if (extensions == null) { return null; @@ -1047,6 +1006,8 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * oid String. * * @param oid the Object Identifier value for the extension. + * @return the DER-encoded extension value, or {@code null} if + * the extensions are not present or the value is not found */ public byte[] getExtensionValue(String oid) { try { @@ -1054,13 +1015,11 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { String extAlias = OIDMap.getName(findOID); Extension certExt = null; CertificateExtensions exts = info.getExtensions(); - + if (exts == null) { + return null; + } if (extAlias == null) { // may be unknown // get the extensions, search through' for this oid - if (exts == null) { - return null; - } - for (Extension ex : exts.getAllExtensions()) { ObjectIdentifier inCertOID = ex.getExtensionId(); if (inCertOID.equals(findOID)) { @@ -1069,12 +1028,10 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { } } } else { // there's subclass that can handle this extension - certExt = getInfo().getExtensions().getExtension(extAlias); + certExt = exts.getExtension(extAlias); } if (certExt == null) { - if (exts != null) { - certExt = exts.getUnparseableExtensions().get(oid); - } + certExt = exts.getUnparseableExtensions().get(oid); if (certExt == null) { return null; } @@ -1098,8 +1055,12 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { */ public boolean[] getKeyUsage() { try { + CertificateExtensions extensions = info.getExtensions(); + if (extensions == null) { + return null; + } KeyUsageExtension certExt = (KeyUsageExtension) - getInfo().getExtensions().getExtension(KeyUsageExtension.NAME); + extensions.getExtension(KeyUsageExtension.NAME); if (certExt == null) return null; diff --git a/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java b/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java index 162ed46de20..63eb4057f8e 100644 --- a/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java +++ b/test/jdk/sun/security/util/HostnameChecker/TestHostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, 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 @@ -36,6 +36,7 @@ import java.util.List; import jdk.test.lib.security.CertUtils; import sun.security.util.*; import sun.security.x509.X509CertImpl; +import sun.security.x509.X509CertInfo; /** * Certificate 1: @@ -225,7 +226,7 @@ public class TestHostnameChecker { } private static X509Certificate mock(String domain) { - return new X509CertImpl(null, null, null, new byte[0]) { + return new X509CertImpl(new X509CertInfo(), null, null, new byte[0]) { @Override public Collection> getSubjectAlternativeNames() { return List.of(List.of(2, domain)); diff --git a/test/jdk/sun/security/x509/X509CertImpl/CertExtensions.java b/test/jdk/sun/security/x509/X509CertImpl/CertExtensions.java new file mode 100644 index 00000000000..f8ee13e8f51 --- /dev/null +++ b/test/jdk/sun/security/x509/X509CertImpl/CertExtensions.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. + */ + +/** + * @test + * @bug 8346094 + * @summary validating getExtensionValue and getKeyUsage with specified and + * unspecified extensions on the X509Certificate. + * @library /test/lib + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + */ + +import jdk.test.lib.Asserts; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.*; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + + +public class CertExtensions { + + public static void main(String[] args) throws Exception { + X509CertImpl x509Certimpl = createCertificate(); + /** + * Certificate is created without extensions. Invoking getExtensionValue + * with oid must return NULL else it is incorrect + */ + Asserts.assertNull(x509Certimpl.getExtensionValue("2.5.29.17")); + /** + * Certificate is created with extensions. Invoking getExtensionValue + * with oid must not return NULL else it is incorrect + */ + x509Certimpl.getInfo().setExtensions(createCertificateExtensions( + x509Certimpl.getInfo().getKey().getKey())); + Asserts.assertNotNull(x509Certimpl.getExtensionValue("2.5.29.17")); + /** + * Certificate is created with extensions. Invoking getExtensionValue + * with invalid oid must return NULL else it is incorrect + */ + Asserts.assertNull(x509Certimpl.getExtensionValue("1.2.3.4")); + /** + * Certificate is created with extensions. Invoking getKeyUsage + * must not return NULL else it is incorrect + */ + Asserts.assertNotNull(x509Certimpl.getKeyUsage()); + /** + * Certificate is created without extensions. Invoking getKeyUsage + * must return NULL else it is incorrect + */ + x509Certimpl.getInfo().setExtensions(null); + Asserts.assertNull(x509Certimpl.getKeyUsage()); + } + + private static X509CertImpl createCertificate() throws Exception { + X509CertImpl x509Certimpl = null; + try { + X509CertInfo x509CertInfo = new X509CertInfo(); + x509CertInfo.setVersion(new CertificateVersion(CertificateVersion.V3)); + + // Generate Key Pair (RSA) + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + x509CertInfo.setKey(new CertificateX509Key(publicKey)); + + // Create and set the DN name for Subject and Issuer. + X500Name subject = new X500Name("CN=www.Subject.com, O=MyOrg, OU=LocalBiz, L=XYZ, S=YY, C=XX"); + X500Name issuer = new X500Name("CN=www.Issuer.com, O=Oracle,OU=Java,L=XYZ,S=YY, C=XX"); + x509CertInfo.setIssuer(issuer); + x509CertInfo.setSubject(subject); + + // create and set the subject and issuer unique identity + byte[] issuerId = {1, 2, 3, 4, 5}; + byte[] subjectId = {6, 7, 8, 9, 10}; + x509CertInfo.setSubjectUniqueId(new UniqueIdentity(subjectId)); + x509CertInfo.setIssuerUniqueId(new UniqueIdentity(issuerId)); + + // create and set the serial number + BigInteger serialNumber = BigInteger.valueOf(new SecureRandom().nextInt(Integer.MAX_VALUE)); + x509CertInfo.setSerialNumber(new CertificateSerialNumber(serialNumber)); + + // create and set the validity interval + Date notBefore = new Date(); // Valid from now + Date notAfter = new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000); // Valid for 1 year + x509CertInfo.setValidity(new CertificateValidity(notBefore, notAfter)); + + // Create Certificate Info which is the representation of X509 Certificate. + x509CertInfo.setAlgorithmId(new CertificateAlgorithmId(AlgorithmId.get("SHA256withRSA"))); + + // Sign the certificate + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(privateKey); + signature.update(x509CertInfo.getEncodedInfo()); + byte[] signedData = signature.sign(); + byte[] signedCert = {}; + + x509Certimpl = new X509CertImpl(x509CertInfo, + AlgorithmId.get("SHA256withRSA"), signedData, signedCert); + } catch (Exception e) { + System.out.println("caught exception while creating the certificate : " + e.getMessage()); + throw e; + } + return x509Certimpl; + } + + public static sun.security.x509.CertificateExtensions createCertificateExtensions + (PublicKey publicKey) throws IOException, NoSuchAlgorithmException { + // Create Extensions + sun.security.x509.CertificateExtensions certificateExtensions = + new sun.security.x509.CertificateExtensions(); + + GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com"); + GeneralName mail = new GeneralName(mailInf); + GeneralNameInterface dnsInf = new DNSName("Oracle.com"); + GeneralName dns = new GeneralName(dnsInf); + GeneralNameInterface uriInf = new URIName("http://www.Oracle.com"); + GeneralName uri = new GeneralName(uriInf); + + // localhost + byte[] address = new byte[]{127, 0, 0, 1}; + + GeneralNameInterface ipInf = new IPAddressName(address); + GeneralName ip = new GeneralName(ipInf); + + GeneralNameInterface oidInf = new OIDName(ObjectIdentifier.of("1.2.3.4")); + GeneralName oid = new GeneralName(oidInf); + + + GeneralNames subjectNames = new GeneralNames(); + subjectNames.add(mail); + subjectNames.add(dns); + subjectNames.add(uri); + SubjectAlternativeNameExtension subjectName = new SubjectAlternativeNameExtension(subjectNames); + + GeneralNames issuerNames = new GeneralNames(); + issuerNames.add(ip); + issuerNames.add(oid); + IssuerAlternativeNameExtension issuerName = new IssuerAlternativeNameExtension(issuerNames); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles")); + cal.set(2014, 03, 10, 12, 30, 30); + cal.set(2000, 11, 15, 12, 30, 30); + Date lastDate = cal.getTime(); + Date firstDate = new Date(); + PrivateKeyUsageExtension pkusage = new PrivateKeyUsageExtension(firstDate, lastDate); + + KeyUsageExtension usage = new KeyUsageExtension(); + usage.set(KeyUsageExtension.CRL_SIGN, true); + usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true); + usage.set(KeyUsageExtension.NON_REPUDIATION, true); + MessageDigest md = MessageDigest.getInstance("SHA"); + + byte[] keyId = md.digest(publicKey.getEncoded()); + KeyIdentifier kid = new KeyIdentifier(keyId); + SerialNumber sn = new SerialNumber(42); + AuthorityKeyIdentifierExtension aki = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn); + + SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension(keyId); + + BasicConstraintsExtension cons = new BasicConstraintsExtension(true, 10); + + PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4); + + certificateExtensions.setExtension(SubjectAlternativeNameExtension.NAME, subjectName); + certificateExtensions.setExtension(IssuerAlternativeNameExtension.NAME, issuerName); + certificateExtensions.setExtension(PrivateKeyUsageExtension.NAME, pkusage); + certificateExtensions.setExtension(KeyUsageExtension.NAME, usage); + certificateExtensions.setExtension(AuthorityKeyIdentifierExtension.NAME, aki); + certificateExtensions.setExtension(SubjectKeyIdentifierExtension.NAME, ski); + certificateExtensions.setExtension(BasicConstraintsExtension.NAME, cons); + certificateExtensions.setExtension(PolicyConstraintsExtension.NAME, pce); + return certificateExtensions; + } +} From 3487f8cbd55b06d332d897a010ae8eb371dd4956 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 19 Feb 2025 17:08:01 +0000 Subject: [PATCH 060/587] 8350102: Decouple jpackage test-lib Executor.Result and Executor classes Reviewed-by: almatvee --- .../helpers/jdk/jpackage/test/Executor.java | 64 +++++++++++-------- .../jdk/jpackage/test/JPackageCommand.java | 4 +- .../jdk/jpackage/test/WindowsHelper.java | 6 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index b00f72a328e..a8a849cb9e7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.regex.Pattern; @@ -76,6 +77,10 @@ public final class Executor extends CommandArguments { return setToolProvider(v.asToolProvider()); } + public Optional getExecutable() { + return Optional.ofNullable(executable); + } + public Executor setDirectory(Path v) { directory = v; return this; @@ -173,10 +178,10 @@ public final class Executor extends CommandArguments { return this; } - public class Result { + public record Result(int exitCode, List output, Supplier cmdline) { - Result(int exitCode) { - this.exitCode = exitCode; + public Result { + Objects.requireNonNull(cmdline); } public String getFirstLineOfOutput() { @@ -187,14 +192,10 @@ public final class Executor extends CommandArguments { return output; } - public String getPrintableCommandLine() { - return Executor.this.getPrintableCommandLine(); - } - public Result assertExitCodeIs(int expectedExitCode) { TKit.assertEquals(expectedExitCode, exitCode, String.format( "Check command %s exited with %d code", - getPrintableCommandLine(), expectedExitCode)); + cmdline.get(), expectedExitCode)); return this; } @@ -205,9 +206,6 @@ public final class Executor extends CommandArguments { public int getExitCode() { return exitCode; } - - final int exitCode; - private List output; } public Result executeWithoutExitCodeCheck() { @@ -408,28 +406,34 @@ public final class Executor extends CommandArguments { } } - Result reply = new Result(process.waitFor()); - trace("Done. Exit code: " + reply.exitCode); + final int exitCode = process.waitFor(); + trace("Done. Exit code: " + exitCode); + final List output; if (outputLines != null) { - reply.output = Collections.unmodifiableList(outputLines); + output = Collections.unmodifiableList(outputLines); + } else { + output = null; } - return reply; + return createResult(exitCode, output); } - private Result runToolProvider(PrintStream out, PrintStream err) { + private int runToolProvider(PrintStream out, PrintStream err) { trace("Execute " + getPrintableCommandLine() + "..."); - Result reply = new Result(toolProvider.run(out, err, args.toArray( - String[]::new))); - trace("Done. Exit code: " + reply.exitCode); - return reply; + final int exitCode = toolProvider.run(out, err, args.toArray( + String[]::new)); + trace("Done. Exit code: " + exitCode); + return exitCode; } + private Result createResult(int exitCode, List output) { + return new Result(exitCode, output, this::getPrintableCommandLine); + } private Result runToolProvider() throws IOException { if (!withSavedOutput()) { if (saveOutputType.contains(SaveOutputType.DUMP)) { - return runToolProvider(System.out, System.err); + return createResult(runToolProvider(System.out, System.err), null); } PrintStream nullPrintStream = new PrintStream(new OutputStream() { @@ -438,36 +442,40 @@ public final class Executor extends CommandArguments { // Nop } }); - return runToolProvider(nullPrintStream, nullPrintStream); + return createResult(runToolProvider(nullPrintStream, nullPrintStream), null); } try (ByteArrayOutputStream buf = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(buf)) { - Result reply = runToolProvider(ps, ps); + final var exitCode = runToolProvider(ps, ps); ps.flush(); + final List output; try (BufferedReader bufReader = new BufferedReader(new StringReader( buf.toString()))) { if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) { String firstLine = bufReader.lines().findFirst().orElse(null); if (firstLine != null) { - reply.output = List.of(firstLine); + output = List.of(firstLine); + } else { + output = null; } } else if (saveOutputType.contains(SaveOutputType.FULL)) { - reply.output = bufReader.lines().collect( - Collectors.toUnmodifiableList()); + output = bufReader.lines().collect(Collectors.toUnmodifiableList()); + } else { + output = null; } if (saveOutputType.contains(SaveOutputType.DUMP)) { Stream lines; if (saveOutputType.contains(SaveOutputType.FULL)) { - lines = reply.output.stream(); + lines = output.stream(); } else { lines = bufReader.lines(); } lines.forEach(System.out::println); } } - return reply; + return createResult(exitCode, output); } } 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 bbf7d429f08..418d7377ec6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -56,7 +56,7 @@ import jdk.jpackage.internal.util.function.ThrowingSupplier; * anything. The simplest is to compile test application and pack in a jar for * use on jpackage command line. */ -public final class JPackageCommand extends CommandArguments { +public class JPackageCommand extends CommandArguments { public JPackageCommand() { prerequisiteActions = new Actions(); @@ -799,7 +799,7 @@ public final class JPackageCommand extends CommandArguments { outputValidator.accept(result.getOutput().stream()); } - if (result.exitCode == 0) { + if (result.exitCode() == 0) { executeVerifyActions(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 9d289c56540..48643463e0b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -72,7 +72,7 @@ public class WindowsHelper { for (int attempt = 0; attempt < 8; ++attempt) { result = misexec.executeWithoutExitCodeCheck(); - if (result.exitCode == 1605) { + if (result.exitCode() == 1605) { // ERROR_UNKNOWN_PRODUCT, attempt to uninstall not installed // package return; @@ -81,7 +81,7 @@ public class WindowsHelper { // The given Executor may either be of an msiexec command or an // unpack.bat script containing the msiexec command. In the later // case, when misexec returns 1618, the unpack.bat may return 1603 - if ((result.exitCode == 1618) || (result.exitCode == 1603)) { + if ((result.exitCode() == 1618) || (result.exitCode() == 1603)) { // Another installation is already in progress. // Wait a little and try again. Long timeout = 1000L * (attempt + 3); // from 3 to 10 seconds @@ -523,7 +523,7 @@ public class WindowsHelper { var status = Executor.of("reg", "query", keyPath, "/v", valueName) .saveOutput() .executeWithoutExitCodeCheck(); - if (status.exitCode == 1) { + if (status.exitCode() == 1) { // Should be the case of no such registry value or key String lookupString = "ERROR: The system was unable to find the specified registry key or value."; TKit.assertTextStream(lookupString) From 76319845255d5f71acb2f88e684ba788bdadfa93 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Wed, 19 Feb 2025 17:26:41 +0000 Subject: [PATCH 061/587] 8349923: Refactor StackMapTable constructor and StackMapReader Reviewed-by: coleenp, dholmes --- src/hotspot/share/classfile/stackMapTable.cpp | 203 ++++++++++-------- src/hotspot/share/classfile/stackMapTable.hpp | 49 +++-- src/hotspot/share/classfile/verifier.cpp | 5 +- 3 files changed, 150 insertions(+), 107 deletions(-) diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index b66416ff1bf..ff8c8378027 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -29,38 +29,49 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -StackMapTable::StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, - u2 max_locals, u2 max_stack, - char* code_data, int code_len, TRAPS) { - _code_length = code_len; +StackMapTable::StackMapTable(StackMapReader* reader, TRAPS) { + _code_length = reader->code_length(); _frame_count = reader->get_frame_count(); if (_frame_count > 0) { - _frame_array = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, - StackMapFrame*, _frame_count); - StackMapFrame* pre_frame = init_frame; - for (int32_t i = 0; i < _frame_count; i++) { - StackMapFrame* frame = reader->next( - pre_frame, i == 0, max_locals, max_stack, - CHECK_VERIFY(pre_frame->verifier())); - _frame_array[i] = frame; - int offset = frame->offset(); - if (offset >= code_len || code_data[offset] == 0) { - frame->verifier()->verify_error( - ErrorContext::bad_stackmap(i, frame), - "StackMapTable error: bad offset"); - return; + _frame_array = new GrowableArray(_frame_count); + while (!reader->at_end()) { + StackMapFrame* frame = reader->next(CHECK_VERIFY(reader->prev_frame()->verifier())); + if (frame != nullptr) { + _frame_array->push(frame); } - pre_frame = frame; } + reader->check_end(CHECK); + // Correct frame count based on how many actual frames are generated + _frame_count = _frame_array->length(); + } +} + +void StackMapReader::check_offset(StackMapFrame* frame) { + int offset = frame->offset(); + if (offset >= _code_length || _code_data[offset] == 0) { + _verifier->verify_error(ErrorContext::bad_stackmap(0, frame), + "StackMapTable error: bad offset"); + } +} + +void StackMapReader::check_size(TRAPS) { + if (_frame_count < _parsed_frame_count) { + StackMapStream::stackmap_format_error("wrong attribute size", THREAD); + } +} + +void StackMapReader::check_end(TRAPS) { + assert(_stream->at_end(), "must be"); + if (_frame_count != _parsed_frame_count) { + StackMapStream::stackmap_format_error("wrong attribute size", THREAD); } - reader->check_end(CHECK); } // This method is only called by method in StackMapTable. int StackMapTable::get_index_from_offset(int32_t offset) const { int i = 0; for (; i < _frame_count; i++) { - if (_frame_array[i]->offset() == offset) { + if (_frame_array->at(i)->offset() == offset) { return i; } } @@ -95,7 +106,7 @@ bool StackMapTable::match_stackmap( return false; } - StackMapFrame *stackmap_frame = _frame_array[frame_index]; + StackMapFrame* stackmap_frame = _frame_array->at(frame_index); bool result = true; if (match) { // Has direct control flow from last instruction, need to match the two @@ -137,16 +148,20 @@ void StackMapTable::print_on(outputStream* str) const { { streamIndentor si(str); for (int32_t i = 0; i < _frame_count; ++i) { - _frame_array[i]->print_on(str); + _frame_array->at(i)->print_on(str); } } str->print_cr(" }"); } -StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data, - int32_t code_len, TRAPS) : - _verifier(v), _stream(stream), - _code_data(code_data), _code_length(code_len) { +StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, + char* code_data, int32_t code_len, + StackMapFrame* init_frame, + u2 max_locals, u2 max_stack, TRAPS) : + _verifier(v), _stream(stream), _code_data(code_data), + _code_length(code_len), _parsed_frame_count(0), + _prev_frame(init_frame), _max_locals(max_locals), + _max_stack(max_stack), _first(true) { methodHandle m = v->method(); if (m->has_stackmap_table()) { _cp = constantPoolHandle(THREAD, m->constants()); @@ -210,45 +225,56 @@ VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) { return VerificationType::bogus_type(); } -StackMapFrame* StackMapReader::next( - StackMapFrame* pre_frame, bool first, u2 max_locals, u2 max_stack, TRAPS) { +StackMapFrame* StackMapReader::next(TRAPS) { + _parsed_frame_count++; + check_size(CHECK_NULL); + StackMapFrame* frame = next_helper(CHECK_VERIFY_(_verifier, nullptr)); + if (frame != nullptr) { + check_offset(frame); + _prev_frame = frame; + } + return frame; +} + +StackMapFrame* StackMapReader::next_helper(TRAPS) { StackMapFrame* frame; int offset; VerificationType* locals = nullptr; u1 frame_type = _stream->get_u1(CHECK_NULL); if (frame_type < 64) { // same_frame - if (first) { + if (_first) { offset = frame_type; // Can't share the locals array since that is updated by the verifier. - if (pre_frame->locals_size() > 0) { + if (_prev_frame->locals_size() > 0) { locals = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, VerificationType, pre_frame->locals_size()); + THREAD, VerificationType, _prev_frame->locals_size()); } } else { - offset = pre_frame->offset() + frame_type + 1; - locals = pre_frame->locals(); + offset = _prev_frame->offset() + frame_type + 1; + locals = _prev_frame->locals(); } frame = new StackMapFrame( - offset, pre_frame->flags(), pre_frame->locals_size(), 0, - max_locals, max_stack, locals, nullptr, _verifier); - if (first && locals != nullptr) { - frame->copy_locals(pre_frame); + offset, _prev_frame->flags(), _prev_frame->locals_size(), 0, + _max_locals, _max_stack, locals, nullptr, _verifier); + if (_first && locals != nullptr) { + frame->copy_locals(_prev_frame); } + _first = false; return frame; } if (frame_type < 128) { // same_locals_1_stack_item_frame - if (first) { + if (_first) { offset = frame_type - 64; // Can't share the locals array since that is updated by the verifier. - if (pre_frame->locals_size() > 0) { + if (_prev_frame->locals_size() > 0) { locals = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, VerificationType, pre_frame->locals_size()); + THREAD, VerificationType, _prev_frame->locals_size()); } } else { - offset = pre_frame->offset() + frame_type - 63; - locals = pre_frame->locals(); + offset = _prev_frame->offset() + frame_type - 63; + locals = _prev_frame->locals(); } VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, VerificationType, 2); @@ -259,13 +285,14 @@ StackMapFrame* StackMapReader::next( stack_size = 2; } check_verification_type_array_size( - stack_size, max_stack, CHECK_VERIFY_(_verifier, nullptr)); + stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr)); frame = new StackMapFrame( - offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, - max_locals, max_stack, locals, stack, _verifier); - if (first && locals != nullptr) { - frame->copy_locals(pre_frame); + offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size, + _max_locals, _max_stack, locals, stack, _verifier); + if (_first && locals != nullptr) { + frame->copy_locals(_prev_frame); } + _first = false; return frame; } @@ -279,16 +306,16 @@ StackMapFrame* StackMapReader::next( if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { // same_locals_1_stack_item_frame_extended - if (first) { + if (_first) { offset = offset_delta; // Can't share the locals array since that is updated by the verifier. - if (pre_frame->locals_size() > 0) { + if (_prev_frame->locals_size() > 0) { locals = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, VerificationType, pre_frame->locals_size()); + THREAD, VerificationType, _prev_frame->locals_size()); } } else { - offset = pre_frame->offset() + offset_delta + 1; - locals = pre_frame->locals(); + offset = _prev_frame->offset() + offset_delta + 1; + locals = _prev_frame->locals(); } VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, VerificationType, 2); @@ -299,27 +326,28 @@ StackMapFrame* StackMapReader::next( stack_size = 2; } check_verification_type_array_size( - stack_size, max_stack, CHECK_VERIFY_(_verifier, nullptr)); + stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr)); frame = new StackMapFrame( - offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, - max_locals, max_stack, locals, stack, _verifier); - if (first && locals != nullptr) { - frame->copy_locals(pre_frame); + offset, _prev_frame->flags(), _prev_frame->locals_size(), stack_size, + _max_locals, _max_stack, locals, stack, _verifier); + if (_first && locals != nullptr) { + frame->copy_locals(_prev_frame); } + _first = false; return frame; } if (frame_type <= SAME_EXTENDED) { // chop_frame or same_frame_extended - locals = pre_frame->locals(); - int length = pre_frame->locals_size(); + locals = _prev_frame->locals(); + int length = _prev_frame->locals_size(); int chops = SAME_EXTENDED - frame_type; int new_length = length; - u1 flags = pre_frame->flags(); + u1 flags = _prev_frame->flags(); if (chops != 0) { new_length = chop(locals, length, chops); check_verification_type_array_size( - new_length, max_locals, CHECK_VERIFY_(_verifier, nullptr)); + new_length, _max_locals, CHECK_VERIFY_(_verifier, nullptr)); // Recompute flags since uninitializedThis could have been chopped. flags = 0; for (int i=0; i 0) { @@ -339,28 +367,28 @@ StackMapFrame* StackMapReader::next( locals = nullptr; } } else { - offset = pre_frame->offset() + offset_delta + 1; + offset = _prev_frame->offset() + offset_delta + 1; } frame = new StackMapFrame( - offset, flags, new_length, 0, max_locals, max_stack, + offset, flags, new_length, 0, _max_locals, _max_stack, locals, nullptr, _verifier); - if (first && locals != nullptr) { - frame->copy_locals(pre_frame); + if (_first && locals != nullptr) { + frame->copy_locals(_prev_frame); } + _first = false; return frame; } else if (frame_type < SAME_EXTENDED + 4) { // append_frame int appends = frame_type - SAME_EXTENDED; - int real_length = pre_frame->locals_size(); + int real_length = _prev_frame->locals_size(); int new_length = real_length + appends*2; locals = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, new_length); - VerificationType* pre_locals = pre_frame->locals(); - int i; - for (i=0; ilocals_size(); i++) { + VerificationType* pre_locals = _prev_frame->locals(); + for (int i = 0; i < _prev_frame->locals_size(); i++) { locals[i] = pre_locals[i]; } - u1 flags = pre_frame->flags(); - for (i=0; iflags(); + for (int i = 0; i < appends; i++) { locals[real_length] = parse_verification_type(&flags, CHECK_NULL); if (locals[real_length].is_category2()) { locals[real_length + 1] = locals[real_length].to_category2_2nd(); @@ -369,15 +397,16 @@ StackMapFrame* StackMapReader::next( ++real_length; } check_verification_type_array_size( - real_length, max_locals, CHECK_VERIFY_(_verifier, nullptr)); - if (first) { + real_length, _max_locals, CHECK_VERIFY_(_verifier, nullptr)); + if (_first) { offset = offset_delta; } else { - offset = pre_frame->offset() + offset_delta + 1; + offset = _prev_frame->offset() + offset_delta + 1; } frame = new StackMapFrame( - offset, flags, real_length, 0, max_locals, - max_stack, locals, nullptr, _verifier); + offset, flags, real_length, 0, _max_locals, + _max_stack, locals, nullptr, _verifier); + _first = false; return frame; } if (frame_type == FULL) { @@ -389,8 +418,7 @@ StackMapFrame* StackMapReader::next( locals = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, VerificationType, locals_size*2); } - int i; - for (i=0; iget_u2(CHECK_NULL); int real_stack_size = 0; VerificationType* stack = nullptr; @@ -408,7 +436,7 @@ StackMapFrame* StackMapReader::next( stack = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, VerificationType, stack_size*2); } - for (i=0; ioffset() + offset_delta + 1; + offset = _prev_frame->offset() + offset_delta + 1; } frame = new StackMapFrame( offset, flags, real_locals_size, real_stack_size, - max_locals, max_stack, locals, stack, _verifier); + _max_locals, _max_stack, locals, stack, _verifier); + _first = false; return frame; } _stream->stackmap_format_error( - "reserved frame type", CHECK_VERIFY_(pre_frame->verifier(), nullptr)); + "reserved frame type", CHECK_VERIFY_(_prev_frame->verifier(), nullptr)); return nullptr; } diff --git a/src/hotspot/share/classfile/stackMapTable.hpp b/src/hotspot/share/classfile/stackMapTable.hpp index a8ec3fc45db..cc4202f3280 100644 --- a/src/hotspot/share/classfile/stackMapTable.hpp +++ b/src/hotspot/share/classfile/stackMapTable.hpp @@ -44,16 +44,14 @@ class StackMapTable : public StackObj { // Widening the type and making it signed will help detect these. int32_t _code_length; int32_t _frame_count; // Stackmap frame count - StackMapFrame** _frame_array; + GrowableArray* _frame_array; public: - StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, - u2 max_locals, u2 max_stack, - char* code_data, int code_len, TRAPS); + StackMapTable(StackMapReader* reader, TRAPS); inline int32_t get_frame_count() const { return _frame_count; } inline int get_offset(int index) const { - return _frame_array[index]->offset(); + return _frame_array->at(index)->offset(); } // Match and/or update current_frame to the frame in stackmap table with @@ -116,9 +114,25 @@ class StackMapReader : StackObj { char* _code_data; int32_t _code_length; - // information get from the attribute - int32_t _frame_count; // frame count + // information from the attribute + int32_t _frame_count; + // Number of frames parsed + int32_t _parsed_frame_count; + + // Previous frame buffer + StackMapFrame* _prev_frame; + + // information from method + u2 _max_locals; + u2 _max_stack; + + // Check if reading first entry + bool _first; + + StackMapFrame* next_helper(TRAPS); + void check_offset(StackMapFrame* frame); + void check_size(TRAPS); int32_t chop(VerificationType* locals, int32_t length, int32_t chops); VerificationType parse_verification_type(u1* flags, TRAPS); void check_verification_type_array_size( @@ -141,18 +155,19 @@ class StackMapReader : StackObj { public: // Constructor - StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data, - int32_t code_len, TRAPS); + StackMapReader(ClassVerifier* v, StackMapStream* stream, + char* code_data, int32_t code_len, + StackMapFrame* init_frame, + u2 max_locals, u2 max_stack, TRAPS); - inline int32_t get_frame_count() const { return _frame_count; } - StackMapFrame* next(StackMapFrame* pre_frame, bool first, - u2 max_locals, u2 max_stack, TRAPS); + inline int32_t get_frame_count() const { return _frame_count; } + inline StackMapFrame* prev_frame() const { return _prev_frame; } + inline char* code_data() const { return _code_data; } + inline int32_t code_length() const { return _code_length; } + inline bool at_end() const { return _stream->at_end(); } - void check_end(TRAPS) { - if (!_stream->at_end()) { - StackMapStream::stackmap_format_error("wrong attribute size", CHECK); - } - } + StackMapFrame* next(TRAPS); + void check_end(TRAPS); }; #endif // SHARE_CLASSFILE_STACKMAPTABLE_HPP diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 1e9bdcc682d..b1daee82747 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -736,9 +736,8 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { Array* stackmap_data = m->stackmap_data(); StackMapStream stream(stackmap_data); - StackMapReader reader(this, &stream, code_data, code_length, THREAD); - StackMapTable stackmap_table(&reader, ¤t_frame, max_locals, max_stack, - code_data, code_length, CHECK_VERIFY(this)); + StackMapReader reader(this, &stream, code_data, code_length, ¤t_frame, max_locals, max_stack, THREAD); + StackMapTable stackmap_table(&reader, CHECK_VERIFY(this)); LogTarget(Debug, verification) lt; if (lt.is_enabled()) { From 7734f8ed13f04ba01258b4fbe18a3d9b66f7fc7a Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Wed, 19 Feb 2025 18:56:26 +0000 Subject: [PATCH 062/587] 8349664: HEX dump should always use ASCII or ISO_8859_1 Reviewed-by: weijun --- .../sun/security/util/HexDumpEncoder.java | 8 +- .../security/util/HexDumpEncoderTests.java | 99 +++++++++++++++++++ 2 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 test/jdk/sun/security/util/HexDumpEncoderTests.java diff --git a/src/java.base/share/classes/sun/security/util/HexDumpEncoder.java b/src/java.base/share/classes/sun/security/util/HexDumpEncoder.java index 0d1b4ae8984..2431b95562f 100644 --- a/src/java.base/share/classes/sun/security/util/HexDumpEncoder.java +++ b/src/java.base/share/classes/sun/security/util/HexDumpEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, 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 @@ -84,7 +84,7 @@ public class HexDumpEncoder { protected void encodeBufferPrefix(OutputStream o) throws IOException { offset = 0; - pStream = new PrintStream(o); + pStream = new PrintStream(o, false, ISO_8859_1); } protected void encodeLinePrefix(OutputStream o, int len) { @@ -303,6 +303,8 @@ public class HexDumpEncoder { /** * A 'streamless' version of encode that simply takes a buffer of * bytes and returns a string containing the encoded buffer. + *

+ * Returned string is encoded with the ISO-8859-1, also known as ISO-LATIN-1. */ public String encodeBuffer(byte[] aBuffer) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -313,7 +315,7 @@ public class HexDumpEncoder { // This should never happen. throw new Error("CharacterEncoder.encodeBuffer internal error"); } - return (outStream.toString()); + return (outStream.toString(ISO_8859_1)); } /** diff --git a/test/jdk/sun/security/util/HexDumpEncoderTests.java b/test/jdk/sun/security/util/HexDumpEncoderTests.java new file mode 100644 index 00000000000..9ff08cdb192 --- /dev/null +++ b/test/jdk/sun/security/util/HexDumpEncoderTests.java @@ -0,0 +1,99 @@ +/* + * 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.test.lib.Asserts; +import jdk.test.lib.process.ProcessTools; +import sun.security.util.HexDumpEncoder; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/* + * @test + * @bug 8349664 + * @summary HEX dump should always use ASCII or ISO_8859_1 + * @modules java.base/sun.security.util + * @library /test/lib + */ +public class HexDumpEncoderTests { + + + private static String[] getTestCommand(final String encoding) { + return new String[]{ + "--add-modules", "java.base", + "--add-exports", "java.base/sun.security.util=ALL-UNNAMED", + "-Dfile.encoding=" + encoding, + HexDumpEncoderTests.HexDumpEncoderTest.class.getName() + }; + } + + public static void main(String[] args) throws Exception { + + final var testCommandIso = getTestCommand("ISO-8859-1"); + + final var resultIso = ProcessTools.executeTestJava(testCommandIso); + resultIso.shouldHaveExitValue(0); + + // This will take all available StandardCharsets and test them all comparing to the ISO_8859_1 + // Dome im parallel, as this is significantly faster + Arrays.stream(StandardCharsets.class.getDeclaredFields()) + .parallel() + .forEach(field -> { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + try { + final var charset = (Charset) field.get(StandardCharsets.ISO_8859_1); // getting the charset to test + + final var testCommand = getTestCommand(charset.name()); + + final var result = ProcessTools.executeTestJava(testCommand); + result.shouldHaveExitValue(0); + + // The outputs of the ISO encoding must be identical to the one tested + Asserts.assertEquals(resultIso.getStdout(), + result.getStdout(), + "Encoding " + charset.name()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + public static class HexDumpEncoderTest { + + /** + * This will test the encode and encode buffer functions at once, + * as they are both representing the string in LATIN_1 + *

+ * The output is put as a system.out + */ + public static void main(String[] args) throws Exception { + + final var encoder = new HexDumpEncoder(); + + System.out.printf("\nCert Encoded With Encode Buffer: %s\n", encoder.encodeBuffer(new byte[100])); + System.out.printf("\nCert Encoded With Encode: %s\n", encoder.encode(new byte[100])); + } + } +} From 4e60c2d937fca8170b356f36e72b271104130c40 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Wed, 19 Feb 2025 19:36:30 +0000 Subject: [PATCH 063/587] 8349699: XSL transform fails with certain UTF-8 characters on 1024 byte boundaries Reviewed-by: lancea, naoto --- .../xml/internal/serializer/ToStream.java | 6 +- .../jaxp/unittest/transform/JDK8207760.java | 125 +++++++++++++++++- 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java index fc01f006e97..7bff17a455f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -55,7 +55,7 @@ import org.xml.sax.SAXException; * serializers (xml, html, text ...) that write output to a stream. * * @xsl.usage internal - * @LastModified: Mar 2022 + * @LastModified: Feb 2025 */ abstract public class ToStream extends SerializerBase { @@ -955,7 +955,7 @@ abstract public class ToStream extends SerializerBase { throws IOException, SAXException { int status = -1; - if (i + 1 >= end) + if (i + 1 >= end && m_highSurrogate == 0) { m_highSurrogate = c; return status; diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/JDK8207760.java b/test/jaxp/javax/xml/jaxp/unittest/transform/JDK8207760.java index 00c1b8a8e25..6055fa878bc 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/transform/JDK8207760.java +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/JDK8207760.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 @@ -41,10 +41,10 @@ import org.testng.annotations.DataProvider; /* * @test + * @bug 8207760 8349699 + * @summary Verifies that a surrogate pair at the edge of a buffer is properly handled * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm transform.JDK8207760 - * @summary Verifies that a surrogate pair at the edge of a buffer is properly handled - * @bug 8207760 */ public class JDK8207760 { final String xsl8207760 = @@ -93,6 +93,14 @@ public class JDK8207760 { "\n" + ""; + final String xsl8349699 = """ + + + + + + """; + @DataProvider(name = "xsls") public Object[][] getDataBug8207760_cdata() { return new Object[][]{ @@ -101,6 +109,117 @@ public class JDK8207760 { }; } + /* + * Data for verifying the patch for JDK8349699 + * @see testBug8349699 + */ + @DataProvider(name = "surrogatePair") + public Object[][] getDataFor8349699() { + return new Object[][]{ + // a surrogate pair in an XML element placed anywhere in a string + {getXML(1024, 1024, "\uD835\uDF00"), getString(1024, 1024, "\uD835\uDF00")}, + {getXML(1023, 1023, "\uD835\uDF00"), getString(1023, 1023, "\uD835\uDF00")}, + {getXML(1023,0, "\uD835\uDF00"), getString(1023,0, "\uD835\uDF00")}, + {getXML(1023,120, "\uD835\uDF00"), getString(1023,120, "\uD835\uDF00")}, + // this is the original test as demonstrated in the bug report + {getXML(1017,1017, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00"), + getString(1017,1017, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00")}, + {getXML(1017,0, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00"), + getString(1017,0, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00")}, + {getXML(1017,120, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00"), + getString(1017,120, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uDF00\uD835\uDF00")}, + }; + } + + /* + * Data for verifying the patch for JDK8349699 + * @see testBug8349699N + */ + @DataProvider(name = "invalidSurrogatePair") + public Object[][] getDataFor8349699N() { + return new Object[][]{ + // invalid pair: high/high + {getXML(1024, 1024, "\uD835\uD835")}, + {getXML(1023, 1023, "\uD835\uD835")}, + {getXML(1023,0, "\uD835\uD835")}, + {getXML(1023,120, "\uD835\uD835")}, + // invalid pair: low/low + {getXML(1024, 1024, "\uDF00\uDF00")}, + {getXML(1023, 1023, "\uDF00\uDF00")}, + {getXML(1023,0, "\uDF00\uDF00")}, + {getXML(1023,120, "\uDF00\uDF00")}, + // invalid pair in the original test string + {getXML(1017,1017, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uD835\uD835\uDF00")}, + {getXML(1017,0, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uD835\uD835\uDF00")}, + {getXML(1017,120, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uD835\uD835\uD835\uDF00")}, + {getXML(1017,1017, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uDF00\uDF00\uD835\uDF00")}, + {getXML(1017,0, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uDF00\uDF00\uD835\uDF00")}, + {getXML(1017,120, "\uD835\uDF03\uD835\uDF00\uD835\uDF00\uDF00\uDF00\uD835\uDF00")}, + }; + } + + /* + * @bug 8349699 + * Verifies that a surrogate pair at the edge of a buffer is properly handled + * when serializing into a Character section. + */ + @Test(dataProvider = "surrogatePair") + public final void testBug8349699(String xml, String expected) throws Exception { + Transformer t = createTransformerFromInputstream( + new ByteArrayInputStream(xsl8349699.getBytes(StandardCharsets.UTF_8))); + StringWriter sw = new StringWriter(); + t.transform(new StreamSource(new StringReader(xml)), new StreamResult(sw)); + Assert.assertEquals(sw.toString(), expected); + } + + /* + * @bug 8349699 + * Verifies that invalid surrogate pairs are caught. + */ + @Test(dataProvider = "invalidSurrogatePair") + public final void testBug8349699N(String xml) throws Exception { + Assert.assertThrows(TransformerException.class, () -> { + Transformer t = createTransformerFromInputstream( + new ByteArrayInputStream(xsl8349699.getBytes(StandardCharsets.UTF_8))); + StringWriter sw = new StringWriter(); + t.transform(new StreamSource(new StringReader(xml)), new StreamResult(sw)); + }); + } + + /** + * Returns an XML with the input string inserted in a text of length 'len' at + * the position 'pos'. + * @param len the length of the text to be placed in the XML + * @param pos the position at which the input string will be inserted into the text + * @param input the input string + * @return an XML + */ + private String getXML(int len, int pos, String input) { + StringBuilder sb = new StringBuilder(""); + sb.append(getString(len, pos, input)); + sb.append(""); + return sb.toString(); + } + + /** + * Returns a text string with the input string inserted at the specified position. + * @param len the length of the text to be returned + * @param pos the position at which the input string will be inserted into the text + * @param input the input string + * @return a text string + */ + private String getString(int len, int pos, String input) { + StringBuilder sb = new StringBuilder(); + if (pos == 0) { + sb.append(input).append("x".repeat(len)); + } else if (pos == len) { + sb.append("x".repeat(len)).append(input); + } else { + sb.append("x".repeat(pos)).append(input).append("x".repeat(len - pos)); + } + return sb.toString(); + } + /* * @bug 8207760 * Verifies that a surrogate pair at the edge of a buffer is properly handled From 4fb70c79c1383507bd42cd7f569cbde28393a2b8 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 19 Feb 2025 19:58:11 +0000 Subject: [PATCH 064/587] 8229012: When single stepping, the debug agent can cause the thread to remain in interpreter mode after single stepping completes Reviewed-by: kevinw, sspitsyn --- .../share/native/libjdwp/stepControl.c | 62 ++++- .../sun/jdi/SingleStepCompilationTest.java | 236 ++++++++++++++++++ 2 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 test/jdk/com/sun/jdi/SingleStepCompilationTest.java diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c index aeec8175b17..cf330d74d29 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c @@ -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 @@ -858,6 +858,17 @@ stepControl_beginStep(JNIEnv *env, jthread thread, jint size, jint depth, return error; } +static jint +getThreadState(jthread thread) +{ + jint state = 0; + jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) + (gdata->jvmti, thread, &state); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error, "getting thread state"); + } + return state; +} static void clearStep(jthread thread, StepRequest *step) @@ -877,15 +888,60 @@ clearStep(jthread thread, StepRequest *step) (void)eventHandler_free(step->methodEnterHandlerNode); step->methodEnterHandlerNode = NULL; } - step->pending = JNI_FALSE; - /* * Warning: Do not clear step->method, step->lineEntryCount, * or step->lineEntries here, they will likely * be needed on the next step. */ + jvmtiError error; + jboolean needsSuspending; // true if we needed to suspend this thread + + // The thread needs suspending if it is not the current thread and is + // not already suspended. + if (isSameObject(getEnv(), threadControl_currentThread(), thread)) { + needsSuspending = JNI_FALSE; + } else { + jint state = getThreadState(thread); + needsSuspending = ((state & JVMTI_THREAD_STATE_SUSPENDED) == 0); + } + + if (needsSuspending) { + // Don't use threadControl_suspendThread() here. It does a lot of + // locking, increasing the risk of deadlock issues. None of that + // locking is needed here. + error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread) + (gdata->jvmti, thread); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error, "suspending thread"); + } + } + + error = JVMTI_FUNC_PTR(gdata->jvmti,ClearAllFramePops) + (gdata->jvmti, thread); + if (error != JVMTI_ERROR_NONE) { +#ifdef DEBUG + jint currentDepth = getFrameCount(thread); + jint state = getThreadState(thread); + tty_message("JVMTI ERROR(%d): ClearAllFramePops (state=0x%x fromDepth=%d currentDepth=%d)", + error, state, step->fromStackDepth, currentDepth); + printThreadInfo(thread); + printStackTrace(thread); + threadControl_dumpThread(thread); +#endif + EXIT_ERROR(error, "clearing all frame pops"); + } + + if (needsSuspending) { + error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread) + (gdata->jvmti, thread); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error, "resuming thread"); + } + } } + + step->pending = JNI_FALSE; } jvmtiError diff --git a/test/jdk/com/sun/jdi/SingleStepCompilationTest.java b/test/jdk/com/sun/jdi/SingleStepCompilationTest.java new file mode 100644 index 00000000000..f821c4f2dff --- /dev/null +++ b/test/jdk/com/sun/jdi/SingleStepCompilationTest.java @@ -0,0 +1,236 @@ +/* + * 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 TEST IS LINE NUMBER SENSITIVE + +/** + * @test + * @bug 8229012 + * @summary Verify that during single stepping a method is not compiled and + * after single stepping it is compiled. + * @requires vm.compMode == "Xmixed" + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g SingleStepCompilationTest.java + * @run driver SingleStepCompilationTest + */ + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +import java.util.*; +import java.lang.reflect.Method; + +import jdk.test.whitebox.WhiteBox; + +class TestTarg { + public final static int BKPT_LINE = 66; + + public static void main(String[] args) { + // Call buswork() and verify that is get compiled. + busyWork("Warmup"); + if (!isCompiled()) { + throw new RuntimeException("busywork() did not get compiled after warmup"); + } + + // We need to force deopt the method now. Although we are about to force interp_only + // mode by enabling single stepping, this does not result in the method being + // deopt right away. It just causes the compiled method not to be used. + deoptimizeMethod(); + + // Call busywork() again. This time the debugger will have single stepping + // enabled. After calling, verify that busywork() is not compiled. + busyWork("StepOver"); // BKPT_LINE: We do a STEP_OVER here + if (isCompiled()) { + throw new RuntimeException("busywork() compiled during single stepping"); + } + + // Call busywork a 3rd time. This time the debugger will not have single stepping + // enabled. After calling, verify that busywork is compiled. + busyWork("AfterStep"); + if (!isCompiled()) { + throw new RuntimeException("busywork() not compiled after single stepping completes"); + } + } + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static Method busyWorkMethod; + static { + try { + busyWorkMethod = TestTarg.class.getDeclaredMethod("busyWork", String.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private static boolean isCompiled() { + return WB.isMethodCompiled(busyWorkMethod, true) || WB.isMethodCompiled(busyWorkMethod, false); + } + + private static void deoptimizeMethod() { + System.out.println("Decompile count before: " + WB.getMethodDecompileCount(busyWorkMethod)); + WB.deoptimizeMethod(busyWorkMethod, true); + WB.deoptimizeMethod(busyWorkMethod, false); + System.out.println("Decompile count after: " + WB.getMethodDecompileCount(busyWorkMethod)); + } + + // We put the array and the result variables in static volatiles just to make sure + // the compiler doesn't optimize them away. + public static final int ARRAY_SIZE = 1000*1024; + public static volatile int[] a = new int[ARRAY_SIZE]; + public static volatile long result = 0; + + // Do something compute intensive to trigger compilation. + public static void busyWork(String phase) { + // Although timing is not necessary for this test, it is useful to have in the + // log output for troubleshooting. The timing when step over is enabled should + // be sigficantly slower than when not. + long start = System.currentTimeMillis(); + + // Burn some CPU time and trigger OSR compilation. + for (int j = 0; j < 500; j++) { + for (int i = 0; i < ARRAY_SIZE; i++) { + a[i] = j*i + i << 5 + j; + } + } + for (int i = 0; i < ARRAY_SIZE; i++) { + result += a[i]; + } + + long end = System.currentTimeMillis(); + long totalTime = end - start; + System.out.println(phase + " time: " + totalTime); + } +} + +/********** test program **********/ + +public class SingleStepCompilationTest extends TestScaffold { + ClassType targetClass; + ThreadReference mainThread; + + SingleStepCompilationTest (String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + /* + * We need to pass some extra args to the debuggee for WhiteBox support and + * for more consistent compilation behavior. + */ + String[] newArgs = new String[5]; + if (args.length != 0) { + throw new RuntimeException("Unexpected arguments passed to test"); + } + + // These are all needed for WhiteBoxAPI + newArgs[0] = "-Xbootclasspath/a:."; + newArgs[1] = "-XX:+UnlockDiagnosticVMOptions"; + newArgs[2] = "-XX:+WhiteBoxAPI"; + + // In order to make sure the compilation is complete before we exit busyWork(), + // we don't allow background compilations. + newArgs[3] = "-XX:-BackgroundCompilation"; + + // Disabled tiered compilations so a new compilation doesn't start in the middle + // of executing busyWork(). (Might not really be needed) + newArgs[4] = "-XX:-TieredCompilation"; + + new SingleStepCompilationTest(newArgs).startTests(); + } + + /********** event handlers **********/ + + EventRequestManager erm; + BreakpointRequest bkptRequest; + StepRequest stepRequest; + + // When we get a bkpt we want to disable the request and enable single stepping. + public void breakpointReached(BreakpointEvent event) { + System.out.println("Got BreakpointEvent: " + event); + EventRequest req = event.request(); + req.disable(); + stepRequest = erm.createStepRequest(mainThread, + StepRequest.STEP_LINE, + StepRequest.STEP_OVER); + stepRequest.enable(); + } + + public void stepCompleted(StepEvent event) { + System.out.println("Got StepEvent: " + event); + EventRequest req = event.request(); + req.disable(); + } + + public void eventSetComplete(EventSet set) { + set.resume(); + } + + public void vmDisconnected(VMDisconnectEvent event) { + System.out.println("Got VMDisconnectEvent"); + } + + /********** test core **********/ + + protected void runTests() throws Exception { + /* + * Get to the top of main() to determine targetClass and mainThread. + */ + BreakpointEvent bpe = startToMain("TestTarg"); + targetClass = (ClassType)bpe.location().declaringType(); + mainThread = bpe.thread(); + erm = vm().eventRequestManager(); + + // The BKPT_LINE is the line we will STEP_OVER. + Location loc1 = findLocation(targetClass, TestTarg.BKPT_LINE); + bkptRequest = erm.createBreakpointRequest(loc1); + bkptRequest.enable(); + + try { + addListener(this); + } catch (Exception ex) { + ex.printStackTrace(); + failure("failure: Could not add listener"); + throw new RuntimeException("SingleStepCompilationTest: failed", ex); + } + + vm().resume(); + waitForVMDisconnect(); + + System.out.println("done with loop"); + removeListener(this); + + /* + * Deal with results of test. If anything has called failure("foo") + * then testFailed will be true. + */ + if (!testFailed) { + System.out.println("SingleStepCompilationTest: passed"); + } else { + throw new Exception("SingleStepCompilationTest: failed"); + } + } +} From 92efab90db24a76cc28fc1ae1db870a0dd670266 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Wed, 19 Feb 2025 21:02:27 +0000 Subject: [PATCH 065/587] 8350344: Cross-build failure: _vptr name conflict Reviewed-by: kvn --- src/hotspot/share/code/codeBlob.cpp | 34 ++++++++++++++--------------- src/hotspot/share/code/codeBlob.hpp | 10 ++++----- src/hotspot/share/code/nmethod.hpp | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 3ed00a08e40..9b61d9e6650 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -73,29 +73,29 @@ static_assert(!std::is_polymorphic::value, "no virtual metho // Add proxy vtables. // We need only few for now - they are used only from prints. -const nmethod::Vptr nmethod::_vptr; -const BufferBlob::Vptr BufferBlob::_vptr; -const RuntimeStub::Vptr RuntimeStub::_vptr; -const SingletonBlob::Vptr SingletonBlob::_vptr; -const DeoptimizationBlob::Vptr DeoptimizationBlob::_vptr; -const UpcallStub::Vptr UpcallStub::_vptr; +const nmethod::Vptr nmethod::_vpntr; +const BufferBlob::Vptr BufferBlob::_vpntr; +const RuntimeStub::Vptr RuntimeStub::_vpntr; +const SingletonBlob::Vptr SingletonBlob::_vpntr; +const DeoptimizationBlob::Vptr DeoptimizationBlob::_vpntr; +const UpcallStub::Vptr UpcallStub::_vpntr; const CodeBlob::Vptr* CodeBlob::vptr() const { constexpr const CodeBlob::Vptr* array[(size_t)CodeBlobKind::Number_Of_Kinds] = { nullptr/* None */, - &nmethod::_vptr, - &BufferBlob::_vptr, - &AdapterBlob::_vptr, - &VtableBlob::_vptr, - &MethodHandlesAdapterBlob::_vptr, - &RuntimeStub::_vptr, - &DeoptimizationBlob::_vptr, - &SafepointBlob::_vptr, + &nmethod::_vpntr, + &BufferBlob::_vpntr, + &AdapterBlob::_vpntr, + &VtableBlob::_vpntr, + &MethodHandlesAdapterBlob::_vpntr, + &RuntimeStub::_vpntr, + &DeoptimizationBlob::_vpntr, + &SafepointBlob::_vpntr, #ifdef COMPILER2 - &ExceptionBlob::_vptr, - &UncommonTrapBlob::_vptr, + &ExceptionBlob::_vpntr, + &UncommonTrapBlob::_vpntr, #endif - &UpcallStub::_vptr + &UpcallStub::_vpntr }; return array[(size_t)_kind]; diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index fd9a96a2a6b..d0ac2bf1b5f 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -346,7 +346,7 @@ class BufferBlob: public RuntimeBlob { } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; @@ -434,7 +434,7 @@ class RuntimeStub: public RuntimeBlob { } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; @@ -474,7 +474,7 @@ class SingletonBlob: public RuntimeBlob { } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; @@ -557,7 +557,7 @@ class DeoptimizationBlob: public SingletonBlob { } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; @@ -685,7 +685,7 @@ class UpcallStub: public RuntimeBlob { } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; #endif // SHARE_CODE_CODEBLOB_HPP diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 39bf18547d8..ac9b1a7098f 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -996,7 +996,7 @@ public: } }; - static const Vptr _vptr; + static const Vptr _vpntr; }; #endif // SHARE_CODE_NMETHOD_HPP From 3ebed78328bd64d2e18369d63d6ea323b87a7b24 Mon Sep 17 00:00:00 2001 From: Nicole Xu Date: Thu, 20 Feb 2025 01:33:58 +0000 Subject: [PATCH 066/587] 8349943: [JMH] Use jvmArgs consistently Reviewed-by: syan, redestad, haosun --- .../bench/java/lang/foreign/CallByRefHighArity.java | 4 ++-- .../openjdk/bench/java/lang/foreign/LoopOverRandom.java | 4 ++-- .../openjdk/bench/java/lang/foreign/SegmentOfBuffer.java | 6 +++--- test/micro/org/openjdk/bench/java/security/MLDSA.java | 2 +- .../micro/org/openjdk/bench/java/security/MLKEMBench.java | 2 +- .../org/openjdk/bench/javax/crypto/full/AESBench.java | 4 ++-- .../jdk/incubator/vector/VectorMultiplyOptBenchmark.java | 4 ++-- .../jdk/incubator/vector/VectorXXH3HashingBenchmark.java | 4 ++-- test/micro/org/openjdk/bench/vm/compiler/MergeStores.java | 8 +++++--- 9 files changed, 20 insertions(+), 18 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java index 417a7c39c1a..51060e3ff6d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallByRefHighArity.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 @@ -35,7 +35,7 @@ import java.util.function.Supplier; @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) public class CallByRefHighArity { static { diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java index 392ac6d667b..b21f4d72007 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverRandom.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 @@ -46,7 +46,7 @@ import jdk.internal.misc.Unsafe; @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @State(org.openjdk.jmh.annotations.Scope.Thread) @OutputTimeUnit(TimeUnit.MICROSECONDS) -@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"}) public class LoopOverRandom extends JavaLayouts { static final int SEED = 0; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentOfBuffer.java b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentOfBuffer.java index 25bfd44b063..973d800eb4c 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/SegmentOfBuffer.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/SegmentOfBuffer.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 @@ -57,13 +57,13 @@ public class SegmentOfBuffer { } @Benchmark - @Fork(value = 3, jvmArgsAppend = "-XX:CompileCommand=inline,jdk.internal.foreign.AbstractMemorySegmentImpl::ofBuffer,false") + @Fork(value = 3, jvmArgs = "-XX:CompileCommand=inline,jdk.internal.foreign.AbstractMemorySegmentImpl::ofBuffer,false") public long ofBufferInlineFalse() { return MemorySegment.ofBuffer(buffer).address(); } @Benchmark - @Fork(value = 3, jvmArgsAppend = "-XX:CompileCommand=inline,jdk.internal.foreign.AbstractMemorySegmentImpl::ofBuffer,true") + @Fork(value = 3, jvmArgs = "-XX:CompileCommand=inline,jdk.internal.foreign.AbstractMemorySegmentImpl::ofBuffer,true") public long ofBufferInlineTrue() { return MemorySegment.ofBuffer(buffer).address(); } diff --git a/test/micro/org/openjdk/bench/java/security/MLDSA.java b/test/micro/org/openjdk/bench/java/security/MLDSA.java index 7f3d77a0b82..36b616ab599 100644 --- a/test/micro/org/openjdk/bench/java/security/MLDSA.java +++ b/test/micro/org/openjdk/bench/java/security/MLDSA.java @@ -56,7 +56,7 @@ import java.util.concurrent.TimeUnit; @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsAppend = {"--add-opens", "java.base/sun.security.provider=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-opens", "java.base/sun.security.provider=ALL-UNNAMED"}) public class MLDSA { @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87"} ) diff --git a/test/micro/org/openjdk/bench/java/security/MLKEMBench.java b/test/micro/org/openjdk/bench/java/security/MLKEMBench.java index 30481ed86a5..db87c24b48f 100644 --- a/test/micro/org/openjdk/bench/java/security/MLKEMBench.java +++ b/test/micro/org/openjdk/bench/java/security/MLKEMBench.java @@ -55,7 +55,7 @@ import java.util.concurrent.TimeUnit; @State(Scope.Thread) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsAppend = {"--add-opens", "java.base/com.sun.crypto.provider=ALL-UNNAMED"}) +@Fork(value = 3, jvmArgs = {"--add-opens", "java.base/com.sun.crypto.provider=ALL-UNNAMED"}) public class MLKEMBench { @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"} ) diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java index f04e5d015a2..0977d2bc462 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.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 @@ -39,7 +39,7 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidParameterSpecException; -@Fork(jvmArgsAppend = {"-Xms20g", "-Xmx20g", "-XX:+UseZGC"}) +@Fork(jvmArgs = {"-Xms20g", "-Xmx20g", "-XX:+UseZGC"}) public class AESBench extends CryptoBase { public static final int SET_SIZE = 8; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorMultiplyOptBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorMultiplyOptBenchmark.java index 51f8300a044..a6c2db965f0 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorMultiplyOptBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorMultiplyOptBenchmark.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 @@ -32,7 +32,7 @@ import java.util.stream.*; @State(Scope.Benchmark) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorMultiplyOptBenchmark { @Param({"1024", "2048", "4096"}) private int SIZE; diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorXXH3HashingBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorXXH3HashingBenchmark.java index 32056da49aa..8a40e0fd95b 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorXXH3HashingBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorXXH3HashingBenchmark.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 @@ -32,7 +32,7 @@ import java.util.stream.*; @State(Scope.Benchmark) @Warmup(iterations = 3, time = 1) @Measurement(iterations = 5, time = 1) -@Fork(value = 1, jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorXXH3HashingBenchmark { @Param({"1024", "2048", "4096", "8192"}) private int SIZE; diff --git a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java index 809ec01f495..679502c121d 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/MergeStores.java +++ b/test/micro/org/openjdk/bench/vm/compiler/MergeStores.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 @@ -743,8 +743,10 @@ public class MergeStores { UNSAFE.putLongUnaligned(null, native_adr + offset + 0, vL); } - @Fork(value = 1, jvmArgsPrepend = { - "-XX:+UnlockDiagnosticVMOptions", "-XX:-MergeStores" + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:-MergeStores", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.util=ALL-UNNAMED" }) public static class MergeStoresDisabled extends MergeStores {} } From 0131c1bfd8ccfdf4f3d73cddfc2a87e2a6e99581 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 20 Feb 2025 02:13:41 +0000 Subject: [PATCH 067/587] 8349953: Avoid editing AOTConfiguration file in "make test JTREG=AOT_JDK=true" Reviewed-by: erikj, ccheung --- make/Main.gmk | 14 ++++- make/RunTests.gmk | 61 ++++++++++---------- make/test/BuildTestSetupAOT.gmk | 69 +++++++++++++++++++++++ src/hotspot/share/cds/classListParser.cpp | 7 +-- test/setup_aot/TestSetupAOT.java | 59 +++++++++++++++++++ 5 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 make/test/BuildTestSetupAOT.gmk create mode 100644 test/setup_aot/TestSetupAOT.java diff --git a/make/Main.gmk b/make/Main.gmk index 4690139e6ad..f2f1bce0e10 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -753,6 +753,17 @@ $(eval $(call SetupTarget, test-image-lib, \ DEPS := build-test-lib, \ )) +$(eval $(call SetupTarget, build-test-setup-aot, \ + MAKEFILE := test/BuildTestSetupAOT, \ + DEPS := interim-langtools exploded-image, \ +)) + +$(eval $(call SetupTarget, test-image-setup-aot, \ + MAKEFILE := test/BuildTestSetupAOT, \ + TARGET := images, \ + DEPS := build-test-setup-aot, \ +)) + ifeq ($(BUILD_FAILURE_HANDLER), true) # Builds the failure handler jtreg extension $(eval $(call SetupTarget, build-test-failure-handler, \ @@ -1281,7 +1292,8 @@ all-docs-bundles: docs-jdk-bundles docs-javase-bundles docs-reference-bundles # This target builds the test image test-image: prepare-test-image test-image-jdk-jtreg-native \ test-image-demos-jdk test-image-libtest-jtreg-native \ - test-image-lib test-image-lib-native + test-image-lib test-image-lib-native \ + test-image-setup-aot ifneq ($(JVM_TEST_IMAGE_TARGETS), ) # If JVM_TEST_IMAGE_TARGETS is externally defined, use it instead of the diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 3e20de3f82e..616341a8901 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -703,6 +703,9 @@ define SetJtregValue endif endef +################################################################################ +# Helper function for creating a customized AOT cache for running tests +################################################################################ # Parameter 1 is the name of the rule. # @@ -713,48 +716,47 @@ endef # $1_AOT_TARGETS List of all targets that the test rule will need to depend on # $1_AOT_JDK_CACHE The AOT cache file to be used to run the test with # -SetupAot = $(NamedParamsMacroTemplate) -define SetupAotBody - $1_AOT_JDK_CONF := $$($1_TEST_SUPPORT_DIR)/aot/jdk.aotconf +SetupAOT = $(NamedParamsMacroTemplate) +define SetupAOTBody + $1_AOT_JDK_CONF := $$($1_TEST_SUPPORT_DIR)/aot/jdk.aotconf $1_AOT_JDK_CACHE := $$($1_TEST_SUPPORT_DIR)/aot/jdk.aotcache + $1_AOT_JDK_LOG := $$($1_TEST_SUPPORT_DIR)/aot/TestSetupAOT.log - $1_JAVA_TOOL_OPTS := $$(addprefix -J, $$($1_VM_OPTIONS)) + # We execute the training run with $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.class + # to touch a fair number of classes inside the JDK. Note that we can't specify a classpath, + # or else the AOT cache cannot be used with jtreg test cases that use a different value + # for their classpaths. Instead, we run in the $(TEST_IMAGE_DIR)/setup_aot/ directory. + # The "java" launcher will have an implicit classpath of ".", so it can pick up the TestSetupAOT + # class from the JVM's current directory. + # + # The TestSetupAOT class (or any other classes that are loaded from ".") will be excluded + # from the the AOT cache as "." is an unsupported location. As a result, the AOT cache will contain + # only classes from the JDK. $$($1_AOT_JDK_CACHE): $$(JDK_IMAGE_DIR)/release $$(call MakeDir, $$($1_TEST_SUPPORT_DIR)/aot) - $(foreach jtool, javac javap jlink jar, \ - $(info AOT: Create cache configuration for $(jtool)) \ - $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/aot.$(jtool), ( \ - $$(FIXPATH) $(JDK_UNDER_TEST)/bin/$(jtool) $$($1_JAVA_TOOL_OPTS) \ - -J-XX:AOTMode=record -J-XX:AOTConfiguration=$$($1_AOT_JDK_CONF).$(jtool) --help \ - )) - ) - - $$(info AOT: Copy $(JDK_UNDER_TEST)/lib/classlist to $$($1_AOT_JDK_CONF).jdk ) + $$(call LogWarn, AOT: Create cache configuration) \ $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/aot, ( \ - $$(FIXPATH) $(CP) $(JDK_UNDER_TEST)/lib/classlist $$($1_AOT_JDK_CONF).jdk \ + $(CD) $(TEST_IMAGE_DIR)/setup_aot; \ + $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ + -Xlog:cds,cds+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error \ + -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ + TestSetupAOT > $$($1_AOT_JDK_LOG) \ )) - $$(FIXPATH) $$(CAT) $$($1_AOT_JDK_CONF).* > $$($1_AOT_JDK_CONF).temp - $$(FIXPATH) $$(CAT) $$($1_AOT_JDK_CONF).temp | $(GREP) -v '#' | $(GREP) -v '@' | $(SORT) | \ - $(SED) -e 's/id:.*//g' | uniq \ - > $$($1_AOT_JDK_CONF) - $$(FIXPATH) $$(CAT) $$($1_AOT_JDK_CONF).temp | $(GREP) '@cp' | $(SORT) \ - >> $$($1_AOT_JDK_CONF) - - $$(info AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) + $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/aot, ( \ - $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ - $$($1_VM_OPTIONS) -Xlog:cds,cds+class=debug:file=$$($1_AOT_JDK_CACHE).log \ - -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ + $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ + $$($1_VM_OPTIONS) -Xlog:cds,cds+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error \ + -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ + -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ )) $1_AOT_TARGETS += $$($1_AOT_JDK_CACHE) endef - SetupRunJtregTest = $(NamedParamsMacroTemplate) define SetupRunJtregTestBody $1_TEST_RESULTS_DIR := $$(TEST_RESULTS_DIR)/$1 @@ -946,11 +948,10 @@ define SetupRunJtregTestBody endif ifeq ($$(JTREG_AOT_JDK), true) - $$(info Add AOT target for $1) - $$(eval $$(call SetupAot, $1, VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) + $$(call LogWarn, Add AOT target for $1) + $$(eval $$(call SetupAOT, $1, VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) - $$(info AOT_TARGETS=$$($1_AOT_TARGETS)) - $$(info AOT_JDK_CACHE=$$($1_AOT_JDK_CACHE)) + $$(call LogWarn, AOT_JDK_CACHE=$$($1_AOT_JDK_CACHE)) $1_JTREG_BASIC_OPTIONS += -vmoption:-XX:AOTCache="$$($1_AOT_JDK_CACHE)" endif diff --git a/make/test/BuildTestSetupAOT.gmk b/make/test/BuildTestSetupAOT.gmk new file mode 100644 index 00000000000..46b18005366 --- /dev/null +++ b/make/test/BuildTestSetupAOT.gmk @@ -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. 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 MakeFileStart.gmk + +################################################################################ +# This file builds the TestSetupAOT.class, which is used by SetupAOT +# in ../RunTests.gmk +################################################################################ + +include CopyFiles.gmk +include JavaCompilation.gmk + +################################################################################ + +SETUP_AOT_BASEDIR := $(TOPDIR)/test/setup_aot +SETUP_AOT_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/setup_aot +SETUP_AOT_CLASS := $(SETUP_AOT_SUPPORT)/classes/TestSetupAOT.class + +$(eval $(call SetupJavaCompilation, BUILD_SETUP_AOT, \ + TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ + SRC := $(SETUP_AOT_BASEDIR), \ + BIN := $(SETUP_AOT_SUPPORT)/classes, \ +)) + +TARGETS += $(BUILD_SETUP_AOT) + +################################################################################ +# Targets for building test-image. +################################################################################ + +# Copy to hotspot jtreg test image +$(eval $(call SetupCopyFiles, COPY_SETUP_AOT, \ + SRC := $(SETUP_AOT_SUPPORT)/classes, \ + DEST := $(TEST_IMAGE_DIR)/setup_aot, \ + FILES := TestSetupAOT.class, \ +)) + +IMAGES_TARGETS += $(COPY_SETUP_AOT) + +images: $(IMAGES_TARGETS) + +.PHONY: images + +################################################################################ + +include MakeFileEnd.gmk diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 1b4b6ffb22c..9a5ac12b475 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -443,10 +443,9 @@ void ClassListParser::print_diagnostic_info(outputStream* st, const char* msg, v error_index = 0; } - jio_fprintf(defaultStream::error_stream(), - "An error has occurred while processing class list file %s %zu:%d.\n", - _classlist_file, lineno(), (error_index + 1)); - jio_vfprintf(defaultStream::error_stream(), msg, ap); + st->print("An error has occurred while processing class list file %s %zu:%d.\n", + _classlist_file, lineno(), (error_index + 1)); + st->vprint(msg, ap); if (_line_len <= 0) { st->print("\n"); diff --git a/test/setup_aot/TestSetupAOT.java b/test/setup_aot/TestSetupAOT.java new file mode 100644 index 00000000000..1cae8bae246 --- /dev/null +++ b/test/setup_aot/TestSetupAOT.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. + */ + +import java.util.spi.ToolProvider; + +// This program is executed by make/RunTests.gmk to support running HotSpot tests +// in the "AOT mode", for example: +// +// make test JTREG=AOT_JDK=true TEST=open/test/hotspot/jtreg/runtime/invokedynamic +// +// All JDK classes touched by this program will be stored into a customized AOT cache. +// This is a larger set of classes than those stored in the JDK's default CDS archive. +// This customized cache can also have additional optimizations that are not +// enabled in the default CDS archive. For example, AOT-linked classes and lambda +// expressions. In the future, it can also contain AOT profiles and AOT compiled methods. +// +// We can use this customized AOT cache to run various HotSpot tests to improve +// coverage on AOT. +// +// Note that make/RunTests.gmk loads this class using an implicit classpath of ".", so +// this class will be excluded from the customized AOT cache. As a result, +// the customized AOT cache contains *only* classes from the JDK itself. + +public class TestSetupAOT { + public static void main(String[] args) throws Throwable { + String[] tools = { + "javac", "javap", "jlink", "jar", + }; + // TODO: we should do more substantial work than just running with "--help". + // E.g., use javac to compile a program. + for (String tool : tools) { + ToolProvider t = ToolProvider.findFirst(tool) + .orElseThrow(() -> new RuntimeException(tool + " not found")); + t.run(System.out, System.out, "--help"); + } + } +} From 00d4e4a9710f89506f36156c24b0f3c5412971fa Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 20 Feb 2025 02:51:24 +0000 Subject: [PATCH 068/587] 8350051: [JMH] Several tests fails NPE Reviewed-by: erikj, redestad --- make/test/BuildMicrobenchmark.gmk | 13 ++++++++++++- .../openjdk/bench/javax/xml/AbstractXMLMicro.java | 6 ++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 53ee942d5d0..92f40472c3c 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -122,9 +122,20 @@ $(JMH_UNPACKED_JARS_DONE): $(JMH_RUNTIME_JARS) $(RM) $(JMH_UNPACKED_DIR)/*.xml $(TOUCH) $@ +# Copy dependency files for inclusion in the benchmark JARs +$(eval $(call SetupCopyFiles, COPY_JAXP_TEST_XML, \ + SRC := $(TOPDIR)/test/jaxp/javax/xml/jaxp/unittest, \ + DEST := $(MICROBENCHMARK_CLASSES)/org/openjdk/bench/javax/xml, \ + FILES := \ + stream/XMLStreamWriterTest/message_12.xml \ + validation/tck/reZ003vExc23082309.xml \ + transform/msgAttach.xml, \ + FLATTEN := true, \ +)) + # Create benchmarks JAR file with benchmarks for both the old and new JDK $(eval $(call SetupJarArchive, BUILD_JDK_JAR, \ - DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE), \ + DEPENDENCIES := $(BUILD_JDK_MICROBENCHMARK) $(JMH_UNPACKED_JARS_DONE) $(COPY_JAXP_TEST_XML), \ SRCS := $(MICROBENCHMARK_CLASSES) $(JMH_UNPACKED_DIR), \ BIN := $(MICROBENCHMARK_JAR_BIN), \ SUFFIXES := .*, \ diff --git a/test/micro/org/openjdk/bench/javax/xml/AbstractXMLMicro.java b/test/micro/org/openjdk/bench/javax/xml/AbstractXMLMicro.java index 9d7955f3981..95593b38b3b 100644 --- a/test/micro/org/openjdk/bench/javax/xml/AbstractXMLMicro.java +++ b/test/micro/org/openjdk/bench/javax/xml/AbstractXMLMicro.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 @@ -38,15 +38,13 @@ import java.util.concurrent.ConcurrentHashMap; @State(Scope.Benchmark) public abstract class AbstractXMLMicro { - public static final String BUILDIMPL = "build-impl.xml"; - public static final String LOGCOMP = "log_comp.xml"; public static final String MESSAGE12 = "message_12.xml"; public static final String MSGATTACH = "msgAttach.xml"; public static final String REZ = "reZ003vExc23082309.xml"; protected static final ConcurrentHashMap byteCache = new ConcurrentHashMap<>(); - @Param({BUILDIMPL,LOGCOMP,MESSAGE12,MSGATTACH,REZ}) + @Param({MESSAGE12,MSGATTACH,REZ}) protected String doc; /** From 26bf445f4726f1936a0a4cbaf1424c5235424bfb Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 20 Feb 2025 07:24:51 +0000 Subject: [PATCH 069/587] 8350049: [JMH] Float16OperationsBenchmark fails java.lang.NoClassDefFoundError Reviewed-by: jbhateja --- .../bench/jdk/incubator/vector/Float16OperationsBenchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java index ca8c0edfc74..a0a462ad6b1 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java @@ -31,7 +31,7 @@ import static java.lang.Float.*; @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector", "-Xbatch", "-XX:-TieredCompilation"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector", "-Xbatch", "-XX:-TieredCompilation"}) public class Float16OperationsBenchmark { @Param({"256", "512", "1024", "2048"}) int vectorDim; From c5c91a82931d8bd3aa4dc1568162097ef4b66ce0 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Thu, 20 Feb 2025 08:53:19 +0000 Subject: [PATCH 070/587] 8345285: [s390x] test failures: foreign/normalize/TestNormalize.java with C2 Reviewed-by: mdoerr, aph --- src/hotspot/cpu/s390/abstractInterpreter_s390.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp index bddac3953a1..37aa9d9a0e8 100644 --- a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp +++ b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp @@ -190,7 +190,7 @@ void AbstractInterpreter::layout_activation(Method* method, assert(is_bottom_frame && (sender_sp == caller->unextended_sp()), "must initialize sender_sp of bottom skeleton frame when pushing it"); } else { - assert(caller->is_entry_frame(), "is there a new frame type??"); + assert(caller->is_entry_frame() || caller->is_upcall_stub_frame(), "is there a new frame type??"); sender_sp = caller->sp(); // Call_stub only uses it's fp. } @@ -200,6 +200,8 @@ void AbstractInterpreter::layout_activation(Method* method, interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor); *interpreter_frame->interpreter_frame_cache_addr() = method->constants()->cache(); interpreter_frame->interpreter_frame_set_tos_address(tos); - interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); + if (!is_bottom_frame) { + interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); + } interpreter_frame->interpreter_frame_set_top_frame_sp(top_frame_sp); } From 0662e39a6ef722f6e09383566648c794a47ebabe Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 20 Feb 2025 08:58:18 +0000 Subject: [PATCH 071/587] 8350267: Set mtune and mcpu settings in JDK native lib compilation on Linux ppc64(le) Reviewed-by: mdoerr, asteiner, erikj --- make/autoconf/flags-cflags.m4 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 1674d10fa91..857e2b65e57 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -715,11 +715,13 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], if test "x$FLAGS_CPU" = xppc64; then # -mminimal-toc fixes `relocation truncated to fit' error for gcc 4.1. # Use ppc64 instructions, but schedule for power5 - $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -mminimal-toc -mcpu=powerpc64 -mtune=power5" + $1_CFLAGS_CPU="-mcpu=powerpc64 -mtune=power5" + $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -mminimal-toc" elif test "x$FLAGS_CPU" = xppc64le; then # Little endian machine uses ELFv2 ABI. # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. - $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2 -mcpu=power8 -mtune=power10" + $1_CFLAGS_CPU="-mcpu=power8 -mtune=power10" + $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -DABI_ELFv2" fi elif test "x$FLAGS_CPU" = xs390x; then $1_CFLAGS_CPU="-mbackchain -march=z10" From 86d0616276c0a8d60c3b7ff79ade6c83ff0c72a2 Mon Sep 17 00:00:00 2001 From: Hao Sun Date: Thu, 20 Feb 2025 09:03:53 +0000 Subject: [PATCH 072/587] 8350303: ARM32: StubCodeGenerator::verify_stub(StubGenStubId) failed after JDK-8343767 Reviewed-by: shade, adinn --- src/hotspot/share/runtime/stubDeclarations.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index 6930ded7fb8..804bdc579b1 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -552,6 +552,8 @@ catch_exception_entry) \ do_stub(initial, fence) \ do_entry(initial, fence, fence_entry, fence_entry) \ + do_stub(initial, atomic_add) \ + do_entry(initial, atomic_add, atomic_add_entry, atomic_add_entry) \ do_stub(initial, atomic_xchg) \ do_entry(initial, atomic_xchg, atomic_xchg_entry, atomic_xchg_entry) \ do_stub(initial, atomic_cmpxchg) \ @@ -638,8 +640,6 @@ do_arch_blob, \ do_arch_entry, do_arch_entry_init) \ do_blob(compiler) \ - do_stub(compiler, atomic_add) \ - do_entry(compiler, atomic_add, atomic_add_entry, atomic_add_entry) \ do_stub(compiler, array_sort) \ do_entry(compiler, array_sort, array_sort, select_arraysort_function) \ do_stub(compiler, array_partition) \ From 1e87ff01994df16df7de331040fc5d7a4a85f630 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 20 Feb 2025 09:17:40 +0000 Subject: [PATCH 073/587] 8348936: [Accessibility,macOS,VoiceOver] VoiceOver doesn't announce untick on toggling the checkbox with "space" key on macOS 8345728: [Accessibility,macOS,Screen Magnifier]: JCheckbox unchecked state does not magnify but works for checked state Reviewed-by: aivanov, kizune, dnguyen, asemenov --- .../classes/sun/lwawt/macosx/CAccessible.java | 7 +- .../TestJCheckBoxToggleAccessibility.java | 129 ++++++++++++++++++ 2 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/accessibility/TestJCheckBoxToggleAccessibility.java diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index 779423bc28f..8f67a06a13d 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.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 @@ -28,6 +28,7 @@ package sun.lwawt.macosx; import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Objects; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -182,7 +183,7 @@ class CAccessible extends CFRetainedResource implements Accessible { // Do send check box state changes to native side if (thisRole == AccessibleRole.CHECK_BOX) { - if (newValue != null && !newValue.equals(oldValue)) { + if (!Objects.equals(newValue, oldValue)) { valueChanged(ptr); } @@ -208,7 +209,7 @@ class CAccessible extends CFRetainedResource implements Accessible { // Do send toggle button state changes to native side if (thisRole == AccessibleRole.TOGGLE_BUTTON) { - if (newValue != null && !newValue.equals(oldValue)) { + if (!Objects.equals(newValue, oldValue)) { valueChanged(ptr); } } diff --git a/test/jdk/javax/accessibility/TestJCheckBoxToggleAccessibility.java b/test/jdk/javax/accessibility/TestJCheckBoxToggleAccessibility.java new file mode 100644 index 00000000000..2a1d03117b7 --- /dev/null +++ b/test/jdk/javax/accessibility/TestJCheckBoxToggleAccessibility.java @@ -0,0 +1,129 @@ +/* + * 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.BorderLayout; +import java.awt.GridLayout; + +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JToggleButton; + +/* + * @test + * @bug 8348936 8345728 + * @summary Verifies that VoiceOver announces the untick state of CheckBox and + * ToggleButton when space key is pressed. Also verifies that CheckBox + * and ToggleButton untick state is magnified with Screen Magnifier. + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestJCheckBoxToggleAccessibility + */ + +public class TestJCheckBoxToggleAccessibility { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + +

Testing with VoiceOver

+ +
    +
  1. Start the VoiceOver application + (Press Command + F5) +
  2. Click on the Frame with CheckBox and ToggleButton + window to move focus +
  3. Press Spacebar +
  4. VO should announce the checked state +
  5. Press Spacebar again +
  6. VO should announce the unchecked state +
  7. Press Tab to move focus to ToggleButton +
  8. Repeat steps 3 to 6 and listen the announcement +
  9. If announcements are incorrect, press Fail +
  10. Stop the VoiceOver application + (Press Command + F5 again) +
+ +

Testing with Screen Magnifier

+
    +
  1. Enable Screen magnifier on the Mac: + System Settings -> Accessibility -> + Hover Text -> Enable Hover Text
    + Default Hover Text Activation Modifier is Command key +
  2. Move focus back to the test application and perform the following tests + +
      +
    • Test CheckBox states with Screen Magnifier +
        +
      1. Click on CheckBox to select it +
      2. Press the Command key and + hover mouse over CheckBox +
      3. CheckBox ticked state along with its label should be magnified +
      4. Keep the Command key pressed and + click CheckBox to deselect it +
      5. CheckBox unticked state along with its label should be magnified +
      6. Release the Command key +
      7. If Screen Magnifier behaviour is incorrect, press Fail +
      +
    • Test ToggleButton states with Screen Magnifier +
        +
      1. Click on ToggleButton to select it +
      2. Press the Command key and + hover mouse over ToggleButton +
      3. Ticked state along with label should be magnified +
      4. Keep the Command button pressed and + click ToggleButton to deselect it +
      5. Unticked state along with its label should be magnified +
      6. Release the Command key +
      7. If Screen Magnifier behaviour is incorrect, press Fail +
      +
    +
  3. Disable Hover Text (optionally) in the Settings +
+ +

Press Pass if you are able to hear correct VoiceOver announcements and + able to see the correct screen magnifier behaviour.

"""; + + PassFailJFrame.builder() + .title("TestJCheckBoxToggleAccessibility Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .rows(25) + .testUI(TestJCheckBoxToggleAccessibility::createUI) + .testTimeOut(8) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame frame = new JFrame("A Frame with CheckBox and ToggleButton"); + JCheckBox cb = new JCheckBox("CheckBox", false); + JToggleButton tb = new JToggleButton("ToggleButton"); + + JPanel p = new JPanel(new GridLayout(2, 1)); + p.add(cb); + p.add(tb); + frame.getContentPane().add(p, BorderLayout.CENTER); + frame.setSize(400, 400); + return frame; + } +} From 735805d9259037ae594eb4f75e96860d43feea5d Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Thu, 20 Feb 2025 12:03:08 +0000 Subject: [PATCH 074/587] 8349727: [PPC] C1: Improve Class.isInstance intrinsic Reviewed-by: rrich, varadam --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 17 +++--- src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp | 3 +- src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp | 67 +++++++++++++++++++++ src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 31 +++++----- 4 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 67a4a65b871..cae192982d5 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2839,25 +2839,28 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { - // Stubs: Called via rt_call, but dest is a stub address (no function descriptor). + // Stubs: Called via rt_call, but dest is a stub address (no FunctionDescriptor). if (dest == Runtime1::entry_for(C1StubId::register_finalizer_id) || - dest == Runtime1::entry_for(C1StubId::new_multi_array_id )) { + dest == Runtime1::entry_for(C1StubId::new_multi_array_id ) || + dest == Runtime1::entry_for(C1StubId::is_instance_of_id )) { + assert(CodeCache::contains(dest), "simplified call is only for special C1 stubs"); //__ load_const_optimized(R0, dest); __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest)); __ mtctr(R0); __ bctrl(); - assert(info != nullptr, "sanity"); - add_call_info_here(info); - __ post_call_nop(); + if (info != nullptr) { + add_call_info_here(info); + __ post_call_nop(); + } return; } __ call_c(dest, relocInfo::runtime_call_type); + assert(__ last_calls_return_pc() == __ pc(), "pcn not at return pc"); if (info != nullptr) { add_call_info_here(info); + __ post_call_nop(); } - assert(__ last_calls_return_pc() == __ pc(), "pcn not at return pc"); - __ post_call_nop(); } diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index d9ccf63bed3..b9c8ced8ef1 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -1128,9 +1128,10 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { x->profiled_method(), x->profiled_bci()); } + // Intrinsic for Class::isInstance address LIRGenerator::isInstance_entry() { - return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of); + return Runtime1::entry_for(C1StubId::is_instance_of_id); } diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index b1ee11317d2..11c01dcdc60 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -609,6 +609,73 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { } break; + case C1StubId::is_instance_of_id: + { + // Called like a C function, but without FunctionDescriptor (see LIR_Assembler::rt_call). + + // Arguments and return value. + Register mirror = R3_ARG1; + Register obj = R4_ARG2; + Register result = R3_RET; + + // Other argument registers can be used as temp registers. + Register klass = R5; + Register offset = R6; + Register sub_klass = R7; + + Label is_secondary, success; + + // Get the Klass*. + __ ld(klass, java_lang_Class::klass_offset(), mirror); + + // Return false if obj or klass is null. + mirror = noreg; // killed by next instruction + __ li(result, 0); // assume result is false + __ cmpdi(CR0, obj, 0); + __ cmpdi(CR1, klass, 0); + __ cror(CR0, Assembler::equal, CR1, Assembler::equal); + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + + __ lwz(offset, in_bytes(Klass::super_check_offset_offset()), klass); + __ load_klass(sub_klass, obj); + __ cmpwi(CR0, offset, in_bytes(Klass::secondary_super_cache_offset())); + __ beq(CR0, is_secondary); // Klass is a secondary superclass + + // Klass is a concrete class + __ ldx(R0, sub_klass, offset); + __ cmpd(CR0, klass, R0); + if (VM_Version::has_brw()) { + // Power10 can set the result by one instruction. No need for a branch. + __ setbc(result, CR0, Assembler::equal); + } else { + __ beq(CR0, success); + } + __ blr(); + + __ bind(is_secondary); + + // This is necessary because I am never in my own secondary_super list. + __ cmpd(CR0, sub_klass, klass); + __ beq(CR0, success); + + __ lookup_secondary_supers_table_var(sub_klass, klass, + /*temps*/R9, R10, R11, R12, + /*result*/R8); + __ cmpdi(CR0, R8, 0); // 0 means is subclass + if (VM_Version::has_brw()) { + // Power10 can set the result by one instruction. No need for a branch. + __ setbc(result, CR0, Assembler::equal); + } else { + __ beq(CR0, success); + } + __ blr(); + + __ bind(success); + __ li(result, 1); + __ blr(); + } + break; + case C1StubId::monitorenter_nofpu_id: case C1StubId::monitorenter_id: { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 1267fa0e516..6bdb4f80266 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2265,27 +2265,28 @@ void MacroAssembler::check_klass_subtype(Register sub_klass, // generic (count must be >0) // iff found: CR0 eq, scratch == 0 void MacroAssembler::repne_scan(Register addr, Register value, Register count, Register scratch) { - Label Lloop, Lexit; + Label Lloop, Lafter_loop, Lexit; -#ifdef ASSERT - { - Label ok; - cmpdi(CR0, count, 0); - bgt(CR0, ok); - stop("count must be positive"); - bind(ok); - } -#endif + srdi_(scratch, count, 1); + beq(CR0, Lafter_loop); + mtctr(scratch); - mtctr(count); - - bind(Lloop); - ld(scratch, 0 , addr); + bind(Lloop); // 2x unrolled + ld(scratch, 0, addr); xor_(scratch, scratch, value); beq(CR0, Lexit); - addi(addr, addr, wordSize); + ld(scratch, 8, addr); + xor_(scratch, scratch, value); + beq(CR0, Lexit); + addi(addr, addr, 2 * wordSize); bdnz(Lloop); + bind(Lafter_loop); + andi_(scratch, count, 1); + beq(CR0, Lexit); // if taken: CR0 eq and scratch == 0 + ld(scratch, 0, addr); + xor_(scratch, scratch, value); + bind(Lexit); } From 960ad211867d65a993b2fc4e6dafa8cea9827b3f Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 20 Feb 2025 15:47:54 +0000 Subject: [PATCH 075/587] 8349620: Add VMProps for static JDK Reviewed-by: alanb, manc --- src/hotspot/share/prims/whitebox.cpp | 8 +++++++- test/hotspot/jtreg/TEST.ROOT | 3 ++- test/hotspot/jtreg/runtime/modules/ModulesSymLink.java | 1 + test/jdk/TEST.ROOT | 3 ++- test/jtreg-ext/requires/VMProps.java | 5 +++++ test/lib/jdk/test/whitebox/WhiteBox.java | 2 ++ 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 686797f8dd6..a612a3d55a9 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -47,6 +47,7 @@ #include "gc/shared/gcConfig.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genArguments.hpp" +#include "jvm.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" @@ -1804,6 +1805,10 @@ WB_ENTRY(jlong, WB_RootChunkWordSize(JNIEnv* env)) return (jlong)Metaspace::reserve_alignment_words(); WB_END +WB_ENTRY(jboolean, WB_IsStaticallyLinked(JNIEnv* env, jobject wb)) + return JVM_IsStaticallyLinked(); +WB_END + ////////////// WB_ENTRY(jlong, WB_AllocateMetaspace(JNIEnv* env, jobject wb, jobject class_loader, jlong size)) @@ -3003,7 +3008,8 @@ static JNINativeMethod methods[] = { {CC"printString", CC"(Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_PrintString}, {CC"lockAndStuckInSafepoint", CC"()V", (void*)&WB_TakeLockAndHangInSafepoint}, {CC"wordSize", CC"()J", (void*)&WB_WordSize}, - {CC"rootChunkWordSize", CC"()J", (void*)&WB_RootChunkWordSize} + {CC"rootChunkWordSize", CC"()J", (void*)&WB_RootChunkWordSize}, + {CC"isStatic", CC"()Z", (void*)&WB_IsStaticallyLinked} }; diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index ac4321e6839..ffc70d1bb18 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -92,7 +92,8 @@ requires.properties= \ systemd.support \ jdk.containerized \ jlink.runtime.linkable \ - jlink.packagedModules + jlink.packagedModules \ + jdk.static # Minimum jtreg version requiredVersion=7.5.1+1 diff --git a/test/hotspot/jtreg/runtime/modules/ModulesSymLink.java b/test/hotspot/jtreg/runtime/modules/ModulesSymLink.java index f19897f9638..18d618cf8bc 100644 --- a/test/hotspot/jtreg/runtime/modules/ModulesSymLink.java +++ b/test/hotspot/jtreg/runtime/modules/ModulesSymLink.java @@ -27,6 +27,7 @@ * @bug 8220095 * @requires os.family == "linux" | os.family == "mac" * @requires vm.flagless + * @requires !jdk.static * @library /test/lib * @modules java.management * jdk.jlink diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 3b0b824b36f..91c44bc4d05 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -111,7 +111,8 @@ requires.properties= \ jdk.containerized \ jdk.foreign.linker \ jlink.runtime.linkable \ - jlink.packagedModules + jlink.packagedModules \ + jdk.static # Minimum jtreg version requiredVersion=7.5.1+1 diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 7e4553f0611..6f8beff8cf9 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -140,6 +140,7 @@ public class VMProps implements Callable> { map.put("vm.flagless", this::isFlagless); map.put("jdk.foreign.linker", this::jdkForeignLinker); map.put("jlink.packagedModules", this::packagedModules); + map.put("jdk.static", this::isStatic); vmGC(map); // vm.gc.X = true/false vmGCforCDS(map); // may set vm.gc vmOptFinalFlags(map); @@ -820,6 +821,10 @@ public class VMProps implements Callable> { return String.valueOf(CABI.current()); } + private String isStatic() { + return Boolean.toString(WB.isStatic()); + } + /** * Dumps the map to the file if the file name is given as the property. * This functionality could be helpful to know context in the real diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 41ad60a7c4b..7222c6fedcf 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -798,4 +798,6 @@ public class WhiteBox { public native void preTouchMemory(long addr, long size); public native long rss(); + + public native boolean isStatic(); } From 10bf48a6b0b796b48cdca15250e1ee7e7be83c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 20 Feb 2025 15:50:24 +0000 Subject: [PATCH 076/587] 8350214: Test gtest/AsyncLogGtest.java fails after JDK-8349755 Reviewed-by: aboldtch, dholmes --- src/hotspot/share/logging/logAsyncWriter.cpp | 14 ++++++++++---- src/hotspot/share/logging/logAsyncWriter.hpp | 1 - src/hotspot/share/logging/logTag.hpp | 1 - src/hotspot/share/logging/logTagSet.cpp | 8 +------- src/hotspot/share/runtime/globals.hpp | 4 ++++ .../jtreg/runtime/logging/AsyncDeathTest.java | 15 +++++++++++---- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index 44758958dd3..737f001c049 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -30,8 +30,8 @@ #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" #include "runtime/os.inline.hpp" +#include "runtime/globals.hpp" -DEBUG_ONLY(bool AsyncLogWriter::ignore_recursive_logging = false;) class AsyncLogWriter::AsyncLogLocker : public StackObj { static Thread* _holder; @@ -116,10 +116,11 @@ bool AsyncLogWriter::is_enqueue_allowed() { // Do not log while holding the Async log lock. // Try to catch possible occurrences in debug builds. #ifdef ASSERT - if (!AsyncLogWriter::ignore_recursive_logging) { + if (!TestingAsyncLoggingDeathTestNoCrash) { ShouldNotReachHere(); } #endif // ASSERT + return false; } @@ -142,8 +143,13 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations& } AsyncLogLocker locker; - DEBUG_ONLY(log_debug(deathtest)("Induce a recursive log for testing (for crashing)");) - DEBUG_ONLY(log_debug(deathtest2)("Induce a recursive log for testing");) + +#ifdef ASSERT + if (TestingAsyncLoggingDeathTest || TestingAsyncLoggingDeathTestNoCrash) { + log_debug(deathtest)("Induce a recursive log for testing"); + } +#endif // ASSERT + AsyncLogWriter::instance()->enqueue_locked(&output, decorations, msg); return true; } diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index e2c8cb36e07..00818634bdd 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -198,7 +198,6 @@ class AsyncLogWriter : public NonJavaThread { static bool is_enqueue_allowed(); public: - DEBUG_ONLY(static bool ignore_recursive_logging;) static bool enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg); static bool enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator); diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index c3db84930ad..d61e2461e8d 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -69,7 +69,6 @@ class outputStream; LOG_TAG(datacreation) \ LOG_TAG(dcmd) \ DEBUG_ONLY(LOG_TAG(deathtest)) /* Log Internal death test tag */ \ - DEBUG_ONLY(LOG_TAG(deathtest2)) /* Log Internal death test tag */ \ LOG_TAG(decoder) \ LOG_TAG(defaultmethods) \ LOG_TAG(deoptimization) \ diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index 718627be3a5..f7b0e01331c 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -78,13 +78,7 @@ void LogTagSet::log(LogLevelType level, const char* msg) { // the implied memory order of Atomic::add(). LogOutputList::Iterator it = _output_list.iterator(level); LogDecorations decorations(level, *this, _decorators); -#ifdef ASSERT - // If we log for tag deathtest2 then we're testing that recursive logging works. - // In this case, do not crash when detecting recursive logging. - if (this->contains(LogTagType::_deathtest2)) { - AsyncLogWriter::ignore_recursive_logging = true; - } -#endif + for (; it != _output_list.end(); it++) { (*it)->write(decorations, msg); } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 11c13fe3c9e..d3bdb0c68b2 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -481,6 +481,10 @@ const int ObjectAlignmentInBytes = 8; \ develop(bool, ZapTLAB, trueInDebug, \ "Zap allocated TLABs") \ + develop(bool, TestingAsyncLoggingDeathTest, false, \ + "Recursive logging death test") \ + develop(bool, TestingAsyncLoggingDeathTestNoCrash, false, \ + "Recursive logging death test (no crash)") \ \ product(bool, ExecutingUnitTests, false, \ "Whether the JVM is running unit tests or not") \ diff --git a/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java b/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java index 2dff887f108..cd4a50f65c1 100644 --- a/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java +++ b/test/hotspot/jtreg/runtime/logging/AsyncDeathTest.java @@ -38,17 +38,24 @@ import jdk.test.lib.process.OutputAnalyzer; public class AsyncDeathTest { public static void main(String[] args) throws Exception { - // For deathtest we expect the VM to reach ShouldNotReachHere() and die + // TestingAsyncLoggingDeathTest is set: We expect the VM to reach ShouldNotReachHere() and die. ProcessBuilder pb = - ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest=debug", "-XX:-CreateCoredumpOnCrash", "--version"); + ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest=debug", "-XX:-CreateCoredumpOnCrash", "-XX:+TestingAsyncLoggingDeathTest", "--version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotHaveExitValue(0); output.shouldNotContain("Induce a recursive log for testing"); - // For deathtest2 we expect the VM to ignore that recursive logging has been detected and is handled by printing synchronously. + // TestingAsyncLoggingDeathTestNoCrash is set: We expect the VM to ignore that recursive logging has been detected and the logging should be handled by printing synchronously. ProcessBuilder pb2 = - ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest2=debug", "--version"); + ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:os,deathtest=debug", "-XX:+TestingAsyncLoggingDeathTestNoCrash" , "--version"); OutputAnalyzer output2 = new OutputAnalyzer(pb2.start()); output2.shouldHaveExitValue(0); output2.shouldContain("Induce a recursive log for testing"); + + // For -Xlog:all=debug but without any global set, the test should succeed and not contain the recursive message. + ProcessBuilder pb3 = + ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:async", "-Xlog:all=debug", "--version"); + OutputAnalyzer output3 = new OutputAnalyzer(pb3.start()); + output3.shouldHaveExitValue(0); + output3.shouldNotContain("Induce a recursive log for testing"); } } From 53db57648a09c4c380064eea11fcdb680011d741 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 20 Feb 2025 15:53:05 +0000 Subject: [PATCH 077/587] 8350137: After JDK-8348975, Linux builds contain man pages for windows only tools Reviewed-by: erikj --- make/Docs.gmk | 2 +- make/common/Modules.gmk | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index 5c67393fb66..be9efbdc370 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -673,7 +673,7 @@ ifeq ($(ENABLE_PANDOC), true) $(foreach m, $(ALL_MODULES), \ $(eval MAN_$m := $(call ApplySpecFilter, $(filter %.md, $(call FindFiles, \ - $(call FindModuleManDirs, $m))))) \ + $(call FindModuleManDirsForDocs, $m))))) \ $(if $(MAN_$m), \ $(eval $(call SetupProcessMarkdown, MAN_TO_HTML_$m, \ FILES := $(MAN_$m), \ diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 03548ca8778..f4f815c740d 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -87,7 +87,10 @@ SRC_SUBDIRS += share/classes SPEC_SUBDIRS += share/specs -MAN_SUBDIRS += share/man windows/man +MAN_SUBDIRS += share/man $(TARGET_OS)/man + +# The docs should include the sum of all man pages for all platforms +MAN_DOCS_SUBDIRS += share/man windows/man # Find all module-info.java files for the current build target platform and # configuration. @@ -153,6 +156,10 @@ FindModuleManDirs = \ $(strip $(wildcard \ $(foreach sub, $(MAN_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS))))) +FindModuleManDirsForDocs = \ + $(strip $(wildcard \ + $(foreach sub, $(MAN_DOCS_SUBDIRS), $(addsuffix /$(strip $1)/$(sub), $(TOP_SRC_DIRS))))) + # Construct the complete module source path GetModuleSrcPath = \ $(call PathList, \ From 16873732a752d79c3bf1bc450c63839997986d9e Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 20 Feb 2025 17:46:06 +0000 Subject: [PATCH 078/587] 8349933: Mixing of includes and snippets stack causes the wrong -post snippet to be included Reviewed-by: ihse --- make/common/MakeIncludeEnd.gmk | 6 +++--- make/common/MakeIncludeStart.gmk | 8 ++++---- make/common/MakeSnippetEnd.gmk | 6 +++--- make/common/MakeSnippetStart.gmk | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/make/common/MakeIncludeEnd.gmk b/make/common/MakeIncludeEnd.gmk index f0520d84b6c..7023a861fa1 100644 --- a/make/common/MakeIncludeEnd.gmk +++ b/make/common/MakeIncludeEnd.gmk @@ -34,12 +34,12 @@ ifneq ($(NO_CUSTOM_EXTENSIONS), true) endif # Pop our helper name off the stack -HELPER_STACK := $(wordlist 2, $(words $(HELPER_STACK)), $(HELPER_STACK)) +INCLUDE_STACK := $(wordlist 2, $(words $(INCLUDE_STACK)), $(INCLUDE_STACK)) # Print an indented message, also counting the top-level makefile as a level ifeq ($(LOG_FLOW), true) - $(info :$(foreach s, top $(HELPER_STACK), )Leave $(THIS_INCLUDE)) + $(info :$(foreach s, top $(INCLUDE_STACK) $(SNIPPET_STACK), )Leave $(THIS_INCLUDE)) endif # Restore the previous helper name -THIS_INCLUDE := $(firstword $(HELPER_STACK)) +THIS_INCLUDE := $(firstword $(INCLUDE_STACK)) diff --git a/make/common/MakeIncludeStart.gmk b/make/common/MakeIncludeStart.gmk index e754114211c..d09f027c1d3 100644 --- a/make/common/MakeIncludeStart.gmk +++ b/make/common/MakeIncludeStart.gmk @@ -39,11 +39,11 @@ else endif ifeq ($(LOG_FLOW), true) - $(info :$(foreach s, top $(HELPER_STACK), )Enter $(THIS_INCLUDE) [$(THIS_INCLUDE_MSG)]) + $(info :$(foreach s, top $(INCLUDE_STACK) $(SNIPPET_STACK), )Enter $(THIS_INCLUDE) [$(THIS_INCLUDE_MSG)]) endif -ifneq ($(filter $(THIS_INCLUDE), $(HELPER_STACK)), ) - $(error Internal makefile error: Include loop detected: $(THIS_INCLUDE) $(HELPER_STACK)) +ifneq ($(filter $(THIS_INCLUDE), $(INCLUDE_STACK)), ) + $(error Internal makefile error: Include loop detected: $(THIS_INCLUDE) $(INCLUDE_STACK)) endif ifeq ($(words $(MAKEFILE_LIST)), 2) @@ -66,7 +66,7 @@ ifneq ($(IS_PREINIT_ENV), true) endif # Push our helper name onto the stack -HELPER_STACK := $(THIS_INCLUDE) $(HELPER_STACK) +INCLUDE_STACK := $(THIS_INCLUDE) $(INCLUDE_STACK) # Setup an automatic include guard ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) diff --git a/make/common/MakeSnippetEnd.gmk b/make/common/MakeSnippetEnd.gmk index 833df2e9edb..7b46310330a 100644 --- a/make/common/MakeSnippetEnd.gmk +++ b/make/common/MakeSnippetEnd.gmk @@ -34,12 +34,12 @@ ifneq ($(NO_CUSTOM_EXTENSIONS), true) endif # Pop our helper name off the stack -HELPER_STACK := $(wordlist 2, $(words $(HELPER_STACK)), $(HELPER_STACK)) +SNIPPET_STACK := $(wordlist 2, $(words $(SNIPPET_STACK)), $(SNIPPET_STACK)) # Print an indented message, also counting the top-level makefile as a level ifeq ($(LOG_FLOW), true) - $(info :$(foreach s, top $(HELPER_STACK), )Leave $(THIS_SNIPPET)) + $(info :$(foreach s, top $(INCLUDE_STACK) $(SNIPPET_STACK), )Leave $(THIS_SNIPPET)) endif # Restore the previous helper name -THIS_SNIPPET := $(firstword $(HELPER_STACK)) +THIS_SNIPPET := $(firstword $(SNIPPET_STACK)) diff --git a/make/common/MakeSnippetStart.gmk b/make/common/MakeSnippetStart.gmk index dfe7f9f0007..1df5a1e20cb 100644 --- a/make/common/MakeSnippetStart.gmk +++ b/make/common/MakeSnippetStart.gmk @@ -33,11 +33,11 @@ endif # Print an indented message, also counting the top-level makefile as a level ifeq ($(LOG_FLOW), true) - $(info :$(foreach s, top $(HELPER_STACK), )Enter $(THIS_SNIPPET) [snippet]) + $(info :$(foreach s, top $(INCLUDE_STACK) $(SNIPPET_STACK), )Enter $(THIS_SNIPPET) [snippet]) endif # Push our helper name onto the stack -HELPER_STACK := $(THIS_SNIPPET) $(HELPER_STACK) +SNIPPET_STACK := $(THIS_SNIPPET) $(SNIPPET_STACK) # Hook to include the corresponding custom file, if present. ifneq ($(NO_CUSTOM_EXTENSIONS), true) From 1eb0db37608ae1dd05accc1e22c57d76fa2c72ce Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 20 Feb 2025 18:00:33 +0000 Subject: [PATCH 079/587] 8350151: Support requires property to filter tests incompatible with --enable-preview Reviewed-by: alanb, rriggs --- test/hotspot/jtreg/TEST.ROOT | 7 +++++-- test/jdk/TEST.ROOT | 8 ++++++-- .../invoke/defineHiddenClass/PreviewHiddenClass.java | 3 ++- test/jtreg-ext/requires/VMProps.java | 5 +++++ test/langtools/TEST.ROOT | 12 +++++++++--- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index ffc70d1bb18..b48a86d4d6d 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -46,13 +46,16 @@ requires.extraPropDefns.bootlibs = ../../lib/jdk/test/whitebox requires.extraPropDefns.libs = \ ../../lib/jdk/test/lib/Platform.java \ ../../lib/jdk/test/lib/Container.java -requires.extraPropDefns.javacOpts = --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED +requires.extraPropDefns.javacOpts = \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.extraPropDefns.vmOpts = \ -XX:+UnlockDiagnosticVMOptions \ -XX:+LogVMOutput -XX:-DisplayVMOutput -XX:LogFile=vmprops.flags.final.vm.log \ -XX:+PrintFlagsFinal \ -XX:+WhiteBoxAPI \ - --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.properties= \ sun.arch.data.model \ vm.simpleArch \ diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 91c44bc4d05..30e2f7cab41 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -74,16 +74,20 @@ requires.extraPropDefns.bootlibs = ../lib/jdk/test/whitebox requires.extraPropDefns.libs = \ ../lib/jdk/test/lib/Platform.java \ ../lib/jdk/test/lib/Container.java -requires.extraPropDefns.javacOpts = --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED +requires.extraPropDefns.javacOpts = \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.extraPropDefns.vmOpts = \ -XX:+UnlockDiagnosticVMOptions \ -XX:+LogVMOutput -XX:-DisplayVMOutput -XX:LogFile=vmprops.flags.final.vm.log \ -XX:+PrintFlagsFinal \ -XX:+WhiteBoxAPI \ - --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.properties= \ sun.arch.data.model \ java.runtime.name \ + java.enablePreview \ vm.flagless \ vm.gc.G1 \ vm.gc.Serial \ diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java index 3b572c6581b..fddbb348517 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.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 @@ -26,6 +26,7 @@ * @bug 8245432 * @modules jdk.compiler * @library /test/lib + * @requires !java.enablePreview * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils * @run testng PreviewHiddenClass diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 6f8beff8cf9..5f74ffa6ea6 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -50,6 +50,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.internal.foreign.CABI; +import jdk.internal.misc.PreviewFeatures; import jdk.test.whitebox.code.Compiler; import jdk.test.whitebox.cpuinfo.CPUInfo; import jdk.test.whitebox.gc.GC; @@ -129,6 +130,7 @@ public class VMProps implements Callable> { map.put("vm.graal.enabled", this::isGraalEnabled); // jdk.hasLibgraal is true if the libgraal shared library file is present map.put("jdk.hasLibgraal", this::hasLibgraal); + map.put("java.enablePreview", this::isPreviewEnabled); map.put("vm.libgraal.jit", this::isLibgraalJIT); map.put("vm.compiler1.enabled", this::isCompiler1Enabled); map.put("vm.compiler2.enabled", this::isCompiler2Enabled); @@ -586,6 +588,9 @@ public class VMProps implements Callable> { return "" + Compiler.isC2Enabled(); } + protected String isPreviewEnabled() { + return "" + PreviewFeatures.isEnabled(); + } /** * A simple check for container support * diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index c6c79ac81df..9b1c5368e66 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -37,10 +37,16 @@ requires.extraPropDefns.bootlibs = ../lib/jdk/test/whitebox requires.extraPropDefns.libs = \ ../lib/jdk/test/lib/Platform.java \ ../lib/jdk/test/lib/Container.java -requires.extraPropDefns.javacOpts = --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED +requires.extraPropDefns.javacOpts = \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.extraPropDefns.vmOpts = \ - -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI \ - --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED + -XX:+UnlockDiagnosticVMOptions \ + -XX:+LogVMOutput -XX:-DisplayVMOutput -XX:LogFile=vmprops.flags.final.vm.log \ + -XX:+PrintFlagsFinal \ + -XX:+WhiteBoxAPI \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED requires.properties= \ vm.continuations \ vm.debug From f979f727b6137be9a3f85baed4fbfdd785970044 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Thu, 20 Feb 2025 18:52:30 +0000 Subject: [PATCH 080/587] 8337723: Remove redundant tests from com/sun/security/sasl/gsskerb Reviewed-by: rhalade --- test/jdk/ProblemList.txt | 3 - test/jdk/TEST.groups | 3 - .../sun/security/sasl/gsskerb/AuthOnly.java | 165 --------------- .../sasl/gsskerb/ConfSecurityLayer.java | 196 ----------------- .../sasl/gsskerb/NoSecurityLayer.java | 199 ------------------ .../PropertiesFileCallbackHandler.java | 145 ------------- .../sun/security/sasl/gsskerb/gsseg_jaas.conf | 21 -- .../sun/security/sasl/gsskerb/log.properties | 3 - .../security/sasl/gsskerb/run-conf-wjaas.csh | 29 --- .../security/sasl/gsskerb/run-nosec-wjaas.csh | 24 --- .../sun/security/sasl/gsskerb/runwjaas.csh | 24 --- .../jdk/sun/security/krb5/auto/SaslBasic.java | 97 +++++++-- 12 files changed, 75 insertions(+), 834 deletions(-) delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/AuthOnly.java delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/ConfSecurityLayer.java delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/NoSecurityLayer.java delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/PropertiesFileCallbackHandler.java delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/gsseg_jaas.conf delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/log.properties delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/run-conf-wjaas.csh delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/run-nosec-wjaas.csh delete mode 100644 test/jdk/com/sun/security/sasl/gsskerb/runwjaas.csh diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index c6e62a55962..7472e4adad2 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -633,9 +633,6 @@ sun/security/smartcardio/TestExclusive.java 8039280 generic- sun/security/smartcardio/TestMultiplePresent.java 8039280 generic-all sun/security/smartcardio/TestPresent.java 8039280 generic-all sun/security/smartcardio/TestTransmit.java 8039280 generic-all -com/sun/security/sasl/gsskerb/AuthOnly.java 8039280 generic-all -com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic-all -com/sun/security/sasl/gsskerb/NoSecurityLayer.java 8039280 generic-all sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index d3b0b3009ca..7c009f557ad 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -631,9 +631,6 @@ jdk_security_manual_no_input = \ :jdk_security_infra \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ - com/sun/security/sasl/gsskerb/AuthOnly.java \ - com/sun/security/sasl/gsskerb/ConfSecurityLayer.java \ - com/sun/security/sasl/gsskerb/NoSecurityLayer.java \ sun/security/smartcardio/TestChannel.java \ sun/security/smartcardio/TestConnect.java \ sun/security/smartcardio/TestConnectAgain.java \ diff --git a/test/jdk/com/sun/security/sasl/gsskerb/AuthOnly.java b/test/jdk/com/sun/security/sasl/gsskerb/AuthOnly.java deleted file mode 100644 index c8e906d0ac1..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/AuthOnly.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -/* - * @test - * @bug 4634892 - * @summary Ensure authentication via GSS-API/Kerberos v5 works. - * @run main/manual AuthOnly - */ - -/* - * Set logging to FINEST to view exchange. - * See runwjaas.csh for instructions for how to run this test. - */ - -import javax.security.sasl.*; -import javax.security.auth.callback.*; -import javax.security.auth.Subject; -import javax.security.auth.login.*; -import com.sun.security.auth.callback.*; -import java.util.HashMap; -import java.util.concurrent.Callable; - -public class AuthOnly { - private static final String MECH = "GSSAPI"; - private static final String SERVER_FQDN = "machineX.imc.org"; - private static final String PROTOCOL = "sample"; - - private static String namesfile, proxyfile; - private static final byte[] EMPTY = new byte[0]; - private static boolean auto; - private static boolean verbose = false; - - public static void main(String[] args) throws Exception { - if (args.length == 0) { - namesfile = null; - auto = true; - } else { - int i = 0; - if (args[i].equals("-m")) { - i++; - auto = false; - } - if (args.length > i) { - namesfile = args[i++]; - if (args.length > i) { - proxyfile = args[i]; - } - } else { - namesfile = null; - } - } - - CallbackHandler clntCbh = null; - final CallbackHandler srvCbh = new PropertiesFileCallbackHandler( - null, namesfile, proxyfile); - - Subject clntSubj = doLogin("client"); - Subject srvSubj = doLogin("server"); - final HashMap clntprops = new HashMap(); - final HashMap srvprops = new HashMap(); - - clntprops.put(Sasl.QOP, "auth"); - srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf"); - - final SaslClient clnt = (SaslClient) - Subject.callAs(clntSubj, new Callable<>() { - public Object call() throws Exception { - return Sasl.createSaslClient( - new String[]{MECH}, null, PROTOCOL, SERVER_FQDN, - clntprops, null); - } - }); - - if (verbose) { - System.out.println(clntSubj); - System.out.println(srvSubj); - } - final SaslServer srv = (SaslServer) - Subject.callAs(srvSubj, new Callable() { - public Object call() throws Exception { - return Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN, - srvprops, srvCbh); - } - }); - - - if (clnt == null) { - throw new IllegalStateException( - "Unable to find client impl for " + MECH); - } - if (srv == null) { - throw new IllegalStateException( - "Unable to find server impl for " + MECH); - } - - byte[] response; - byte[] challenge; - - response = (byte[]) Subject.callAs(clntSubj, - () -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY)); - - while (!clnt.isComplete() || !srv.isComplete()) { - final byte[] responseCopy = response; - challenge = (byte[]) Subject.callAs(srvSubj, - () -> srv.evaluateResponse(responseCopy)); - - if (challenge != null) { - final byte[] challengeCopy = challenge; - response = (byte[]) Subject.callAs(clntSubj, - () -> clnt.evaluateChallenge(challengeCopy)); - } - } - - if (clnt.isComplete() && srv.isComplete()) { - if (verbose) { - System.out.println("SUCCESS"); - System.out.println("authzid is " + srv.getAuthorizationID()); - } - } else { - throw new IllegalStateException("FAILURE: mismatched state:" + - " client complete? " + clnt.isComplete() + - " server complete? " + srv.isComplete()); - } - } - - private static Subject doLogin(String msg) throws LoginException { - LoginContext lc = null; - if (verbose) { - System.out.println(msg); - } - try { - lc = new LoginContext(msg, new TextCallbackHandler()); - - // Attempt authentication - // You might want to do this in a "for" loop to give - // user more than one chance to enter correct username/password - lc.login(); - - } catch (LoginException le) { - throw le; - } - return lc.getSubject(); - } -} diff --git a/test/jdk/com/sun/security/sasl/gsskerb/ConfSecurityLayer.java b/test/jdk/com/sun/security/sasl/gsskerb/ConfSecurityLayer.java deleted file mode 100644 index 8a699a5920d..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/ConfSecurityLayer.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2004, 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. - */ - -/* - * @test - * @bug 5014493 - * @summary SaslServer.wrap throws NullPointerException when security - * layer negotiated. - * @run main/manual ConfSecurityLayer - */ - -/* - * Set logging to FINEST to view exchange. - * See run-conf-wjaas.csh for instructions for how to run this test. - */ - -import javax.security.sasl.*; -import javax.security.auth.callback.*; -import javax.security.auth.Subject; -import javax.security.auth.login.*; -import com.sun.security.auth.callback.*; -import java.util.HashMap; - -public class ConfSecurityLayer { - private static final String MECH = "GSSAPI"; - private static final String SERVER_FQDN = "machineX.imc.org"; - private static final String PROTOCOL = "sample"; - - private static String namesfile, proxyfile; - private static final byte[] EMPTY = new byte[0]; - private static boolean auto; - private static boolean verbose = false; - - public static void main(String[] args) throws Exception { - if (args.length == 0) { - namesfile = null; - auto = true; - } else { - int i = 0; - if (args[i].equals("-m")) { - i++; - auto = false; - } - if (args.length > i) { - namesfile = args[i++]; - if (args.length > i) { - proxyfile = args[i]; - } - } else { - namesfile = null; - } - } - - CallbackHandler clntCbh = null; - final CallbackHandler srvCbh = new PropertiesFileCallbackHandler( - null, namesfile, proxyfile); - - Subject clntSubj = doLogin("client"); - Subject srvSubj = doLogin("server"); - final HashMap clntprops = new HashMap(); - final HashMap srvprops = new HashMap(); - - clntprops.put(Sasl.QOP, "auth-conf"); - srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf"); - - final SaslClient clnt = (SaslClient) - Subject.callAs(clntSubj, () ->Sasl.createSaslClient( - new String[]{MECH}, null, PROTOCOL, SERVER_FQDN, - clntprops, null)); - - if (verbose) { - System.out.println(clntSubj); - System.out.println(srvSubj); - } - final SaslServer srv = (SaslServer) - Subject.callAs(srvSubj, () -> - Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN, - srvprops, srvCbh)); - - - if (clnt == null) { - throw new IllegalStateException( - "Unable to find client impl for " + MECH); - } - if (srv == null) { - throw new IllegalStateException( - "Unable to find server impl for " + MECH); - } - - byte[] response; - byte[] challenge; - - response = Subject.callAs(clntSubj, - () -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY)); - - while (!clnt.isComplete() || !srv.isComplete()) { - final byte[] responseCopy = response; - challenge = Subject.callAs(srvSubj, - () -> srv.evaluateResponse(responseCopy)); - - if (challenge != null) { - final byte[] challengeCopy = challenge; - response = Subject.callAs(clntSubj, - () -> clnt.evaluateChallenge(challengeCopy)); - } - } - - if (clnt.isComplete() && srv.isComplete()) { - if (verbose) { - System.out.println("SUCCESS"); - System.out.println("authzid is " + srv.getAuthorizationID()); - } - } else { - throw new IllegalStateException("FAILURE: mismatched state:" + - " client complete? " + clnt.isComplete() + - " server complete? " + srv.isComplete()); - } - - if (verbose) { - System.out.println(clnt.getNegotiatedProperty(Sasl.QOP)); - } - - // Now try to use security layer - - byte[] clntBuf = new byte[]{0, 1, 2, 3}; - byte[] wrappedClnt = clnt.wrap(clntBuf, 0, clntBuf.length); - System.out.println("plaintext2: " + bytesToString(clntBuf)); - System.out.println("wrapped2: " + bytesToString(wrappedClnt)); - - byte[] srvBuf = new byte[]{10, 11, 12, 13}; - byte[] wrappedSrv = srv.wrap(srvBuf, 0, srvBuf.length); - System.out.println("plaintext1: " + bytesToString(srvBuf)); - System.out.println("wrapped1: " + bytesToString(wrappedSrv)); - - byte[] unwrapped1 = clnt.unwrap(wrappedSrv, 0, wrappedSrv.length); - System.out.println("unwrapped1: " + bytesToString(unwrapped1)); - - byte[] unwrapped2 = srv.unwrap(wrappedClnt, 0, wrappedClnt.length); - System.out.println("unwrapped2: " + bytesToString(unwrapped2)); - } - - private static Subject doLogin(String msg) throws LoginException { - LoginContext lc = null; - if (verbose) { - System.out.println(msg); - } - try { - lc = new LoginContext(msg, new TextCallbackHandler()); - - // Attempt authentication - // You might want to do this in a "for" loop to give - // user more than one chance to enter correct username/password - lc.login(); - - } catch (LoginException le) { - throw le; - } - return lc.getSubject(); - } - - private static String bytesToString(byte[] digest) { - // Get character representation of digest - StringBuffer digestString = new StringBuffer(); - - for (int i = 0; i < digest.length; i++) { - if ((digest[i] & 0x000000ff) < 0x10) { - digestString.append("0" + - Integer.toHexString(digest[i] & 0x000000ff)); - } else { - digestString.append( - Integer.toHexString(digest[i] & 0x000000ff)); - } - } - return digestString.toString(); - } -} diff --git a/test/jdk/com/sun/security/sasl/gsskerb/NoSecurityLayer.java b/test/jdk/com/sun/security/sasl/gsskerb/NoSecurityLayer.java deleted file mode 100644 index 45d7d1fc1fb..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/NoSecurityLayer.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -/* - * @test - * @bug 4873552 - * @summary GSS-API/krb5 SASL mechanism should throw IllegalStateException - * for auth-only - * @run main/manual NoSecurityLayer - */ - -/* - * Set logging to FINEST to view exchange. - * See run-nosec-wjaas.csh for instructions for how to run this test. - */ - -import javax.security.sasl.*; -import javax.security.auth.callback.*; -import javax.security.auth.Subject; -import javax.security.auth.login.*; -import com.sun.security.auth.callback.*; -import java.util.HashMap; - -public class NoSecurityLayer { - private static final String MECH = "GSSAPI"; - private static final String SERVER_FQDN = "anti.imc.org"; - private static final String PROTOCOL = "sample"; - - private static String namesfile, proxyfile; - private static final byte[] EMPTY = new byte[0]; - private static boolean auto; - private static boolean verbose = false; - - public static void main(String[] args) throws Exception { - if (args.length == 0) { - namesfile = null; - auto = true; - } else { - int i = 0; - if (args[i].equals("-m")) { - i++; - auto = false; - } - if (args.length > i) { - namesfile = args[i++]; - if (args.length > i) { - proxyfile = args[i]; - } - } else { - namesfile = null; - } - } - - CallbackHandler clntCbh = null; - final CallbackHandler srvCbh = new PropertiesFileCallbackHandler( - null, namesfile, proxyfile); - - Subject clntSubj = doLogin("client"); - Subject srvSubj = doLogin("server"); - final HashMap clntprops = new HashMap(); - final HashMap srvprops = new HashMap(); - - clntprops.put(Sasl.QOP, "auth"); - srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf"); - - final SaslClient clnt = - Subject.callAs(clntSubj, () -> - Sasl.createSaslClient( - new String[]{MECH}, null, PROTOCOL, SERVER_FQDN, - clntprops, null)); - - if (verbose) { - System.out.println(clntSubj); - System.out.println(srvSubj); - } - final SaslServer srv = - Subject.callAs(srvSubj, () -> - Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN, - srvprops, srvCbh)); - - - if (clnt == null) { - throw new IllegalStateException( - "Unable to find client impl for " + MECH); - } - if (srv == null) { - throw new IllegalStateException( - "Unable to find server impl for " + MECH); - } - - byte[] response; - byte[] challenge; - - response = Subject.callAs(clntSubj, - () -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY)); - - while (!clnt.isComplete() || !srv.isComplete()) { - final byte[] responseCopy = response; - challenge = Subject.callAs(srvSubj, - () -> srv.evaluateResponse(responseCopy)); - - if (challenge != null) { - final byte[] challengeCopy = challenge; - response = Subject.callAs(clntSubj, - () -> clnt.evaluateChallenge(challengeCopy)); - } - } - - if (clnt.isComplete() && srv.isComplete()) { - if (verbose) { - System.out.println("SUCCESS"); - System.out.println("authzid is " + srv.getAuthorizationID()); - } - } else { - throw new IllegalStateException("FAILURE: mismatched state:" + - " client complete? " + clnt.isComplete() + - " server complete? " + srv.isComplete()); - } - - if (verbose) { - System.out.println(clnt.getNegotiatedProperty(Sasl.QOP)); - } - - // Now try to use security layer - - byte[] clntBuf = new byte[]{0, 1, 2, 3}; - try { - byte[] wrapped = clnt.wrap(clntBuf, 0, clntBuf.length); - throw new Exception( - "clnt wrap should not be allowed w/no security layer"); - } catch (IllegalStateException e) { - // expected - } - - byte[] srvBuf = new byte[]{10, 11, 12, 13}; - try { - byte[] wrapped = srv.wrap(srvBuf, 0, srvBuf.length); - throw new Exception( - "srv wrap should not be allowed w/no security layer"); - } catch (IllegalStateException e) { - // expected - } - - try { - byte[] unwrapped = clnt.unwrap(clntBuf, 0, clntBuf.length); - throw new Exception( - "clnt wrap should not be allowed w/no security layer"); - } catch (IllegalStateException e) { - // expected - } - - try { - byte[] unwrapped = srv.unwrap(srvBuf, 0, srvBuf.length); - throw new Exception( - "srv wrap should not be allowed w/no security layer"); - } catch (IllegalStateException e) { - // expected - } - } - - private static Subject doLogin(String msg) throws LoginException { - LoginContext lc = null; - if (verbose) { - System.out.println(msg); - } - try { - lc = new LoginContext(msg, new TextCallbackHandler()); - - // Attempt authentication - // You might want to do this in a "for" loop to give - // user more than one chance to enter correct username/password - lc.login(); - - } catch (LoginException le) { - throw le; - } - return lc.getSubject(); - } -} diff --git a/test/jdk/com/sun/security/sasl/gsskerb/PropertiesFileCallbackHandler.java b/test/jdk/com/sun/security/sasl/gsskerb/PropertiesFileCallbackHandler.java deleted file mode 100644 index 79f19c74f58..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/PropertiesFileCallbackHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * 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.security.auth.callback.*; -import java.util.Map; -import java.util.Properties; -import java.io.*; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.RealmCallback; - -public final class PropertiesFileCallbackHandler implements CallbackHandler { - private Properties pwDb, namesDb, proxyDb; - - /** - * Contents of files are in the Properties file format. - * - * @param pwFile name of file containing name/password pairs - * @param namesFile name of file containing name to canonicalized name - * @param proxyFile name of file containing authname to list of authzids - */ - public PropertiesFileCallbackHandler(String pwFile, String namesFile, - String proxyFile) throws IOException { - String dir = System.getProperty("test.src"); - if (dir == null) { - dir = "."; - } - dir = dir + "/"; - - if (pwFile != null) { - pwDb = new Properties(); - pwDb.load(new FileInputStream(dir+pwFile)); - } - - if (namesFile != null) { - namesDb = new Properties(); - namesDb.load(new FileInputStream(dir+namesFile)); - } - - if (proxyFile != null) { - proxyDb = new Properties(); - proxyDb.load(new FileInputStream(dir+proxyFile)); - } - } - - public void handle(Callback[] callbacks) - throws UnsupportedCallbackException { - NameCallback ncb = null; - PasswordCallback pcb = null; - AuthorizeCallback acb = null; - RealmCallback rcb = null; - - for (int i = 0; i < callbacks.length; i++) { - if (callbacks[i] instanceof NameCallback) { - ncb = (NameCallback) callbacks[i]; - } else if (callbacks[i] instanceof PasswordCallback) { - pcb = (PasswordCallback) callbacks[i]; - } else if (callbacks[i] instanceof AuthorizeCallback) { - acb = (AuthorizeCallback) callbacks[i]; - } else if (callbacks[i] instanceof RealmCallback) { - rcb = (RealmCallback) callbacks[i]; - } else { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - - // Process retrieval of password; can get password iff - // username is available in NameCallback - // - // Ignore realm for now; could potentially use different dbs for - // different realms - - if (pcb != null && ncb != null) { - String username = ncb.getDefaultName(); - String pw = pwDb.getProperty(username); - if (pw != null) { - char[] pwchars = pw.toCharArray(); - pcb.setPassword(pwchars); - // Clear pw - for (int i = 0; i = 0) { - // XXX need to search for subtrings or use StringTokenizer - // to avoid incorrectly matching subnames - acb.setAuthorized(true); - } - } - - if (acb.isAuthorized()) { - // Set canonicalized name - String canonAuthzid = (namesDb != null ? - namesDb.getProperty(authzid) : null); - if (canonAuthzid != null) { - acb.setAuthorizedID(canonAuthzid); - } - } - } - } -} diff --git a/test/jdk/com/sun/security/sasl/gsskerb/gsseg_jaas.conf b/test/jdk/com/sun/security/sasl/gsskerb/gsseg_jaas.conf deleted file mode 100644 index 18deaa715d9..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/gsseg_jaas.conf +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Login Configuration for JAAS. - * - * Specify that Kerberos v5 is a required login module for the - * example classes: GssExample and Mutual. - */ -other { - com.sun.security.auth.module.Krb5LoginModule required; -}; - -client { - com.sun.security.auth.module.Krb5LoginModule required - principal="john@IMC.ORG"; -}; -server { - com.sun.security.auth.module.Krb5LoginModule required storeKey=true - principal="sample/machineX.imc.org@IMC.ORG" - useKeyTab=true - keyTab=machineX.keytab; -}; - diff --git a/test/jdk/com/sun/security/sasl/gsskerb/log.properties b/test/jdk/com/sun/security/sasl/gsskerb/log.properties deleted file mode 100644 index c301c787474..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/log.properties +++ /dev/null @@ -1,3 +0,0 @@ -javax.security.sasl.level=FINE -#handlers=java.util.logging.ConsoleHandler -#java.util.logging.ConsoleHandler.level=FINE diff --git a/test/jdk/com/sun/security/sasl/gsskerb/run-conf-wjaas.csh b/test/jdk/com/sun/security/sasl/gsskerb/run-conf-wjaas.csh deleted file mode 100644 index f284d3e43e6..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/run-conf-wjaas.csh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/csh -f -# -# @bug 5014493 -# @summary SaslServer.wrap throws NullPointerException when security -# layer negotiated -# -# BEFORE running this test, you need to set up the environment as follows. -# 1. Create a 'sample' service principal in the KDC. -# 2. Create a keytab for the server principal 'sample/fqdn@REALM' -# where 'fqdn' is the fully qualified domain name of the server and -# REALM is the KDC's realm. The principal must be a host-based service. -# For example, a principal name might be -# 'sample/machineX.imc.org@IMC.ORG'. -# On Windows, for example, you use the ktpass utility to create a host keytab -# file. -# c:> ktpass -princ sample/machineX.imc.org@IMC.ORG -mapuser sample \ -# -ptype KRB5_NT_SRV_HST \ -# -pass servertest123 -out machineX.keytab -# 3. Create a user principal in the KDC. -# 4. Set up a JAAS login module configuration file like gsseg_jaas.conf, updating -# the client and server entries according to the principal and machine names -# used. -# 5. Update AuthOnly.SERVER_FQDN with fqdn of server machine. -# 6. To examine exchange, turn on logging by adding -# -Djava.util.logging.config.file=log.properties -# 7. Update the realm and kdc settings in this script. -# -# -$JAVA_HOME/bin/java -Djava.security.krb5.realm=IMC.ORG -Djava.security.krb5.kdc=machineX.imc.org -Djava.security.auth.login.config=gsseg_jaas.conf ConfSecurityLayer diff --git a/test/jdk/com/sun/security/sasl/gsskerb/run-nosec-wjaas.csh b/test/jdk/com/sun/security/sasl/gsskerb/run-nosec-wjaas.csh deleted file mode 100644 index afac8e0eeae..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/run-nosec-wjaas.csh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/csh -f -# -# BEFORE running this test, you need to set up the environment as follows. -# 1. Create a 'sample' service principal in the KDC. -# 2. Create a keytab for the server principal 'sample/fqdn@REALM' -# where 'fqdn' is the fully qualified domain name of the server and -# REALM is the KDC's realm. The principal must be a host-based service. -# For example, a principal name might be -# 'sample/machineX.imc.org@IMC.ORG'. -# On Windows, for example, you use the ktpass utility to create a host keytab -# file. -# c:> ktpass -princ sample/machineX.imc.org@IMC.ORG -mapuser sample \ -# -ptype KRB5_NT_SRV_HST \ -# -pass servertest123 -out machineX.keytab -# 3. Create a user principal in the KDC. -# 4. Set up a JAAS login module configuration file like gsseg_jaas.conf, updating -# the client and server entries according to the principal and machine names -# used. -# 5. Update AuthOnly.SERVER_FQDN with fqdn of server machine. -# 6. To examine exchange, turn on logging by adding -# -Djava.util.logging.config.file=log.properties -# 7. Update the realm and kdc settings in this script. -# -java -Djava.security.krb5.realm=IMC.ORG -Djava.security.krb5.kdc=machineX.imc.org -Djava.security.auth.login.config=gsseg_jaas.conf NoSecurityLayer diff --git a/test/jdk/com/sun/security/sasl/gsskerb/runwjaas.csh b/test/jdk/com/sun/security/sasl/gsskerb/runwjaas.csh deleted file mode 100644 index 9757b818de4..00000000000 --- a/test/jdk/com/sun/security/sasl/gsskerb/runwjaas.csh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/csh -f -# -# BEFORE running this test, you need to set up the environment as follows. -# 1. Create a 'sample' service principal in the KDC. -# 2. Create a keytab for the server principal 'sample/fqdn@REALM' -# where 'fqdn' is the fully qualified domain name of the server and -# REALM is the KDC's realm. The principal must be a host-based service. -# For example, a principal name might be -# 'sample/machineX.imc.org@IMC.ORG'. -# On Windows, for example, you use the ktpass utility to create a host keytab -# file. -# c:> ktpass -princ sample/machineX.imc.org@IMC.ORG -mapuser sample \ -# -ptype KRB5_NT_SRV_HST \ -# -pass servertest123 -out machineX.keytab -# 3. Create a user principal in the KDC. -# 4. Set up a JAAS login module configuration file like gsseg_jaas.conf, updating -# the client and server entries according to the principal and machine names -# used. -# 5. Update AuthOnly.SERVER_FQDN with fqdn of server machine. -# 6. To examine exchange, turn on logging by adding -# -Djava.util.logging.config.file=log.properties -# 7. Update the realm and kdc settings in this script. -# -java -Djava.security.krb5.realm=IMC.ORG -Djava.security.krb5.kdc=machineX.imc.org -Djava.security.auth.login.config=gsseg_jaas.conf AuthOnly diff --git a/test/jdk/sun/security/krb5/auto/SaslBasic.java b/test/jdk/sun/security/krb5/auto/SaslBasic.java index 0aebdefbe04..89eb22383f2 100644 --- a/test/jdk/sun/security/krb5/auto/SaslBasic.java +++ b/test/jdk/sun/security/krb5/auto/SaslBasic.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 @@ -32,12 +32,11 @@ * @run main/othervm -Djdk.net.hosts.file=TestHosts SaslBasic unbound auth-conf * @run main/othervm -Djdk.net.hosts.file=TestHosts SaslBasic bound auth */ -import java.io.IOException; +import static jdk.test.lib.Asserts.assertEquals; + import java.util.Arrays; import java.util.HashMap; import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.*; // The basic krb5 test skeleton you can copy from @@ -61,15 +60,12 @@ public class SaslBasic { srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf"); SaslServer ss = Sasl.createSaslServer("GSSAPI", "server", bound? name: null, srvprops, - new CallbackHandler() { - public void handle(Callback[] callbacks) - throws IOException, UnsupportedCallbackException { - for (Callback cb : callbacks) { - if (cb instanceof RealmCallback) { - ((RealmCallback) cb).setText(OneKDC.REALM); - } else if (cb instanceof AuthorizeCallback) { - ((AuthorizeCallback) cb).setAuthorized(true); - } + callbacks -> { + for (Callback cb : callbacks) { + if (cb instanceof RealmCallback) { + ((RealmCallback) cb).setText(OneKDC.REALM); + } else if (cb instanceof AuthorizeCallback) { + ((AuthorizeCallback) cb).setAuthorized(true); } } }); @@ -89,28 +85,85 @@ public class SaslBasic { String boundName = (String)ss.getNegotiatedProperty( Sasl.BOUND_SERVER_NAME); if (!boundName.equals(name)) { - throw new Exception("Wrong bound server name"); + throw new RuntimeException("Wrong bound server name"); } } Object key = ss.getNegotiatedProperty( "com.sun.security.jgss.inquiretype.krb5_get_session_key"); if (key == null) { - throw new Exception("Extended negotiated property not read"); + throw new RuntimeException("Extended negotiated property not read"); } if (args[1].equals("auth")) { // 8170732. These are the maximum size bytes after jgss/krb5 wrap. if (lastClientToken[17] != 0 || lastClientToken[18] != 0 || lastClientToken[19] != 0) { - throw new Exception("maximum size for auth must be 0"); + throw new RuntimeException("maximum size for auth must be 0"); } + testWrapUnwrapNoSecLayer(sc, ss); } else { - byte[] hello = "hello".getBytes(); - token = sc.wrap(hello, 0, hello.length); - token = ss.unwrap(token, 0, token.length); - if (!Arrays.equals(hello, token)) { - throw new Exception("Message altered"); - } + testWrapUnwrapWithSecLayer(sc, ss); + } + } + + private static void testWrapUnwrapWithSecLayer(SaslClient sc, SaslServer ss) + throws SaslException { + byte[] token; + byte[] hello = "hello".getBytes(); + + // test client wrap and server unwrap + token = sc.wrap(hello, 0, hello.length); + token = ss.unwrap(token, 0, token.length); + + if (!Arrays.equals(hello, token)) { + throw new RuntimeException("Client message altered"); + } + + // test server wrap and client unwrap + token = ss.wrap(hello, 0, hello.length); + token = sc.unwrap(token, 0, token.length); + + if (!Arrays.equals(hello, token)) { + throw new RuntimeException("Server message altered"); + } + } + + private static void testWrapUnwrapNoSecLayer(SaslClient sc, SaslServer ss) + throws SaslException { + byte[] clntBuf = new byte[]{0, 1, 2, 3}; + byte[] srvBuf = new byte[]{10, 11, 12, 13}; + String expectedError = "No security layer negotiated"; + + try { + sc.wrap(clntBuf, 0, clntBuf.length); + throw new RuntimeException( + "client wrap should not be allowed w/no security layer"); + } catch (IllegalStateException e) { + assertEquals(expectedError, e.getMessage()); + } + + try { + ss.wrap(srvBuf, 0, srvBuf.length); + throw new RuntimeException( + "server wrap should not be allowed w/no security layer"); + } catch (IllegalStateException e) { + assertEquals(expectedError, e.getMessage()); + } + + try { + sc.unwrap(clntBuf, 0, clntBuf.length); + throw new RuntimeException( + "client unwrap should not be allowed w/no security layer"); + } catch (IllegalStateException e) { + assertEquals(expectedError, e.getMessage()); + } + + try { + ss.unwrap(srvBuf, 0, srvBuf.length); + throw new RuntimeException( + "server unwrap should not be allowed w/no security layer"); + } catch (IllegalStateException e) { + assertEquals(expectedError, e.getMessage()); } } } From 16033ea79a01b27a7f5cbb31d64da0e80afc7dc3 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Thu, 20 Feb 2025 18:52:57 +0000 Subject: [PATCH 081/587] 8342238: Test javax/crypto/CryptoPermissions/InconsistentEntries.java writes files in tested JDK dir Reviewed-by: jnimeh, rhalade --- .../InconsistentEntries.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java b/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java index 9c06cbaf613..85118f34d03 100644 --- a/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java +++ b/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.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,14 +29,16 @@ * @run testng/othervm InconsistentEntries */ +import java.util.List; +import jdk.test.lib.Utils; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.ProcessTools; import org.testng.Assert; -import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import javax.crypto.*; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -45,42 +47,35 @@ import java.security.Security; public class InconsistentEntries { - private static final String JDK_HOME = System.getProperty("test.jdk"); - private static final String TEST_SRC = System.getProperty("test.src"); - private static final Path POLICY_DIR = Paths.get(JDK_HOME, "conf", "security", - "policy", "testlimited"); - private static final Path POLICY_FILE = Paths.get(TEST_SRC, "default_local.policy"); - - Path targetFile = null; + private static final String JDK_HOME = System.getProperty("test.jdk", "."); + private static final String TEST_SRC = System.getProperty("test.src", "."); + private static final Path TEMP_JDK_HOME = Path.of("java"); + private static final Path POLICY_DIR = TEMP_JDK_HOME.resolve(Path.of("conf", "security", + "policy", "testlimited")); + private static final Path POLICY_FILE_SRC = Paths.get(TEST_SRC, "default_local.policy"); + private static final Path POLICY_FILE_TARGET = POLICY_DIR + .resolve(POLICY_FILE_SRC.getFileName()); @BeforeTest - public void setUp() throws IOException { + public void setUp() throws Exception { + // Clone the tested JDK to the scratch directory + CDSTestUtils.clone(new File(JDK_HOME), new File(TEMP_JDK_HOME.toString())); + + // create policy directory in the cloned JDK if (!POLICY_DIR.toFile().exists()) { Files.createDirectory(POLICY_DIR); } - targetFile = POLICY_DIR.resolve(POLICY_FILE.getFileName()); - Files.copy(POLICY_FILE, targetFile, StandardCopyOption.REPLACE_EXISTING); + // copy policy file into policy directory + Files.copy(POLICY_FILE_SRC, POLICY_FILE_TARGET, StandardCopyOption.REPLACE_EXISTING); } - @AfterTest - public void cleanUp() throws IOException { - Files.delete(targetFile); - } - - @Test - public void test() throws Exception { - String JAVA_HOME = System.getProperty("java.home"); - String FS = System.getProperty("file.separator"); - Path testlimited = Path.of(JAVA_HOME + FS + "conf" + FS + "security" + - FS + "policy" + FS + "testlimited"); - if (!Files.exists(testlimited)) { + public static void main(String[] args) throws Throwable { + if (!Files.exists(POLICY_DIR)) { throw new RuntimeException( "custom policy subdirectory: testlimited does not exist"); } - - File testpolicy = new File(JAVA_HOME + FS + "conf" + FS + "security" + - FS + "policy" + FS + "testlimited" + FS + "default_local.policy"); + File testpolicy = new File(POLICY_FILE_TARGET.toString()); if (testpolicy.length() == 0) { throw new RuntimeException( "policy: default_local.policy does not exist or is empty"); @@ -91,4 +86,16 @@ public class InconsistentEntries { Assert.assertThrows(ExceptionInInitializerError.class, () -> Cipher.getMaxAllowedKeyLength("AES")); } + + @Test + public void test() throws Exception { + String tmpJava = TEMP_JDK_HOME.resolve("bin").resolve("java").toString(); + String[] args = Utils.prependTestJavaOpts(InconsistentEntries.class.getName()); + ProcessBuilder pb = new ProcessBuilder(tmpJava); + pb.command().addAll(List.of(args)); + + ProcessTools + .executeProcess(pb) + .shouldHaveExitValue(0); + } } From c73fead5caea8008586b31a5009c64011637b8cc Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 21 Feb 2025 09:48:54 +0000 Subject: [PATCH 082/587] 8350383: Test: add more test case for string compare (UL case) Reviewed-by: fyang --- .../jtreg/compiler/intrinsics/string/TestStringIntrinsics.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java index 65984029397..062866d657f 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java @@ -155,6 +155,7 @@ public class TestStringIntrinsics { char cL = latin1.charAt(indexL); char cU = utf16.charAt(indexU); invokeAndCheck(m, cL - cU, latin1, latin1.replace(cL, cU)); + invokeAndCheck(m, cU - cL, latin1.replace(cL, cU), latin1); invokeAndCheck(m, cU - cL, utf16, utf16.replace(cU, cL)); // Different lengths From 1b6281d98cf0e7c5435c563bfedd6f07b79bfa62 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 21 Feb 2025 10:25:50 +0000 Subject: [PATCH 083/587] 8321003: RISC-V: C2 MulReductionVI 8321004: RISC-V: C2 MulReductionVL Reviewed-by: fyang, rehn --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 39 +++++++++++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 4 ++ src/hotspot/cpu/riscv/riscv_v.ad | 68 +++++++++++++++++++ .../loopopts/superword/ProdRed_Int.java | 6 +- .../loopopts/superword/RedTest_int.java | 4 ++ .../loopopts/superword/RedTest_long.java | 4 ++ 6 files changed, 124 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index c23a574e401..34a61177774 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2954,6 +2954,45 @@ void C2_MacroAssembler::reduce_integral_v(Register dst, Register src1, vmv_x_s(dst, tmp); } +void C2_MacroAssembler::reduce_mul_integral_v(Register dst, Register src1, VectorRegister src2, + VectorRegister vtmp1, VectorRegister vtmp2, + BasicType bt, uint vector_length, VectorMask vm) { + assert(bt == T_BYTE || bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported element type"); + vsetvli_helper(bt, vector_length); + + vector_length /= 2; + if (vm != Assembler::unmasked) { + // This behaviour is consistent with spec requirements of vector API, for `reduceLanes`: + // If no elements are selected, an operation-specific identity value is returned. + // If the operation is MUL, then the identity value is one. + vmv_v_i(vtmp1, 1); + vmerge_vvm(vtmp2, vtmp1, src2); // vm == v0 + vslidedown_vi(vtmp1, vtmp2, vector_length); + + vsetvli_helper(bt, vector_length); + vmul_vv(vtmp1, vtmp1, vtmp2); + } else { + vslidedown_vi(vtmp1, src2, vector_length); + + vsetvli_helper(bt, vector_length); + vmul_vv(vtmp1, vtmp1, src2); + } + + while (vector_length > 1) { + vector_length /= 2; + vslidedown_vi(vtmp2, vtmp1, vector_length); + vsetvli_helper(bt, vector_length); + vmul_vv(vtmp1, vtmp1, vtmp2); + } + + vmv_x_s(dst, vtmp1); + if (bt == T_INT) { + mulw(dst, dst, src1); + } else { + mul(dst, dst, src1); + } +} + // Set vl and vtype for full and partial vector operations. // (vma = mu, vta = tu, vill = false) void C2_MacroAssembler::vsetvli_helper(BasicType bt, uint vector_length, LMUL vlmul, Register tmp) { diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 114ad0a101c..c79c360d2eb 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -239,6 +239,10 @@ int opc, BasicType bt, uint vector_length, VectorMask vm = Assembler::unmasked); + void reduce_mul_integral_v(Register dst, Register src1, VectorRegister src2, + VectorRegister vtmp1, VectorRegister vtmp2, BasicType bt, + uint vector_length, VectorMask vm = Assembler::unmasked); + void vsetvli_helper(BasicType bt, uint vector_length, LMUL vlmul = Assembler::m1, Register tmp = t0); void compare_integral_v(VectorRegister dst, VectorRegister src1, VectorRegister src2, int cond, diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 7be169ef709..9892d2b9c03 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -2,6 +2,7 @@ // Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2020, 2023, Arm Limited. All rights reserved. // Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. +// Copyright (c) 2023, 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 @@ -99,6 +100,12 @@ source %{ return false; } break; + case Op_MulReductionVI: + case Op_MulReductionVL: + // When vlen < 4, our log2(vlen) implementation does not help to gain performance improvement. + if (vlen < 4) { + return false; + } default: break; } @@ -2427,6 +2434,67 @@ instruct vreduce_minD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, v ins_pipe(pipe_slow); %} + +// ------------------------------ Vector reduction mul ------------------------- + +instruct reduce_mulI(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc, + vReg tmp1, vReg tmp2) %{ + match(Set dst (MulReductionVI isrc vsrc)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_mulI $dst, $isrc, $vsrc\t" %} + + ins_encode %{ + __ reduce_mul_integral_v($dst$$Register, $isrc$$Register, as_VectorRegister($vsrc$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + Matcher::vector_element_basic_type(this, $vsrc), Matcher::vector_length(this, $vsrc)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_mulI_masked(iRegINoSp dst, iRegIorL2I isrc, vReg vsrc, + vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ + match(Set dst (MulReductionVI (Binary isrc vsrc) v0)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_mulI_masked $dst, $isrc, $vsrc, $v0\t" %} + + ins_encode %{ + __ reduce_mul_integral_v($dst$$Register, $isrc$$Register, as_VectorRegister($vsrc$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + Matcher::vector_element_basic_type(this, $vsrc), Matcher::vector_length(this, $vsrc), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_mulL(iRegLNoSp dst, iRegL isrc, vReg vsrc, + vReg tmp1, vReg tmp2) %{ + match(Set dst (MulReductionVL isrc vsrc)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_mulL $dst, $isrc, $vsrc\t" %} + + ins_encode %{ + __ reduce_mul_integral_v($dst$$Register, $isrc$$Register, as_VectorRegister($vsrc$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + Matcher::vector_element_basic_type(this, $vsrc), Matcher::vector_length(this, $vsrc)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_mulL_masked(iRegLNoSp dst, iRegL isrc, vReg vsrc, + vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ + match(Set dst (MulReductionVL (Binary isrc vsrc) v0)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_mulL_masked $dst, $isrc, $vsrc, $v0\t" %} + + ins_encode %{ + __ reduce_mul_integral_v($dst$$Register, $isrc$$Register, as_VectorRegister($vsrc$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + Matcher::vector_element_basic_type(this, $vsrc), Matcher::vector_length(this, $vsrc), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // vector replicate instruct replicate(vReg dst, iRegIorL2I src) %{ diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java index 17f3a97a8e8..ebc8251e025 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.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 @@ -85,6 +85,10 @@ public class ProdRed_Int { @IR(applyIfCPUFeature = {"sse4.1", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, + counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop public static int prodReductionImplement(int[] a, int[] b, int total) { for (int i = 0; i < a.length; i++) { total *= a[i] + b[i]; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_int.java b/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_int.java index d4b6777ded8..5cf7077cf17 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_int.java @@ -219,6 +219,10 @@ public class RedTest_int { @IR(applyIfCPUFeature = {"sse4.1", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, + counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop public static int mulReductionImplement( int[] a, int[] b, diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_long.java b/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_long.java index 63228330ed5..10cd32bbbc7 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_long.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/RedTest_long.java @@ -226,6 +226,10 @@ public class RedTest_long { applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, applyIfPlatform = {"64-bit", "true"}, counts = {IRNode.MUL_REDUCTION_VL, ">= 1", IRNode.MUL_REDUCTION_VL, "<= 2"}) // one for main-loop, one for vector-post-loop + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, + counts = {IRNode.MUL_REDUCTION_VL, ">= 1", IRNode.MUL_REDUCTION_VL, "<= 2"}) // one for main-loop, one for vector-post-loop public static long mulReductionImplement( long[] a, long[] b, From dfcd0df60c60cf89dc01682264a573ad39e61a17 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 21 Feb 2025 10:26:55 +0000 Subject: [PATCH 084/587] 8350019: HttpClient: DelegatingExecutor should resort to the fallback executor only on RejectedExecutionException Reviewed-by: dfuchs --- .../jdk/internal/net/http/HttpClientImpl.java | 6 +- .../DelegatingExecutorTestDriver.java | 30 +++ .../net/http/DelegatingExecutorTest.java | 176 ++++++++++++++++++ 3 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 test/jdk/java/net/httpclient/whitebox/DelegatingExecutorTestDriver.java create mode 100644 test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DelegatingExecutorTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 4d7518d4054..c58f0b0c752 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.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 @@ -172,13 +172,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { public void ensureExecutedAsync(Runnable command) { try { delegate.execute(command); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { errorHandler.accept(command, t); ASYNC_POOL.execute(command); } } - private void shutdown() { + void shutdown() { if (delegate instanceof ExecutorService service) { service.shutdown(); } diff --git a/test/jdk/java/net/httpclient/whitebox/DelegatingExecutorTestDriver.java b/test/jdk/java/net/httpclient/whitebox/DelegatingExecutorTestDriver.java new file mode 100644 index 00000000000..4b1b783b1b6 --- /dev/null +++ b/test/jdk/java/net/httpclient/whitebox/DelegatingExecutorTestDriver.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 + * @bug 8350019 + * @summary Verifies `HttpClientImpl.DelegatingExecutor` behavior + * @modules java.net.http/jdk.internal.net.http + * @run junit java.net.http/jdk.internal.net.http.DelegatingExecutorTest + */ diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DelegatingExecutorTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DelegatingExecutorTest.java new file mode 100644 index 00000000000..5b96ce4125d --- /dev/null +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DelegatingExecutorTest.java @@ -0,0 +1,176 @@ +/* + * 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.net.http; + +import jdk.internal.net.http.HttpClientImpl.DelegatingExecutor; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class DelegatingExecutorTest { + + @Test + public void testInlineExecution() { + Thread callSiteThread = Thread.currentThread(); + Thread[] runSiteThreadRef = {null}; + new DelegatingExecutor(() -> false, null, null) + .execute(() -> runSiteThreadRef[0] = Thread.currentThread()); + assertSame(callSiteThread, runSiteThreadRef[0]); + } + + @Test + public void testDelegateDeferral() { + ImmediateExecutor delegate = new ImmediateExecutor(); + Runnable task = () -> {}; + new DelegatingExecutor(() -> true, delegate, null).execute(task); + delegate.assertReception(task); + } + + @Test + public void testRejectedExecutionException() throws InterruptedException { + + // Create a deterministically throwing task + RuntimeException error = new RejectedExecutionException(); + FirstThrowingAndThenCompletingRunnable task = new FirstThrowingAndThenCompletingRunnable(error); + + // Create a recording delegate + ImmediateExecutor delegate = new ImmediateExecutor(); + + // Create a recording error handler + List reportedTasks = new ArrayList<>(); + List reportedErrors = new ArrayList<>(); + BiConsumer errorHandler = (task_, error_) -> { + synchronized (this) { + reportedTasks.add(task_); + reportedErrors.add(error_); + } + }; + + // Verify the initial failing execution + new DelegatingExecutor(() -> true, delegate, errorHandler).execute(task); + delegate.assertReception(task); + + // Verify fallback to the async. pool + assertEquals(1, reportedTasks.size()); + assertSame(task, reportedTasks.getFirst()); + assertEquals(1, reportedErrors.size()); + assertSame(error, reportedErrors.getFirst()); + boolean completed = task.completionLatch.await(5, TimeUnit.SECONDS); + assertTrue(completed); + + } + + @Test + public void testNotRejectedExecutionException() { + + // Create a deterministically throwing task + RuntimeException error = new RuntimeException(); + FirstThrowingAndThenCompletingRunnable task = new FirstThrowingAndThenCompletingRunnable(error); + + // Create a recording delegate + ImmediateExecutor delegate = new ImmediateExecutor(); + + // Verify the immediate exception propagation + Throwable thrownError = assertThrows( + Throwable.class, + () -> new DelegatingExecutor(() -> true, delegate, null).execute(task)); + delegate.assertReception(task); + assertSame(error, thrownError); + + } + + private static final class ImmediateExecutor implements Executor { + + private final List receivedTasks = new ArrayList<>(); + + @Override + public synchronized void execute(Runnable task) { + receivedTasks.add(task); + task.run(); + } + + private synchronized void assertReception(Runnable... tasks) { + assertSame(tasks.length, receivedTasks.size()); + for (int taskIndex = 0; taskIndex < tasks.length; taskIndex++) { + assertSame(tasks[taskIndex], receivedTasks.get(taskIndex)); + } + } + + } + + private static final class FirstThrowingAndThenCompletingRunnable implements Runnable { + + private final AtomicInteger invocationCounter = new AtomicInteger(0); + + private final CountDownLatch completionLatch = new CountDownLatch(1); + + private final RuntimeException exception; + + private FirstThrowingAndThenCompletingRunnable(RuntimeException exception) { + this.exception = exception; + } + + @Override + public void run() { + switch (invocationCounter.getAndIncrement()) { + case 0: throw exception; + case 1: { completionLatch.countDown(); break; } + default: fail(); + } + } + + } + + @Test + public void testDelegateShutdown() { + AtomicInteger invocationCounter = new AtomicInteger(); + try (ExecutorService delegate = new ThreadPoolExecutor(1, 1, 1, TimeUnit.DAYS, new LinkedBlockingQueue<>()) { + @Override + public void shutdown() { + invocationCounter.incrementAndGet(); + super.shutdown(); + } + }) { + new DelegatingExecutor(() -> true, delegate, null).shutdown(); + assertEquals(1, invocationCounter.get()); + } + } + +} From 24b557361a481d7f38f8016506573623b91bd8c8 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Fri, 21 Feb 2025 16:17:31 +0000 Subject: [PATCH 085/587] 8350444: Check for verifer error in StackMapReader::check_offset() Reviewed-by: coleenp, dholmes --- src/hotspot/share/classfile/stackMapTable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index ff8c8378027..b452beecb00 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -231,6 +231,9 @@ StackMapFrame* StackMapReader::next(TRAPS) { StackMapFrame* frame = next_helper(CHECK_VERIFY_(_verifier, nullptr)); if (frame != nullptr) { check_offset(frame); + if (frame->verifier()->has_error()) { + return nullptr; + } _prev_frame = frame; } return frame; From bd8ad309b59bceb3073a8d6411cca74e73508885 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Fri, 21 Feb 2025 16:39:17 +0000 Subject: [PATCH 086/587] 8350285: Shenandoah: Regression caused by ShenandoahLock under extreme contention Reviewed-by: shade, kdnilsen --- .../share/gc/shenandoah/shenandoahLock.cpp | 19 ++++++++++++++++--- .../share/gc/shenandoah/shenandoahLock.hpp | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index be72127c6ec..47a144a638f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -45,6 +45,7 @@ void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block."); // Spin this much, but only on multi-processor systems. int ctr = os::is_MP() ? 0xFF : 0; + int yields = 0; // Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread. while (Atomic::load(&_state) == locked || Atomic::cmpxchg(&_state, unlocked, locked) != unlocked) { @@ -67,17 +68,29 @@ void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { // VM thread to arm the poll sooner. while (SafepointSynchronize::is_synchronizing() && !SafepointMechanism::local_poll_armed(java_thread)) { - os::naked_yield(); + yield_or_sleep(yields); } } else { - os::naked_yield(); + yield_or_sleep(yields); } } else { - os::naked_yield(); + yield_or_sleep(yields); } } } +void ShenandoahLock::yield_or_sleep(int &yields) { + // Simple yield-sleep policy: do one 100us sleep after every N yields. + // Tested with different values of N, and chose 3 for best performance. + if (yields < 3) { + os::naked_yield(); + yields++; + } else { + os::naked_short_nanosleep(100000); + yields = 0; + } +} + ShenandoahSimpleLock::ShenandoahSimpleLock() { assert(os::mutex_init_done(), "Too early!"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp index 4d7eefd460c..0cef2414c0d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp @@ -42,6 +42,8 @@ private: template void contended_lock_internal(JavaThread* java_thread); + static void yield_or_sleep(int &yields); + public: ShenandoahLock() : _state(unlocked), _owner(nullptr) {}; From b45c32cd4fb55fac4fc5161b9cd76415c69b203b Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 21 Feb 2025 19:09:38 +0000 Subject: [PATCH 087/587] 8350287: Cleanup SA's support for CodeBlob subclasses Reviewed-by: kvn, sspitsyn --- .../sun/jvm/hotspot/code/AdapterBlob.java | 56 -------------- .../sun/jvm/hotspot/code/BufferBlob.java | 52 ------------- .../sun/jvm/hotspot/code/CodeBlob.java | 77 ++++--------------- .../sun/jvm/hotspot/code/CodeCache.java | 7 -- .../jvm/hotspot/code/DeoptimizationBlob.java | 52 ------------- .../sun/jvm/hotspot/code/ExceptionBlob.java | 55 ------------- .../code/MethodHandlesAdapterBlob.java | 56 -------------- .../sun/jvm/hotspot/code/RuntimeBlob.java | 60 --------------- .../sun/jvm/hotspot/code/RuntimeStub.java | 64 --------------- .../sun/jvm/hotspot/code/SafepointBlob.java | 54 ------------- .../sun/jvm/hotspot/code/SingletonBlob.java | 52 ------------- .../jvm/hotspot/code/UncommonTrapBlob.java | 54 ------------- .../sun/jvm/hotspot/code/UpcallStub.java | 2 +- .../sun/jvm/hotspot/code/VtableBlob.java | 40 ---------- .../classes/sun/jvm/hotspot/tools/PStack.java | 22 +----- 15 files changed, 18 insertions(+), 685 deletions(-) delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java deleted file mode 100644 index 8fa69a2686c..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/AdapterBlob.java +++ /dev/null @@ -1,56 +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. - * - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class AdapterBlob extends RuntimeBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - // Type type = db.lookupType("AdapterBlob"); - - // // FIXME: add any needed fields - } - - public AdapterBlob(Address addr) { - super(addr); - } - - public String getName() { - return "AdapterBlob: " + super.getName(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java deleted file mode 100644 index 8f2ed2aa601..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/BufferBlob.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class BufferBlob extends RuntimeBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("BufferBlob"); - - // FIXME: add any needed fields - } - - public BufferBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java index 326600d79f4..b401f3656f9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -52,20 +52,12 @@ public class CodeBlob extends VMObject { private static CIntegerField dataOffsetField; private static CIntegerField frameSizeField; private static AddressField oopMapsField; + private static CIntegerField callerMustGCArgumentsField; - // Kinds of Codeblob + // Kinds of CodeBlobs that we need to know about. private static int NMethodKind; - private static int BufferKind; - private static int AdapterKind; - private static int VtableKind; - private static int MHAdapterKind; private static int RuntimeStubKind; - private static int DeoptimizationKind; - private static int ExceptionKind; - private static int SafepointKind; - private static int UncommonTrapKind; private static int UpcallKind; - private static int NumberOfKinds; private static Class[] wrapperClasses; @@ -89,6 +81,7 @@ public class CodeBlob extends VMObject { dataOffsetField = type.getCIntegerField("_data_offset"); frameSizeField = type.getCIntegerField("_frame_size"); oopMapsField = type.getAddressField("_oop_maps"); + callerMustGCArgumentsField = type.getCIntegerField("_caller_must_gc_arguments"); if (VM.getVM().isServerCompiler()) { matcherInterpreterFramePointerReg = @@ -96,38 +89,8 @@ public class CodeBlob extends VMObject { } NMethodKind = db.lookupIntConstant("CodeBlobKind::Nmethod").intValue(); - BufferKind = db.lookupIntConstant("CodeBlobKind::Buffer").intValue(); - AdapterKind = db.lookupIntConstant("CodeBlobKind::Adapter").intValue(); - VtableKind = db.lookupIntConstant("CodeBlobKind::Vtable").intValue(); - MHAdapterKind = db.lookupIntConstant("CodeBlobKind::MHAdapter").intValue(); RuntimeStubKind = db.lookupIntConstant("CodeBlobKind::RuntimeStub").intValue(); - DeoptimizationKind = db.lookupIntConstant("CodeBlobKind::Deoptimization").intValue(); - SafepointKind = db.lookupIntConstant("CodeBlobKind::Safepoint").intValue(); UpcallKind = db.lookupIntConstant("CodeBlobKind::Upcall").intValue(); - NumberOfKinds = db.lookupIntConstant("CodeBlobKind::Number_Of_Kinds").intValue(); - if (VM.getVM().isServerCompiler()) { - ExceptionKind = db.lookupIntConstant("CodeBlobKind::Exception").intValue(); - UncommonTrapKind = db.lookupIntConstant("CodeBlobKind::UncommonTrap").intValue(); - } else { - // Set invalid value to not match default. - ExceptionKind = NumberOfKinds + 1; - UncommonTrapKind = NumberOfKinds + 1; - } - - wrapperClasses = new Class[NumberOfKinds]; - wrapperClasses[NMethodKind] = NMethod.class; - wrapperClasses[BufferKind] = BufferBlob.class; - wrapperClasses[AdapterKind] = AdapterBlob.class; - wrapperClasses[VtableKind] = VtableBlob.class; - wrapperClasses[MHAdapterKind] = MethodHandlesAdapterBlob.class; - wrapperClasses[RuntimeStubKind] = RuntimeStub.class; - wrapperClasses[DeoptimizationKind] = DeoptimizationBlob.class; - wrapperClasses[SafepointKind] = SafepointBlob.class; - wrapperClasses[UpcallKind] = UpcallStub.class; - if (VM.getVM().isServerCompiler()) { - wrapperClasses[ExceptionKind] = ExceptionBlob.class; - wrapperClasses[UncommonTrapKind] = UncommonTrapBlob.class; - } } static { @@ -140,7 +103,16 @@ public class CodeBlob extends VMObject { public static Class getClassFor(Address addr) { CodeBlob cb = new CodeBlob(addr); - return wrapperClasses[cb.getKind()]; + int kind = cb.getKind(); + if (kind == NMethodKind) { + return NMethod.class; + } else if (kind == UpcallKind) { + return UpcallStub.class; + } else { + // All other CodeBlob kinds have no special functionality in SA and can be + // represented by the generic CodeBlob class. + return CodeBlob.class; + } } public Address headerBegin() { return getAddress(); } @@ -196,35 +168,16 @@ public class CodeBlob extends VMObject { // Typing - public boolean isBufferBlob() { return getKind() == BufferKind; } - public boolean isNMethod() { return getKind() == NMethodKind; } public boolean isRuntimeStub() { return getKind() == RuntimeStubKind; } public boolean isUpcallStub() { return getKind() == UpcallKind; } - public boolean isDeoptimizationBlob() { return getKind() == DeoptimizationKind; } - - public boolean isUncommonTrapBlob() { return getKind() == UncommonTrapKind; } - - public boolean isExceptionBlob() { return getKind() == ExceptionKind; } - - public boolean isSafepointBlob() { return getKind() == SafepointKind; } - - public boolean isAdapterBlob() { return getKind() == AdapterKind; } - - public boolean isMHAdapterBlob() { return getKind() == MHAdapterKind; } - - public boolean isVtableBlob() { return getKind() == VtableKind; } - - // Fine grain nmethod support: isNMethod() == isJavaMethod() || isNativeMethod() || isOSRMethod() public boolean isJavaMethod() { return false; } public boolean isNativeMethod() { return false; } - /** On-Stack Replacement method */ - public boolean isOSRMethod() { return false; } public NMethod asNMethodOrNull() { if (isNMethod()) return (NMethod)this; @@ -266,7 +219,9 @@ public class CodeBlob extends VMObject { } // Returns true, if the next frame is responsible for GC'ing oops passed as arguments - public boolean callerMustGCArguments() { return false; } + public boolean callerMustGCArguments() { + return callerMustGCArgumentsField.getValue(addr) != 0; + } public void print() { printOn(System.out); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java index 73135a873e5..ff8b29ae12e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java @@ -96,13 +96,6 @@ public class CodeCache { // addr - address inside of a code blob public CodeBlob createCodeBlobWrapper(Address cbStart, Address addr) { Class cbClass = CodeBlob.getClassFor(cbStart); - if (cbClass == null) { - String message = "Couldn't deduce type of CodeBlob "; - message = message + "@" + cbStart + " "; - message = message + "for PC=" + addr; - - throw new RuntimeException(message); - } CodeBlob result = (CodeBlob) VMObjectFactory.newObject(cbClass, cbStart); if (Assert.ASSERTS_ENABLED) { // The pointer to the HeapBlock that contains this blob is outside of the blob, diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java deleted file mode 100644 index 51a5184ca85..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/DeoptimizationBlob.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class DeoptimizationBlob extends SingletonBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("DeoptimizationBlob"); - - // FIXME: add any needed fields - } - - public DeoptimizationBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java deleted file mode 100644 index 30025a41866..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/ExceptionBlob.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -/** ExceptionBlob: used for exception unwinding in compiled code - (currently only used by Compiler 2) */ - -public class ExceptionBlob extends SingletonBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("ExceptionBlob"); - - // FIXME: add any needed fields - } - - public ExceptionBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java deleted file mode 100644 index 53c9593d0b8..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java +++ /dev/null @@ -1,56 +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. - * - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MethodHandlesAdapterBlob extends AdapterBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("MethodHandlesAdapterBlob"); - - // FIXME: add any needed fields - } - - public MethodHandlesAdapterBlob(Address addr) { - super(addr); - } - - public String getName() { - return "MethodHandlesAdapterBlob: " + super.getName(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeBlob.java deleted file mode 100644 index d6f69d622b1..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeBlob.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2016, 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. - * - */ - -package sun.jvm.hotspot.code; - -import java.util.*; - -import sun.jvm.hotspot.compiler.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class RuntimeBlob extends CodeBlob { - - // Only used by server compiler on x86; computed over in SA rather - // than relying on computation in target VM - private static final int NOT_YET_COMPUTED = -2; - private static final int UNDEFINED = -1; - private int linkOffset = NOT_YET_COMPUTED; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("RuntimeBlob"); - } - - public RuntimeBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java deleted file mode 100644 index f51dcd76516..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/RuntimeStub.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class RuntimeStub extends RuntimeBlob { - private static CIntegerField callerMustGCArgumentsField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("RuntimeStub"); - callerMustGCArgumentsField = type.getCIntegerField("_caller_must_gc_arguments"); - - // FIXME: add any needed fields - } - - public RuntimeStub(Address addr) { - super(addr); - } - - public boolean callerMustGCArguments() { - return callerMustGCArgumentsField.getValue(addr) != 0; - } - - - public String getName() { - return "RuntimeStub: " + super.getName(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java deleted file mode 100644 index 3f3ba79ff9f..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SafepointBlob.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -/** SafepointBlob: handles illegal_instruction exceptions during a safepoint */ - -public class SafepointBlob extends SingletonBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("SafepointBlob"); - - // FIXME: add any needed fields - } - - public SafepointBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java deleted file mode 100644 index 5a80b957e1d..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/SingletonBlob.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class SingletonBlob extends RuntimeBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("SingletonBlob"); - - // FIXME: add any needed fields - } - - public SingletonBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java deleted file mode 100644 index 077e49b5fe6..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UncommonTrapBlob.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.code; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -/** UncommonTrapBlob (currently only used by Compiler 2) */ - -public class UncommonTrapBlob extends SingletonBlob { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("UncommonTrapBlob"); - - // FIXME: add any needed fields - } - - public UncommonTrapBlob(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java index eeb5821bb60..360e047943b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java @@ -31,7 +31,7 @@ import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; -public class UpcallStub extends RuntimeBlob { +public class UpcallStub extends CodeBlob { private static CIntegerField frameDataOffsetField; private static AddressField lastJavaFPField; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java deleted file mode 100644 index a193d5ff340..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/VtableBlob.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, NTT DATA. - * 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 sun.jvm.hotspot.code; - -import sun.jvm.hotspot.debugger.Address; - -public class VtableBlob extends BufferBlob { - - public VtableBlob(Address addr) { - super(addr); - } - - public String getName() { - return "VtableBlob: " + super.getName(); - } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 945dd6bcc49..a0099b4c4de 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -160,28 +160,8 @@ public class PStack extends Tool { out.println(""); } } - } else if (cb.isBufferBlob()) { - out.println(""); - } else if (cb.isAdapterBlob()) { - out.println(""); - } else if (cb.isVtableBlob()) { - out.println(""); - } else if (cb.isMHAdapterBlob()) { - out.println(""); - } else if (cb.isRuntimeStub()) { - out.println(""); - } else if (cb.isUpcallStub()) { - out.println(""); - } else if (cb.isDeoptimizationBlob()) { - out.println(""); - } else if (cb.isUncommonTrapBlob()) { - out.println(""); - } else if (cb.isExceptionBlob()) { - out.println(""); - } else if (cb.isSafepointBlob()) { - out.println(""); } else { - out.println(""); + out.println("<" + cb.getName() + ">"); } } else { printUnknown(out); From 9d9d7a17d3d1a8971712ef1b22e919012350db6f Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Fri, 21 Feb 2025 20:30:02 +0000 Subject: [PATCH 088/587] 8349759: Add unit test for CertificateBuilder and SimpleOCSPServer test utilities Reviewed-by: mullan --- .../test/lib/security/CPVAlgTestWithOCSP.java | 230 ++++++++++++++++++ .../test/lib/security/CertificateBuilder.java | 46 ++-- .../test/lib/security/SimpleOCSPServer.java | 93 +++---- 3 files changed, 309 insertions(+), 60 deletions(-) create mode 100644 test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java diff --git a/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java b/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java new file mode 100644 index 00000000000..c1874492a3b --- /dev/null +++ b/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java @@ -0,0 +1,230 @@ +/* + * 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 8349759 + * @summary Test the CertificateBuilder and SimpleOCSPServer test utility + * classes using a range of signature algorithms and parameters. + * The goal is to test with both no-parameter and parameterized + * signature algorithms and use the CertPathValidator to validate + * the correctness of the certificate and OCSP server-side structures. + * @modules java.base/sun.security.x509 + * java.base/sun.security.provider.certpath + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm CPVAlgTestWithOCSP RSA + * @run main/othervm CPVAlgTestWithOCSP RSA:3072 + * @run main/othervm CPVAlgTestWithOCSP DSA + * @run main/othervm CPVAlgTestWithOCSP DSA:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:4096:SHA-512:SHA3-384:128:1 + * @run main/othervm CPVAlgTestWithOCSP EC + * @run main/othervm CPVAlgTestWithOCSP EC:secp521r1 + * @run main/othervm CPVAlgTestWithOCSP Ed25519 + * @run main/othervm CPVAlgTestWithOCSP ML-DSA-65 + */ + +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.security.spec.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.security.SimpleOCSPServer; +import jdk.test.lib.security.CertificateBuilder; + +import static java.security.cert.PKIXRevocationChecker.Option.NO_FALLBACK; + +public class CPVAlgTestWithOCSP { + + static final String passwd = "passphrase"; + static final String ROOT_ALIAS = "root"; + static final boolean[] CA_KU_FLAGS = {true, false, false, false, false, + true, true, false, false}; + static final boolean[] EE_KU_FLAGS = {true, false, false, false, false, + false, false, false, false}; + static final List EE_EKU_OIDS = List.of("1.3.6.1.5.5.7.3.1", + "1.3.6.1.5.5.7.3.2"); + + public static void main(String[] args) throws Exception { + if (args == null || args.length < 1) { + throw new RuntimeException( + "Usage: CPVAlgTestWithOCSP "); + } + String keyGenAlg = args[0]; + + // Generate Root and EE keys + KeyPairGenerator keyGen = getKpGen(keyGenAlg); + KeyPair rootCaKP = keyGen.genKeyPair(); + KeyPair eeKp = keyGen.genKeyPair(); + + // Set up the Root CA Cert + // Make a 3 year validity starting from 60 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + long end = start + TimeUnit.DAYS.toMillis(1085); + CertificateBuilder cbld = new CertificateBuilder(); + cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"). + setPublicKey(rootCaKP.getPublic()). + setSerialNumber(new BigInteger("1")). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(rootCaKP.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addBasicConstraintsExt(true, true, -1). + addKeyUsageExt(CA_KU_FLAGS); + + // Make our Root CA Cert! + X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate()); + log("Root CA Created:\n%s", rootCert); + + // Now build a keystore and add the keys and cert + KeyStore.Builder keyStoreBuilder = + KeyStore.Builder.newInstance("PKCS12", null, + new KeyStore.PasswordProtection("adminadmin0".toCharArray())); + KeyStore rootKeystore = keyStoreBuilder.getKeyStore(); + Certificate[] rootChain = {rootCert}; + rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), + passwd.toCharArray(), rootChain); + + // Now fire up the OCSP responder + SimpleOCSPServer rootOcsp = new SimpleOCSPServer(rootKeystore, + passwd, ROOT_ALIAS, null); + rootOcsp.enableLog(true); + rootOcsp.setNextUpdateInterval(3600); + rootOcsp.start(); + + // Wait 60 seconds for server ready + boolean readyStatus = rootOcsp.awaitServerReady(60, TimeUnit.SECONDS); + if (!readyStatus) { + throw new RuntimeException("Server not ready"); + } + int rootOcspPort = rootOcsp.getPort(); + String rootRespURI = "http://localhost:" + rootOcspPort; + log("Root OCSP Responder URI is %s", rootRespURI); + + // Let's make an EE cert + // Make a 1 year validity starting from 60 days ago + start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + end = start + TimeUnit.DAYS.toMillis(365); + cbld.reset().setSubjectName("CN=Brave Sir Robin, O=SomeCompany"). + setPublicKey(eeKp.getPublic()). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(eeKp.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addKeyUsageExt(EE_KU_FLAGS). + addExtendedKeyUsageExt(EE_EKU_OIDS). + addSubjectAltNameDNSExt(Collections.singletonList("localhost")). + addAIAExt(Collections.singletonList(rootRespURI)); + X509Certificate eeCert = cbld.build(rootCert, rootCaKP.getPrivate()); + log("EE CA Created:\n%s", eeCert); + + // Provide end entity cert revocation info to the Root CA + // OCSP responder. + Map revInfo = + new HashMap<>(); + revInfo.put(eeCert.getSerialNumber(), + new SimpleOCSPServer.CertStatusInfo( + SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); + rootOcsp.updateStatusDb(revInfo); + + // validate chain + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXRevocationChecker prc = + (PKIXRevocationChecker) cpv.getRevocationChecker(); + prc.setOptions(EnumSet.of(NO_FALLBACK)); + PKIXParameters params = + new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); + params.addCertPathChecker(prc); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(List.of(eeCert)); + cpv.validate(cp, params); + } + + private static KeyPairGenerator getKpGen(String keyGenAlg) + throws GeneralSecurityException { + String[] algComps = keyGenAlg.split(":"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(algComps[0]); + int bitLen; + + // Handle any parameters in additional tokenized fields + switch (algComps[0].toUpperCase()) { + case "EC": + // The curve name will be the second token, or secp256r1 + // if not provided. + String curveName = (algComps.length >= 2) ? algComps[1] : + "secp256r1"; + kpg.initialize(new ECGenParameterSpec(curveName)); + break; + case "RSA": + case "DSA": + // Form is RSA|DSA[:] + bitLen = (algComps.length >= 2) ? + Integer.parseInt(algComps[1]) : 2048; + kpg.initialize(bitLen); + break; + case "RSASSA-PSS": + // Form is RSASSA-PSS[:[:HASH:MGFHASH:SALTLEN:TR]] + switch (algComps.length) { + case 1: // Default key length and parameters + kpg.initialize(2048); + break; + case 2: // Specified key length, default params + kpg.initialize(Integer.parseInt(algComps[1])); + break; + default: // len > 2, key length and specified parameters + bitLen = Integer.parseInt(algComps[1]); + String hashAlg = algComps[2]; + MGF1ParameterSpec mSpec = (algComps.length >= 4) ? + new MGF1ParameterSpec(algComps[3]) : + MGF1ParameterSpec.SHA256; + int saltLen = (algComps.length >= 5) ? + Integer.parseInt(algComps[4]) : 32; + int trail = (algComps.length >= 6) ? + Integer.parseInt(algComps[5]) : + PSSParameterSpec.TRAILER_FIELD_BC; + PSSParameterSpec pSpec = new PSSParameterSpec(hashAlg, + "MGF1", mSpec, saltLen, trail); + kpg.initialize(new RSAKeyGenParameterSpec(bitLen, + RSAKeyGenParameterSpec.F4, pSpec)); + break; + } + + // Default: just use the KPG as-is, no additional init needed. + } + + return kpg; + } + + /** + * Log a message on stdout + * + * @param format the format string for the log entry + * @param args zero or more arguments corresponding to the format string + */ + private static void log(String format, Object ... args) { + System.out.format(format + "\n", args); + } +} diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index 7ff066bc7e0..60358c9a4ea 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -51,7 +51,6 @@ import sun.security.x509.DNSName; import sun.security.x509.GeneralName; import sun.security.x509.GeneralNames; import sun.security.x509.KeyUsageExtension; -import sun.security.x509.SerialNumber; import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; @@ -288,11 +287,8 @@ public class CertificateBuilder { * * @param bitSettings Boolean array for all nine bit settings in the order * documented in RFC 5280 section 4.2.1.3. - * - * @throws IOException if an encoding error occurs. */ - public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) - throws IOException { + public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) { return addExtension(new KeyUsageExtension(bitSettings)); } @@ -305,11 +301,9 @@ public class CertificateBuilder { * @param maxPathLen The maximum path length issued by this CA. Values * less than zero will omit this field from the resulting extension and * no path length constraint will be asserted. - * - * @throws IOException if an encoding error occurs. */ public CertificateBuilder addBasicConstraintsExt(boolean crit, boolean isCA, - int maxPathLen) throws IOException { + int maxPathLen) { return addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen)); } @@ -389,7 +383,27 @@ public class CertificateBuilder { } /** - * Build the certificate. + * Build the certificate using the default algorithm for the provided + * signing key. + * + * @param issuerCert The certificate of the issuing authority, or + * {@code null} if the resulting certificate is self-signed. + * @param issuerKey The private key of the issuing authority + * + * @return The resulting {@link X509Certificate} + * + * @throws IOException if an encoding error occurs. + * @throws CertificateException If the certificate cannot be generated + * by the underlying {@link CertificateFactory} + */ + public X509Certificate build(X509Certificate issuerCert, + PrivateKey issuerKey) throws IOException, CertificateException { + return build(issuerCert, issuerKey, + SignatureUtil.getDefaultSigAlgForKey(issuerKey)); + } + + /** + * Build the certificate using the key and specified signing algorithm. * * @param issuerCert The certificate of the issuing authority, or * {@code null} if the resulting certificate is self-signed. @@ -401,14 +415,10 @@ public class CertificateBuilder { * @throws IOException if an encoding error occurs. * @throws CertificateException If the certificate cannot be generated * by the underlying {@link CertificateFactory} - * @throws NoSuchAlgorithmException If an invalid signature algorithm - * is provided. */ public X509Certificate build(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws IOException, CertificateException, NoSuchAlgorithmException { - // TODO: add some basic checks (key usage, basic constraints maybe) - + throws IOException, CertificateException { byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); return (X509Certificate)factory.generateCertificate(bais); @@ -437,15 +447,14 @@ public class CertificateBuilder { */ private byte[] encodeTopLevel(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws CertificateException, IOException, NoSuchAlgorithmException { + throws CertificateException, IOException { - AlgorithmId signAlg = AlgorithmId.get(algName); + AlgorithmId signAlg; DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream(); try { - Signature sig = SignatureUtil.fromKey(signAlg.getName(), issuerKey, (Provider)null); - // Rewrite signAlg, RSASSA-PSS needs some parameters. + Signature sig = SignatureUtil.fromKey(algName, issuerKey, ""); signAlg = SignatureUtil.fromSignature(sig, issuerKey); tbsCertBytes = encodeTbsCert(issuerCert, signAlg); sig.update(tbsCertBytes); @@ -566,7 +575,6 @@ public class CertificateBuilder { */ private void encodeExtensions(DerOutputStream tbsStream) throws IOException { - if (extensions.isEmpty()) { return; } diff --git a/test/lib/jdk/test/lib/security/SimpleOCSPServer.java b/test/lib/jdk/test/lib/security/SimpleOCSPServer.java index e8ce021b138..4e25467ca80 100644 --- a/test/lib/jdk/test/lib/security/SimpleOCSPServer.java +++ b/test/lib/jdk/test/lib/security/SimpleOCSPServer.java @@ -25,6 +25,7 @@ package jdk.test.lib.security; import java.io.*; import java.net.*; +import java.nio.charset.StandardCharsets; import java.security.*; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; @@ -61,7 +62,7 @@ public class SimpleOCSPServer { static final int FREE_PORT = 0; // CertStatus values - public static enum CertStatus { + public enum CertStatus { CERT_STATUS_GOOD, CERT_STATUS_REVOKED, CERT_STATUS_UNKNOWN, @@ -69,14 +70,14 @@ public class SimpleOCSPServer { // Fields used for the networking portion of the responder private ServerSocket servSocket; - private InetAddress listenAddress; + private final InetAddress listenAddress; private int listenPort; // Keystore information (certs, keys, etc.) - private KeyStore keystore; - private X509Certificate issuerCert; - private X509Certificate signerCert; - private PrivateKey signerKey; + private final KeyStore keystore; + private final X509Certificate issuerCert; + private final X509Certificate signerCert; + private final PrivateKey signerKey; // Fields used for the operational portions of the server private boolean logEnabled = false; @@ -91,9 +92,9 @@ public class SimpleOCSPServer { // Fields used in the generation of responses private long nextUpdateInterval = -1; private Date nextUpdate = null; - private ResponderId respId; - private AlgorithmId sigAlgId; - private Map statusDb = + private final ResponderId respId; + private String sigAlgName; + private final Map statusDb = Collections.synchronizedMap(new HashMap<>()); /** @@ -140,25 +141,24 @@ public class SimpleOCSPServer { public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks, String password, String issuerAlias, String signerAlias) throws GeneralSecurityException, IOException { - Objects.requireNonNull(ks, "Null keystore provided"); + keystore = Objects.requireNonNull(ks, "Null keystore provided"); Objects.requireNonNull(issuerAlias, "Null issuerName provided"); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); - keystore = ks; - issuerCert = (X509Certificate)ks.getCertificate(issuerAlias); + issuerCert = (X509Certificate)keystore.getCertificate(issuerAlias); if (issuerCert == null) { throw new IllegalArgumentException("Certificate for alias " + issuerAlias + " not found"); } if (signerAlias != null) { - signerCert = (X509Certificate)ks.getCertificate(signerAlias); + signerCert = (X509Certificate)keystore.getCertificate(signerAlias); if (signerCert == null) { throw new IllegalArgumentException("Certificate for alias " + signerAlias + " not found"); } - signerKey = (PrivateKey)ks.getKey(signerAlias, + signerKey = (PrivateKey)keystore.getKey(signerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + @@ -166,14 +166,14 @@ public class SimpleOCSPServer { } } else { signerCert = issuerCert; - signerKey = (PrivateKey)ks.getKey(issuerAlias, + signerKey = (PrivateKey)keystore.getKey(issuerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + issuerAlias + " not found"); } } - sigAlgId = AlgorithmId.get(SignatureUtil.getDefaultSigAlgForKey(signerKey)); + sigAlgName = SignatureUtil.getDefaultSigAlgForKey(signerKey); respId = new ResponderId(signerCert.getSubjectX500Principal()); listenAddress = addr; listenPort = port; @@ -495,8 +495,14 @@ public class SimpleOCSPServer { public void setSignatureAlgorithm(String algName) throws NoSuchAlgorithmException { if (!started) { - sigAlgId = AlgorithmId.get(algName); - log("Signature algorithm set to " + sigAlgId.getName()); + // We don't care about the AlgorithmId object, we're just + // using it to validate the algName parameter. + AlgorithmId.get(algName); + sigAlgName = algName; + log("Signature algorithm set to " + algName); + } else { + log("Signature algorithm cannot be set on a running server, " + + "stop the server first"); } } @@ -604,9 +610,9 @@ public class SimpleOCSPServer { * object may be used to construct OCSP responses. */ public static class CertStatusInfo { - private CertStatus certStatusType; + private final CertStatus certStatusType; private CRLReason reason; - private Date revocationTime; + private final Date revocationTime; /** * Create a Certificate status object by providing the status only. @@ -745,7 +751,7 @@ public class SimpleOCSPServer { // This will be tokenized so we know if we are dealing with // a GET or POST. String[] headerTokens = readLine(in).split(" "); - LocalOcspRequest ocspReq = null; + LocalOcspRequest ocspReq; LocalOcspResponse ocspResp = null; ResponseStatus respStat = ResponseStatus.INTERNAL_ERROR; try { @@ -794,7 +800,7 @@ public class SimpleOCSPServer { out.flush(); log("Closing " + ocspSocket); - } catch (IOException | CertificateException exc) { + } catch (IOException | GeneralSecurityException exc) { err(exc); } } @@ -826,10 +832,10 @@ public class SimpleOCSPServer { append("\r\n"); } sb.append("\r\n"); - - out.write(sb.toString().getBytes("UTF-8")); - out.write(respBytes); log(resp.toString()); + + out.write(sb.toString().getBytes(StandardCharsets.UTF_8)); + out.write(respBytes); } /** @@ -940,7 +946,7 @@ public class SimpleOCSPServer { // "/" off before decoding. return new LocalOcspRequest(Base64.getMimeDecoder().decode( URLDecoder.decode(headerTokens[1].replaceAll("/", ""), - "UTF-8"))); + StandardCharsets.UTF_8))); } /** @@ -974,8 +980,7 @@ public class SimpleOCSPServer { bos.write(b); } } - - return new String(bos.toByteArray(), "UTF-8"); + return bos.toString(StandardCharsets.UTF_8); } } @@ -1052,7 +1057,6 @@ public class SimpleOCSPServer { if (sigItems[2].isContextSpecific((byte)0)) { DerValue[] certDerItems = sigItems[2].data.getSequence(4); - int i = 0; for (DerValue dv : certDerItems) { X509Certificate xc = new X509CertImpl(dv); certificates.add(xc); @@ -1131,7 +1135,7 @@ public class SimpleOCSPServer { * Return the list of X.509 Certificates in this OCSP request. * * @return an unmodifiable {@code List} of zero or more - * {@cpde X509Certificate} objects. + * {@code X509Certificate} objects. */ private List getCertificates() { return Collections.unmodifiableList(certificates); @@ -1295,7 +1299,8 @@ public class SimpleOCSPServer { private final Map responseExtensions; private byte[] signature; private final List certificates; - private final byte[] encodedResponse; + private final Signature signEngine; + private final AlgorithmId sigAlgId; /** * Constructor for the generation of non-successful responses @@ -1305,9 +1310,11 @@ public class SimpleOCSPServer { * @throws IOException if an error happens during encoding * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat) - throws IOException { + throws IOException, GeneralSecurityException { this(respStat, null, null); } @@ -1324,10 +1331,13 @@ public class SimpleOCSPServer { * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful, and a {@code null} {@code itemMap} * has been provided. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat, Map itemMap, - Map reqExtensions) throws IOException { + Map reqExtensions) + throws IOException, GeneralSecurityException { responseStatus = Objects.requireNonNull(respStat, "Illegal null response status"); if (responseStatus == ResponseStatus.SUCCESSFUL) { @@ -1348,13 +1358,18 @@ public class SimpleOCSPServer { certificates.add(signerCert); } certificates.add(issuerCert); + // Create the signature object and AlgorithmId that we'll use + // later to create the signature on this response. + signEngine = SignatureUtil.fromKey(sigAlgName, signerKey, ""); + sigAlgId = SignatureUtil.fromSignature(signEngine, signerKey); } else { respItemMap = null; producedAtDate = null; responseExtensions = null; certificates = null; + signEngine = null; + sigAlgId = null; } - encodedResponse = this.getBytes(); } /** @@ -1436,13 +1451,9 @@ public class SimpleOCSPServer { basicORItemStream.write(tbsResponseBytes); try { - // Create the signature - Signature sig = SignatureUtil.fromKey( - sigAlgId.getName(), signerKey, (Provider)null); - sig.update(tbsResponseBytes); - signature = sig.sign(); - // Rewrite signAlg, RSASSA-PSS needs some parameters. - sigAlgId = SignatureUtil.fromSignature(sig, signerKey); + // Create the signature with the initialized Signature object + signEngine.update(tbsResponseBytes); + signature = signEngine.sign(); sigAlgId.encode(basicORItemStream); basicORItemStream.putBitString(signature); } catch (GeneralSecurityException exc) { From 825ab20ba99b1f1127dd94b87ae56020d1831529 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 21 Feb 2025 21:06:54 +0000 Subject: [PATCH 089/587] 8350456: Test javax/crypto/CryptoPermissions/InconsistentEntries.java crashed: EXCEPTION_ACCESS_VIOLATION Reviewed-by: rhalade, jnimeh --- .../InconsistentEntries.java | 4 +-- test/lib/jdk/test/lib/util/FileUtils.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java b/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java index 85118f34d03..1e84316867e 100644 --- a/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java +++ b/test/jdk/javax/crypto/CryptoPermissions/InconsistentEntries.java @@ -31,8 +31,8 @@ import java.util.List; import jdk.test.lib.Utils; -import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -59,7 +59,7 @@ public class InconsistentEntries { @BeforeTest public void setUp() throws Exception { // Clone the tested JDK to the scratch directory - CDSTestUtils.clone(new File(JDK_HOME), new File(TEMP_JDK_HOME.toString())); + FileUtils.copyDirectory(Path.of(JDK_HOME), TEMP_JDK_HOME); // create policy directory in the cloned JDK if (!POLICY_DIR.toFile().exists()) { diff --git a/test/lib/jdk/test/lib/util/FileUtils.java b/test/lib/jdk/test/lib/util/FileUtils.java index 7b2ab434af2..8b99d1e9d54 100644 --- a/test/lib/jdk/test/lib/util/FileUtils.java +++ b/test/lib/jdk/test/lib/util/FileUtils.java @@ -36,6 +36,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.time.Instant; import java.util.ArrayList; @@ -48,6 +49,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import java.util.stream.Stream; + import jdk.test.lib.Platform; import com.sun.management.UnixOperatingSystemMXBean; @@ -364,6 +367,30 @@ public final class FileUtils { }); } + /** + * Copies a directory and all entries in the directory to a destination path. + * Makes the access permission of the destination entries writable. + * + * @param src the path of the source directory + * @param dst the path of the destination directory + * @throws IOException if an I/O error occurs while walking the file tree + * @throws RuntimeException if an I/O error occurs during the copy operation + * or if the source or destination paths are invalid + */ + public static void copyDirectory(Path src, Path dst) throws IOException { + try (Stream stream = Files.walk(src)) { + stream.forEach(sourcePath -> { + try { + Path destPath = dst.resolve(src.relativize(sourcePath)); + Files.copy(sourcePath, destPath, StandardCopyOption.REPLACE_EXISTING); + destPath.toFile().setWritable(true); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + // Return the current process handle count @SuppressWarnings("restricted") public static long getProcessHandleCount() { From 25322aae8e224680db376098d2e45f26cf3334a0 Mon Sep 17 00:00:00 2001 From: Dmitry Chuyko Date: Fri, 21 Feb 2025 21:43:54 +0000 Subject: [PATCH 090/587] 8350258: AArch64: Client build fails after JDK-8347917 Reviewed-by: dlong, kvn --- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 7201674cd63..b07fa2fa9df 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -507,11 +507,11 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { intptr_t* unextended_sp = interpreter_frame_sender_sp(); intptr_t* sender_fp = link(); -#if COMPILER2_OR_JVMCI +#if defined(COMPILER1) || COMPILER2_OR_JVMCI if (map->update_map()) { update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); } -#endif // COMPILER2_OR_JVMCI +#endif // defined(COMPILER1) || COMPILER1_OR_COMPILER2 // For ROP protection, Interpreter will have signed the sender_pc, // but there is no requirement to authenticate it here. From 5cbd9d1fe19b6d9516233cd1ed8d3ba340b7a1e6 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 22 Feb 2025 03:11:42 +0000 Subject: [PATCH 091/587] 8349959: Test CR6740048.java passes unexpectedly missing CR6740048.xsd Reviewed-by: joehw --- .../javax/xml/jaxp/unittest/validation/CR6740048.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/jaxp/javax/xml/jaxp/unittest/validation/CR6740048.java b/test/jaxp/javax/xml/jaxp/unittest/validation/CR6740048.java index 6fcff45fc05..fbb515aca70 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/validation/CR6740048.java +++ b/test/jaxp/javax/xml/jaxp/unittest/validation/CR6740048.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 @@ -59,11 +59,9 @@ public class CR6740048 { DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilderFactory.setNamespaceAware(true); - if (xsd != null) { - docBuilderFactory.setValidating(true); - docBuilderFactory.setAttribute(SCHEMA_LANGUAGE_URL, XML_SCHEMA_URL); - docBuilderFactory.setAttribute(SCHEMA_SOURCE_URL, xsd); - } + docBuilderFactory.setValidating(true); + docBuilderFactory.setAttribute(SCHEMA_LANGUAGE_URL, XML_SCHEMA_URL); + docBuilderFactory.setAttribute(SCHEMA_SOURCE_URL, xsd); final DocumentBuilder documentBuilder = docBuilderFactory.newDocumentBuilder(); documentBuilder.setErrorHandler(new ErrorHandler() { From a891630817844c8c42994da3b3110925ca4595a0 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Sat, 22 Feb 2025 10:16:51 +0000 Subject: [PATCH 092/587] 8350480: RISC-V: Relax assertion about registers in C2_MacroAssembler::minmax_fp Reviewed-by: mli, fjiang --- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 34a61177774..e52cf7565be 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2135,7 +2135,8 @@ void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Regis // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, bool is_double, bool is_min) { - assert_different_registers(dst, src1, src2); + assert_different_registers(dst, src1); + assert_different_registers(dst, src2); Label Done, Compare; From 05b481294cbf2ad7c8d917b8e039e7aebcf91104 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Sun, 23 Feb 2025 02:35:57 +0000 Subject: [PATCH 093/587] 8350041: Skip test/jdk/java/lang/String/nativeEncoding/StringPlatformChars.java on static JDK Reviewed-by: alanb --- .../java/lang/String/nativeEncoding/StringPlatformChars.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/lang/String/nativeEncoding/StringPlatformChars.java b/test/jdk/java/lang/String/nativeEncoding/StringPlatformChars.java index db4c407a17a..fec8b34e5ad 100644 --- a/test/jdk/java/lang/String/nativeEncoding/StringPlatformChars.java +++ b/test/jdk/java/lang/String/nativeEncoding/StringPlatformChars.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 @@ -23,6 +23,7 @@ /* * @test + * @requires !jdk.static * @run main/othervm/native -Xcheck:jni StringPlatformChars */ import java.util.Arrays; From 0795d11bfc0c6640ed7e9f05a17eb2a733d88bc0 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 24 Feb 2025 03:13:55 +0000 Subject: [PATCH 094/587] 8350464: The flags to set the native priority for the VMThread and Java threads need a broader range Reviewed-by: stuefe, shade --- src/hotspot/share/runtime/globals.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d3bdb0c68b2..61c4c0633c7 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.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 @@ -1605,47 +1605,47 @@ const int ObjectAlignmentInBytes = 8; product(int, VMThreadPriority, -1, \ "The native priority at which the VM thread should run " \ "(-1 means no change)") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority1_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority2_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority3_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority4_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority5_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority6_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority7_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority8_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority9_To_OSPriority, -1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(int, JavaPriority10_To_OSPriority,-1, \ "Map Java priorities to OS priorities") \ - range(-1, 127) \ + range(min_jint, max_jint) \ \ product(bool, UseCriticalJavaThreadPriority, false, EXPERIMENTAL, \ "Java thread priority 10 maps to critical scheduling priority") \ From 302bed055c3b4881f97c584d5953273b9dbc2969 Mon Sep 17 00:00:00 2001 From: Ao Qi Date: Mon, 24 Feb 2025 03:17:56 +0000 Subject: [PATCH 095/587] 8350499: Minimal build fails with slowdebug builds Reviewed-by: kbarrett, dholmes --- src/hotspot/share/classfile/verifier.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index b1daee82747..4434b06c0b8 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -31,7 +31,6 @@ #include "classfile/stackMapTableFormat.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" -#include "classfile/systemDictionaryShared.hpp" #include "classfile/verifier.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" @@ -60,6 +59,9 @@ #include "services/threadService.hpp" #include "utilities/align.hpp" #include "utilities/bytes.hpp" +#if INCLUDE_CDS +#include "classfile/systemDictionaryShared.hpp" +#endif #define NOFAILOVER_MAJOR_VERSION 51 #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51 @@ -234,11 +236,13 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { exception_name == vmSymbols::java_lang_ClassFormatError())) { log_info(verification)("Fail over class verification to old verifier for: %s", klass->external_name()); log_info(class, init)("Fail over class verification to old verifier for: %s", klass->external_name()); +#if INCLUDE_CDS // Exclude any classes that fail over during dynamic dumping if (CDSConfig::is_dumping_dynamic_archive()) { SystemDictionaryShared::warn_excluded(klass, "Failed over class verification while dynamic dumping"); SystemDictionaryShared::set_excluded(klass); } +#endif message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len); exception_message = message_buffer; exception_name = inference_verify( From a5c9a4dbde410c687f05951b8f1d3cf72fcaedc0 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 24 Feb 2025 07:28:05 +0000 Subject: [PATCH 096/587] 8349032: C2: Parse Predicate refactoring in Loop Unswitching broke fix for JDK-8290850 Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/loopPredicate.cpp | 7 +- src/hotspot/share/opto/loopnode.hpp | 6 +- src/hotspot/share/opto/predicates.cpp | 14 ++-- src/hotspot/share/opto/predicates.hpp | 8 +-- .../TestParsePredicateUCTWithPhi.java | 69 +++++++++++++++++++ 5 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/predicates/TestParsePredicateUCTWithPhi.java diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index dc7d125cc91..96e0fd26d0d 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -96,8 +96,11 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred, // // We will create a region to guard the uct call if there is no one there. // The continuation projection (if_cont) of the new_iff is returned which -// is an IfTrue projection. This code is also used to clone predicates to cloned loops. -IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_success_proj, +// is an IfTrue projection. This code is also used to clone predicates to +// cloned loops. 'rewire_uncommon_proj_phi_inputs' should be set to the +// non-default value 'true' when called for a false-path loop during +// Loop Unswitching. +IfTrueNode* PhaseIdealLoop::create_new_if_for_predicate(const ParsePredicateSuccessProj* parse_predicate_success_proj, Node* new_entry, const Deoptimization::DeoptReason reason, const int opcode, const bool rewire_uncommon_proj_phi_inputs) { assert(parse_predicate_success_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 91508c512cb..4e5a60ee3cd 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1358,9 +1358,9 @@ public: bool* p_short_scale, int depth); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - IfTrueNode* create_new_if_for_predicate( - ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, int opcode, - bool rewire_uncommon_proj_phi_inputs = false); + IfTrueNode* create_new_if_for_predicate(const ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, int opcode, + bool rewire_uncommon_proj_phi_inputs = false); private: // Helper functions for create_new_if_for_predicate() diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index d2b33ceed44..6badaa65487 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -81,20 +81,20 @@ ParsePredicateNode* ParsePredicate::init_parse_predicate(const Node* parse_predi return nullptr; } -ParsePredicate ParsePredicate::clone_to_unswitched_loop(Node* new_control, const bool is_true_path_loop, +ParsePredicate ParsePredicate::clone_to_unswitched_loop(Node* new_control, const bool is_false_path_loop, PhaseIdealLoop* phase) const { ParsePredicateSuccessProj* success_proj = phase->create_new_if_for_predicate(_success_proj, new_control, _parse_predicate_node->deopt_reason(), - Op_ParsePredicate, is_true_path_loop); - NOT_PRODUCT(trace_cloned_parse_predicate(is_true_path_loop, success_proj)); + Op_ParsePredicate, is_false_path_loop); + NOT_PRODUCT(trace_cloned_parse_predicate(is_false_path_loop, success_proj)); return ParsePredicate(success_proj, _parse_predicate_node->deopt_reason()); } #ifndef PRODUCT -void ParsePredicate::trace_cloned_parse_predicate(const bool is_true_path_loop, +void ParsePredicate::trace_cloned_parse_predicate(const bool is_false_path_loop, const ParsePredicateSuccessProj* success_proj) { if (TraceLoopPredicate) { - tty->print("Parse Predicate cloned to %s path loop: ", is_true_path_loop ? "true" : "false"); + tty->print("Parse Predicate cloned to %s path loop: ", is_false_path_loop ? "false" : "true"); success_proj->in(0)->dump(); } } @@ -1066,8 +1066,8 @@ void CloneUnswitchedLoopPredicatesVisitor::visit(const ParsePredicate& parse_pre _has_hoisted_check_parse_predicates = true; } - _clone_predicate_to_true_path_loop.clone_parse_predicate(parse_predicate, true); - _clone_predicate_to_false_path_loop.clone_parse_predicate(parse_predicate, false); + _clone_predicate_to_true_path_loop.clone_parse_predicate(parse_predicate, false); + _clone_predicate_to_false_path_loop.clone_parse_predicate(parse_predicate, true); parse_predicate.kill(_phase->igvn()); } diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index c4e2bbc79c6..bfc1b23115e 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -296,7 +296,7 @@ class ParsePredicate : public Predicate { } static ParsePredicateNode* init_parse_predicate(const Node* parse_predicate_proj, Deoptimization::DeoptReason deopt_reason); - NOT_PRODUCT(static void trace_cloned_parse_predicate(bool is_true_path_loop, + NOT_PRODUCT(static void trace_cloned_parse_predicate(bool is_false_path_loop, const ParsePredicateSuccessProj* success_proj);) public: @@ -327,7 +327,7 @@ class ParsePredicate : public Predicate { return _success_proj; } - ParsePredicate clone_to_unswitched_loop(Node* new_control, bool is_true_path_loop, + ParsePredicate clone_to_unswitched_loop(Node* new_control, bool is_false_path_loop, PhaseIdealLoop* phase) const; // Kills this Parse Predicate by marking it useless. Will be folded away in the next IGVN round. @@ -1106,9 +1106,9 @@ public: ClonePredicateToTargetLoop(LoopNode* target_loop_head, const NodeInLoopBody& node_in_loop_body, PhaseIdealLoop* phase); // Clones the provided Parse Predicate to the head of the current predicate chain at the target loop. - void clone_parse_predicate(const ParsePredicate& parse_predicate, bool is_true_path_loop) { + void clone_parse_predicate(const ParsePredicate& parse_predicate, bool is_false_path_loop) { ParsePredicate cloned_parse_predicate = parse_predicate.clone_to_unswitched_loop(_old_target_loop_entry, - is_true_path_loop, _phase); + is_false_path_loop, _phase); _target_loop_predicate_chain.insert_predicate(cloned_parse_predicate); } diff --git a/test/hotspot/jtreg/compiler/predicates/TestParsePredicateUCTWithPhi.java b/test/hotspot/jtreg/compiler/predicates/TestParsePredicateUCTWithPhi.java new file mode 100644 index 00000000000..977b7b31940 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/TestParsePredicateUCTWithPhi.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. + */ + +/* + * @test + * @bug 8349032 + * @summary Test that UCT for a Parse Predicate with a Phi does not incorrectly have a top input after Loop Unswitching. + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,*TestParsePredicateUCTWithPhi*::test + * compiler.predicates.TestParsePredicateUCTWithPhi + */ + +package compiler.predicates; + +public class TestParsePredicateUCTWithPhi { + static int iFld; + static int[][] iArrFld = new int[100][100]; + static int[] iArr = new int[100]; + + public static void main(String[] strArr) { + for (int i = 0; i < 10; i++) { + test(); + } + } + + static void test() { + int i1 = 3; + for (int i = 7; i < 28; i++) { + int i20 = 4; + try { + iArr[3] = i1 / i; + } catch (ArithmeticException a_e) { + } + try { + i1 = 6 / iArrFld[i][i]; + } catch (ArithmeticException a_e) { + } + int i22 = 1; + while (++i22 < 7) { + try { + i20 = i20 / iArrFld[i][i]; + i1 = 0; + i1 = iArr[1] / i; + } catch (ArithmeticException a_e) { + } + iFld = i20; + } + } + } +} From f755fadc3d7fd1e09cdc2442531fa724ebb77dce Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 24 Feb 2025 07:38:29 +0000 Subject: [PATCH 097/587] 8349653: Clarify the docs for MemorySegment::reinterpret Reviewed-by: jvernee, mcimadamore --- .../java/lang/foreign/MemorySegment.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 70af8e7e041..3d85e4c32cc 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -756,14 +756,14 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { /** * Returns a new memory segment with the same address and size as this segment, but - * with the provided scope. As such, the returned segment cannot be accessed after - * the provided arena has been closed. Moreover, the returned segment can be + * with the provided arena's scope. As such, the returned segment cannot be accessed + * after the provided arena has been closed. Moreover, the returned segment can be * accessed compatibly with the confinement restrictions associated with the provided * arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, * the returned segment can only be accessed by the arena's owner thread, regardless * of the confinement restrictions associated with this segment. In other words, this * method returns a segment that can be used as any other segment allocated using the - * provided arena. However, The returned segment is backed by the same memory region + * provided arena. However, the returned segment is backed by the same memory region * as that of the original segment. As such, the region of memory backing the * returned segment is deallocated only when this segment's arena is closed. * This might lead to use-after-free issues, as the returned segment can be @@ -771,15 +771,15 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * segment's arena. *

* Clients can specify an optional cleanup action that should be executed when the - * provided scope becomes invalid. This cleanup action receives a fresh memory + * provided arena's scope becomes invalid. This cleanup action receives a fresh memory * segment that is obtained from this segment as follows: * {@snippet lang=java : * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(byteSize()); * } * That is, the cleanup action receives a segment that is associated with the global - * scope, and is accessible from any thread. The size of the segment accepted by the - * cleanup action is {@link #byteSize()}. + * arena's scope, and is accessible from any thread. The size of the segment accepted + * by the cleanup action is {@link #byteSize()}. *

* If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. @@ -790,8 +790,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @apiNote The cleanup action (if present) should take care not to leak the received * segment to external clients that might access the segment after its * backing region of memory is no longer available. Furthermore, if the - * provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, - * the cleanup action must not prevent the scope from becoming + * provided arena is an {@linkplain Arena#ofAuto() automatic arena}, + * the cleanup action must not prevent the arena from becoming * {@linkplain java.lang.ref##reachability unreachable}. * A failure to do so will permanently prevent the regions of memory * allocated by the automatic arena from being deallocated. @@ -812,14 +812,14 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { /** * Returns a new segment with the same address as this segment, but with the provided - * size and scope. As such, the returned segment cannot be accessed after the - * provided arena has been closed. Moreover, if the returned segment can be accessed - * compatibly with the confinement restrictions associated with the provided arena: - * that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, + * size and the provided arena's scope. As such, the returned segment cannot be + * accessed after the provided arena has been closed. Moreover, if the returned + * segment can be accessed compatibly with the confinement restrictions associated + * with the provided arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, * the returned segment can only be accessed by the arena's owner thread, regardless * of the confinement restrictions associated with this segment. In other words, this * method returns a segment that can be used as any other segment allocated using the - * provided arena. However, The returned segment is backed by the same memory region + * provided arena. However, the returned segment is backed by the same memory region * as that of the original segment. As such, the region of memory backing the * returned segment is deallocated only when this segment's arena is closed. * This might lead to use-after-free issues, as the returned segment can be @@ -827,15 +827,15 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * segment's arena. *

* Clients can specify an optional cleanup action that should be executed when the - * provided scope becomes invalid. This cleanup action receives a fresh memory + * provided arena's scope becomes invalid. This cleanup action receives a fresh memory * segment that is obtained from this segment as follows: * {@snippet lang=java : * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(newSize); * } * That is, the cleanup action receives a segment that is associated with the global - * scope, and is accessible from any thread. The size of the segment accepted by the - * cleanup action is {@code newSize}. + * arena's scope, and is accessible from any thread. The size of the segment accepted + * by the cleanup action is {@code newSize}. *

* If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. @@ -846,8 +846,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @apiNote The cleanup action (if present) should take care not to leak the received * segment to external clients that might access the segment after its * backing region of memory is no longer available. Furthermore, if the - * provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, - * the cleanup action must not prevent the scope from becoming + * provided arena is an {@linkplain Arena#ofAuto() automatic arena}, + * the cleanup action must not prevent the arena from becoming * {@linkplain java.lang.ref##reachability unreachable}. * A failure to do so will permanently prevent the regions of memory * allocated by the automatic arena from being deallocated. From e410af00e69587b86536b298b869ddc898fd9862 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 24 Feb 2025 07:40:17 +0000 Subject: [PATCH 098/587] 8342393: Promote commutative vector IR node sharing Reviewed-by: vlivanov, epeter, sviswanathan --- src/hotspot/share/opto/vectornode.cpp | 57 +- src/hotspot/share/opto/vectornode.hpp | 2 + .../VectorCommutativeOperSharingTest.java | 576 ++++++++++++++++++ ...VectorCommutativeOperSharingBenchmark.java | 155 +++++ 4 files changed, 789 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java create mode 100644 test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 4ef864fe9c4..dc7fd18a8d0 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1042,10 +1042,65 @@ Node* VectorNode::try_to_gen_masked_vector(PhaseGVN* gvn, Node* node, const Type } } +bool VectorNode::should_swap_inputs_to_help_global_value_numbering() { + // Predicated vector operations are sensitive to ordering of inputs. + // When the mask corresponding to a vector lane is false then + // the result of the operation is corresponding lane of its first operand. + // i.e. RES = VEC1.lanewise(OPER, VEC2, MASK) is semantically equivalent to + // RES = BLEND(VEC1, VEC1.lanewise(OPER, VEC2), MASK) + if (is_predicated_vector()) { + return false; + } + + switch(Opcode()) { + case Op_AddVB: + case Op_AddVS: + case Op_AddVI: + case Op_AddVL: + case Op_AddVF: + case Op_AddVD: + + case Op_MulVB: + case Op_MulVS: + case Op_MulVI: + case Op_MulVL: + case Op_MulVF: + case Op_MulVD: + + case Op_MaxV: + case Op_MinV: + case Op_XorV: + case Op_OrV: + case Op_AndV: + case Op_UMinV: + case Op_UMaxV: + + case Op_AndVMask: + case Op_OrVMask: + case Op_XorVMask: + + case Op_SaturatingAddV: + assert(req() == 3, "Must be a binary operation"); + // For non-predicated commutative operations, sort the inputs in + // increasing order of node indices. + if (in(1)->_idx > in(2)->_idx) { + return true; + } + // fallthrough + default: + return false; + } +} + Node* VectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (Matcher::vector_needs_partial_operations(this, vect_type())) { return try_to_gen_masked_vector(phase, this, vect_type()); } + + // Sort inputs of commutative non-predicated vector operations to help value numbering. + if (should_swap_inputs_to_help_global_value_numbering()) { + swap_edges(1, 2); + } return nullptr; } @@ -2076,7 +2131,7 @@ Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* zero = phase->transform(phase->zerocon(bt)); return VectorNode::scalar2vector(zero, length(), bt, bottom_type()->isa_vectmask() != nullptr); } - return nullptr; + return VectorNode::Ideal(phase, can_reshape); } Node* VectorBlendNode::Identity(PhaseGVN* phase) { diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 0bd1c71d7e6..50220c9362b 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -88,6 +88,8 @@ class VectorNode : public TypeNode { static bool is_convert_opcode(int opc); static bool is_minmax_opcode(int opc); + bool should_swap_inputs_to_help_global_value_numbering(); + static bool is_vshift_cnt_opcode(int opc); static bool is_rotate_opcode(int opc); diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java new file mode 100644 index 00000000000..c2237000e6f --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java @@ -0,0 +1,576 @@ +/* + * 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.vectorapi; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import java.util.Random; +import jdk.incubator.vector.*; +import jdk.test.lib.Utils; + +/** + * @test + * @bug 8342393 + * @key randomness + * @library /test/lib / + * @summary Promote vector IR node sharing + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorCommutativeOperSharingTest + */ + +public class VectorCommutativeOperSharingTest { + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_PREFERRED; + + private static int LENGTH = 128; + private static final Random RD = Utils.getRandomInstance(); + + private static int[] ia; + private static int[] ib; + private static int[] ir1; + private static int[] ir2; + private static int[] ir3; + private static int[] ir4; + + static { + ia = new int[LENGTH]; + ib = new int[LENGTH]; + ir1 = new int[LENGTH]; + ir2 = new int[LENGTH]; + ir3 = new int[LENGTH]; + ir4 = new int[LENGTH]; + + for (int i = 0; i < LENGTH; i++) { + ia[i] = RD.nextInt(Integer.MAX_VALUE); + ib[i] = RD.nextInt(Integer.MAX_VALUE); + } + } + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", + IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", + IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, + applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing1(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + vec1.lanewise(VectorOperators.MUL, vec2) + .lanewise(VectorOperators.MUL, vec2.lanewise(VectorOperators.MUL, vec1)) + .intoArray(ir2, index); + vec1.lanewise(VectorOperators.MAX, vec2) + .lanewise(VectorOperators.MAX, vec2.lanewise(VectorOperators.MAX, vec1)) + .intoArray(ir3, index); + vec1.lanewise(VectorOperators.MIN, vec2) + .lanewise(VectorOperators.MIN, vec2.lanewise(VectorOperators.MIN, vec1)) + .intoArray(ir4, index); + } + + @Run(test = "testVectorIRSharing1") + public void testVectorIRSharingDriver1() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing1(i); + } + checkVectorIRSharing1(); + } + + public void checkVectorIRSharing1() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ib[i]) + (ib[i] + ia[i])); + Verify.checkEQ(ir2[i], (ia[i] * ib[i]) * (ib[i] * ia[i])); + Verify.checkEQ(ir3[i], Integer.max(Integer.max(ia[i], ib[i]), Integer.max(ib[i], ia[i]))); + Verify.checkEQ(ir4[i], Integer.min(Integer.max(ia[i], ib[i]), Integer.min(ib[i], ia[i]))); + } + } + + @Test + @IR(counts = {IRNode.XOR_VI, IRNode.VECTOR_SIZE_ANY, " 0 ", + IRNode.OR_VI, IRNode.VECTOR_SIZE_ANY, " 1 ", + IRNode.AND_VI, IRNode.VECTOR_SIZE_ANY, " 1 "}, + applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing2(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + vec1.lanewise(VectorOperators.XOR, vec2) + .lanewise(VectorOperators.XOR, vec2.lanewise(VectorOperators.XOR, vec1)) + .intoArray(ir1, index); + vec1.lanewise(VectorOperators.AND, vec2) + .lanewise(VectorOperators.AND, vec2.lanewise(VectorOperators.AND, vec1)) + .intoArray(ir2, index); + vec1.lanewise(VectorOperators.OR, vec2) + .lanewise(VectorOperators.OR, vec2.lanewise(VectorOperators.OR, vec1)) + .intoArray(ir3, index); + } + + @Run(test = "testVectorIRSharing2") + public void testVectorIRSharingDriver2() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing2(i); + } + checkVectorIRSharing2(); + } + + public void checkVectorIRSharing2() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] ^ ib[i]) ^ (ib[i] ^ ia[i])); + Verify.checkEQ(ir2[i], (ia[i] & ib[i]) & (ib[i] & ia[i])); + Verify.checkEQ(ir3[i], (ia[i] | ib[i]) | (ib[i] | ia[i])); + } + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx2", "true"}) + public void testVectorIRSharing3(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + vec1.lanewise(VectorOperators.SADD, vec2) + .lanewise(VectorOperators.SADD, vec2.lanewise(VectorOperators.SADD, vec1)) + .intoArray(ir4, index); + } + + @Run(test = "testVectorIRSharing3") + public void testVectorIRSharingDriver3() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing3(i); + } + checkVectorIRSharing3(); + } + + public void checkVectorIRSharing3() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir4[i], VectorMath.addSaturating(VectorMath.addSaturating(ia[i], ib[i]), + VectorMath.addSaturating(ib[i], ia[i]))); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing4(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec1) + (vec1 + vec1) + vec1.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing4") + public void testVectorIRSharingDriver4() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing4(i); + } + checkVectorIRSharing4(); + } + + public void checkVectorIRSharing4() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ia[i]) + (ia[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing5(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec1) + (vec1 + vec2) + vec1.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing5") + public void testVectorIRSharingDriver5() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing5(i); + } + checkVectorIRSharing5(); + } + + public void checkVectorIRSharing5() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ia[i]) + (ia[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing6(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec1) + (vec2 + vec1) + vec1.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing6") + public void testVectorIRSharingDriver6() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing6(i); + } + checkVectorIRSharing6(); + } + + public void checkVectorIRSharing6() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ia[i]) + (ib[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing7(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec1) + (vec2 + vec2) + vec1.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing7") + public void testVectorIRSharingDriver7() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing7(i); + } + checkVectorIRSharing7(); + } + + public void checkVectorIRSharing7() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ia[i]) + (ib[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing8(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec2) + (vec1 + vec1) + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing8") + public void testVectorIRSharingDriver8() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing8(i); + } + checkVectorIRSharing8(); + } + + public void checkVectorIRSharing8() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ib[i]) + (ia[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing9(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec2) + (vec1 + vec2) + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing9") + public void testVectorIRSharingDriver9() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing9(i); + } + checkVectorIRSharing9(); + } + + public void checkVectorIRSharing9() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ib[i]) + (ia[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing10(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec2) + (vec2 + vec1) + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing10") + public void testVectorIRSharingDriver10() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing10(i); + } + checkVectorIRSharing10(); + } + + public void checkVectorIRSharing10() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ib[i]) + (ib[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing11(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec1 + vec2) + (vec2 + vec2) + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing11") + public void testVectorIRSharingDriver11() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing11(i); + } + checkVectorIRSharing11(); + } + + public void checkVectorIRSharing11() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ia[i] + ib[i]) + (ib[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing12(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec1) + (vec1 + vec1) + vec2.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing12") + public void testVectorIRSharingDriver12() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing12(i); + } + checkVectorIRSharing12(); + } + + public void checkVectorIRSharing12() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ia[i]) + (ia[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing13(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec1) + (vec1 + vec2) + vec2.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing13") + public void testVectorIRSharingDriver13() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing13(i); + } + checkVectorIRSharing13(); + } + + public void checkVectorIRSharing13() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ia[i]) + (ia[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 2 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing14(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec1) + (vec2 + vec1) + vec2.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing14") + public void testVectorIRSharingDriver14() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing14(i); + } + checkVectorIRSharing14(); + } + + public void checkVectorIRSharing14() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ia[i]) + (ib[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing15(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec1) + (vec2 + vec2) + vec2.lanewise(VectorOperators.ADD, vec1) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing15") + public void testVectorIRSharingDriver15() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing15(i); + } + checkVectorIRSharing15(); + } + + public void checkVectorIRSharing15() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ia[i]) + (ib[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing16(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec2) + (vec1 + vec1) + vec2.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing16") + public void testVectorIRSharingDriver16() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing16(i); + } + checkVectorIRSharing16(); + } + + public void checkVectorIRSharing16() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ib[i]) + (ia[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing17(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec2) + (vec1 + vec2) + vec2.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec1.lanewise(VectorOperators.ADD, vec2)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing17") + public void testVectorIRSharingDriver17() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing17(i); + } + checkVectorIRSharing17(); + } + + public void checkVectorIRSharing17() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ib[i]) + (ia[i] + ib[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeature = {"avx", "true"}) + public void testVectorIRSharing18(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // (vec2 + vec2) + (vec2 + vec1) + vec2.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing18") + public void testVectorIRSharingDriver18() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing18(i); + } + checkVectorIRSharing18(); + } + + public void checkVectorIRSharing18() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], (ib[i] + ib[i]) + (ib[i] + ia[i])); + } + } + + @Test + @IR(counts = {IRNode.ADD_VI, IRNode.VECTOR_SIZE_ANY, " 3 "}, applyIfCPUFeatureOr = {"avx512vl", "true", "sve", "true"}) + public void testVectorIRSharing19(int index) { + VectorMask VMASK = VectorMask.fromLong(I_SPECIES, ((1 << 4) - 1)); + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // PRED:(vec1 + vec2) + PRED:(vec2 + vec1) + vec1.lanewise(VectorOperators.ADD, vec2, VMASK) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1, VMASK)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing19") + public void testVectorIRSharingDriver19() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing19(i); + } + checkVectorIRSharing19(); + } + + public void checkVectorIRSharing19() { + VectorMask VMASK = VectorMask.fromLong(I_SPECIES, ((1 << 4) - 1)); + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + boolean mask = VMASK.laneIsSet(i & (I_SPECIES.length() - 1)); + Verify.checkEQ(ir1[i], (mask ? ia[i] + ib[i] : ia[i]) + (mask ? ib[i] + ia[i] : ib[i])); + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java new file mode 100644 index 00000000000..91851efa4f3 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.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. + * + */ + +package org.openjdk.bench.jdk.incubator.vector; + +import java.util.Random; +import java.util.Arrays; +import jdk.incubator.vector.*; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; + +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +public class VectorCommutativeOperSharingBenchmark { + @Param({"1024","2048"}) + int size; + + byte[] bytesrc1; + byte[] bytesrc2; + byte[] byteres; + + short[] shortsrc1; + short[] shortsrc2; + short[] shortres; + + int[] intsrc1; + int[] intsrc2; + int[] intres; + + long[] longsrc1; + long[] longsrc2; + long[] longres; + + @Setup(Level.Trial) + public void BmSetup() { + Random r = new Random(1024); + bytesrc1 = new byte[size]; + bytesrc2 = new byte[size]; + byteres = new byte[size]; + + shortsrc1 = new short[size]; + shortsrc2 = new short[size]; + shortres = new short[size]; + + intsrc1 = new int[size]; + intsrc2 = new int[size]; + intres = new int[size]; + + longsrc1 = new long[size]; + longsrc2 = new long[size]; + longres = new long[size]; + + Arrays.fill(bytesrc1, (byte)1); + Arrays.fill(bytesrc2, (byte)2); + + Arrays.fill(shortsrc1, (short)1); + Arrays.fill(shortsrc2, (short)2); + + Arrays.fill(intsrc1, 1); + Arrays.fill(intsrc2, 2); + + Arrays.fill(longsrc1, 1); + Arrays.fill(longsrc2, 2); + } + + @Benchmark + public void commutativeByteOperationShairing() { + for (int i = 0; i < size; i += ByteVector.SPECIES_PREFERRED.length()) { + ByteVector vec1 = ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc1, i); + ByteVector vec2 = ByteVector.fromArray(ByteVector.SPECIES_PREFERRED, bytesrc2, i); + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .lanewise(VectorOperators.MUL, vec1.lanewise(VectorOperators.MUL, vec2)) + .lanewise(VectorOperators.MUL, vec2.lanewise(VectorOperators.MUL, vec1)) + .lanewise(VectorOperators.AND, vec1.lanewise(VectorOperators.AND, vec2)) + .lanewise(VectorOperators.AND, vec2.lanewise(VectorOperators.AND, vec1)) + .lanewise(VectorOperators.OR, vec1.lanewise(VectorOperators.OR, vec2)) + .lanewise(VectorOperators.OR, vec2.lanewise(VectorOperators.OR, vec1)) + .intoArray(byteres, i); + } + } + + @Benchmark + public void commutativeShortOperationShairing() { + for (int i = 0; i < size; i += ShortVector.SPECIES_PREFERRED.length()) { + ShortVector vec1 = ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc1, i); + ShortVector vec2 = ShortVector.fromArray(ShortVector.SPECIES_PREFERRED, shortsrc2, i); + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .lanewise(VectorOperators.MUL, vec1.lanewise(VectorOperators.MUL, vec2)) + .lanewise(VectorOperators.MUL, vec2.lanewise(VectorOperators.MUL, vec1)) + .lanewise(VectorOperators.AND, vec1.lanewise(VectorOperators.AND, vec2)) + .lanewise(VectorOperators.AND, vec2.lanewise(VectorOperators.AND, vec1)) + .lanewise(VectorOperators.OR, vec1.lanewise(VectorOperators.OR, vec2)) + .lanewise(VectorOperators.OR, vec2.lanewise(VectorOperators.OR, vec1)) + .intoArray(shortres, i); + } + } + + @Benchmark + public void commutativeIntOperationShairing() { + for (int i = 0; i < size; i += IntVector.SPECIES_PREFERRED.length()) { + IntVector vec1 = IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc1, i); + IntVector vec2 = IntVector.fromArray(IntVector.SPECIES_PREFERRED, intsrc2, i); + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .lanewise(VectorOperators.MUL, vec1.lanewise(VectorOperators.MUL, vec2)) + .lanewise(VectorOperators.MUL, vec2.lanewise(VectorOperators.MUL, vec1)) + .lanewise(VectorOperators.AND, vec1.lanewise(VectorOperators.AND, vec2)) + .lanewise(VectorOperators.AND, vec2.lanewise(VectorOperators.AND, vec1)) + .lanewise(VectorOperators.OR, vec1.lanewise(VectorOperators.OR, vec2)) + .lanewise(VectorOperators.OR, vec2.lanewise(VectorOperators.OR, vec1)) + .intoArray(intres, i); + } + } + + @Benchmark + public void commutativeLongOperationShairing() { + for (int i = 0; i < size; i += LongVector.SPECIES_PREFERRED.length()) { + LongVector vec1 = LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc1, i); + LongVector vec2 = LongVector.fromArray(LongVector.SPECIES_PREFERRED, longsrc2, i); + vec1.lanewise(VectorOperators.ADD, vec2) + .lanewise(VectorOperators.ADD, vec2.lanewise(VectorOperators.ADD, vec1)) + .lanewise(VectorOperators.MUL, vec1.lanewise(VectorOperators.MUL, vec2)) + .lanewise(VectorOperators.MUL, vec2.lanewise(VectorOperators.MUL, vec1)) + .lanewise(VectorOperators.AND, vec1.lanewise(VectorOperators.AND, vec2)) + .lanewise(VectorOperators.AND, vec2.lanewise(VectorOperators.AND, vec1)) + .lanewise(VectorOperators.OR, vec1.lanewise(VectorOperators.OR, vec2)) + .lanewise(VectorOperators.OR, vec2.lanewise(VectorOperators.OR, vec1)) + .intoArray(longres, i); + } + } +} From 65f79c145b7b1b32ed064a37ad4d2b6aca935a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Mon, 24 Feb 2025 12:03:42 +0000 Subject: [PATCH 099/587] 8347335: ZGC: Use limitless mark stack memory Reviewed-by: aboldtch, iwalulya --- src/hotspot/share/gc/z/zAddressSpaceLimit.cpp | 6 - src/hotspot/share/gc/z/zAddressSpaceLimit.hpp | 1 - src/hotspot/share/gc/z/zArguments.cpp | 9 - src/hotspot/share/gc/z/zBarrierSet.cpp | 2 +- src/hotspot/share/gc/z/zGeneration.cpp | 8 +- src/hotspot/share/gc/z/zGeneration.hpp | 4 +- src/hotspot/share/gc/z/zGlobals.hpp | 11 - src/hotspot/share/gc/z/zHeap.cpp | 8 +- src/hotspot/share/gc/z/zHeap.hpp | 2 +- src/hotspot/share/gc/z/zInitialize.cpp | 1 - src/hotspot/share/gc/z/zMark.cpp | 66 ++-- src/hotspot/share/gc/z/zMark.hpp | 31 +- src/hotspot/share/gc/z/zMark.inline.hpp | 2 +- src/hotspot/share/gc/z/zMarkStack.cpp | 332 +++++++++++------- src/hotspot/share/gc/z/zMarkStack.hpp | 118 +++---- src/hotspot/share/gc/z/zMarkStack.inline.hpp | 207 ++++------- .../share/gc/z/zMarkStackAllocator.cpp | 236 ------------- .../share/gc/z/zMarkTerminate.inline.hpp | 4 +- src/hotspot/share/gc/z/zMarkingSMR.cpp | 112 ++++++ ...MarkStackAllocator.hpp => zMarkingSMR.hpp} | 67 +--- src/hotspot/share/gc/z/zRemembered.cpp | 2 +- src/hotspot/share/gc/z/zStat.cpp | 9 +- src/hotspot/share/gc/z/zStat.hpp | 1 - src/hotspot/share/gc/z/z_globals.hpp | 4 - src/hotspot/share/runtime/arguments.cpp | 1 + 25 files changed, 504 insertions(+), 740 deletions(-) delete mode 100644 src/hotspot/share/gc/z/zMarkStackAllocator.cpp create mode 100644 src/hotspot/share/gc/z/zMarkingSMR.cpp rename src/hotspot/share/gc/z/{zMarkStackAllocator.hpp => zMarkingSMR.hpp} (50%) diff --git a/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp b/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp index c737644472c..fc42d9f3db1 100644 --- a/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp +++ b/src/hotspot/share/gc/z/zAddressSpaceLimit.cpp @@ -39,12 +39,6 @@ static size_t address_space_limit() { return SIZE_MAX; } -size_t ZAddressSpaceLimit::mark_stack() { - // Allow mark stacks to occupy 10% of the address space - const size_t limit = address_space_limit() / 10; - return align_up(limit, ZMarkStackSpaceExpandSize); -} - size_t ZAddressSpaceLimit::heap() { // Allow the heap to occupy 50% of the address space const size_t limit = address_space_limit() / MaxVirtMemFraction; diff --git a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp index d8e7e7cfd36..66e01f0ebb0 100644 --- a/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp +++ b/src/hotspot/share/gc/z/zAddressSpaceLimit.hpp @@ -29,7 +29,6 @@ class ZAddressSpaceLimit : public AllStatic { public: - static size_t mark_stack(); static size_t heap(); }; diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index 7c082252133..ee761d03e18 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -120,15 +120,6 @@ void ZArguments::select_max_gc_threads() { void ZArguments::initialize() { GCArguments::initialize(); - // Check mark stack size - const size_t mark_stack_space_limit = ZAddressSpaceLimit::mark_stack(); - if (ZMarkStackSpaceLimit > mark_stack_space_limit) { - if (!FLAG_IS_DEFAULT(ZMarkStackSpaceLimit)) { - vm_exit_during_initialization("ZMarkStackSpaceLimit too large for limited address space"); - } - FLAG_SET_DEFAULT(ZMarkStackSpaceLimit, mark_stack_space_limit); - } - // Enable NUMA by default if (FLAG_IS_DEFAULT(UseNUMA)) { FLAG_SET_DEFAULT(UseNUMA, true); diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index f88a593b1c3..a4893fc351a 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -101,7 +101,7 @@ void ZBarrierSet::on_thread_attach(Thread* thread) { void ZBarrierSet::on_thread_detach(Thread* thread) { // Flush and free any remaining mark stacks - ZHeap::heap()->mark_flush_and_free(thread); + ZHeap::heap()->mark_flush(thread); } static void deoptimize_allocation(JavaThread* thread) { diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 9a2535d527f..0dc8e93b8e7 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -131,10 +131,6 @@ ZGeneration::ZGeneration(ZGenerationId id, ZPageTable* page_table, ZPageAllocato _stat_relocation(), _gc_timer(nullptr) {} -bool ZGeneration::is_initialized() const { - return _mark.is_initialized(); -} - ZWorkers* ZGeneration::workers() { return &_workers; } @@ -151,8 +147,8 @@ void ZGeneration::threads_do(ThreadClosure* tc) const { _workers.threads_do(tc); } -void ZGeneration::mark_flush_and_free(Thread* thread) { - _mark.flush_and_free(thread); +void ZGeneration::mark_flush(Thread* thread) { + _mark.flush(thread); } void ZGeneration::mark_free() { diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 3e18919eee4..2670ab51699 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -99,8 +99,6 @@ protected: void log_phase_switch(Phase from, Phase to); public: - bool is_initialized() const; - // GC phases void set_phase(Phase new_phase); bool is_phase_relocate() const; @@ -161,7 +159,7 @@ public: void mark_object(zaddress addr); template void mark_object_if_active(zaddress addr); - void mark_flush_and_free(Thread* thread); + void mark_flush(Thread* thread); // Relocation void synchronize_relocation(); diff --git a/src/hotspot/share/gc/z/zGlobals.hpp b/src/hotspot/share/gc/z/zGlobals.hpp index f7c0a3eaa26..918301b1853 100644 --- a/src/hotspot/share/gc/z/zGlobals.hpp +++ b/src/hotspot/share/gc/z/zGlobals.hpp @@ -67,17 +67,6 @@ const int ZObjectAlignmentLarge = 1 << ZObjectAlignmentLargeShif const size_t ZCacheLineSize = ZPlatformCacheLineSize; #define ZCACHE_ALIGNED ATTRIBUTE_ALIGNED(ZCacheLineSize) -// Mark stack space -const size_t ZMarkStackSpaceExpandSize = (size_t)1 << 25; // 32M - -// Mark stack and magazine sizes -const size_t ZMarkStackSizeShift = 11; // 2K -const size_t ZMarkStackSize = (size_t)1 << ZMarkStackSizeShift; -const size_t ZMarkStackHeaderSize = (size_t)1 << 4; // 16B -const size_t ZMarkStackSlots = (ZMarkStackSize - ZMarkStackHeaderSize) / sizeof(uintptr_t); -const size_t ZMarkStackMagazineSize = (size_t)1 << 15; // 32K -const size_t ZMarkStackMagazineSlots = (ZMarkStackMagazineSize / ZMarkStackSize) - 1; - // Mark stripe size const size_t ZMarkStripeShift = ZGranuleSizeShift; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 7169b915cb5..bca9e2f8c41 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -68,7 +68,7 @@ ZHeap::ZHeap() assert(_heap == nullptr, "Already initialized"); _heap = this; - if (!_page_allocator.is_initialized() || !_young.is_initialized() || !_old.is_initialized()) { + if (!_page_allocator.is_initialized()) { return; } @@ -271,9 +271,9 @@ void ZHeap::keep_alive(oop obj) { ZBarrier::mark(addr); } -void ZHeap::mark_flush_and_free(Thread* thread) { - _young.mark_flush_and_free(thread); - _old.mark_flush_and_free(thread); +void ZHeap::mark_flush(Thread* thread) { + _young.mark_flush(thread); + _old.mark_flush(thread); } bool ZHeap::is_allocating(zaddress addr) const { diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 955cdf6fd79..4bf4727c3e3 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -99,7 +99,7 @@ public: bool is_object_live(zaddress addr) const; bool is_object_strongly_live(zaddress addr) const; void keep_alive(oop obj); - void mark_flush_and_free(Thread* thread); + void mark_flush(Thread* thread); // Page allocation ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); diff --git a/src/hotspot/share/gc/z/zInitialize.cpp b/src/hotspot/share/gc/z/zInitialize.cpp index a8d6a32a7d5..125231355ac 100644 --- a/src/hotspot/share/gc/z/zInitialize.cpp +++ b/src/hotspot/share/gc/z/zInitialize.cpp @@ -31,7 +31,6 @@ #include "gc/z/zInitialize.hpp" #include "gc/z/zJNICritical.hpp" #include "gc/z/zLargePages.hpp" -#include "gc/z/zMarkStackAllocator.hpp" #include "gc/z/zNMT.hpp" #include "gc/z/zNUMA.hpp" #include "gc/z/zStat.hpp" diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 554cef8cec5..e0c68213ca3 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -81,8 +81,8 @@ static const ZStatSubPhase ZSubPhaseConcurrentMarkRootColoredOld("Concurrent Mar ZMark::ZMark(ZGeneration* generation, ZPageTable* page_table) : _generation(generation), _page_table(page_table), - _allocator(), - _stripes(_allocator.start()), + _marking_smr(), + _stripes(), _terminate(), _work_nproactiveflush(0), _work_nterminateflush(0), @@ -92,10 +92,6 @@ ZMark::ZMark(ZGeneration* generation, ZPageTable* page_table) _ncontinue(0), _nworkers(0) {} -bool ZMark::is_initialized() const { - return _allocator.is_initialized(); -} - size_t ZMark::calculate_nstripes(uint nworkers) const { // Calculate the number of stripes from the number of workers we use, // where the number of stripes must be a power of two and we want to @@ -196,7 +192,7 @@ void ZMark::push_partial_array(zpointer* addr, size_t length, bool finalizable) log_develop_trace(gc, marking)("Array push partial: " PTR_FORMAT " (%zu), stripe: %zu", p2i(addr), length, _stripes.stripe_id(stripe)); - stacks->push(&_allocator, &_stripes, stripe, &_terminate, entry, false /* publish */); + stacks->push(&_stripes, stripe, &_terminate, entry, false /* publish */); } static void mark_barrier_on_oop_array(volatile zpointer* p, size_t length, bool finalizable, bool young) { @@ -471,21 +467,26 @@ bool ZMark::rebalance_work(ZMarkContext* context) { const size_t nstripes = _stripes.nstripes(); if (assumed_nstripes != nstripes) { + // The number of stripes has changed; reflect that change locally context->set_nstripes(nstripes); - } else if (nstripes < calculate_nstripes(_nworkers) && _allocator.clear_and_get_expanded_recently()) { + } else if (nstripes < calculate_nstripes(_nworkers) && _stripes.is_crowded()) { + // We are running on a reduced number of threads to minimize the amount of work + // hidden in local stacks when the stripes are less well balanced. When this situation + // starts getting crowded, we bump the number of stripes again. const size_t new_nstripes = nstripes << 1; - _stripes.set_nstripes(new_nstripes); - context->set_nstripes(new_nstripes); + if (_stripes.try_set_nstripes(nstripes, new_nstripes)) { + context->set_nstripes(new_nstripes); + } } ZMarkStripe* stripe = _stripes.stripe_for_worker(_nworkers, WorkerThread::worker_id()); if (context->stripe() != stripe) { // Need to switch stripe context->set_stripe(stripe); - flush_and_free(); + flush(Thread::current()); } else if (!_terminate.saturated()) { // Work imbalance detected; striped marking is likely going to be in the way - flush_and_free(); + flush(Thread::current()); } SuspendibleThreadSet::yield(); @@ -502,7 +503,7 @@ bool ZMark::drain(ZMarkContext* context) { context->set_nstripes(_stripes.nstripes()); // Drain stripe stacks - while (stacks->pop(&_allocator, &_stripes, context->stripe(), entry)) { + while (stacks->pop(&_marking_smr, &_stripes, context->stripe(), &entry)) { mark_and_follow(context, entry); if ((processed++ & 31) == 0 && rebalance_work(context)) { @@ -541,7 +542,7 @@ bool ZMark::try_steal_global(ZMarkContext* context) { for (ZMarkStripe* victim_stripe = _stripes.stripe_next(stripe); victim_stripe != stripe; victim_stripe = _stripes.stripe_next(victim_stripe)) { - ZMarkStack* const stack = victim_stripe->steal_stack(); + ZMarkStack* const stack = victim_stripe->steal_stack(&_marking_smr); if (stack != nullptr) { // Success, install the stolen stack stacks->install(&_stripes, stripe, stack); @@ -557,19 +558,19 @@ bool ZMark::try_steal(ZMarkContext* context) { return try_steal_local(context) || try_steal_global(context); } -class ZMarkFlushAndFreeStacksClosure : public HandshakeClosure { +class ZMarkFlushStacksClosure : public HandshakeClosure { private: ZMark* const _mark; bool _flushed; public: - ZMarkFlushAndFreeStacksClosure(ZMark* mark) - : HandshakeClosure("ZMarkFlushAndFreeStacks"), + ZMarkFlushStacksClosure(ZMark* mark) + : HandshakeClosure("ZMarkFlushStacks"), _mark(mark), _flushed(false) {} void do_thread(Thread* thread) { - if (_mark->flush_and_free(thread)) { + if (_mark->flush(thread)) { _flushed = true; if (SafepointSynchronize::is_at_safepoint()) { log_debug(gc, marking)("Thread broke mark termination %s", thread->name()); @@ -606,7 +607,7 @@ public: }; bool ZMark::flush() { - ZMarkFlushAndFreeStacksClosure cl(this); + ZMarkFlushStacksClosure cl(this); VM_ZMarkFlushOperation vm_cl(&cl); Handshake::execute(&cl); VMThread::execute(&vm_cl); @@ -623,8 +624,7 @@ bool ZMark::try_terminate_flush() { verify_worker_stacks_empty(); } - return flush() || - _terminate.resurrected(); + return flush() || _terminate.resurrected(); } bool ZMark::try_proactive_flush() { @@ -850,7 +850,7 @@ public: // the set of workers executing during root scanning // can be different from the set of workers executing // during mark. - ZHeap::heap()->mark_flush_and_free(Thread::current()); + ZHeap::heap()->mark_flush(Thread::current()); } }; @@ -908,7 +908,7 @@ public: // the set of workers executing during root scanning // can be different from the set of workers executing // during mark. - ZHeap::heap()->mark_flush_and_free(Thread::current()); + ZHeap::heap()->mark_flush(Thread::current()); } }; @@ -934,7 +934,7 @@ public: // publish such marking stacks to prevent that generation from getting a mark continue. // We also flush in case of a resize where a new worker thread continues the marking // work, causing a mark continue for the collected generation. - ZHeap::heap()->mark_flush_and_free(Thread::current()); + ZHeap::heap()->mark_flush(Thread::current()); } virtual void resize_workers(uint nworkers) { @@ -978,7 +978,7 @@ bool ZMark::try_end() { } // Try end marking - ZMarkFlushAndFreeStacksClosure cl(this); + ZMarkFlushStacksClosure cl(this); Threads::non_java_threads_do(&cl); // Check if non-java threads have any pending marking @@ -1012,25 +1012,15 @@ bool ZMark::end() { void ZMark::free() { // Free any unused mark stack space - _allocator.free(); - - // Update statistics - _generation->stat_mark()->at_mark_free(_allocator.size()); + _marking_smr.free(); } -void ZMark::flush_and_free() { - Thread* const thread = Thread::current(); - flush_and_free(thread); -} - -bool ZMark::flush_and_free(Thread* thread) { +bool ZMark::flush(Thread* thread) { if (thread->is_Java_thread()) { ZThreadLocalData::store_barrier_buffer(thread)->flush(); } ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::mark_stacks(thread, _generation->id()); - const bool flushed = stacks->flush(&_allocator, &_stripes, &_terminate); - stacks->free(&_allocator); - return flushed; + return stacks->flush(&_stripes, &_terminate); } class ZVerifyMarkStacksEmptyClosure : public ThreadClosure { diff --git a/src/hotspot/share/gc/z/zMark.hpp b/src/hotspot/share/gc/z/zMark.hpp index 552bf3b959d..07e73849af6 100644 --- a/src/hotspot/share/gc/z/zMark.hpp +++ b/src/hotspot/share/gc/z/zMark.hpp @@ -25,8 +25,8 @@ #define SHARE_GC_Z_ZMARK_HPP #include "gc/z/zAddress.hpp" +#include "gc/z/zMarkingSMR.hpp" #include "gc/z/zMarkStack.hpp" -#include "gc/z/zMarkStackAllocator.hpp" #include "gc/z/zMarkStackEntry.hpp" #include "gc/z/zMarkTerminate.hpp" #include "oops/oopsHierarchy.hpp" @@ -55,18 +55,18 @@ public: static const bool Finalizable = true; private: - ZGeneration* const _generation; - ZPageTable* const _page_table; - ZMarkStackAllocator _allocator; - ZMarkStripeSet _stripes; - ZMarkTerminate _terminate; - volatile size_t _work_nproactiveflush; - volatile size_t _work_nterminateflush; - size_t _nproactiveflush; - size_t _nterminateflush; - size_t _ntrycomplete; - size_t _ncontinue; - uint _nworkers; + ZGeneration* const _generation; + ZPageTable* const _page_table; + ZMarkingSMR _marking_smr; + ZMarkStripeSet _stripes; + ZMarkTerminate _terminate; + volatile size_t _work_nproactiveflush; + volatile size_t _work_nterminateflush; + size_t _nproactiveflush; + size_t _nterminateflush; + size_t _ntrycomplete; + size_t _ncontinue; + uint _nworkers; size_t calculate_nstripes(uint nworkers) const; @@ -101,8 +101,6 @@ private: public: ZMark(ZGeneration* generation, ZPageTable* page_table); - bool is_initialized() const; - template void mark_object(zaddress addr); @@ -113,8 +111,7 @@ public: bool end(); void free(); - void flush_and_free(); - bool flush_and_free(Thread* thread); + bool flush(Thread* thread); // Following work void prepare_work(); diff --git a/src/hotspot/share/gc/z/zMark.inline.hpp b/src/hotspot/share/gc/z/zMark.inline.hpp index 9edc57a6000..26c84679cc0 100644 --- a/src/hotspot/share/gc/z/zMark.inline.hpp +++ b/src/hotspot/share/gc/z/zMark.inline.hpp @@ -84,7 +84,7 @@ inline void ZMark::mark_object(zaddress addr) { assert(ZHeap::heap()->is_young(addr) == _generation->is_young(), "Phase/object mismatch"); const bool publish = !gc_thread; - stacks->push(&_allocator, &_stripes, stripe, &_terminate, entry, publish); + stacks->push(&_stripes, stripe, &_terminate, entry, publish); } #endif // SHARE_GC_Z_ZMARK_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zMarkStack.cpp b/src/hotspot/share/gc/z/zMarkStack.cpp index 00a534d236f..692defc50f1 100644 --- a/src/hotspot/share/gc/z/zMarkStack.cpp +++ b/src/hotspot/share/gc/z/zMarkStack.cpp @@ -21,41 +21,214 @@ * questions. */ +#include "gc/z/zMarkingSMR.hpp" #include "gc/z/zMarkStack.inline.hpp" -#include "gc/z/zMarkStackAllocator.hpp" #include "gc/z/zMarkTerminate.inline.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" #include "utilities/powerOfTwo.hpp" -ZMarkStripe::ZMarkStripe(uintptr_t base) - : _published(base), - _overflowed(base) {} +ZMarkStack* ZMarkStack::create(bool first_stack) { + // When allocating the first stack on a stripe, we try to use a + // smaller mark stack to promote sharing of stacks with other + // threads instead. Once more than one stack is needed, we revert + // to a larger stack size instead, which reduces synchronization + // overhead of churning around stacks on a stripe. + const size_t capacity = first_stack ? 128 : 512; -ZMarkStripeSet::ZMarkStripeSet(uintptr_t base) - : _nstripes_mask(0), - _stripes() { + void* const memory = AttachedArray::alloc(capacity); + return ::new (memory) ZMarkStack(capacity); +} - // Re-construct array elements with the correct base - for (size_t i = 0; i < ARRAY_SIZE(_stripes); i++) { - _stripes[i] = ZMarkStripe(base); +void ZMarkStack::destroy(ZMarkStack* stack) { + stack->~ZMarkStack(); + AttachedArray::free(stack); +} + +ZMarkStack::ZMarkStack(size_t capacity) + : _top(0), + _entries(capacity) {} + +ZMarkStackListNode::ZMarkStackListNode(ZMarkStack* stack) + : _stack(stack), + _next() {} + +ZMarkStack* ZMarkStackListNode::stack() const { + return _stack; +} + +ZMarkStackListNode* ZMarkStackListNode::next() const { + return _next; +} + +void ZMarkStackListNode::set_next(ZMarkStackListNode* next) { + _next = next; +} + +ZMarkStackList::ZMarkStackList() + : _head(), + _length() {} + +bool ZMarkStackList::is_empty() const { + return Atomic::load(&_head) == nullptr; +} + +void ZMarkStackList::push(ZMarkStack* stack) { + ZMarkStackListNode* const node = new ZMarkStackListNode(stack); + ZMarkStackListNode* head = Atomic::load(&_head); + for (;;) { + node->set_next(head); + // Between reading the head and the linearizing CAS that pushes + // the node onto the list, there could be an ABA problem. Except, + // on the pushing side, that is benign. The node is never + // dereferenced while pushing and if we were to detect the ABA + // situation and run this loop one more time, we would end up + // having the same side effects: set the next pointer to the same + // head again, and CAS the head link. + ZMarkStackListNode* prev = Atomic::cmpxchg(&_head, head, node, memory_order_release); + + if (prev == head) { + // Success + + // Bookkeep the population count + Atomic::inc(&_length, memory_order_relaxed); + return; + } + + // Retry + head = prev; } } +ZMarkStack* ZMarkStackList::pop(ZMarkingSMR* marking_smr) { + ZMarkStackListNode* volatile* const hazard_ptr = marking_smr->hazard_ptr(); + + ZMarkStackListNode* head = Atomic::load(&_head); + for (;;) { + if (head == nullptr) { + // Stack is empty + return nullptr; + } + + // Establish what the head is and publish a hazard pointer denoting + // that the head is not safe to concurrently free while we are in the + // middle of popping it and finding out that we lost the race. + Atomic::store(hazard_ptr, head); + + // A full fence is needed to ensure the store and subsequent load do + // not reorder. If they did reorder, the second head load could happen + // before other threads scanning hazard pointers can observe it, meaning + // it could get concurrently freed. + OrderAccess::fence(); + + // The acquire fence when loading the head is necessary to make sure + // the next pointer load below observes the next pointer published + // with the releasing CAS for the push operation that published the + // marking stack. + ZMarkStackListNode* const head_after_publish = Atomic::load_acquire(&_head); + if (head_after_publish != head) { + // Race during hazard pointer publishing + head = head_after_publish; + continue; + } + + // With the hazard pointer published, we can read the next pointer, + // knowing that it is indeed the next pointer of the intended logical + // head node that we established above. + ZMarkStackListNode* const next = head->next(); + + // Popping entries from the list does not require any particular memory + // ordering. + ZMarkStackListNode* const prev = Atomic::cmpxchg(&_head, head, next, memory_order_relaxed); + + if (prev == head) { + // Success + + // The ABA hazard is gone after the CAS. We use release_store to ensure + // that the relinquishing of the hazard pointer becomes observable after + // the unlinking CAS. + Atomic::release_store(hazard_ptr, (ZMarkStackListNode*)nullptr); + + // Perform bookkeeping of the population count. + Atomic::dec(&_length, memory_order_relaxed); + + ZMarkStack* result = head->stack(); + + marking_smr->free_node(head); + + return result; + } + + // Retry + head = prev; + } +} + +size_t ZMarkStackList::length() const { + const ssize_t result = Atomic::load(&_length); + + if (result < 0) { + return 0; + } + + return (size_t)result; +} + +ZMarkStripe::ZMarkStripe() + : _published(), + _overflowed() {} + +ZMarkStack* ZMarkStripe::steal_stack(ZMarkingSMR* marking_smr) { + // Steal overflowed stacks first, then published stacks + ZMarkStack* const stack = _overflowed.pop(marking_smr); + if (stack != nullptr) { + return stack; + } + + return _published.pop(marking_smr); +} + +size_t ZMarkStripe::population() const { + return _overflowed.length() + _published.length(); +} + +ZMarkStripeSet::ZMarkStripeSet() + : _nstripes_mask(0), + _stripes() {} + void ZMarkStripeSet::set_nstripes(size_t nstripes) { assert(is_power_of_2(nstripes), "Must be a power of two"); assert(is_power_of_2(ZMarkStripesMax), "Must be a power of two"); assert(nstripes >= 1, "Invalid number of stripes"); assert(nstripes <= ZMarkStripesMax, "Invalid number of stripes"); - // Mutators may read these values concurrently. It doesn't matter - // if they see the old or new values. - Atomic::store(&_nstripes_mask, nstripes - 1); + const size_t new_nstripes_mask = nstripes - 1; + _nstripes_mask = new_nstripes_mask; log_debug(gc, marking)("Using %zu mark stripes", nstripes); } +bool ZMarkStripeSet::try_set_nstripes(size_t old_nstripes, size_t new_nstripes) { + assert(is_power_of_2(new_nstripes), "Must be a power of two"); + assert(is_power_of_2(ZMarkStripesMax), "Must be a power of two"); + assert(new_nstripes >= 1, "Invalid number of stripes"); + assert(new_nstripes <= ZMarkStripesMax, "Invalid number of stripes"); + + const size_t old_nstripes_mask = old_nstripes - 1; + const size_t new_nstripes_mask = new_nstripes - 1; + + // Mutators may read these values concurrently. It doesn't matter + // if they see the old or new values. + if (Atomic::cmpxchg(&_nstripes_mask, old_nstripes_mask, new_nstripes_mask) == old_nstripes_mask) { + log_debug(gc, marking)("Using %zu mark stripes", new_nstripes); + return true; + } + + return false; +} + size_t ZMarkStripeSet::nstripes() const { return Atomic::load(&_nstripes_mask) + 1; } @@ -70,6 +243,20 @@ bool ZMarkStripeSet::is_empty() const { return true; } +bool ZMarkStripeSet::is_crowded() const { + size_t population = 0; + const size_t crowded_threshold = nstripes() << 4; + + for (size_t i = 0; i < ZMarkStripesMax; i++) { + population += _stripes[i].population(); + if (population > crowded_threshold) { + return true; + } + } + + return false; +} + ZMarkStripe* ZMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) { const size_t mask = Atomic::load(&_nstripes_mask); const size_t nstripes = mask + 1; @@ -92,8 +279,7 @@ ZMarkStripe* ZMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) { return &_stripes[index]; } -ZMarkThreadLocalStacks::ZMarkThreadLocalStacks() - : _magazine(nullptr) { +ZMarkThreadLocalStacks::ZMarkThreadLocalStacks() { for (size_t i = 0; i < ZMarkStripesMax; i++) { _stacks[i] = nullptr; } @@ -110,104 +296,8 @@ bool ZMarkThreadLocalStacks::is_empty(const ZMarkStripeSet* stripes) const { return true; } -ZMarkStack* ZMarkThreadLocalStacks::allocate_stack(ZMarkStackAllocator* allocator) { - if (_magazine == nullptr) { - // Allocate new magazine - _magazine = allocator->alloc_magazine(); - if (_magazine == nullptr) { - return nullptr; - } - } - - ZMarkStack* stack = nullptr; - - if (!_magazine->pop(stack)) { - // Magazine is empty, convert magazine into a new stack - _magazine->~ZMarkStackMagazine(); - stack = new ((void*)_magazine) ZMarkStack(); - _magazine = nullptr; - } - - return stack; -} - -void ZMarkThreadLocalStacks::free_stack(ZMarkStackAllocator* allocator, ZMarkStack* stack) { - for (;;) { - if (_magazine == nullptr) { - // Convert stack into a new magazine - stack->~ZMarkStack(); - _magazine = new ((void*)stack) ZMarkStackMagazine(); - return; - } - - if (_magazine->push(stack)) { - // Success - return; - } - - // Free and uninstall full magazine - allocator->free_magazine(_magazine); - _magazine = nullptr; - } -} - -bool ZMarkThreadLocalStacks::push_slow(ZMarkStackAllocator* allocator, - ZMarkStripe* stripe, - ZMarkStack** stackp, - ZMarkTerminate* terminate, - ZMarkStackEntry entry, - bool publish) { - ZMarkStack* stack = *stackp; - - for (;;) { - if (stack == nullptr) { - // Allocate and install new stack - *stackp = stack = allocate_stack(allocator); - if (stack == nullptr) { - // Out of mark stack memory - return false; - } - } - - if (stack->push(entry)) { - // Success - return true; - } - - // Publish/Overflow and uninstall stack - stripe->publish_stack(stack, terminate, publish); - *stackp = stack = nullptr; - } -} - -bool ZMarkThreadLocalStacks::pop_slow(ZMarkStackAllocator* allocator, - ZMarkStripe* stripe, - ZMarkStack** stackp, - ZMarkStackEntry& entry) { - ZMarkStack* stack = *stackp; - - for (;;) { - if (stack == nullptr) { - // Try steal and install stack - *stackp = stack = stripe->steal_stack(); - if (stack == nullptr) { - // Nothing to steal - return false; - } - } - - if (stack->pop(entry)) { - // Success - return true; - } - - // Free and uninstall stack - free_stack(allocator, stack); - *stackp = stack = nullptr; - } -} - -bool ZMarkThreadLocalStacks::flush(ZMarkStackAllocator* allocator, ZMarkStripeSet* stripes, ZMarkTerminate* terminate) { +bool ZMarkThreadLocalStacks::flush(ZMarkStripeSet* stripes, + ZMarkTerminate* terminate) { bool flushed = false; // Flush all stacks @@ -220,22 +310,10 @@ bool ZMarkThreadLocalStacks::flush(ZMarkStackAllocator* allocator, ZMarkStripeSe } // Free/Publish and uninstall stack - if (stack->is_empty()) { - free_stack(allocator, stack); - } else { - stripe->publish_stack(stack, terminate, true /* publish */); - flushed = true; - } + stripe->publish_stack(stack, terminate, true /* publish */); + flushed = true; *stackp = nullptr; } return flushed; } - -void ZMarkThreadLocalStacks::free(ZMarkStackAllocator* allocator) { - // Free and uninstall magazine - if (_magazine != nullptr) { - allocator->free_magazine(_magazine); - _magazine = nullptr; - } -} diff --git a/src/hotspot/share/gc/z/zMarkStack.hpp b/src/hotspot/share/gc/z/zMarkStack.hpp index 8a24c84c8d9..7c0e6d4c712 100644 --- a/src/hotspot/share/gc/z/zMarkStack.hpp +++ b/src/hotspot/share/gc/z/zMarkStack.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 @@ -24,73 +24,81 @@ #ifndef SHARE_GC_Z_ZMARKSTACK_HPP #define SHARE_GC_Z_ZMARKSTACK_HPP +#include "gc/z/zAttachedArray.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zMarkStackEntry.hpp" +#include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" +class ZMarkingSMR; +class ZMarkStripe; class ZMarkTerminate; -template -class ZStack { +class ZMarkStack { private: - size_t _top; - ZStack* _next; - T _slots[S]; + using AttachedArray = ZAttachedArray; + size_t _top; + const AttachedArray _entries; + + ZMarkStackEntry* slots(); + + ZMarkStack(size_t capacity); + +public: + static ZMarkStack* create(bool first_stack); + static void destroy(ZMarkStack* stack); + + bool is_empty() const; bool is_full() const; -public: - ZStack(); - - bool is_empty() const; - - bool push(T value); - bool pop(T& value); - - ZStack* next() const; - ZStack** next_addr(); + void push(ZMarkStackEntry value); + ZMarkStackEntry pop(); }; -template -class ZCACHE_ALIGNED ZStackList { +class ZMarkStackListNode : public CHeapObj { private: - uintptr_t _base; - T* volatile _head; - - T* encode_versioned_pointer(const T* stack, uint32_t version) const; - void decode_versioned_pointer(const T* vstack, T** stack, uint32_t* version) const; + ZMarkStack* const _stack; + ZMarkStackListNode* _next; public: - explicit ZStackList(uintptr_t base); + ZMarkStackListNode(ZMarkStack* stack); + + ZMarkStack* stack() const; + + ZMarkStackListNode* next() const; + void set_next(ZMarkStackListNode* next); +}; + +class ZCACHE_ALIGNED ZMarkStackList { +private: + ZMarkStackListNode* volatile _head; + ssize_t volatile _length; + +public: + ZMarkStackList(); bool is_empty() const; - void push(T* stack); - T* pop(); + size_t length() const; - void clear(); + void push(ZMarkStack* stack); + ZMarkStack* pop(ZMarkingSMR* marking_smr); }; -using ZMarkStack = ZStack; -using ZMarkStackList = ZStackList; -using ZMarkStackMagazine = ZStack; -using ZMarkStackMagazineList = ZStackList; - -static_assert(sizeof(ZMarkStack) == ZMarkStackSize, "ZMarkStack size mismatch"); -static_assert(sizeof(ZMarkStackMagazine) <= ZMarkStackSize, "ZMarkStackMagazine size too large"); - class ZMarkStripe { private: ZCACHE_ALIGNED ZMarkStackList _published; ZCACHE_ALIGNED ZMarkStackList _overflowed; public: - explicit ZMarkStripe(uintptr_t base = 0); + explicit ZMarkStripe(); bool is_empty() const; + size_t population() const; void publish_stack(ZMarkStack* stack, ZMarkTerminate* terminate, bool publish); - ZMarkStack* steal_stack(); + ZMarkStack* steal_stack(ZMarkingSMR* marking_smr); }; class ZMarkStripeSet { @@ -99,12 +107,14 @@ private: ZMarkStripe _stripes[ZMarkStripesMax]; public: - explicit ZMarkStripeSet(uintptr_t base); + explicit ZMarkStripeSet(); void set_nstripes(size_t nstripes); + bool try_set_nstripes(size_t old_nstripes, size_t new_nstripes); size_t nstripes() const; bool is_empty() const; + bool is_crowded() const; size_t stripe_id(const ZMarkStripe* stripe) const; ZMarkStripe* stripe_at(size_t index); @@ -113,27 +123,9 @@ public: ZMarkStripe* stripe_for_addr(uintptr_t addr); }; -class ZMarkStackAllocator; - class ZMarkThreadLocalStacks { private: - ZMarkStackMagazine* _magazine; - ZMarkStack* _stacks[ZMarkStripesMax]; - - ZMarkStack* allocate_stack(ZMarkStackAllocator* allocator); - void free_stack(ZMarkStackAllocator* allocator, ZMarkStack* stack); - - bool push_slow(ZMarkStackAllocator* allocator, - ZMarkStripe* stripe, - ZMarkStack** stackp, - ZMarkTerminate* terminate, - ZMarkStackEntry entry, - bool publish); - - bool pop_slow(ZMarkStackAllocator* allocator, - ZMarkStripe* stripe, - ZMarkStack** stackp, - ZMarkStackEntry& entry); + ZMarkStack* _stacks[ZMarkStripesMax]; public: ZMarkThreadLocalStacks(); @@ -147,23 +139,19 @@ public: ZMarkStack* steal(ZMarkStripeSet* stripes, ZMarkStripe* stripe); - bool push(ZMarkStackAllocator* allocator, - ZMarkStripeSet* stripes, + void push(ZMarkStripeSet* stripes, ZMarkStripe* stripe, ZMarkTerminate* terminate, ZMarkStackEntry entry, bool publish); - bool pop(ZMarkStackAllocator* allocator, + bool pop(ZMarkingSMR* marking_smr, ZMarkStripeSet* stripes, ZMarkStripe* stripe, - ZMarkStackEntry& entry); + ZMarkStackEntry* entry); - bool flush(ZMarkStackAllocator* allocator, - ZMarkStripeSet* stripes, + bool flush(ZMarkStripeSet* stripes, ZMarkTerminate* terminate); - - void free(ZMarkStackAllocator* allocator); }; #endif // SHARE_GC_Z_ZMARKSTACK_HPP diff --git a/src/hotspot/share/gc/z/zMarkStack.inline.hpp b/src/hotspot/share/gc/z/zMarkStack.inline.hpp index cd8667dd73f..ed3b167762c 100644 --- a/src/hotspot/share/gc/z/zMarkStack.inline.hpp +++ b/src/hotspot/share/gc/z/zMarkStack.inline.hpp @@ -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 @@ -26,142 +26,30 @@ #include "gc/z/zMarkStack.hpp" +#include "gc/z/zAttachedArray.inline.hpp" #include "gc/z/zMarkTerminate.inline.hpp" -#include "runtime/atomic.hpp" #include "utilities/debug.hpp" -template -inline ZStack::ZStack() - : _top(0), - _next(nullptr) {} - -template -inline bool ZStack::is_empty() const { +inline bool ZMarkStack::is_empty() const { return _top == 0; } -template -inline bool ZStack::is_full() const { - return _top == S; +inline bool ZMarkStack::is_full() const { + return _top == _entries.length(); } -template -inline bool ZStack::push(T value) { - if (is_full()) { - return false; - } - - _slots[_top++] = value; - return true; +inline ZMarkStackEntry* ZMarkStack::slots() { + return _entries(this); } -template -inline bool ZStack::pop(T& value) { - if (is_empty()) { - return false; - } - - value = _slots[--_top]; - return true; +inline void ZMarkStack::push(ZMarkStackEntry value) { + assert(!is_full(), "can't push to full stack"); + slots()[_top++] = value; } -template -inline ZStack* ZStack::next() const { - return _next; -} - -template -inline ZStack** ZStack::next_addr() { - return &_next; -} - -template -inline ZStackList::ZStackList(uintptr_t base) - : _base(base), - _head(encode_versioned_pointer(nullptr, 0)) {} - -template -inline T* ZStackList::encode_versioned_pointer(const T* stack, uint32_t version) const { - uint64_t addr; - - if (stack == nullptr) { - addr = (uint32_t)-1; - } else { - addr = ((uint64_t)stack - _base) >> ZMarkStackSizeShift; - } - - return (T*)((addr << 32) | (uint64_t)version); -} - -template -inline void ZStackList::decode_versioned_pointer(const T* vstack, T** stack, uint32_t* version) const { - const uint64_t addr = (uint64_t)vstack >> 32; - - if (addr == (uint32_t)-1) { - *stack = nullptr; - } else { - *stack = (T*)((addr << ZMarkStackSizeShift) + _base); - } - - *version = (uint32_t)(uint64_t)vstack; -} - -template -inline bool ZStackList::is_empty() const { - const T* vstack = _head; - T* stack = nullptr; - uint32_t version = 0; - - decode_versioned_pointer(vstack, &stack, &version); - return stack == nullptr; -} - -template -inline void ZStackList::push(T* stack) { - T* vstack = _head; - uint32_t version = 0; - - for (;;) { - decode_versioned_pointer(vstack, stack->next_addr(), &version); - T* const new_vstack = encode_versioned_pointer(stack, version + 1); - T* const prev_vstack = Atomic::cmpxchg(&_head, vstack, new_vstack); - if (prev_vstack == vstack) { - // Success - break; - } - - // Retry - vstack = prev_vstack; - } -} - -template -inline T* ZStackList::pop() { - T* vstack = _head; - T* stack = nullptr; - uint32_t version = 0; - - for (;;) { - decode_versioned_pointer(vstack, &stack, &version); - if (stack == nullptr) { - return nullptr; - } - - T* const new_vstack = encode_versioned_pointer(stack->next(), version + 1); - T* const prev_vstack = Atomic::cmpxchg(&_head, vstack, new_vstack); - if (prev_vstack == vstack) { - // Success - return stack; - } - - // Retry - vstack = prev_vstack; - } -} - -template -inline void ZStackList::clear() { - _head = encode_versioned_pointer(nullptr, 0); +inline ZMarkStackEntry ZMarkStack::pop() { + assert(!is_empty(), "can't pop from empty stack"); + return slots()[--_top]; } inline bool ZMarkStripe::is_empty() const { @@ -175,6 +63,8 @@ inline void ZMarkStripe::publish_stack(ZMarkStack* stack, ZMarkTerminate* termin // to publish stacks that overflowed. The intention here is to avoid // contention between mutators and GC workers as much as possible, while // still allowing GC workers to help out and steal work from each other. + assert(!stack->is_empty(), "we never publish empty stacks"); + if (publish) { _published.push(stack); } else { @@ -184,16 +74,6 @@ inline void ZMarkStripe::publish_stack(ZMarkStack* stack, ZMarkTerminate* termin terminate->wake_up(); } -inline ZMarkStack* ZMarkStripe::steal_stack() { - // Steal overflowed stacks first, then published stacks - ZMarkStack* const stack = _overflowed.pop(); - if (stack != nullptr) { - return stack; - } - - return _published.pop(); -} - inline size_t ZMarkStripeSet::stripe_id(const ZMarkStripe* stripe) const { const size_t index = ((uintptr_t)stripe - (uintptr_t)_stripes) / sizeof(ZMarkStripe); assert(index < ZMarkStripesMax, "Invalid index"); @@ -236,32 +116,63 @@ inline ZMarkStack* ZMarkThreadLocalStacks::steal(ZMarkStripeSet* stripes, return stack; } -inline bool ZMarkThreadLocalStacks::push(ZMarkStackAllocator* allocator, - ZMarkStripeSet* stripes, +inline void ZMarkThreadLocalStacks::push(ZMarkStripeSet* stripes, ZMarkStripe* stripe, ZMarkTerminate* terminate, ZMarkStackEntry entry, bool publish) { - ZMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - ZMarkStack* const stack = *stackp; - if (stack != nullptr && stack->push(entry)) { - return true; + const size_t stripe_id = stripes->stripe_id(stripe); + ZMarkStack** const stackp = &_stacks[stripe_id]; + ZMarkStack* const prev_stack = *stackp; + + if (prev_stack != nullptr) { + if (!prev_stack->is_full()) { + // There's a stack and it isn't full: just push + prev_stack->push(entry); + return; + } + + // Publish full stacks + stripe->publish_stack(prev_stack, terminate, publish); + *stackp = nullptr; } - return push_slow(allocator, stripe, stackp, terminate, entry, publish); + // If no stack was available, allocate one and push to it + const bool first_stack = prev_stack == nullptr; + ZMarkStack* const new_stack = ZMarkStack::create(first_stack); + *stackp = new_stack; + + new_stack->push(entry); } -inline bool ZMarkThreadLocalStacks::pop(ZMarkStackAllocator* allocator, +inline bool ZMarkThreadLocalStacks::pop(ZMarkingSMR* marking_smr, ZMarkStripeSet* stripes, ZMarkStripe* stripe, - ZMarkStackEntry& entry) { + ZMarkStackEntry* entry) { ZMarkStack** const stackp = &_stacks[stripes->stripe_id(stripe)]; - ZMarkStack* const stack = *stackp; - if (stack != nullptr && stack->pop(entry)) { - return true; + ZMarkStack* stack = *stackp; + + // First make sure there is a stack to pop from + if (stack == nullptr) { + // If we have no stack, try to steal one + stack = stripe->steal_stack(marking_smr); + *stackp = stack; + + if (stack == nullptr) { + // Out of stacks to pop from + return false; + } } - return pop_slow(allocator, stripe, stackp, entry); + *entry = stack->pop(); + + if (stack->is_empty()) { + // Eagerly free empty stacks while on a worker thread + ZMarkStack::destroy(stack); + *stackp = nullptr; + } + + return true; } #endif // SHARE_GC_Z_ZMARKSTACK_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp deleted file mode 100644 index 02a903985e7..00000000000 --- a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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 - * 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/gc_globals.hpp" -#include "gc/z/zInitialize.hpp" -#include "gc/z/zLock.inline.hpp" -#include "gc/z/zMarkStack.inline.hpp" -#include "gc/z/zMarkStackAllocator.hpp" -#include "logging/log.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -ZMarkStackSpace::ZMarkStackSpace() - : _expand_lock(), - _start(0), - _top(0), - _end(0) { - assert(ZMarkStackSpaceLimit >= ZMarkStackSpaceExpandSize, "ZMarkStackSpaceLimit too small"); - - // Reserve address space - const size_t size = ZMarkStackSpaceLimit; - const uintptr_t addr = (uintptr_t)os::reserve_memory(size, !ExecMem, mtGC); - if (addr == 0) { - ZInitialize::error_d("Failed to reserve address space for mark stacks"); - return; - } - - // Successfully initialized - _start = _top = _end = addr; - - // Prime space - _end += expand_space(); -} - -bool ZMarkStackSpace::is_initialized() const { - return _start != 0; -} - -uintptr_t ZMarkStackSpace::start() const { - return _start; -} - -size_t ZMarkStackSpace::size() const { - return _end - _start; -} - -size_t ZMarkStackSpace::used() const { - return _top - _start; -} - -size_t ZMarkStackSpace::expand_space() { - const size_t expand_size = ZMarkStackSpaceExpandSize; - const size_t old_size = size(); - const size_t new_size = old_size + expand_size; - - if (new_size > ZMarkStackSpaceLimit) { - // Expansion limit reached. This is a fatal error since we - // currently can't recover from running out of mark stack space. - fatal("Mark stack space exhausted. Use -XX:ZMarkStackSpaceLimit= to increase the " - "maximum number of bytes allocated for mark stacks. Current limit is %zuM.", - ZMarkStackSpaceLimit / M); - } - - log_debug(gc, marking)("Expanding mark stack space: %zuM->%zuM", - old_size / M, new_size / M); - - // Expand - os::commit_memory_or_exit((char*)_end, expand_size, false /* executable */, "Mark stack space"); - - return expand_size; -} - -size_t ZMarkStackSpace::shrink_space() { - // Shrink to what is currently used - const size_t old_size = size(); - const size_t new_size = align_up(used(), ZMarkStackSpaceExpandSize); - const size_t shrink_size = old_size - new_size; - - if (shrink_size > 0) { - // Shrink - log_debug(gc, marking)("Shrinking mark stack space: %zuM->%zuM", - old_size / M, new_size / M); - - const uintptr_t shrink_start = _end - shrink_size; - os::uncommit_memory((char*)shrink_start, shrink_size, false /* executable */); - } - - return shrink_size; -} - -uintptr_t ZMarkStackSpace::alloc_space(size_t size) { - uintptr_t top = Atomic::load(&_top); - - for (;;) { - const uintptr_t end = Atomic::load(&_end); - const uintptr_t new_top = top + size; - if (new_top > end) { - // Not enough space left - return 0; - } - - const uintptr_t prev_top = Atomic::cmpxchg(&_top, top, new_top); - if (prev_top == top) { - // Success - return top; - } - - // Retry - top = prev_top; - } -} - -uintptr_t ZMarkStackSpace::expand_and_alloc_space(size_t size) { - ZLocker locker(&_expand_lock); - - // Retry allocation before expanding - uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - // Expand - const size_t expand_size = expand_space(); - - // Increment top before end to make sure another - // thread can't steal out newly expanded space. - addr = Atomic::fetch_then_add(&_top, size); - Atomic::add(&_end, expand_size); - - return addr; -} - -uintptr_t ZMarkStackSpace::alloc(size_t size) { - assert(size <= ZMarkStackSpaceExpandSize, "Invalid size"); - - const uintptr_t addr = alloc_space(size); - if (addr != 0) { - return addr; - } - - return expand_and_alloc_space(size); -} - -void ZMarkStackSpace::free() { - _end -= shrink_space(); - _top = _start; -} - -ZMarkStackAllocator::ZMarkStackAllocator() - : _space(), - _freelist(_space.start()), - _expanded_recently(false) {} - -bool ZMarkStackAllocator::is_initialized() const { - return _space.is_initialized(); -} - -uintptr_t ZMarkStackAllocator::start() const { - return _space.start(); -} - -size_t ZMarkStackAllocator::size() const { - return _space.size(); -} - -ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t addr, size_t size) { - assert(is_aligned(size, ZMarkStackSize), "Invalid size"); - - // Use first stack as magazine - ZMarkStackMagazine* const magazine = new ((void*)addr) ZMarkStackMagazine(); - for (size_t i = ZMarkStackSize; i < size; i += ZMarkStackSize) { - ZMarkStack* const stack = new ((void*)(addr + i)) ZMarkStack(); - const bool success = magazine->push(stack); - assert(success, "Magazine should never get full"); - } - - return magazine; -} - -ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { - // Try allocating from the free list first - ZMarkStackMagazine* const magazine = _freelist.pop(); - if (magazine != nullptr) { - return magazine; - } - - if (!Atomic::load(&_expanded_recently)) { - Atomic::cmpxchg(&_expanded_recently, false, true); - } - - // Allocate new magazine - const uintptr_t addr = _space.alloc(ZMarkStackMagazineSize); - if (addr == 0) { - return nullptr; - } - - return create_magazine_from_space(addr, ZMarkStackMagazineSize); -} - -bool ZMarkStackAllocator::clear_and_get_expanded_recently() { - if (!Atomic::load(&_expanded_recently)) { - return false; - } - - return Atomic::cmpxchg(&_expanded_recently, true, false); -} - -void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) { - _freelist.push(magazine); -} - -void ZMarkStackAllocator::free() { - _freelist.clear(); - _space.free(); -} diff --git a/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp b/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp index 79d3f8ef2a0..cdd9e7dce25 100644 --- a/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp +++ b/src/hotspot/share/gc/z/zMarkTerminate.inline.hpp @@ -28,6 +28,7 @@ #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/z/zLock.inline.hpp" +#include "gc/z/zMarkStack.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/osThread.hpp" @@ -60,8 +61,7 @@ inline void ZMarkTerminate::leave() { inline void ZMarkTerminate::maybe_reduce_stripes(ZMarkStripeSet* stripes, size_t used_nstripes) { size_t nstripes = stripes->nstripes(); if (used_nstripes == nstripes && nstripes > 1u) { - nstripes >>= 1; - stripes->set_nstripes(nstripes); + stripes->try_set_nstripes(nstripes, nstripes >> 1); } } diff --git a/src/hotspot/share/gc/z/zMarkingSMR.cpp b/src/hotspot/share/gc/z/zMarkingSMR.cpp new file mode 100644 index 00000000000..2335d009c74 --- /dev/null +++ b/src/hotspot/share/gc/z/zMarkingSMR.cpp @@ -0,0 +1,112 @@ +/* + * 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 + * 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/z/zMarkingSMR.hpp" +#include "gc/z/zMarkStack.inline.hpp" +#include "gc/z/zValue.inline.hpp" +#include "runtime/atomic.hpp" + +ZMarkingSMR::ZMarkingSMR() + : _worker_states(), + _expanded_recently() { +} + +void ZMarkingSMR::free_node(ZMarkStackListNode* node) { + // We use hazard pointers as an safe memory reclamation (SMR) technique, + // for marking stacks. Each stripe has a lock-free stack of mark stacks. + // When a GC thread (1) pops a mark stack from this lock-free stack, + // there is a small window of time when the head has been read and we + // are about to read its next pointer. It is then of great importance + // that the node is not concurrently freed by another concurrent GC + // thread (2), popping the same entry. In such an event, the memory + // of the freed node could, for example become part of a separate + // node, and potentially pushed onto a separate stripe, with a + // different next pointer referring to a node of the other stripe. + // When GC thread (1) then reads the next pointer of what it believed + // to be the current head node of the first stripe, it actually read + // a next pointer of a logically different node, pointing into the + // other stripe. GC thread (2) could then pop the node from the second + // mark stripe and re-insert it as the head of the first stripe. + // Disaster eventually hits when GC thread (1) succeeds with its + // CAS (ABA problem), switching the loaded head to the loaded next + // pointer of the head. Due to the next pointer belonging to a logically + // different node than the logical head, we can accidentally corrupt the + // stack integrity. Using hazard pointers involves publishing what head + // was observed by GC thread (1), so that GC thread (2) knows not to + // free the node when popping it in this race. This prevents the racy + // interactions from causing any such use-after-free problems. + + assert(Thread::current()->is_Worker_thread(), "must be a worker"); + + ZWorkerState* const local_state = _worker_states.addr(); + ZArray* const freeing = &local_state->_freeing; + freeing->append(node); + + if (freeing->length() < (int)ZPerWorkerStorage::count() * 8) { + return; + } + + ZPerWorkerIterator iter(&_worker_states); + ZArray* const scanned_hazards = &local_state->_scanned_hazards; + + for (ZWorkerState* remote_state; iter.next(&remote_state);) { + ZMarkStackListNode* const hazard = Atomic::load(&remote_state->_hazard_ptr); + + if (hazard != nullptr) { + scanned_hazards->append(hazard); + } + } + + int kept = 0; + for (int i = 0; i < freeing->length(); ++i) { + ZMarkStackListNode* node = freeing->at(i); + freeing->at_put(i, nullptr); + + if (scanned_hazards->contains(node)) { + // Keep + freeing->at_put(kept++, node); + } else { + // Delete + delete node; + } + } + + scanned_hazards->clear(); + freeing->trunc_to(kept); +} + +void ZMarkingSMR::free() { + // Here it is free by definition to free mark stacks. + ZPerWorkerIterator iter(&_worker_states); + for (ZWorkerState* worker_state; iter.next(&worker_state);) { + ZArray* const freeing = &worker_state->_freeing; + for (ZMarkStackListNode* node: *freeing) { + delete node; + } + freeing->clear(); + } +} + +ZMarkStackListNode* volatile* ZMarkingSMR::hazard_ptr() { + return &_worker_states.addr()->_hazard_ptr; +} diff --git a/src/hotspot/share/gc/z/zMarkStackAllocator.hpp b/src/hotspot/share/gc/z/zMarkingSMR.hpp similarity index 50% rename from src/hotspot/share/gc/z/zMarkStackAllocator.hpp rename to src/hotspot/share/gc/z/zMarkingSMR.hpp index dc18a23e101..a6c5afe76c9 100644 --- a/src/hotspot/share/gc/z/zMarkStackAllocator.hpp +++ b/src/hotspot/share/gc/z/zMarkingSMR.hpp @@ -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 @@ -24,61 +24,30 @@ #ifndef SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP #define SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP -#include "gc/z/zGlobals.hpp" -#include "gc/z/zLock.hpp" -#include "gc/z/zMarkStack.hpp" +#include "gc/z/zArray.hpp" +#include "gc/z/zValue.hpp" #include "utilities/globalDefinitions.hpp" +#include "memory/allocation.hpp" -class ZMarkStackSpace { +class ZMarkStackListNode; + +class ZMarkingSMR: public CHeapObj { private: - ZLock _expand_lock; - uintptr_t _start; - volatile uintptr_t _top; - volatile uintptr_t _end; - volatile bool _recently_expanded; + struct ZWorkerState { + ZMarkStackListNode* volatile _hazard_ptr; + ZArray _scanned_hazards; + ZArray _freeing; + }; - size_t used() const; - - size_t expand_space(); - size_t shrink_space(); - - uintptr_t alloc_space(size_t size); - uintptr_t expand_and_alloc_space(size_t size); + ZPerWorker _worker_states; + volatile bool _expanded_recently; public: - ZMarkStackSpace(); - - bool is_initialized() const; - - uintptr_t start() const; - size_t size() const; - - uintptr_t alloc(size_t size); - void free(); -}; - -class ZMarkStackAllocator : public CHeapObj { -private: - ZCACHE_ALIGNED ZMarkStackSpace _space; - ZCACHE_ALIGNED ZMarkStackMagazineList _freelist; - ZCACHE_ALIGNED volatile bool _expanded_recently; - - ZMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size); - -public: - ZMarkStackAllocator(); - - bool is_initialized() const; - - uintptr_t start() const; - size_t size() const; - - bool clear_and_get_expanded_recently(); - - ZMarkStackMagazine* alloc_magazine(); - void free_magazine(ZMarkStackMagazine* magazine); - + ZMarkingSMR(); void free(); + ZMarkStackListNode* allocate_stack(); + void free_node(ZMarkStackListNode* stack); + ZMarkStackListNode* volatile* hazard_ptr(); }; #endif // SHARE_GC_Z_ZMARKSTACKALLOCATOR_HPP diff --git a/src/hotspot/share/gc/z/zRemembered.cpp b/src/hotspot/share/gc/z/zRemembered.cpp index 4cfc349acc4..3bb17152d41 100644 --- a/src/hotspot/share/gc/z/zRemembered.cpp +++ b/src/hotspot/share/gc/z/zRemembered.cpp @@ -550,7 +550,7 @@ public: // publish such marking stacks to prevent that generation from getting a mark continue. // We also flush in case of a resize where a new worker thread continues the marking // work, causing a mark continue for the collected generation. - ZHeap::heap()->mark_flush_and_free(Thread::current()); + ZHeap::heap()->mark_flush(Thread::current()); } virtual void resize_workers(uint nworkers) { diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 3fe60f48e89..558ccdf105a 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -1424,8 +1424,7 @@ ZStatMark::ZStatMark() _nproactiveflush(), _nterminateflush(), _ntrycomplete(), - _ncontinue(), - _mark_stack_usage() {} + _ncontinue() {} void ZStatMark::at_mark_start(size_t nstripes) { _nstripes = nstripes; @@ -1441,10 +1440,6 @@ void ZStatMark::at_mark_end(size_t nproactiveflush, _ncontinue = ncontinue; } -void ZStatMark::at_mark_free(size_t mark_stack_usage) { - _mark_stack_usage = mark_stack_usage; -} - void ZStatMark::print() { log_info(gc, marking)("Mark: " "%zu stripe(s), " @@ -1457,8 +1452,6 @@ void ZStatMark::print() { _nterminateflush, _ntrycomplete, _ncontinue); - - log_info(gc, marking)("Mark Stack Usage: %zuM", _mark_stack_usage / M); } // diff --git a/src/hotspot/share/gc/z/zStat.hpp b/src/hotspot/share/gc/z/zStat.hpp index d1693857918..0078c963626 100644 --- a/src/hotspot/share/gc/z/zStat.hpp +++ b/src/hotspot/share/gc/z/zStat.hpp @@ -506,7 +506,6 @@ public: size_t nterminateflush, size_t ntrycomplete, size_t ncontinue); - void at_mark_free(size_t mark_stack_usage); void print(); }; diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index 4e307632969..4555b470cac 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -41,10 +41,6 @@ "Maximum allowed heap fragmentation") \ range(0, 100) \ \ - product(size_t, ZMarkStackSpaceLimit, 8*G, \ - "Maximum number of bytes allocated for mark stacks") \ - range(32*M, 1024*G) \ - \ product(double, ZCollectionInterval, 0, \ "Force GC at a fixed time interval (in seconds). " \ "Backwards compatible alias for ZCollectionIntervalMajor") \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index baeb591ef1a..b3f70592f6f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -534,6 +534,7 @@ static SpecialFlag const special_jvm_flags[] = { { "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() }, { "ZGenerational", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::undefined() }, + { "ZMarkStackSpaceLimit", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::undefined() }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, From ddb256911032cd7e6fae17c342261276066d8d25 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 24 Feb 2025 19:54:48 +0000 Subject: [PATCH 100/587] 8280682: Refactor AOT code source validation checks Co-authored-by: Ioi Lam Reviewed-by: iklam, asmehra, dholmes, kvn --- src/hotspot/share/cds/aotClassLocation.cpp | 999 ++++++++++++++++++ src/hotspot/share/cds/aotClassLocation.hpp | 269 +++++ src/hotspot/share/cds/archiveHeapLoader.hpp | 3 +- src/hotspot/share/cds/cdsConfig.cpp | 1 + src/hotspot/share/cds/cdsConstants.cpp | 1 - src/hotspot/share/cds/cdsProtectionDomain.cpp | 26 +- src/hotspot/share/cds/cppVtables.cpp | 1 - src/hotspot/share/cds/dynamicArchive.cpp | 15 +- src/hotspot/share/cds/filemap.cpp | 828 +-------------- src/hotspot/share/cds/filemap.hpp | 196 +--- src/hotspot/share/cds/heapShared.cpp | 6 +- src/hotspot/share/cds/metaspaceShared.cpp | 33 +- src/hotspot/share/cds/unregisteredClasses.cpp | 1 + src/hotspot/share/classfile/classLoader.cpp | 246 +---- src/hotspot/share/classfile/classLoader.hpp | 58 +- .../share/classfile/classLoader.inline.hpp | 43 +- .../share/classfile/classLoaderDataShared.cpp | 17 + .../share/classfile/classLoaderDataShared.hpp | 4 +- .../share/classfile/classLoaderExt.cpp | 254 +---- .../share/classfile/classLoaderExt.hpp | 90 +- src/hotspot/share/classfile/moduleEntry.cpp | 6 +- src/hotspot/share/classfile/stringTable.cpp | 1 - .../share/classfile/systemDictionary.cpp | 14 +- src/hotspot/share/memory/allocation.hpp | 3 +- src/hotspot/share/oops/klass.hpp | 6 +- src/hotspot/share/prims/jvmtiEnv.cpp | 4 +- src/hotspot/share/runtime/arguments.cpp | 1 - src/hotspot/share/runtime/threads.cpp | 9 - .../cds/appcds/BootClassPathMismatch.java | 23 +- .../runtime/cds/appcds/ClassPathAttr.java | 38 +- .../cds/appcds/CommonAppClasspath.java | 4 +- .../runtime/cds/appcds/NonExistClasspath.java | 4 +- .../cds/appcds/PrintSharedArchiveAndExit.java | 18 +- .../cds/appcds/SharedArchiveConsistency.java | 12 +- .../cds/appcds/TraceLongClasspath.java | 14 +- .../runtime/cds/appcds/WrongClasspath.java | 4 +- .../dynamicArchive/ArchiveConsistency.java | 18 +- .../dynamicArchive/WrongTopClasspath.java | 4 +- .../jigsaw/modulepath/ModulePathAndFMG.java | 47 +- .../lib/jdk/test/lib/cds/CDSArchiveUtils.java | 9 +- 40 files changed, 1537 insertions(+), 1793 deletions(-) create mode 100644 src/hotspot/share/cds/aotClassLocation.cpp create mode 100644 src/hotspot/share/cds/aotClassLocation.hpp diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp new file mode 100644 index 00000000000..8d453fe1773 --- /dev/null +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -0,0 +1,999 @@ +/* + * 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 + * 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/aotClassLocation.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" +#include "classfile/javaClasses.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/metadataFactory.hpp" +#include "memory/metaspaceClosure.hpp" +#include "memory/resourceArea.hpp" +#include "oops/array.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/arguments.hpp" +#include "utilities/classpathStream.hpp" +#include "utilities/formatBuffer.hpp" +#include "utilities/stringUtils.hpp" + +#include +#include + +AOTClassLocationConfig* AOTClassLocationConfig::_dumptime_instance = nullptr; +const AOTClassLocationConfig* AOTClassLocationConfig::_runtime_instance = nullptr; + +// A ClassLocationStream represents a list of code locations, which can be iterated using +// start() and has_next(). +class ClassLocationStream { +protected: + GrowableArray _array; + int _current; + + // Add one path to this stream. + void add_one_path(const char* path) { + _array.append(path); + } + + // Add all paths specified in cp; cp must be from -classpath or -Xbootclasspath/a. + void add_paths_in_classpath(const char* cp) { + ClasspathStream cp_stream(cp); + while (cp_stream.has_next()) { + add_one_path(cp_stream.get_next()); + } + } + +public: + ClassLocationStream() : _array(), _current(0) {} + + void print(outputStream* st) const { + const char* sep = ""; + for (int i = 0; i < _array.length(); i++) { + st->print("%s%s", sep, _array.at(i)); + sep = os::path_separator(); + } + } + + void add(ClassLocationStream& css) { + for (css.start(); css.has_next();) { + add_one_path(css.get_next()); + } + } + + // Iteration + void start() { _current = 0; } + bool has_next() const { return _current < _array.length(); } + const char* get_next() { + return _array.at(_current++); + } + + int current() const { return _current; } + bool is_empty() const { return _array.length() == 0; } +}; + +class BootCpClassLocationStream : public ClassLocationStream { +public: + BootCpClassLocationStream() : ClassLocationStream() { + // Arguments::get_boot_class_path() contains $JAVA_HOME/lib/modules, but we treat that separately + for (const char* bootcp = Arguments::get_boot_class_path(); *bootcp != '\0'; ++bootcp) { + if (*bootcp == *os::path_separator()) { + ++bootcp; + add_paths_in_classpath(bootcp); + break; + } + } + } +}; + +class AppCpClassLocationStream : public ClassLocationStream { +public: + AppCpClassLocationStream() : ClassLocationStream() { + const char* appcp = Arguments::get_appclasspath(); + if (strcmp(appcp, ".") == 0) { + appcp = ""; + } + add_paths_in_classpath(appcp); + } +}; + +class ModulePathClassLocationStream : public ClassLocationStream { + bool _has_non_jar_modules; +public: + ModulePathClassLocationStream(); + bool has_non_jar_modules() { return _has_non_jar_modules; } +}; + +// AllClassLocationStreams is used to iterate over all the code locations that +// are available to the application from -Xbootclasspath, -classpath and --module-path. +// When creating an AOT cache, we store the contents from AllClassLocationStreams +// into an array of AOTClassLocations. See AOTClassLocationConfig::dumptime_init_helper(). +// When loading the AOT cache in a production run, we compare the contents of the +// stored AOTClassLocations against the current AllClassLocationStreams to determine whether +// the AOT cache is compatible with the current JVM. See AOTClassLocationConfig::validate(). +class AllClassLocationStreams { + BootCpClassLocationStream _boot_cp; // Specified by -Xbootclasspath/a + AppCpClassLocationStream _app_cp; // Specified by -classpath + ModulePathClassLocationStream _module_path; // Specified by --module-path + ClassLocationStream _boot_and_app_cp; // Convenience for iterating over both _boot and _app +public: + BootCpClassLocationStream& boot_cp() { return _boot_cp; } + AppCpClassLocationStream& app_cp() { return _app_cp; } + ModulePathClassLocationStream& module_path() { return _module_path; } + ClassLocationStream& boot_and_app_cp() { return _boot_and_app_cp; } + + AllClassLocationStreams() : _boot_cp(), _app_cp(), _module_path(), _boot_and_app_cp() { + _boot_and_app_cp.add(_boot_cp); + _boot_and_app_cp.add(_app_cp); + } +}; + +static bool has_jar_suffix(const char* filename) { + // In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix. + // Performing the same check here. + const char* dot = strrchr(filename, '.'); + if (dot != nullptr && strcmp(dot + 1, "jar") == 0) { + return true; + } + return false; +} + +static int compare_module_path_by_name(const char** p1, const char** p2) { + return strcmp(*p1, *p2); +} + +ModulePathClassLocationStream::ModulePathClassLocationStream() : ClassLocationStream(), _has_non_jar_modules(false) { + // Note: for handling of --module-path, see + // https://openjdk.org/jeps/261#Module-paths + // https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/module/ModuleFinder.html#of(java.nio.file.Path...) + + const char* jdk_module_path = Arguments::get_property("jdk.module.path"); + if (jdk_module_path == nullptr) { + return; + } + + ClasspathStream cp_stream(jdk_module_path); + while (cp_stream.has_next()) { + const char* path = cp_stream.get_next(); + DIR* dirp = os::opendir(path); + if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) { + add_one_path(path); + } else if (dirp != nullptr) { + struct dirent* dentry; + bool found_jar = false; + while ((dentry = os::readdir(dirp)) != nullptr) { + const char* file_name = dentry->d_name; + if (has_jar_suffix(file_name)) { + size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1; + char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len); + int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name); + assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string"); + add_one_path(full_name); + found_jar = true; + } else if (strcmp(file_name, ".") != 0 && strcmp(file_name, "..") != 0) { + // Found some non jar entries + _has_non_jar_modules = true; + log_info(class, path)("Found non-jar path: '%s%s%s'", path, os::file_separator(), file_name); + } + } + if (!found_jar) { + log_info(class, path)("Found exploded module path: '%s'", path); + _has_non_jar_modules = true; + } + os::closedir(dirp); + } else { + _has_non_jar_modules = true; + } + } + + _array.sort(compare_module_path_by_name); +} + +AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* path, int index, + Group group, bool from_cpattr, bool is_jrt) { + size_t path_length = 0; + size_t manifest_length = 0; + bool check_time = false; + time_t timestamp = 0; + int64_t filesize = 0; + FileType type = FileType::NORMAL; + // Do not record the actual path of the jrt, as the entire JDK can be moved to a different + // directory. + const char* recorded_path = is_jrt ? "" : path; + path_length = strlen(recorded_path); + + struct stat st; + if (os::stat(path, &st) == 0) { + if ((st.st_mode & S_IFMT) == S_IFDIR) { + type = FileType::DIR; + } else { + timestamp = st.st_mtime; + filesize = st.st_size; + + // 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; + } else { + log_error(cds)("Unable to open file %s.", path); + MetaspaceShared::unrecoverable_loading_error(); + } + + ResourceMark rm(current); + char* manifest = nullptr; + + if (!is_jrt && type == FileType::NORMAL) { + manifest = read_manifest(current, path, manifest_length); // resource allocated + } + + size_t cs_size = header_size() + + + path_length + 1 /* nul-terminated */ + + manifest_length + 1; /* nul-terminated */ + + AOTClassLocation* cs = (AOTClassLocation*)os::malloc(cs_size, mtClassShared); + memset(cs, 0, cs_size); + cs->_path_length = path_length; + cs->_manifest_length = manifest_length; + cs->_check_time = check_time; + cs->_from_cpattr = from_cpattr; + cs->_timestamp = timestamp; + cs->_filesize = filesize; + cs->_file_type = type; + cs->_group = group; + cs->_index = index; + + strcpy(((char*)cs) + cs->path_offset(), recorded_path); + if (manifest_length > 0) { + memcpy(((char*)cs) + cs->manifest_offset(), manifest, manifest_length); + } + assert(*(cs->manifest() + cs->manifest_length()) == '\0', "should be nul-terminated"); + + if (strstr(cs->manifest(), "Multi-Release: true") != nullptr) { + cs->_is_multi_release_jar = true; + } + + if (strstr(cs->manifest(), "Extension-List:") != nullptr) { + vm_exit_during_cds_dumping(err_msg("-Xshare:dump does not support Extension-List in JAR manifest: %s", path)); + } + + return cs; +} + +char* AOTClassLocation::read_manifest(JavaThread* current, const char* path, size_t& manifest_length) { + manifest_length = 0; + + struct stat st; + if (os::stat(path, &st) != 0) { + return nullptr; + } + + ClassPathEntry* cpe = ClassLoader::create_class_path_entry(current, path, &st); + if (cpe == nullptr) { + // is a file, but not a JAR file + return nullptr; + } + assert(cpe->is_jar_file(), "should not be called with a directory"); + + const char* name = "META-INF/MANIFEST.MF"; + char* manifest; + jint size; + manifest = (char*) ((ClassPathZipEntry*)cpe)->open_entry(current, name, &size, true); + + if (manifest == nullptr || size <= 0) { // No Manifest + manifest_length = 0; + } else { + manifest_length = (size_t)size; + } + + delete cpe; + return manifest; +} + +// The result is resource allocated. +char* AOTClassLocation::get_cpattr() const { + if (_manifest_length == 0) { + return nullptr; + } + + size_t buf_size = _manifest_length + 1; + char* buf = NEW_RESOURCE_ARRAY(char, buf_size); + memcpy(buf, manifest(), _manifest_length); + buf[_manifest_length] = 0; // make sure it's 0-terminated + + // See http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#JAR%20Manifest + // Replace all CR/LF and CR with LF + StringUtils::replace_no_expand(buf, "\r\n", "\n"); + // Remove all new-line continuation (remove all "\n " substrings) + StringUtils::replace_no_expand(buf, "\n ", ""); + + const char* tag = "Class-Path: "; + size_t tag_len = strlen(tag); + char* found = nullptr; + char* line_start = buf; + char* end = buf + _manifest_length; + + assert(*end == 0, "must be nul-terminated"); + + while (line_start < end) { + char* line_end = strchr(line_start, '\n'); + if (line_end == nullptr) { + // JAR spec require the manifest file to be terminated by a new line. + break; + } + if (strncmp(tag, line_start, tag_len) == 0) { + if (found != nullptr) { + // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java + // If duplicated entries are found, the last one is used. + log_warning(cds)("Warning: Duplicate name in Manifest: %s.\n" + "Ensure that the manifest does not have duplicate entries, and\n" + "that blank lines separate individual sections in both your\n" + "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, path()); + } + found = line_start + tag_len; + assert(found <= line_end, "sanity"); + *line_end = '\0'; + } + line_start = line_end + 1; + } + + return found; +} + +AOTClassLocation* AOTClassLocation::write_to_archive() const { + AOTClassLocation* archived_copy = (AOTClassLocation*)ArchiveBuilder::ro_region_alloc(total_size()); + memcpy((char*)archived_copy, (char*)this, total_size()); + return archived_copy; +} + +const char* AOTClassLocation::file_type_string() const { + switch (_file_type) { + case FileType::NORMAL: return "file"; + case FileType::DIR: return "dir"; + case FileType::NOT_EXIST: default: return "not-exist"; + } +} + +bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_classes) const { + struct stat st; + if (os::stat(runtime_path, &st) != 0) { + if (_file_type != FileType::NOT_EXIST) { + log_warning(cds)("Required classpath entry does not exist: %s", runtime_path); + return false; + } + } else if ((st.st_mode & S_IFMT) == S_IFDIR) { + if (_file_type == FileType::NOT_EXIST) { + log_warning(cds)("'%s' must not exist", runtime_path); + return false; + } + if (_file_type == FileType::NORMAL) { + log_warning(cds)("'%s' must be a file", runtime_path); + return false; + } + if (!os::dir_is_empty(runtime_path)) { + log_warning(cds)("directory is not empty: '%s'", runtime_path); + return false; + } + } else { + if (_file_type == FileType::NOT_EXIST) { + log_warning(cds)("'%s' must not exist", runtime_path); + if (has_aot_linked_classes) { + log_error(cds)("CDS archive has aot-linked classes. It cannot be used because the " + "file %s exists", runtime_path); + return false; + } else { + log_warning(cds)("Archived non-system classes are disabled because the " + "file %s exists", runtime_path); + FileMapInfo::current_info()->set_has_platform_or_app_classes(false); + if (DynamicArchive::is_mapped()) { + FileMapInfo::dynamic_info()->set_has_platform_or_app_classes(false); + } + } + } + if (_file_type == FileType::DIR) { + log_warning(cds)("'%s' must be a directory", runtime_path); + return false; + } + bool size_differs = _filesize != st.st_size; + bool time_differs = _check_time && (_timestamp != st.st_mtime); + if (size_differs || time_differs) { + log_warning(cds)("This file is not the one used while building the shared archive file: '%s'%s%s", + runtime_path, + time_differs ? ", timestamp has changed" : "", + size_differs ? ", size has changed" : ""); + return false; + } + } + + log_info(class, path)("ok"); + return true; +} + +void AOTClassLocationConfig::dumptime_init(JavaThread* current) { + assert(CDSConfig::is_dumping_archive(), ""); + _dumptime_instance = NEW_C_HEAP_OBJ(AOTClassLocationConfig, mtClassShared); + _dumptime_instance->dumptime_init_helper(current); + if (current->has_pending_exception()) { + // we can get an exception only when we run out of metaspace, but that + // shouldn't happen this early in bootstrap. + java_lang_Throwable::print(current->pending_exception(), tty); + vm_exit_during_initialization("AOTClassLocationConfig::dumptime_init_helper() failed unexpectedly"); + } +} + +void AOTClassLocationConfig::dumptime_init_helper(TRAPS) { + ResourceMark rm; + GrowableClassLocationArray tmp_array; + AllClassLocationStreams all_css; + + AOTClassLocation* jrt = AOTClassLocation::allocate(THREAD, ClassLoader::get_jrt_entry()->name(), + 0, Group::MODULES_IMAGE, + /*from_cpattr*/false, /*is_jrt*/true); + tmp_array.append(jrt); + + parse(THREAD, tmp_array, all_css.boot_cp(), Group::BOOT_CLASSPATH, /*parse_manifest*/true); + _boot_classpath_end = tmp_array.length(); + + parse(THREAD, tmp_array, all_css.app_cp(), Group::APP_CLASSPATH, /*parse_manifest*/true); + _app_classpath_end = tmp_array.length(); + + parse(THREAD, tmp_array, all_css.module_path(), Group::MODULE_PATH, /*parse_manifest*/false); + _module_end = tmp_array.length(); + + _class_locations = MetadataFactory::new_array(ClassLoaderData::the_null_class_loader_data(), + tmp_array.length(), CHECK); + for (int i = 0; i < tmp_array.length(); i++) { + _class_locations->at_put(i, tmp_array.at(i)); + } + + const char* lcp = find_lcp(all_css.boot_and_app_cp(), _dumptime_lcp_len); + if (_dumptime_lcp_len > 0) { + os::free((void*)lcp); + log_info(class, path)("Longest common prefix = %s (%zu chars)", lcp, _dumptime_lcp_len); + } else { + assert(_dumptime_lcp_len == 0, "sanity"); + log_info(class, path)("Longest common prefix = (0 chars)"); + } + + _has_non_jar_modules = all_css.module_path().has_non_jar_modules(); + _has_platform_classes = false; + _has_app_classes = false; + _max_used_index = 0; +} + +// Find the longest common prefix of two paths, up to max_lcp_len. +// E.g. p1 = "/a/b/foo" +// p2 = "/a/b/bar" +// max_lcp_len = 3 +// -> returns 3 +static size_t find_lcp_of_two_paths(const char* p1, const char* p2, size_t max_lcp_len) { + size_t lcp_len = 0; + char sep = os::file_separator()[0]; + for (size_t i = 0; ; i++) { + char c1 = *p1++; + char c2 = *p2++; + if (c1 == 0 || c2 == 0 || c1 != c2) { + break; + } + if (c1 == sep) { + lcp_len = i + 1; + assert(lcp_len <= max_lcp_len, "sanity"); + if (lcp_len == max_lcp_len) { + break; + } + } + } + return lcp_len; +} + +// cheap-allocated if lcp_len > 0 +const char* AOTClassLocationConfig::find_lcp(ClassLocationStream& css, size_t& lcp_len) { + const char* first_path = nullptr; + char sep = os::file_separator()[0]; + + for (css.start(); css.has_next(); ) { + const char* path = css.get_next(); + if (first_path == nullptr) { + first_path = path; + const char* p = strrchr(first_path, sep); + if (p == nullptr) { + lcp_len = 0; + return ""; + } else { + lcp_len = p - first_path + 1; + } + } else { + lcp_len = find_lcp_of_two_paths(first_path, path, lcp_len); + if (lcp_len == 0) { + return ""; + } + } + } + + if (first_path != nullptr && lcp_len > 0) { + char* lcp = NEW_C_HEAP_ARRAY(char, lcp_len + 1, mtClassShared); + lcp[0] = 0; + strncat(lcp, first_path, lcp_len); + return lcp; + } else { + lcp_len = 0; + return ""; + } +} + +void AOTClassLocationConfig::parse(JavaThread* current, GrowableClassLocationArray& tmp_array, + ClassLocationStream& css, Group group, bool parse_manifest) { + for (css.start(); css.has_next(); ) { + add_class_location(current, tmp_array, css.get_next(), group, parse_manifest, /*from_cpattr*/false); + } +} + +void AOTClassLocationConfig::add_class_location(JavaThread* current, GrowableClassLocationArray& tmp_array, + const char* path, Group group, bool parse_manifest, bool from_cpattr) { + AOTClassLocation* cs = AOTClassLocation::allocate(current, path, tmp_array.length(), group, from_cpattr); + tmp_array.append(cs); + + if (!parse_manifest) { + // parse_manifest is true for -classpath and -Xbootclasspath/a, and false for --module-path. + return; + } + + ResourceMark rm; + char* cp_attr = cs->get_cpattr(); // resource allocated + if (cp_attr != nullptr && strlen(cp_attr) > 0) { + //trace_class_path("found Class-Path: ", cp_attr); FIXME + + char sep = os::file_separator()[0]; + const char* dir_name = cs->path(); + const char* dir_tail = strrchr(dir_name, sep); +#ifdef _WINDOWS + // On Windows, we also support forward slash as the file separator when locating entries in the classpath entry. + const char* dir_tail2 = strrchr(dir_name, '/'); + if (dir_tail == nullptr) { + dir_tail = dir_tail2; + } else if (dir_tail2 != nullptr && dir_tail2 > dir_tail) { + dir_tail = dir_tail2; + } +#endif + int dir_len; + if (dir_tail == nullptr) { + dir_len = 0; + } else { + dir_len = pointer_delta_as_int(dir_tail, dir_name) + 1; + } + + // Split the cp_attr by spaces, and add each file + char* file_start = cp_attr; + char* end = file_start + strlen(file_start); + + while (file_start < end) { + char* file_end = strchr(file_start, ' '); + if (file_end != nullptr) { + *file_end = 0; + file_end += 1; + } else { + file_end = end; + } + + size_t name_len = strlen(file_start); + if (name_len > 0) { + ResourceMark rm(current); + size_t libname_len = dir_len + name_len; + char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1); + int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start); + assert((size_t)n == libname_len, "Unexpected number of characters in string"); + + // Avoid infinite recursion when two JAR files refer to each + // other via cpattr. + bool found_duplicate = false; + for (int i = boot_cp_start_index(); i < tmp_array.length(); i++) { + if (strcmp(tmp_array.at(i)->path(), libname) == 0) { + found_duplicate = true; + break; + } + } + if (!found_duplicate) { + add_class_location(current, tmp_array, libname, group, parse_manifest, /*from_cpattr*/true); + } + } + + file_start = file_end; + } + } +} + +AOTClassLocation const* AOTClassLocationConfig::class_location_at(int index) const { + return _class_locations->at(index); +} + +int AOTClassLocationConfig::get_module_shared_path_index(Symbol* location) const { + if (location->starts_with("jrt:", 4)) { + assert(class_location_at(0)->is_modules_image(), "sanity"); + return 0; + } + + if (num_module_paths() == 0) { + // The archive(s) were created without --module-path option + return -1; + } + + if (!location->starts_with("file:", 5)) { + return -1; + } + + // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table() + ResourceMark rm; + const char* file = ClassLoader::uri_to_path(location->as_C_string()); + for (int i = module_path_start_index(); i < module_path_end_index(); i++) { + const AOTClassLocation* cs = class_location_at(i); + assert(!cs->has_unnamed_module(), "must be"); + bool same = os::same_files(file, cs->path()); + log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, + location->as_C_string(), cs->path(), same ? "same" : "different"); + if (same) { + return i; + } + } + return -1; +} + +// We allow non-empty dirs as long as no classes have been loaded from them. +void AOTClassLocationConfig::check_nonempty_dirs() const { + assert(CDSConfig::is_dumping_archive(), "sanity"); + + bool has_nonempty_dir = false; + dumptime_iterate([&](AOTClassLocation* cs) { + if (cs->index() > _max_used_index) { + return false; // stop iterating + } + if (cs->is_dir()) { + if (!os::dir_is_empty(cs->path())) { + log_error(cds)("Error: non-empty directory '%s'", cs->path()); + has_nonempty_dir = true; + } + } + return true; // keep iterating + }); + + if (has_nonempty_dir) { + vm_exit_during_cds_dumping("Cannot have non-empty directory in paths", nullptr); + } +} + +AOTClassLocationConfig* AOTClassLocationConfig::write_to_archive() const { + Array* archived_copy = ArchiveBuilder::new_ro_array(_class_locations->length()); + for (int i = 0; i < _class_locations->length(); i++) { + archived_copy->at_put(i, _class_locations->at(i)->write_to_archive()); + ArchivePtrMarker::mark_pointer((address*)archived_copy->adr_at(i)); + } + + AOTClassLocationConfig* dumped = (AOTClassLocationConfig*)ArchiveBuilder::ro_region_alloc(sizeof(AOTClassLocationConfig)); + memcpy(dumped, this, sizeof(AOTClassLocationConfig)); + dumped->_class_locations = archived_copy; + ArchivePtrMarker::mark_pointer(&dumped->_class_locations); + + return dumped; +} + +bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_aot_linked_classes, + int index_start, int index_end, + ClassLocationStream& runtime_css, + bool use_lcp_match, const char* runtime_lcp, + size_t runtime_lcp_len) const { + if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check + return true; + } + + ResourceMark rm; + const char* which = is_boot_classpath ? "boot" : "app"; + LogTarget(Info, class, path) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print("Checking %s classpath", which); + ls.print_cr("%s", use_lcp_match ? " (with longest common prefix substitution)" : ""); + ls.print("- expected : '"); + print_dumptime_classpath(ls, index_start, index_end, use_lcp_match, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len); + ls.print_cr("'"); + ls.print("- actual : '"); + runtime_css.print(&ls); + ls.print_cr("'"); + } + + runtime_css.start(); + for (int i = index_start; i < index_end; i++) { + ResourceMark rm; + const AOTClassLocation* cs = class_location_at(i); + const char* effective_dumptime_path = cs->path(); + if (use_lcp_match && _dumptime_lcp_len > 0) { + effective_dumptime_path = substitute(effective_dumptime_path, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len); + } + + log_info(class, path)("Checking '%s' %s%s", effective_dumptime_path, cs->file_type_string(), + cs->from_cpattr() ? " (from JAR manifest ClassPath attribute)" : ""); + if (!cs->from_cpattr() && file_exists(effective_dumptime_path)) { + if (!runtime_css.has_next()) { + log_warning(cds)("%s classpath has fewer elements than expected", which); + return false; + } + const char* runtime_path = runtime_css.get_next(); + while (!file_exists(runtime_path) && runtime_css.has_next()) { + runtime_path = runtime_css.get_next(); + } + if (!os::same_files(effective_dumptime_path, runtime_path)) { + log_warning(cds)("The name of %s classpath [%d] does not match: expected '%s', got '%s'", + which, runtime_css.current(), effective_dumptime_path, runtime_path); + return false; + } + } + + if (!cs->check(effective_dumptime_path, has_aot_linked_classes)) { + return false; + } + } + + // Check if the runtime boot classpath has more entries than the one stored in the archive and if the app classpath + // or the module path requires validation. + if (is_boot_classpath && runtime_css.has_next() && (need_to_check_app_classpath() || num_module_paths() > 0)) { + // the check passes if all the extra runtime boot classpath entries are non-existent + if (check_paths_existence(runtime_css)) { + log_warning(cds)("boot classpath is longer than expected"); + return false; + } + } + + return true; +} + +bool AOTClassLocationConfig::file_exists(const char* filename) const{ + struct stat st; + return (os::stat(filename, &st) == 0 && st.st_size > 0); +} + +bool AOTClassLocationConfig::check_paths_existence(ClassLocationStream& runtime_css) const { + bool exist = false; + while (runtime_css.has_next()) { + const char* path = runtime_css.get_next(); + if (file_exists(path)) { + exist = true; + break; + } + } + return exist; +} + +bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, int index_start, int index_end, + ClassLocationStream& runtime_css, + bool* has_extra_module_paths) const { + if (index_start >= index_end && runtime_css.is_empty()) { // nothing to check + return true; + } + + ResourceMark rm; + + LogTarget(Info, class, path) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Checking module paths"); + ls.print("- expected : '"); + print_dumptime_classpath(ls, index_start, index_end, false, 0, nullptr, 0); + ls.print_cr("'"); + ls.print("- actual : '"); + runtime_css.print(&ls); + ls.print_cr("'"); + } + + // Make sure all the dumptime module paths exist and are unchanged + for (int i = index_start; i < index_end; i++) { + const AOTClassLocation* cs = class_location_at(i); + const char* dumptime_path = cs->path(); + + assert(!cs->from_cpattr(), "not applicable for module path"); + log_info(class, path)("Checking '%s' %s", dumptime_path, cs->file_type_string()); + + if (!cs->check(dumptime_path, has_aot_linked_classes)) { + return false; + } + } + + // We allow runtime_css to be a superset of the module paths specified in dumptime. E.g., + // Dumptime: A:C + // Runtime: A:B:C + runtime_css.start(); + for (int i = index_start; i < index_end; i++) { + const AOTClassLocation* cs = class_location_at(i); + const char* dumptime_path = cs->path(); + + while (true) { + if (!runtime_css.has_next()) { + log_warning(cds)("module path has fewer elements than expected"); + *has_extra_module_paths = true; + return true; + } + // Both this->class_locations() and runtime_css are alphabetically sorted. Skip + // items in runtime_css until we see dumptime_path. + const char* runtime_path = runtime_css.get_next(); + if (!os::same_files(dumptime_path, runtime_path)) { + *has_extra_module_paths = true; + return true; + } else { + break; + } + } + } + + if (runtime_css.has_next()) { + *has_extra_module_paths = true; + } + + return true; +} + +void AOTClassLocationConfig::print_dumptime_classpath(LogStream& ls, int index_start, int index_end, + bool do_substitute, size_t remove_prefix_len, + const char* prepend, size_t prepend_len) const { + const char* sep = ""; + for (int i = index_start; i < index_end; i++) { + ResourceMark rm; + const AOTClassLocation* cs = class_location_at(i); + const char* path = cs->path(); + if (!cs->from_cpattr()) { + ls.print("%s", sep); + if (do_substitute) { + path = substitute(path, remove_prefix_len, prepend, prepend_len); + } + ls.print("%s", path); + sep = os::path_separator(); + } + } +} + +// Returned path is resource-allocated +const char* AOTClassLocationConfig::substitute(const char* path, // start with this path (which was recorded from dump time) + size_t remove_prefix_len, // remove this number of chars from the beginning + const char* prepend, // prepend this string + size_t prepend_len) { // length of the prepended string + size_t len = strlen(path); + assert(len > remove_prefix_len, "sanity"); + assert(prepend_len == strlen(prepend), "sanity"); + len -= remove_prefix_len; + len += prepend_len; + + char* buf = NEW_RESOURCE_ARRAY(char, len + 1); + int n = os::snprintf(buf, len + 1, "%s%s", prepend, path + remove_prefix_len); + assert(size_t(n) == len, "sanity"); + + return buf; +} + +// For performance, we avoid using LCP match if there's at least one +// AOTClassLocation can be matched exactly: this means all other AOTClassLocations must be +// matched exactly. +bool AOTClassLocationConfig::need_lcp_match(AllClassLocationStreams& all_css) const { + if (app_cp_end_index() == boot_cp_start_index()) { + // No need to use lcp-match when there are no boot/app paths. + // TODO: LCP-match not yet supported for modules. + return false; + } + + if (need_lcp_match_helper(boot_cp_start_index(), boot_cp_end_index(), all_css.boot_cp()) && + need_lcp_match_helper(app_cp_start_index(), app_cp_end_index(), all_css.app_cp())) { + return true; + } else { + return false; + } +} + +bool AOTClassLocationConfig::need_lcp_match_helper(int start, int end, ClassLocationStream& css) const { + int i = start; + for (css.start(); i < end && css.has_next(); ) { + const AOTClassLocation* cs = class_location_at(i++); + const char* runtime_path = css.get_next(); + if (cs->must_exist() && os::same_files(cs->path(), runtime_path)) { + // Most likely, we will come to here at the first iteration. + return false; + } + } + return true; +} + +bool AOTClassLocationConfig::validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const { + ResourceMark rm; + AllClassLocationStreams all_css; + + const char* jrt = ClassLoader::get_jrt_entry()->name(); + bool success = class_location_at(0)->check(jrt, has_aot_linked_classes); + log_info(class, path)("Modules image %s validation: %s", jrt, success ? "passed" : "failed"); + if (!success) { + return false; + } + if (class_locations()->length() == 1) { + if ((module_path_start_index() >= module_path_end_index()) && Arguments::get_property("jdk.module.path") != nullptr) { + *has_extra_module_paths = true; + } else { + *has_extra_module_paths = false; + } + } else { + bool use_lcp_match = need_lcp_match(all_css); + const char* runtime_lcp; + size_t runtime_lcp_len; + + log_info(class, path)("Longest common prefix substitution in boot/app classpath matching: %s", + use_lcp_match ? "yes" : "no"); + if (use_lcp_match) { + runtime_lcp = find_lcp(all_css.boot_and_app_cp(), runtime_lcp_len); + log_info(class, path)("Longest common prefix: %s (%zu chars)", runtime_lcp, runtime_lcp_len); + } else { + runtime_lcp = nullptr; + runtime_lcp_len = 0; + } + + success = check_classpaths(true, has_aot_linked_classes, boot_cp_start_index(), boot_cp_end_index(), all_css.boot_cp(), + use_lcp_match, runtime_lcp, runtime_lcp_len); + log_info(class, path)("Archived boot classpath validation: %s", success ? "passed" : "failed"); + + if (success && need_to_check_app_classpath()) { + success = check_classpaths(false, has_aot_linked_classes, app_cp_start_index(), app_cp_end_index(), all_css.app_cp(), + use_lcp_match, runtime_lcp, runtime_lcp_len); + log_info(class, path)("Archived app classpath validation: %s", success ? "passed" : "failed"); + } + + if (success) { + success = check_module_paths(has_aot_linked_classes, module_path_start_index(), module_path_end_index(), + all_css.module_path(), has_extra_module_paths); + log_info(class, path)("Archived module path validation: %s%s", success ? "passed" : "failed", + (*has_extra_module_paths) ? " (extra module paths found)" : ""); + } + + if (runtime_lcp_len > 0) { + os::free((void*)runtime_lcp); + } + } + + if (success) { + _runtime_instance = this; + } else { + const char* mismatch_msg = "shared class paths mismatch"; + const char* hint_msg = log_is_enabled(Info, class, path) ? + "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; + if (RequireSharedSpaces && !PrintSharedArchiveAndExit) { + log_error(cds)("%s%s", mismatch_msg, hint_msg); + MetaspaceShared::unrecoverable_loading_error(); + } else { + log_warning(cds)("%s%s", mismatch_msg, hint_msg); + } + } + return success; +} diff --git a/src/hotspot/share/cds/aotClassLocation.hpp b/src/hotspot/share/cds/aotClassLocation.hpp new file mode 100644 index 00000000000..cb53e9c96e9 --- /dev/null +++ b/src/hotspot/share/cds/aotClassLocation.hpp @@ -0,0 +1,269 @@ +/* + * 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 + * 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_AOTCLASSLOCATION_HPP +#define SHARE_CDS_AOTCLASSLOCATION_HPP + +#include "memory/allocation.hpp" +#include "oops/array.hpp" +#include "utilities/exceptions.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +class AllClassLocationStreams; +class ClassLocationStream; +class LogStream; + +// An AOTClassLocation is a location where the application is configured to load Java classes +// from. It can be: +// - the location of $JAVA_HOME/lib/modules +// - an entry in -Xbootclasspath/a +// - an entry in -classpath +// - a JAR file specified using --module-path. +// +// AOTClassLocation is similar to java.security.CodeSource, except: +// - Only local files/dirs are allowed. Directories must be empty. Network locations are not allowed. +// - No code signing information is recorded. +// +// We avoid using pointers in AOTClassLocation to avoid runtime pointer relocation. Each AOTClassLocation +// is a variable-size structure: +// [ all fields specified below (sizeof(AOTClassLocation) bytes) ] +// [ path (_path_length bytes, including the terminating zero) ] +// [ manifest (_manifest_length bytes, including the terminating zero) ] +class AOTClassLocation { +public: + enum class Group : int { + MODULES_IMAGE, + BOOT_CLASSPATH, + APP_CLASSPATH, + MODULE_PATH + }; +private: + enum class FileType : int { + NORMAL, + DIR, + NOT_EXIST + }; + size_t _path_length; // does NOT include terminating zero + size_t _manifest_length; // does NOT include terminating zero + bool _check_time; + bool _from_cpattr; + bool _is_multi_release_jar; // is this a JAR file that has multi-release classes? + FileType _file_type; + Group _group; + int _index; // index of this AOTClassLocation inside AOTClassLocationConfig::_class_locations + time_t _timestamp; + int64_t _filesize; + + static size_t header_size() { return sizeof(AOTClassLocation); } // bytes + size_t path_offset() const { return header_size(); } + size_t manifest_offset() const { return path_offset() + _path_length + 1; } + static char* read_manifest(JavaThread* current, const char* path, size_t& manifest_length); + +public: + static AOTClassLocation* allocate(JavaThread* current, const char* path, int index, Group group, + bool from_cpattr = false, bool is_jrt = false); + + size_t total_size() const { return manifest_offset() + _manifest_length + 1; } + const char* path() const { return ((const char*)this) + path_offset(); } + size_t manifest_length() const { return _manifest_length; } + const char* manifest() const { return ((const char*)this) + manifest_offset(); } + bool must_exist() const { return _file_type != FileType::NOT_EXIST; } + bool must_not_exist() const { return _file_type == FileType::NOT_EXIST; } + bool is_dir() const { return _file_type == FileType::DIR; } + int index() const { return _index; } + bool is_modules_image() const { return _group == Group::MODULES_IMAGE; } + bool from_boot_classpath() const { return _group == Group::BOOT_CLASSPATH; } + bool from_app_classpath() const { return _group == Group::APP_CLASSPATH; } + bool from_module_path() const { return _group == Group::MODULE_PATH; } + bool is_multi_release_jar() const { return _is_multi_release_jar; } + + // Only boot/app classpaths can contain unnamed module + bool has_unnamed_module() const { return from_boot_classpath() || from_app_classpath(); } + + char* get_cpattr() const; + AOTClassLocation* write_to_archive() const; + + // Returns true IFF this AOTClassLocation is discovered from the -classpath or -Xbootclasspath/a by parsing the + // "Class-Path" attribute of a JAR file. + bool from_cpattr() const { return _from_cpattr; } + const char* file_type_string() const; + bool check(const char* runtime_path, bool has_aot_linked_classes) const; +}; + +// AOTClassLocationConfig +// +// Keep track of the set of AOTClassLocations used when an AOTCache is created. +// To load the AOTCache in a production run, the JVM must be using a compatible set of +// AOTClassLocations (subjected to AOTClassLocationConfig::validate()). +// +// In general, validation is performed on the AOTClassLocations to ensure the code locations used +// during AOTCache creation are the same as when the AOTCache is used during runtime. +// Non-existent entries are recorded during AOTCache creation. Those non-existent entries, +// if they are specified at runtime, must not exist. +// +// Some details on validation: +// - the boot classpath can be appended to at runtime if there's no app classpath and no +// module path specified when an AOTCache is created; +// - the app classpath can be appended to at runtime; +// - the module path at runtime can be a superset of the one specified during AOTCache creation. + +class AOTClassLocationConfig : public CHeapObj { + using Group = AOTClassLocation::Group; + using GrowableClassLocationArray = GrowableArrayCHeap; + + // Note: both of the following are non-null if we are dumping a dynamic archive. + static AOTClassLocationConfig* _dumptime_instance; + static const AOTClassLocationConfig* _runtime_instance; + + Array* _class_locations; // jrt -> -Xbootclasspath/a -> -classpath -> --module_path + int _boot_classpath_end; + int _app_classpath_end; + int _module_end; + bool _has_non_jar_modules; + bool _has_platform_classes; + bool _has_app_classes; + int _max_used_index; + size_t _dumptime_lcp_len; + + // accessors + Array* class_locations() const { return _class_locations; } + + void parse(JavaThread* current, GrowableClassLocationArray& tmp_array, ClassLocationStream& css, + Group group, bool parse_manifest); + void add_class_location(JavaThread* current, GrowableClassLocationArray& tmp_array, const char* path, + Group group, bool parse_manifest, bool from_cpattr); + void dumptime_init_helper(TRAPS); + + bool check_classpaths(bool is_boot_classpath, bool has_aot_linked_classes, + int index_start, int index_end, ClassLocationStream& runtime_css, + bool use_lcp_match, const char* runtime_lcp, size_t runtime_lcp_len) const; + bool check_module_paths(bool has_aot_linked_classes, int index_start, int index_end, ClassLocationStream& runtime_css, + bool* has_extra_module_paths) const; + bool file_exists(const char* filename) const; + bool check_paths_existence(ClassLocationStream& runtime_css) const; + + static const char* substitute(const char* path, size_t remove_prefix_len, + const char* prepend, size_t prepend_len); + static const char* find_lcp(ClassLocationStream& css, size_t& lcp_len); + bool need_lcp_match(AllClassLocationStreams& all_css) const; + bool need_lcp_match_helper(int start, int end, ClassLocationStream& css) const; + + template void dumptime_iterate_helper(FUNC func) const { + assert(_class_locations != nullptr, "sanity"); + int n = _class_locations->length(); + for (int i = 0; i < n; i++) { + if (!func(_class_locations->at(i))) { + break; + } + } + } + + template void iterate(FUNC func) const { + int n = class_locations()->length(); + for (int i = 0; i < n; i++) { + if (!func(class_locations()->at(i))) { + break; + } + } + } + + void check_nonempty_dirs() const; + bool need_to_check_app_classpath() const { + return (num_app_classpaths() > 0) && (_max_used_index >= app_cp_start_index()) && has_platform_or_app_classes(); + } + + void print_dumptime_classpath(LogStream& ls, int index_start, int index_limit, + bool do_substitute, size_t remove_prefix_len, + const char* prepend, size_t prepend_len) const; +public: + static AOTClassLocationConfig* dumptime() { + assert(_dumptime_instance != nullptr, "can only be called when dumping an AOT cache"); + return _dumptime_instance; + } + + static const AOTClassLocationConfig* runtime() { + assert(_runtime_instance != nullptr, "can only be called when using an AOT cache"); + return _runtime_instance; + } + + // Common accessors + int boot_cp_start_index() const { return 1; } + int boot_cp_end_index() const { return _boot_classpath_end; } + int app_cp_start_index() const { return boot_cp_end_index(); } + int app_cp_end_index() const { return _app_classpath_end; } + int module_path_start_index() const { return app_cp_end_index(); } + int module_path_end_index() const { return _module_end; } + bool has_platform_or_app_classes() const { return _has_app_classes || _has_platform_classes; } + bool has_non_jar_modules() const { return _has_non_jar_modules; } + int num_boot_classpaths() const { return boot_cp_end_index() - boot_cp_start_index(); } + int num_app_classpaths() const { return app_cp_end_index() - app_cp_start_index(); } + int num_module_paths() const { return module_path_end_index() - module_path_start_index(); } + + int length() const { + return _class_locations->length(); + } + + const AOTClassLocation* class_location_at(int index) const; + int get_module_shared_path_index(Symbol* location) const; + + // Functions used only during dumptime + static void dumptime_init(JavaThread* current); + + static void dumptime_set_has_app_classes() { + _dumptime_instance->_has_app_classes = true; + } + + static void dumptime_set_has_platform_classes() { + _dumptime_instance->_has_platform_classes = true; + } + + static void dumptime_update_max_used_index(int index) { + if (_dumptime_instance == nullptr) { + assert(index == 0, "sanity"); + } else if (_dumptime_instance->_max_used_index < index) { + _dumptime_instance->_max_used_index = index; + } + } + + static void dumptime_check_nonempty_dirs() { + _dumptime_instance->check_nonempty_dirs(); + } + + static bool dumptime_is_ready() { + return _dumptime_instance != nullptr; + } + template static void dumptime_iterate(FUNC func) { + _dumptime_instance->dumptime_iterate_helper(func); + } + + AOTClassLocationConfig* write_to_archive() const; + + // Functions used only during runtime + bool validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const; +}; + + +#endif // SHARE_CDS_AOTCLASSLOCATION_HPP diff --git a/src/hotspot/share/cds/archiveHeapLoader.hpp b/src/hotspot/share/cds/archiveHeapLoader.hpp index 8b9fab91aa3..e559b447ebf 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.hpp +++ b/src/hotspot/share/cds/archiveHeapLoader.hpp @@ -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 @@ -25,7 +25,6 @@ #ifndef SHARE_CDS_ARCHIVEHEAPLOADER_HPP #define SHARE_CDS_ARCHIVEHEAPLOADER_HPP -#include "cds/filemap.hpp" #include "gc/shared/gc_globals.hpp" #include "memory/allocation.hpp" #include "memory/allStatic.hpp" diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index d190f987cbe..564298fa5c8 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -25,6 +25,7 @@ #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" +#include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/moduleEntry.hpp" diff --git a/src/hotspot/share/cds/cdsConstants.cpp b/src/hotspot/share/cds/cdsConstants.cpp index 364f6d74c43..81b5920cc53 100644 --- a/src/hotspot/share/cds/cdsConstants.cpp +++ b/src/hotspot/share/cds/cdsConstants.cpp @@ -37,7 +37,6 @@ CDSConst CDSConstants::offsets[] = { { "GenericCDSFileMapHeader::_base_archive_name_size", offset_of(GenericCDSFileMapHeader, _base_archive_name_size) }, { "CDSFileMapHeaderBase::_regions[0]", offset_of(CDSFileMapHeaderBase, _regions) }, { "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) }, - { "FileMapHeader::_common_app_classpath_prefix_size", offset_of(FileMapHeader, _common_app_classpath_prefix_size) }, { "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) }, { "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) }, { "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) } diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index 49152753a83..dc3d8621db1 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/cdsConfig.hpp" #include "cds/cdsProtectionDomain.hpp" #include "classfile/classLoader.hpp" @@ -49,10 +50,10 @@ OopHandle CDSProtectionDomain::_shared_jar_manifests; Handle CDSProtectionDomain::init_security_info(Handle class_loader, InstanceKlass* ik, PackageEntry* pkg_entry, TRAPS) { int index = ik->shared_classpath_index(); assert(index >= 0, "Sanity"); - SharedClassPathEntry* ent = FileMapInfo::shared_path(index); + const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(index); Symbol* class_name = ik->name(); - if (ent->is_modules_image()) { + if (cl->is_modules_image()) { // For shared app/platform classes originated from the run-time image: // The ProtectionDomains are cached in the corresponding ModuleEntries // for fast access by the VM. @@ -63,15 +64,14 @@ Handle CDSProtectionDomain::init_security_info(Handle class_loader, InstanceKlas return get_shared_protection_domain(class_loader, mod_entry, THREAD); } else { // For shared app/platform classes originated from JAR files on the class path: - // Each of the 3 SystemDictionaryShared::_shared_xxx arrays has the same length - // as the shared classpath table in the shared archive (see - // FileMap::_shared_path_table in filemap.hpp for details). + // Each of the 3 CDSProtectionDomain::_shared_xxx arrays has the same length + // as the shared classpath table in the shared archive. // // If a shared InstanceKlass k is loaded from the class path, let // - // index = k->shared_classpath_index(): + // index = k->shared_classpath_index(); // - // FileMap::_shared_path_table[index] identifies the JAR file that contains k. + // AOTClassLocationConfig::_runtime_instance->_array->at(index) identifies the JAR file that contains k. // // k's protection domain is: // @@ -84,10 +84,10 @@ Handle CDSProtectionDomain::init_security_info(Handle class_loader, InstanceKlas // define_shared_package(class_name, class_loader, manifest, url, CHECK_NH); // // Note that if an element of these 3 _shared_xxx arrays is null, it will be initialized by - // the corresponding SystemDictionaryShared::get_shared_xxx() function. + // the corresponding CDSProtectionDomain::get_shared_xxx() function. Handle manifest = get_shared_jar_manifest(index, CHECK_NH); Handle url = get_shared_jar_url(index, CHECK_NH); - int index_offset = index - ClassLoaderExt::app_class_paths_start_index(); + int index_offset = index - AOTClassLocationConfig::runtime()->app_cp_start_index(); if (index_offset < PackageEntry::max_index_for_defined_in_class_path()) { if (pkg_entry == nullptr || !pkg_entry->is_defined_by_cds_in_class_path(index_offset)) { // define_shared_package only needs to be called once for each package in a jar specified @@ -178,14 +178,14 @@ Handle CDSProtectionDomain::create_jar_manifest(const char* manifest_chars, size Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS) { Handle manifest; if (shared_jar_manifest(shared_path_index) == nullptr) { - SharedClassPathEntry* ent = FileMapInfo::shared_path(shared_path_index); - size_t size = (size_t)ent->manifest_size(); + const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(shared_path_index); + size_t size = cl->manifest_length(); if (size == 0) { return Handle(); } // ByteArrayInputStream bais = new ByteArrayInputStream(buf); - const char* src = ent->manifest(); + const char* src = cl->manifest(); assert(src != nullptr, "No Manifest data"); manifest = create_jar_manifest(src, size, CHECK_NH); atomic_set_shared_jar_manifest(shared_path_index, manifest()); @@ -198,7 +198,7 @@ Handle CDSProtectionDomain::get_shared_jar_manifest(int shared_path_index, TRAPS Handle CDSProtectionDomain::get_shared_jar_url(int shared_path_index, TRAPS) { Handle url_h; if (shared_jar_url(shared_path_index) == nullptr) { - const char* path = FileMapInfo::shared_path_name(shared_path_index); + const char* path = AOTClassLocationConfig::runtime()->class_location_at(shared_path_index)->path(); oop result_oop = to_file_URL(path, url_h, CHECK_(url_h)); atomic_set_shared_jar_url(shared_path_index, result_oop); } diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 155bc08dc2d..39849571015 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -258,7 +258,6 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob case MetaspaceObj::ConstantPoolCacheType: case MetaspaceObj::AnnotationsType: case MetaspaceObj::MethodCountersType: - case MetaspaceObj::SharedClassPathEntryType: case MetaspaceObj::RecordComponentType: // These have no vtables. break; diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index acdb330d91b..4ccf23ff91c 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -24,6 +24,7 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassLinker.hpp" +#include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.inline.hpp" @@ -89,7 +90,7 @@ public: void sort_methods(); void sort_methods(InstanceKlass* ik) const; void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; - void write_archive(char* serialized_data); + void write_archive(char* serialized_data, AOTClassLocationConfig* cl_config); void gather_array_klasses(); public: @@ -138,6 +139,7 @@ public: make_klasses_shareable(); char* serialized_data; + AOTClassLocationConfig* cl_config; { // Write the symbol table and system dictionaries to the RO space. // Note that these tables still point to the *original* objects, so @@ -148,6 +150,7 @@ public: ArchiveBuilder::OtherROAllocMark mark; SystemDictionaryShared::write_to_archive(false); + cl_config = AOTClassLocationConfig::dumptime()->write_to_archive(); DynamicArchive::dump_array_klasses(); AOTClassLinker::write_to_archive(); @@ -161,7 +164,7 @@ public: relocate_to_requested(); - write_archive(serialized_data); + write_archive(serialized_data, cl_config); release_header(); DynamicArchive::post_dump(); @@ -172,7 +175,6 @@ public: } virtual void iterate_roots(MetaspaceClosure* it) { - FileMapInfo::metaspace_pointers_do(it); AOTArtifactFinder::all_cached_classes_do(it); SystemDictionaryShared::dumptime_classes_do(it); iterate_primitive_array_klasses(it); @@ -335,8 +337,8 @@ void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, } } -void DynamicArchiveBuilder::write_archive(char* serialized_data) { - _header->set_shared_path_table(FileMapInfo::shared_path_table().table()); +void DynamicArchiveBuilder::write_archive(char* serialized_data, AOTClassLocationConfig* cl_config) { + _header->set_class_location_config(cl_config); _header->set_serialized_data(serialized_data); FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); @@ -389,8 +391,7 @@ public: log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment"); } - FileMapInfo::check_nonempty_dir_in_shared_path_table(); - + AOTClassLocationConfig::dumptime_check_nonempty_dirs(); _builder.doit(); } ~VM_PopulateDynamicDumpSharedSpace() { diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 990e4bb77e1..015032b2d38 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveHeapWriter.hpp" @@ -156,7 +157,6 @@ void FileMapInfo::populate_header(size_t core_region_alignment) { size_t header_size; size_t base_archive_name_size = 0; size_t base_archive_name_offset = 0; - size_t longest_common_prefix_size = 0; if (is_static()) { c_header_size = sizeof(FileMapHeader); header_size = c_header_size; @@ -173,30 +173,24 @@ void FileMapInfo::populate_header(size_t core_region_alignment) { base_archive_name_offset = c_header_size; } } - ResourceMark rm; - GrowableArray* app_cp_array = create_dumptime_app_classpath_array(); - int len = app_cp_array->length(); - longest_common_prefix_size = longest_common_app_classpath_prefix_len(len, app_cp_array); _header = (FileMapHeader*)os::malloc(header_size, mtInternal); memset((void*)_header, 0, header_size); _header->populate(this, core_region_alignment, header_size, base_archive_name_size, - base_archive_name_offset, - longest_common_prefix_size); + base_archive_name_offset); } void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, size_t header_size, size_t base_archive_name_size, - size_t base_archive_name_offset, size_t common_app_classpath_prefix_size) { + size_t base_archive_name_offset) { // 1. We require _generic_header._magic to be at the beginning of the file // 2. FileMapHeader also assumes that _generic_header is at the beginning of the file assert(offset_of(FileMapHeader, _generic_header) == 0, "must be"); set_header_size((unsigned int)header_size); set_base_archive_name_offset((unsigned int)base_archive_name_offset); set_base_archive_name_size((unsigned int)base_archive_name_size); - set_common_app_classpath_prefix_size((unsigned int)common_app_classpath_prefix_size); set_magic(CDSConfig::is_dumping_dynamic_archive() ? CDS_DYNAMIC_ARCHIVE_MAGIC : CDS_ARCHIVE_MAGIC); set_version(CURRENT_CDS_ARCHIVE_VERSION); @@ -236,22 +230,12 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, // JVM version string ... changes on each build. get_header_version(_jvm_ident); - _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index(); - _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index(); - _max_used_path_index = ClassLoaderExt::max_used_path_index(); - _num_module_paths = ClassLoader::num_module_path_entries(); - _verify_local = BytecodeVerificationLocal; _verify_remote = BytecodeVerificationRemote; - _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes(); - _has_non_jar_in_classpath = ClassLoaderExt::has_non_jar_in_classpath(); + _has_platform_or_app_classes = AOTClassLocationConfig::dumptime()->has_platform_or_app_classes(); _requested_base_address = (char*)SharedBaseAddress; _mapped_base_address = (char*)SharedBaseAddress; _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent; - - if (!CDSConfig::is_dumping_dynamic_archive()) { - set_shared_path_table(info->_shared_path_table); - } } void FileMapHeader::copy_base_archive_name(const char* archive) { @@ -268,7 +252,6 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- crc: 0x%08x", crc()); st->print_cr("- version: 0x%x", version()); st->print_cr("- header_size: " UINT32_FORMAT, header_size()); - st->print_cr("- common_app_classpath_size: " UINT32_FORMAT, common_app_classpath_prefix_size()); st->print_cr("- base_archive_name_offset: " UINT32_FORMAT, base_archive_name_offset()); st->print_cr("- base_archive_name_size: " UINT32_FORMAT, base_archive_name_size()); @@ -294,15 +277,10 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- early_serialized_data_offset: 0x%zx", _early_serialized_data_offset); st->print_cr("- serialized_data_offset: 0x%zx", _serialized_data_offset); st->print_cr("- jvm_ident: %s", _jvm_ident); - st->print_cr("- shared_path_table_offset: 0x%zx", _shared_path_table_offset); - st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index); - st->print_cr("- app_module_paths_start_index: %d", _app_module_paths_start_index); - st->print_cr("- num_module_paths: %d", _num_module_paths); - st->print_cr("- max_used_path_index: %d", _max_used_path_index); + st->print_cr("- class_location_config_offset: 0x%zx", _class_location_config_offset); st->print_cr("- verify_local: %d", _verify_local); st->print_cr("- verify_remote: %d", _verify_remote); st->print_cr("- has_platform_or_app_classes: %d", _has_platform_or_app_classes); - st->print_cr("- has_non_jar_in_classpath: %d", _has_non_jar_in_classpath); st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address)); st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address)); st->print_cr("- heap_root_segments.roots_count: %d" , _heap_root_segments.roots_count()); @@ -321,676 +299,23 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- has_archived_invokedynamic %d", _has_archived_invokedynamic); } -void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) { - _type = non_existent_entry; - set_name(path, CHECK); -} - -void SharedClassPathEntry::init(bool is_modules_image, - bool is_module_path, - ClassPathEntry* cpe, TRAPS) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - _timestamp = 0; - _filesize = 0; - _from_class_path_attr = false; - - struct stat st; - if (os::stat(cpe->name(), &st) == 0) { - if ((st.st_mode & S_IFMT) == S_IFDIR) { - _type = dir_entry; - } else { - // The timestamp of the modules_image is not checked at runtime. - if (is_modules_image) { - _type = modules_image_entry; - } else { - _type = jar_entry; - _timestamp = st.st_mtime; - _from_class_path_attr = cpe->from_class_path_attr(); - _is_multi_release = cpe->is_multi_release_jar(); - } - _filesize = st.st_size; - _is_module_path = is_module_path; - } - } else { - // The file/dir must exist, or it would not have been added - // into ClassLoader::classpath_entry(). - // - // If we can't access a jar file in the boot path, then we can't - // make assumptions about where classes get loaded from. - log_error(cds)("Unable to open file %s.", cpe->name()); - MetaspaceShared::unrecoverable_loading_error(); - } - - // No need to save the name of the module file, as it will be computed at run time - // to allow relocation of the JDK directory. - const char* name = is_modules_image ? "" : cpe->name(); - set_name(name, CHECK); -} - -void SharedClassPathEntry::set_name(const char* name, TRAPS) { - size_t len = strlen(name) + 1; - _name = MetadataFactory::new_array(ClassLoaderData::the_null_class_loader_data(), (int)len, CHECK); - strcpy(_name->data(), name); -} - -void SharedClassPathEntry::copy_from(SharedClassPathEntry* ent, ClassLoaderData* loader_data, TRAPS) { - assert(ent != nullptr, "sanity"); - _type = ent->_type; - _is_module_path = ent->_is_module_path; - _timestamp = ent->_timestamp; - _filesize = ent->_filesize; - _from_class_path_attr = ent->_from_class_path_attr; - set_name(ent->name(), CHECK); - - if (ent->is_jar() && ent->manifest() != nullptr) { - Array* buf = MetadataFactory::new_array(loader_data, - ent->manifest_size(), - CHECK); - char* p = (char*)(buf->data()); - memcpy(p, ent->manifest(), ent->manifest_size()); - set_manifest(buf); - } -} - -const char* SharedClassPathEntry::name() const { - if (CDSConfig::is_using_archive() && is_modules_image()) { - // In order to validate the runtime modules image file size against the archived - // size information, we need to obtain the runtime modules image path. The recorded - // dump time modules image path in the archive may be different from the runtime path - // if the JDK image has beed moved after generating the archive. - return ClassLoader::get_jrt_entry()->name(); - } else { - return _name->data(); - } -} - -bool SharedClassPathEntry::validate(bool is_class_path) const { +bool FileMapInfo::validate_class_location() { assert(CDSConfig::is_using_archive(), "runtime only"); - struct stat st; - const char* name = this->name(); - - bool ok = true; - log_info(class, path)("checking shared classpath entry: %s", name); - if (os::stat(name, &st) != 0 && is_class_path) { - // If the archived module path entry does not exist at runtime, it is not fatal - // (no need to invalid the shared archive) because the shared runtime visibility check - // filters out any archived module classes that do not have a matching runtime - // module path location. - log_warning(cds)("Required classpath entry does not exist: %s", name); - ok = false; - } else if (is_dir()) { - if (!os::dir_is_empty(name)) { - log_warning(cds)("directory is not empty: %s", name); - ok = false; - } - } else { - bool size_differs = _filesize != st.st_size; - bool time_differs = has_timestamp() && _timestamp != st.st_mtime; - if (time_differs || size_differs) { - ok = false; - if (PrintSharedArchiveAndExit) { - log_warning(cds)(time_differs ? "Timestamp mismatch" : "File size mismatch"); - } else { - const char* bad_file_msg = "This file is not the one used while building the shared archive file:"; - log_warning(cds)("%s %s", bad_file_msg, name); - if (!log_is_enabled(Info, cds)) { - log_warning(cds)("%s %s", bad_file_msg, name); - } - if (time_differs) { - log_warning(cds)("%s timestamp has changed.", name); - } - if (size_differs) { - log_warning(cds)("%s size has changed.", name); - } - } - } - } - - if (PrintSharedArchiveAndExit && !ok) { - // If PrintSharedArchiveAndExit is enabled, don't report failure to the - // caller. Please see above comments for more details. - ok = true; - MetaspaceShared::set_archive_loading_failed(); - } - return ok; -} - -bool SharedClassPathEntry::check_non_existent() const { - assert(_type == non_existent_entry, "must be"); - log_info(class, path)("should be non-existent: %s", name()); - struct stat st; - if (os::stat(name(), &st) != 0) { - log_info(class, path)("ok"); - return true; // file doesn't exist - } else { - return false; - } -} - -void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) { - it->push(&_name); - it->push(&_manifest); -} - -void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) { - it->push(&_entries); -} - -void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) { - const int num_entries = - ClassLoader::num_boot_classpath_entries() + - ClassLoader::num_app_classpath_entries() + - ClassLoader::num_module_path_entries() + - FileMapInfo::num_non_existent_class_paths(); - _entries = MetadataFactory::new_array(loader_data, num_entries, CHECK); - for (int i = 0; i < num_entries; i++) { - SharedClassPathEntry* ent = - new (loader_data, SharedClassPathEntry::size(), MetaspaceObj::SharedClassPathEntryType, THREAD) SharedClassPathEntry; - _entries->at_put(i, ent); - } -} - -void FileMapInfo::allocate_shared_path_table(TRAPS) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - - ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); - ClassPathEntry* jrt = ClassLoader::get_jrt_entry(); - - assert(jrt != nullptr, - "No modular java runtime image present when allocating the CDS classpath entry table"); - - _shared_path_table.dumptime_init(loader_data, CHECK); - - // 1. boot class path - int i = 0; - i = add_shared_classpaths(i, "boot", jrt, CHECK); - i = add_shared_classpaths(i, "app", ClassLoader::app_classpath_entries(), CHECK); - i = add_shared_classpaths(i, "module", ClassLoader::module_path_entries(), CHECK); - - for (int x = 0; x < num_non_existent_class_paths(); x++, i++) { - const char* path = _non_existent_class_paths->at(x); - shared_path(i)->init_as_non_existent(path, CHECK); - } - - assert(i == _shared_path_table.size(), "number of shared path entry mismatch"); -} - -int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) { - while (cpe != nullptr) { - bool is_jrt = (cpe == ClassLoader::get_jrt_entry()); - bool is_module_path = i >= ClassLoaderExt::app_module_paths_start_index(); - const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir")); - log_info(class, path)("add %s shared path (%s) %s", which, type, cpe->name()); - SharedClassPathEntry* ent = shared_path(i); - ent->init(is_jrt, is_module_path, cpe, CHECK_0); - if (cpe->is_jar_file()) { - update_jar_manifest(cpe, ent, CHECK_0); - } - if (is_jrt) { - cpe = ClassLoader::get_next_boot_classpath_entry(cpe); + AOTClassLocationConfig* config = header()->class_location_config(); + bool has_extra_module_paths; + if (!config->validate(header()->has_aot_linked_classes(), &has_extra_module_paths)) { + if (PrintSharedArchiveAndExit) { + MetaspaceShared::set_archive_loading_failed(); + return true; } else { - cpe = cpe->next(); - } - i++; - } - - return i; -} - -void FileMapInfo::check_nonempty_dir_in_shared_path_table() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - - bool has_nonempty_dir = false; - - int last = _shared_path_table.size() - 1; - if (last > ClassLoaderExt::max_used_path_index()) { - // no need to check any path beyond max_used_path_index - last = ClassLoaderExt::max_used_path_index(); - } - - for (int i = 0; i <= last; i++) { - SharedClassPathEntry *e = shared_path(i); - if (e->is_dir()) { - const char* path = e->name(); - if (!os::dir_is_empty(path)) { - log_error(cds)("Error: non-empty directory '%s'", path); - has_nonempty_dir = true; - } - } - } - - if (has_nonempty_dir) { - ClassLoader::exit_with_path_failure("Cannot have non-empty directory in paths", nullptr); - } -} - -void FileMapInfo::record_non_existent_class_path_entry(const char* path) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - log_info(class, path)("non-existent Class-Path entry %s", path); - if (_non_existent_class_paths == nullptr) { - _non_existent_class_paths = new (mtClass) GrowableArray(10, mtClass); - } - _non_existent_class_paths->append(os::strdup(path)); -} - -int FileMapInfo::num_non_existent_class_paths() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - if (_non_existent_class_paths != nullptr) { - return _non_existent_class_paths->length(); - } else { - return 0; - } -} - -int FileMapInfo::get_module_shared_path_index(Symbol* location) { - if (location->starts_with("jrt:", 4) && get_number_of_shared_paths() > 0) { - assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); - return 0; - } - - if (ClassLoaderExt::app_module_paths_start_index() >= get_number_of_shared_paths()) { - // The archive(s) were created without --module-path option - return -1; - } - - if (!location->starts_with("file:", 5)) { - return -1; - } - - // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table() - ResourceMark rm; - const char* file = ClassLoader::uri_to_path(location->as_C_string()); - for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { - SharedClassPathEntry* ent = shared_path(i); - if (!ent->is_non_existent()) { - assert(ent->in_named_module(), "must be"); - bool cond = strcmp(file, ent->name()) == 0; - log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, - location->as_C_string(), ent->name(), cond ? "same" : "different"); - if (cond) { - return i; - } - } - } - - return -1; -} - -class ManifestStream: public ResourceObj { - private: - u1* _buffer_start; // Buffer bottom - u1* _buffer_end; // Buffer top (one past last element) - u1* _current; // Current buffer position - - public: - // Constructor - ManifestStream(u1* buffer, int length) : _buffer_start(buffer), - _current(buffer) { - _buffer_end = buffer + length; - } - - static bool is_attr(u1* attr, const char* name) { - return strncmp((const char*)attr, name, strlen(name)) == 0; - } - - static char* copy_attr(u1* value, size_t len) { - char* buf = NEW_RESOURCE_ARRAY(char, len + 1); - strncpy(buf, (char*)value, len); - buf[len] = 0; - return buf; - } -}; - -void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) { - ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); - ResourceMark rm(THREAD); - jint manifest_size; - - assert(cpe->is_jar_file() && ent->is_jar(), "the shared class path entry is not a JAR file"); - char* manifest = ClassLoaderExt::read_manifest(THREAD, cpe, &manifest_size); - if (manifest != nullptr) { - ManifestStream* stream = new ManifestStream((u1*)manifest, - manifest_size); - // Copy the manifest into the shared archive - manifest = ClassLoaderExt::read_raw_manifest(THREAD, cpe, &manifest_size); - Array* buf = MetadataFactory::new_array(loader_data, - manifest_size, - CHECK); - char* p = (char*)(buf->data()); - memcpy(p, manifest, manifest_size); - ent->set_manifest(buf); - } -} - -char* FileMapInfo::skip_first_path_entry(const char* path) { - size_t path_sep_len = strlen(os::path_separator()); - char* p = strstr((char*)path, os::path_separator()); - if (p != nullptr) { - debug_only( { - size_t image_name_len = strlen(MODULES_IMAGE_NAME); - assert(strncmp(p - image_name_len, MODULES_IMAGE_NAME, image_name_len) == 0, - "first entry must be the modules image"); - } ); - p += path_sep_len; - } else { - debug_only( { - assert(ClassLoader::string_ends_with(path, MODULES_IMAGE_NAME), - "first entry must be the modules image"); - } ); - } - return p; -} - -int FileMapInfo::num_paths(const char* path) { - if (path == nullptr) { - return 0; - } - int npaths = 1; - char* p = (char*)path; - while (p != nullptr) { - char* prev = p; - p = strstr((char*)p, os::path_separator()); - if (p != nullptr) { - p++; - // don't count empty path - if ((p - prev) > 1) { - npaths++; - } - } - } - return npaths; -} - -// Returns true if a path within the paths exists and has non-zero size. -bool FileMapInfo::check_paths_existence(const char* paths) { - ClasspathStream cp_stream(paths); - bool exist = false; - struct stat st; - while (cp_stream.has_next()) { - const char* path = cp_stream.get_next(); - if (os::stat(path, &st) == 0 && st.st_size > 0) { - exist = true; - break; - } - } - return exist; -} - -GrowableArray* FileMapInfo::create_dumptime_app_classpath_array() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - GrowableArray* path_array = new GrowableArray(10); - ClassPathEntry* cpe = ClassLoader::app_classpath_entries(); - while (cpe != nullptr) { - path_array->append(cpe->name()); - cpe = cpe->next(); - } - return path_array; -} - -GrowableArray* FileMapInfo::create_path_array(const char* paths) { - GrowableArray* path_array = new GrowableArray(10); - JavaThread* current = JavaThread::current(); - ClasspathStream cp_stream(paths); - bool non_jar_in_cp = header()->has_non_jar_in_classpath(); - while (cp_stream.has_next()) { - const char* path = cp_stream.get_next(); - if (!non_jar_in_cp) { - struct stat st; - if (os::stat(path, &st) == 0) { - path_array->append(path); - } - } else { - const char* canonical_path = ClassLoader::get_canonical_path(path, current); - if (canonical_path != nullptr) { - char* error_msg = nullptr; - jzfile* zip = ClassLoader::open_zip_file(canonical_path, &error_msg, current); - if (zip != nullptr && error_msg == nullptr) { - path_array->append(path); - } - } - } - } - return path_array; -} - -bool FileMapInfo::classpath_failure(const char* msg, const char* name) { - ClassLoader::trace_class_path(msg, name); - if (PrintSharedArchiveAndExit) { - MetaspaceShared::set_archive_loading_failed(); - } - return false; -} - -unsigned int FileMapInfo::longest_common_app_classpath_prefix_len(int num_paths, - GrowableArray* rp_array) { - if (num_paths == 0) { - return 0; - } - unsigned int pos; - for (pos = 0; ; pos++) { - for (int i = 0; i < num_paths; i++) { - if (rp_array->at(i)[pos] != '\0' && rp_array->at(i)[pos] == rp_array->at(0)[pos]) { - continue; - } - // search backward for the pos before the file separator char - while (pos > 0) { - if (rp_array->at(0)[--pos] == *os::file_separator()) { - return pos + 1; - } - } - return 0; - } - } - return 0; -} - -bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, GrowableArray* rp_array, - unsigned int dumptime_prefix_len, unsigned int runtime_prefix_len) { - int i = 0; - int j = shared_path_start_idx; - while (i < num_paths) { - while (shared_path(j)->from_class_path_attr()) { - // shared_path(j) was expanded from the JAR file attribute "Class-Path:" - // during dump time. It's not included in the -classpath VM argument. - j++; - } - assert(strlen(shared_path(j)->name()) > (size_t)dumptime_prefix_len, "sanity"); - const char* dumptime_path = shared_path(j)->name() + dumptime_prefix_len; - assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity"); - const char* runtime_path = rp_array->at(i) + runtime_prefix_len; - if (!os::same_files(dumptime_path, runtime_path)) { return false; } - i++; - j++; - } - return true; -} - -bool FileMapInfo::validate_boot_class_paths() { - // - // - Archive contains boot classes only - relaxed boot path check: - // Extra path elements appended to the boot path at runtime are allowed. - // - // - Archive contains application or platform classes - strict boot path check: - // Validate the entire runtime boot path, which must be compatible - // with the dump time boot path. Appending boot path at runtime is not - // allowed. - // - - // The first entry in boot path is the modules_image (guaranteed by - // ClassLoader::setup_boot_search_path()). Skip the first entry. The - // path of the runtime modules_image may be different from the dump - // time path (e.g. the JDK image is copied to a different location - // after generating the shared archive), which is acceptable. For most - // common cases, the dump time boot path might contain modules_image only. - char* runtime_boot_path = Arguments::get_boot_class_path(); - char* rp = skip_first_path_entry(runtime_boot_path); - assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); - int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image - bool match = true; - - bool relaxed_check = !header()->has_platform_or_app_classes(); - if (dp_len == 0 && rp == nullptr) { - return true; // ok, both runtime and dump time boot paths have modules_images only - } else if (dp_len == 0 && rp != nullptr) { - if (relaxed_check) { - return true; // ok, relaxed check, runtime has extra boot append path entries - } else { - ResourceMark rm; - if (check_paths_existence(rp)) { - // If a path exists in the runtime boot paths, it is considered a mismatch - // since there's no boot path specified during dump time. - match = false; - } - } - } else if (dp_len > 0 && rp != nullptr) { - int num; - ResourceMark rm; - GrowableArray* rp_array = create_path_array(rp); - int rp_len = rp_array->length(); - if (rp_len >= dp_len) { - if (relaxed_check) { - // only check the leading entries in the runtime boot path, up to - // the length of the dump time boot path - num = dp_len; - } else { - // check the full runtime boot path, must match with dump time - num = rp_len; - } - match = check_paths(1, num, rp_array, 0, 0); - } else { - // create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths - // are the same initially, after the call to create_path_array(), the runtime boot classpath length could become - // shorter. We consider boot classpath mismatch in this case. - match = false; - } } - if (!match) { - // The paths are different - return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path); - } - return true; -} - -bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { - const char *appcp = Arguments::get_appclasspath(); - assert(appcp != nullptr, "null app classpath"); - int rp_len = num_paths(appcp); - bool match = false; - if (rp_len < shared_app_paths_len) { - return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp); - } - if (shared_app_paths_len != 0 && rp_len != 0) { - // Prefix is OK: E.g., dump with -cp foo.jar, but run with -cp foo.jar:bar.jar. - ResourceMark rm; - GrowableArray* rp_array = create_path_array(appcp); - if (rp_array->length() == 0) { - // None of the jar file specified in the runtime -cp exists. - return classpath_failure("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp); - } - if (rp_array->length() < shared_app_paths_len) { - // create_path_array() ignores non-existing paths. Although the dump time and runtime app classpath lengths - // are the same initially, after the call to create_path_array(), the runtime app classpath length could become - // shorter. We consider app classpath mismatch in this case. - return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp); - } - - // Handling of non-existent entries in the classpath: we eliminate all the non-existent - // entries from both the dump time classpath (ClassLoader::update_class_path_entry_list) - // and the runtime classpath (FileMapInfo::create_path_array), and check the remaining - // entries. E.g.: - // - // dump : -cp a.jar:NE1:NE2:b.jar -> a.jar:b.jar -> recorded in archive. - // run 1: -cp NE3:a.jar:NE4:b.jar -> a.jar:b.jar -> matched - // run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched - - int j = header()->app_class_paths_start_index(); - match = check_paths(j, shared_app_paths_len, rp_array, 0, 0); - if (!match) { - // To facilitate app deployment, we allow the JAR files to be moved *together* to - // a different location, as long as they are still stored under the same directory - // structure. E.g., the following is OK. - // java -Xshare:dump -cp /a/Foo.jar:/a/b/Bar.jar ... - // java -Xshare:auto -cp /x/y/Foo.jar:/x/y/b/Bar.jar ... - unsigned int dumptime_prefix_len = header()->common_app_classpath_prefix_size(); - unsigned int runtime_prefix_len = longest_common_app_classpath_prefix_len(shared_app_paths_len, rp_array); - if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) { - log_info(class, path)("LCP length for app classpath (dumptime: %u, runtime: %u)", - dumptime_prefix_len, runtime_prefix_len); - match = check_paths(j, shared_app_paths_len, rp_array, - dumptime_prefix_len, runtime_prefix_len); - } - if (!match) { - return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp); - } - } - } - return true; -} - -void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { - LogTarget(Info, class, path) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print("%s", msg); - const char* prefix = ""; - for (int i = start_idx; i < end_idx; i++) { - ls.print("%s%s", prefix, shared_path(i)->name()); - prefix = os::path_separator(); - } - ls.cr(); - } -} - -void FileMapInfo::extract_module_paths(const char* runtime_path, GrowableArray* module_paths) { - GrowableArray* path_array = create_path_array(runtime_path); - int num_paths = path_array->length(); - for (int i = 0; i < num_paths; i++) { - const char* name = path_array->at(i); - ClassLoaderExt::extract_jar_files_from_path(name, module_paths); - } - // module paths are stored in sorted order in the CDS archive. - module_paths->sort(ClassLoaderExt::compare_module_names); -} - -bool FileMapInfo::check_module_paths() { - const char* runtime_path = Arguments::get_property("jdk.module.path"); - int archived_num_module_paths = header()->num_module_paths(); - if (runtime_path == nullptr && archived_num_module_paths == 0) { - return true; - } - if ((runtime_path == nullptr && archived_num_module_paths > 0) || - (runtime_path != nullptr && archived_num_module_paths == 0)) { - return false; - } - ResourceMark rm; - GrowableArray* module_paths = new GrowableArray(3); - extract_module_paths(runtime_path, module_paths); - int num_paths = module_paths->length(); - if (num_paths != archived_num_module_paths) { - return false; - } - return check_paths(header()->app_module_paths_start_index(), num_paths, module_paths, 0, 0); -} - -bool FileMapInfo::validate_shared_path_table() { - assert(CDSConfig::is_using_archive(), "runtime only"); - - _validating_shared_path_table = true; - - // Load the shared path table info from the archive header - _shared_path_table = header()->shared_path_table(); - - bool matched_module_paths = true; - if (CDSConfig::is_dumping_dynamic_archive() || header()->has_full_module_graph()) { - matched_module_paths = check_module_paths(); - } - if (header()->has_full_module_graph() && !matched_module_paths) { + if (header()->has_full_module_graph() && has_extra_module_paths) { CDSConfig::stop_using_optimized_module_handling(); - log_info(cds)("optimized module handling: disabled because of mismatched module paths"); + log_info(cds)("optimized module handling: disabled because extra module path(s) are specified"); } if (CDSConfig::is_dumping_dynamic_archive()) { @@ -998,17 +323,13 @@ bool FileMapInfo::validate_shared_path_table() { // or a simple base archive. // If the base layer archive contains additional path component besides // the runtime image and the -cp, dynamic dumping is disabled. - // - // When dynamic archiving is enabled, the _shared_path_table is overwritten - // to include the application path and stored in the top layer archive. - assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); - if (header()->app_class_paths_start_index() > 1) { + if (config->num_boot_classpaths() > 0) { CDSConfig::disable_dumping_dynamic_archive(); log_warning(cds)( "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } - if (header()->num_module_paths() > 0) { - if (!matched_module_paths) { + if (config->num_module_paths() > 0) { + if (has_extra_module_paths) { CDSConfig::disable_dumping_dynamic_archive(); log_warning(cds)( "Dynamic archiving is disabled because base layer archive has a different module path"); @@ -1016,68 +337,11 @@ bool FileMapInfo::validate_shared_path_table() { } } - log_paths("Expecting BOOT path=", 0, header()->app_class_paths_start_index()); - log_paths("Expecting -Djava.class.path=", header()->app_class_paths_start_index(), header()->app_module_paths_start_index()); - - int module_paths_start_index = header()->app_module_paths_start_index(); - int shared_app_paths_len = 0; - - // validate the path entries up to the _max_used_path_index - for (int i=0; i < header()->max_used_path_index() + 1; i++) { - if (i < module_paths_start_index) { - if (shared_path(i)->validate()) { - // Only count the app class paths not from the "Class-path" attribute of a jar manifest. - if (!shared_path(i)->from_class_path_attr() && i >= header()->app_class_paths_start_index()) { - shared_app_paths_len++; - } - log_info(class, path)("ok"); - } else { - if (_dynamic_archive_info != nullptr && _dynamic_archive_info->_is_static) { - assert(!CDSConfig::is_using_archive(), "UseSharedSpaces should be disabled"); - } - return false; - } - } else if (i >= module_paths_start_index) { - if (shared_path(i)->validate(false /* not a class path entry */)) { - log_info(class, path)("ok"); - } else { - if (_dynamic_archive_info != nullptr && _dynamic_archive_info->_is_static) { - assert(!CDSConfig::is_using_archive(), "UseSharedSpaces should be disabled"); - } - return false; - } - } - } - - if (header()->max_used_path_index() == 0) { - // default archive only contains the module image in the bootclasspath - assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); - } else { - if (!validate_boot_class_paths() || !validate_app_class_paths(shared_app_paths_len)) { - const char* mismatch_msg = "shared class paths mismatch"; - const char* hint_msg = log_is_enabled(Info, class, path) ? - "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; - if (RequireSharedSpaces) { - log_error(cds)("%s%s", mismatch_msg, hint_msg); - MetaspaceShared::unrecoverable_loading_error(); - } else { - log_warning(cds)("%s%s", mismatch_msg, hint_msg); - } - return false; - } - } - - if (!validate_non_existent_class_paths()) { - return false; - } - - _validating_shared_path_table = false; - #if INCLUDE_JVMTI if (_classpath_entries_for_jvmti != nullptr) { os::free(_classpath_entries_for_jvmti); } - size_t sz = sizeof(ClassPathEntry*) * get_number_of_shared_paths(); + size_t sz = sizeof(ClassPathEntry*) * AOTClassLocationConfig::runtime()->length(); _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass); memset((void*)_classpath_entries_for_jvmti, 0, sz); #endif @@ -1085,34 +349,6 @@ bool FileMapInfo::validate_shared_path_table() { return true; } -bool FileMapInfo::validate_non_existent_class_paths() { - // All of the recorded non-existent paths came from the Class-Path: attribute from the JAR - // files on the app classpath. If any of these are found to exist during runtime, - // it will change how classes are loading for the app loader. For safety, disable - // loading of archived platform/app classes (currently there's no way to disable just the - // app classes). - - assert(CDSConfig::is_using_archive(), "runtime only"); - for (int i = header()->app_module_paths_start_index() + header()->num_module_paths(); - i < get_number_of_shared_paths(); - i++) { - SharedClassPathEntry* ent = shared_path(i); - if (!ent->check_non_existent()) { - if (header()->has_aot_linked_classes()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used because the " - "file %s exists", ent->name()); - return false; - } else { - log_warning(cds)("Archived non-system classes are disabled because the " - "file %s exists", ent->name()); - header()->set_has_platform_or_app_classes(false); - } - } - } - - return true; -} - // A utility class for reading/validating the GenericCDSFileMapHeader portion of // a CDS archive's header. The file header of all CDS archives with versions from // CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION (12) are guaranteed to always start @@ -1365,19 +601,12 @@ bool FileMapInfo::init_from_file(int fd) { return false; } - int common_path_size = header()->common_app_classpath_prefix_size(); - if (common_path_size < 0) { - log_warning(cds)("common app classpath prefix len < 0"); - return false; - } - unsigned int base_offset = header()->base_archive_name_offset(); unsigned int name_size = header()->base_archive_name_size(); unsigned int header_size = header()->header_size(); if (base_offset != 0 && name_size != 0) { if (header_size != base_offset + name_size) { log_info(cds)("_header_size: " UINT32_FORMAT, header_size); - log_info(cds)("common_app_classpath_size: " UINT32_FORMAT, header()->common_app_classpath_prefix_size()); log_info(cds)("base_archive_name_size: " UINT32_FORMAT, header()->base_archive_name_size()); log_info(cds)("base_archive_name_offset: " UINT32_FORMAT, header()->base_archive_name_offset()); log_warning(cds)("The shared archive file has an incorrect header size."); @@ -2457,10 +1686,7 @@ void FileMapInfo::assert_mark(bool check) { FileMapInfo* FileMapInfo::_current_info = nullptr; FileMapInfo* FileMapInfo::_dynamic_archive_info = nullptr; bool FileMapInfo::_heap_pointers_need_patching = false; -SharedPathTable FileMapInfo::_shared_path_table; -bool FileMapInfo::_validating_shared_path_table = false; bool FileMapInfo::_memory_mapping_failed = false; -GrowableArray* FileMapInfo::_non_existent_class_paths = nullptr; // Open the shared archive file, read and validate the header // information (version, boot classpath, etc.). If initialization @@ -2469,7 +1695,7 @@ GrowableArray* FileMapInfo::_non_existent_class_paths = nullptr; // Validation of the archive is done in two steps: // // [1] validate_header() - done here. -// [2] validate_shared_path_table - this is done later, because the table is in the RW +// [2] validate_shared_path_table - this is done later, because the table is in the RO // region of the archive, which is not mapped yet. bool FileMapInfo::initialize() { assert(CDSConfig::is_using_archive(), "UseSharedSpaces expected."); @@ -2690,17 +1916,15 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) { } ClassPathEntry* ent = _classpath_entries_for_jvmti[i]; if (ent == nullptr) { - SharedClassPathEntry* scpe = shared_path(i); - assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes - - const char* path = scpe->name(); + const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(i); + const char* path = cl->path(); struct stat st; if (os::stat(path, &st) != 0) { char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); jio_snprintf(msg, strlen(path) + 127, "error in finding JAR file %s", path); THROW_MSG_(vmSymbols::java_io_IOException(), msg, nullptr); } else { - ent = ClassLoader::create_class_path_entry(THREAD, path, &st, false, false, scpe->is_multi_release()); + ent = ClassLoader::create_class_path_entry(THREAD, path, &st); if (ent == nullptr) { char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); @@ -2724,7 +1948,7 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) { ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS) { int path_index = ik->shared_classpath_index(); assert(path_index >= 0, "should be called for shared built-in classes only"); - assert(path_index < (int)get_number_of_shared_paths(), "sanity"); + assert(path_index < AOTClassLocationConfig::runtime()->length(), "sanity"); ClassPathEntry* cpe = get_classpath_entry_for_jvmti(path_index, CHECK_NULL); assert(cpe != nullptr, "must be"); @@ -2734,8 +1958,12 @@ ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle cl const char* const file_name = ClassLoader::file_name_for_class_name(class_name, name->utf8_length()); ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); + const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(path_index); ClassFileStream* cfs; - if (class_loader() != nullptr && !cpe->is_modules_image() && cpe->is_multi_release_jar()) { + if (class_loader() != nullptr && cl->is_multi_release_jar()) { + // This class was loaded from a multi-release JAR file during dump time. The + // process for finding its classfile is complex. Let's defer to the Java code + // in java.lang.ClassLoader. cfs = get_stream_from_class_loader(class_loader, cpe, file_name, CHECK_NULL); } else { cfs = cpe->open_stream_for_loader(THREAD, file_name, loader_data); diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index ae11c6c81cc..22f70635e17 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -42,6 +42,7 @@ static const int JVM_IDENT_MAX = 256; +class AOTClassLocationConfig; class ArchiveHeapInfo; class BitMapView; class CHeapBitMap; @@ -51,89 +52,6 @@ class ClassPathEntry; class outputStream; class ReservedSpace; -class SharedClassPathEntry : public MetaspaceObj { - enum { - modules_image_entry, - jar_entry, - dir_entry, - non_existent_entry, - unknown_entry - }; - - void set_name(const char* name, TRAPS); - - u1 _type; - bool _is_module_path; - bool _from_class_path_attr; - bool _is_multi_release; - time_t _timestamp; // jar timestamp, 0 if is directory, modules image or other - int64_t _filesize; // jar/jimage file size, -1 if is directory, -2 if other - Array* _name; - Array* _manifest; - -public: - SharedClassPathEntry() : _type(0), _is_module_path(false), - _from_class_path_attr(false), _is_multi_release(false), _timestamp(0), - _filesize(0), _name(nullptr), _manifest(nullptr) {} - static int size() { - static_assert(is_aligned(sizeof(SharedClassPathEntry), wordSize), "must be"); - return (int)(sizeof(SharedClassPathEntry) / wordSize); - } - void init(bool is_modules_image, bool is_module_path, ClassPathEntry* cpe, TRAPS); - void init_as_non_existent(const char* path, TRAPS); - void metaspace_pointers_do(MetaspaceClosure* it); - MetaspaceObj::Type type() const { return SharedClassPathEntryType; } - bool validate(bool is_class_path = true) const; - - // The _timestamp only gets set for jar files. - bool has_timestamp() const { - return _timestamp != 0; - } - bool is_dir() const { return _type == dir_entry; } - bool is_modules_image() const { return _type == modules_image_entry; } - bool is_jar() const { return _type == jar_entry; } - bool is_non_existent() const { return _type == non_existent_entry; } - bool from_class_path_attr() { return _from_class_path_attr; } - bool is_multi_release() { return _is_multi_release; } - time_t timestamp() const { return _timestamp; } - const char* name() const; - const char* manifest() const { - return (_manifest == nullptr) ? nullptr : (const char*)_manifest->data(); - } - int manifest_size() const { - return (_manifest == nullptr) ? 0 : _manifest->length(); - } - void set_manifest(Array* manifest) { - _manifest = manifest; - } - bool check_non_existent() const; - void copy_from(SharedClassPathEntry* ent, ClassLoaderData* loader_data, TRAPS); - bool in_named_module() { - return is_modules_image() || // modules image doesn't contain unnamed modules - _is_module_path; // module path doesn't contain unnamed modules - } -}; - -class SharedPathTable { - Array* _entries; -public: - SharedPathTable() : _entries(nullptr) {} - SharedPathTable(Array* entries) : _entries(entries) {} - - void dumptime_init(ClassLoaderData* loader_data, TRAPS); - void metaspace_pointers_do(MetaspaceClosure* it); - - int size() { - return _entries == nullptr ? 0 : _entries->length(); - } - SharedClassPathEntry* path_at(int index) { - return _entries->at(index); - } - Array* table() {return _entries;} - void set_table(Array* table) {_entries = table;} -}; - - class FileMapRegion: private CDSFileMapRegion { public: void assert_is_heap_region() const { @@ -203,30 +121,17 @@ private: size_t _cloned_vtables_offset; // The address of the first cloned vtable size_t _early_serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() - bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath - unsigned int _common_app_classpath_prefix_size; // size of the common prefix of app class paths - // 0 if no common prefix exists // The following fields are all sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's // invoked with. char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump - // The following is a table of all the boot/app/module path entries that were used - // during dumping. At run time, we validate these entries according to their - // SharedClassPathEntry::_type. See: - // check_nonempty_dir_in_shared_path_table() - // validate_shared_path_table() - // validate_non_existent_class_paths() - size_t _shared_path_table_offset; + size_t _class_location_config_offset; - jshort _app_class_paths_start_index; // Index of first app classpath entry - jshort _app_module_paths_start_index; // Index of first module path entry - jshort _max_used_path_index; // max path index referenced during CDS dump - int _num_module_paths; // number of module path entries bool _verify_local; // BytecodeVerificationLocal setting bool _verify_remote; // BytecodeVerificationRemote setting - bool _has_platform_or_app_classes; // Archive contains app classes + bool _has_platform_or_app_classes; // Archive contains app or platform classes char* _requested_base_address; // Archive relocation is not necessary if we map with this base address. char* _mapped_base_address; // Actual base address where archive is mapped. @@ -241,10 +146,14 @@ private: size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap. size_t _rw_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the rw region size_t _ro_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the ro region - char* from_mapped_offset(size_t offset) const { - return mapped_base_address() + offset; + template T from_mapped_offset(size_t offset) const { + return (T)(mapped_base_address() + offset); } void set_as_offset(char* p, size_t *offset); + template void set_as_offset(T p, size_t *offset) { + set_as_offset((char*)p, offset); + } + public: // Accessors -- fields declared in GenericCDSFileMapHeader unsigned int magic() const { return _generic_header._magic; } @@ -253,7 +162,6 @@ public: unsigned int header_size() const { return _generic_header._header_size; } unsigned int base_archive_name_offset() const { return _generic_header._base_archive_name_offset; } unsigned int base_archive_name_size() const { return _generic_header._base_archive_name_size; } - unsigned int common_app_classpath_prefix_size() const { return _common_app_classpath_prefix_size; } void set_magic(unsigned int m) { _generic_header._magic = m; } void set_crc(int crc_value) { _generic_header._crc = crc_value; } @@ -261,7 +169,6 @@ public: void set_header_size(unsigned int s) { _generic_header._header_size = s; } void set_base_archive_name_offset(unsigned int s) { _generic_header._base_archive_name_offset = s; } void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; } - void set_common_app_classpath_prefix_size(unsigned int s) { _common_app_classpath_prefix_size = s; } bool is_static() const { return magic() == CDS_ARCHIVE_MAGIC; } size_t core_region_alignment() const { return _core_region_alignment; } @@ -272,14 +179,13 @@ public: bool compact_headers() const { return _compact_headers; } uintx max_heap_size() const { return _max_heap_size; } CompressedOops::Mode narrow_oop_mode() const { return _narrow_oop_mode; } - char* cloned_vtables() const { return from_mapped_offset(_cloned_vtables_offset); } - char* early_serialized_data() const { return from_mapped_offset(_early_serialized_data_offset); } - char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); } + char* cloned_vtables() const { return from_mapped_offset(_cloned_vtables_offset); } + char* early_serialized_data() const { return from_mapped_offset(_early_serialized_data_offset); } + char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); } const char* jvm_ident() const { return _jvm_ident; } char* requested_base_address() const { return _requested_base_address; } char* mapped_base_address() const { return _mapped_base_address; } bool has_platform_or_app_classes() const { return _has_platform_or_app_classes; } - bool has_non_jar_in_classpath() const { return _has_non_jar_in_classpath; } bool has_aot_linked_classes() const { return _has_aot_linked_classes; } bool compressed_oops() const { return _compressed_oops; } bool compressed_class_pointers() const { return _compressed_class_ptrs; } @@ -291,11 +197,6 @@ public: size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; } size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; } size_t ro_ptrmap_start_pos() const { return _ro_ptrmap_start_pos; } - // FIXME: These should really return int - jshort max_used_path_index() const { return _max_used_path_index; } - jshort app_module_paths_start_index() const { return _app_module_paths_start_index; } - jshort app_class_paths_start_index() const { return _app_class_paths_start_index; } - int num_module_paths() const { return _num_module_paths; } void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; } void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); } @@ -309,8 +210,12 @@ public: void set_ro_ptrmap_start_pos(size_t n) { _ro_ptrmap_start_pos = n; } void copy_base_archive_name(const char* name); - void set_shared_path_table(SharedPathTable table) { - set_as_offset((char*)table.table(), &_shared_path_table_offset); + void set_class_location_config(AOTClassLocationConfig* table) { + set_as_offset(table, &_class_location_config_offset); + } + + AOTClassLocationConfig* class_location_config() { + return from_mapped_offset(_class_location_config_offset); } void set_requested_base(char* b) { @@ -318,11 +223,6 @@ public: _mapped_base_address = nullptr; } - SharedPathTable shared_path_table() const { - return SharedPathTable((Array*) - from_mapped_offset(_shared_path_table_offset)); - } - bool validate(); int compute_crc(); @@ -332,8 +232,7 @@ public: } void populate(FileMapInfo *info, size_t core_region_alignment, size_t header_size, - size_t base_archive_name_size, size_t base_archive_name_offset, - size_t common_app_classpath_size); + size_t base_archive_name_size, size_t base_archive_name_offset); static bool is_valid_region(int region) { return (0 <= region && region < NUM_CDS_REGIONS); } @@ -358,9 +257,6 @@ private: const char* _base_archive_name; FileMapHeader* _header; - static SharedPathTable _shared_path_table; - static bool _validating_shared_path_table; - // FileMapHeader describes the shared space data in the file to be // mapped. This structure gets written to a file. It is not a class, so // that the compilers don't add any compiler-private data to it. @@ -369,20 +265,12 @@ private: static FileMapInfo* _dynamic_archive_info; static bool _heap_pointers_need_patching; static bool _memory_mapping_failed; - static GrowableArray* _non_existent_class_paths; public: FileMapHeader *header() const { return _header; } static bool get_base_archive_name_from_header(const char* archive_name, char** base_archive_name); - static SharedPathTable shared_path_table() { - return _shared_path_table; - } - bool init_from_file(int fd); - static void metaspace_pointers_do(MetaspaceClosure* it) { - _shared_path_table.metaspace_pointers_do(it); - } void log_paths(const char* msg, int start_idx, int end_idx); @@ -408,8 +296,6 @@ public: size_t heap_ptrmap_start_pos() const { return header()->heap_ptrmap_start_pos(); } CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); } - jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); } - jshort app_class_paths_start_index() const { return header()->app_class_paths_start_index(); } char* cloned_vtables() const { return header()->cloned_vtables(); } void set_cloned_vtables(char* p) const { header()->set_cloned_vtables(p); } @@ -494,19 +380,8 @@ public: NOT_CDS(return false;) } - static void allocate_shared_path_table(TRAPS); - static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS); - static void check_nonempty_dir_in_shared_path_table(); - bool check_module_paths(); - bool validate_shared_path_table(); - bool validate_non_existent_class_paths(); + bool validate_class_location(); bool validate_aot_class_linking(); - static void set_shared_path_table(FileMapInfo* info) { - _shared_path_table = info->header()->shared_path_table(); - } - static void update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS); - static int num_non_existent_class_paths(); - static void record_non_existent_class_path_entry(const char* path); #if INCLUDE_JVMTI // Caller needs a ResourceMark because parts of the returned cfs are resource-allocated. @@ -517,21 +392,6 @@ public: TRAPS); #endif - static SharedClassPathEntry* shared_path(int index) { - return _shared_path_table.path_at(index); - } - - static const char* shared_path_name(int index) { - assert(index >= 0, "Sanity"); - return shared_path(index)->name(); - } - - static int get_number_of_shared_paths() { - return _shared_path_table.size(); - } - - static int get_module_shared_path_index(Symbol* location) NOT_CDS_RETURN_(-1); - // The offset of the first core region in the archive, relative to SharedBaseAddress size_t mapping_base_offset() const { return first_core_region()->mapping_offset(); } // The offset of the (exclusive) end of the last core region in this archive, relative to SharedBaseAddress @@ -564,22 +424,6 @@ public: private: void seek_to_position(size_t pos); - char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(nullptr); - int num_paths(const char* path) NOT_CDS_RETURN_(0); - bool check_paths_existence(const char* paths) NOT_CDS_RETURN_(false); - GrowableArray* create_dumptime_app_classpath_array() NOT_CDS_RETURN_(nullptr); - GrowableArray* create_path_array(const char* path) NOT_CDS_RETURN_(nullptr); - bool classpath_failure(const char* msg, const char* name) NOT_CDS_RETURN_(false); - unsigned int longest_common_app_classpath_prefix_len(int num_paths, - GrowableArray* rp_array) - NOT_CDS_RETURN_(0); - bool check_paths(int shared_path_start_idx, int num_paths, - GrowableArray* rp_array, - unsigned int dumptime_prefix_len, - unsigned int runtime_prefix_len) NOT_CDS_RETURN_(false); - void extract_module_paths(const char* runtime_path, GrowableArray* module_paths); - bool validate_boot_class_paths() NOT_CDS_RETURN_(false); - bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false); bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false); void dealloc_heap_region() NOT_CDS_JAVA_HEAP_RETURN; bool can_use_heap_region(); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index b619bd81670..5aa456ea438 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -24,6 +24,7 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassInitializer.hpp" +#include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/archiveHeapWriter.hpp" @@ -1171,11 +1172,12 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") && !CDSConfig::is_using_optimized_module_handling() && // archive was created with --module-path - ClassLoaderExt::num_module_paths() > 0) { + AOTClassLocationConfig::runtime()->num_module_paths() > 0) { // ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path. // Thus, it might contain references to modules that do not exist at runtime. We cannot use it. log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d", - BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), ClassLoaderExt::num_module_paths()); + BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), + AOTClassLocationConfig::runtime()->num_module_paths()); return; } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index ba687bea8ba..b95d524cb1d 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -24,6 +24,7 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassLinker.hpp" +#include "cds/aotClassLocation.hpp" #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/archiveBuilder.hpp" @@ -330,20 +331,9 @@ void MetaspaceShared::initialize_for_static_dump() { // Called by universe_post_init() void MetaspaceShared::post_initialize(TRAPS) { if (CDSConfig::is_using_archive()) { - int size = FileMapInfo::get_number_of_shared_paths(); + int size = AOTClassLocationConfig::runtime()->length(); if (size > 0) { CDSProtectionDomain::allocate_shared_data_arrays(size, CHECK); - if (!CDSConfig::is_dumping_dynamic_archive()) { - FileMapInfo* info; - if (FileMapInfo::dynamic_info() == nullptr) { - info = FileMapInfo::current_info(); - } else { - info = FileMapInfo::dynamic_info(); - } - ClassLoaderExt::init_paths_start_index(info->app_class_paths_start_index()); - ClassLoaderExt::init_app_module_paths_start_index(info->app_module_paths_start_index()); - ClassLoaderExt::init_num_module_paths(info->header()->num_module_paths()); - } } } } @@ -558,7 +548,7 @@ private: SymbolTable::write_to_archive(symbols); } char* dump_early_read_only_tables(); - char* dump_read_only_tables(); + char* dump_read_only_tables(AOTClassLocationConfig*& cl_config); public: @@ -579,7 +569,6 @@ public: StaticArchiveBuilder() : ArchiveBuilder() {} virtual void iterate_roots(MetaspaceClosure* it) { - FileMapInfo::metaspace_pointers_do(it); AOTArtifactFinder::all_cached_classes_do(it); SystemDictionaryShared::dumptime_classes_do(it); Universe::metaspace_pointers_do(it); @@ -614,10 +603,11 @@ char* VM_PopulateDumpSharedSpace::dump_early_read_only_tables() { return start; } -char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { +char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& cl_config) { ArchiveBuilder::OtherROAllocMark mark; SystemDictionaryShared::write_to_archive(); + cl_config = AOTClassLocationConfig::dumptime()->write_to_archive(); AOTClassLinker::write_to_archive(); MetaspaceShared::write_method_handle_intrinsics(); @@ -645,7 +635,7 @@ void VM_PopulateDumpSharedSpace::doit() { SystemDictionary::get_all_method_handle_intrinsics(_pending_method_handle_intrinsics); } - FileMapInfo::check_nonempty_dir_in_shared_path_table(); + AOTClassLocationConfig::dumptime_check_nonempty_dirs(); NOT_PRODUCT(SystemDictionary::verify();) @@ -679,7 +669,8 @@ void VM_PopulateDumpSharedSpace::doit() { dump_shared_symbol_table(_builder.symbols()); char* early_serialized_data = dump_early_read_only_tables(); - char* serialized_data = dump_read_only_tables(); + AOTClassLocationConfig* cl_config; + char* serialized_data = dump_read_only_tables(cl_config); SystemDictionaryShared::adjust_lambda_proxy_class_dictionary(); @@ -695,6 +686,7 @@ void VM_PopulateDumpSharedSpace::doit() { _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()); + _map_info->header()->set_class_location_config(cl_config); } class CollectCLDClosure : public CLDClosure { @@ -791,7 +783,6 @@ void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { void MetaspaceShared::prepare_for_dumping() { assert(CDSConfig::is_dumping_archive(), "sanity"); CDSConfig::check_unsupported_dumping_module_options(); - ClassLoader::initialize_shared_path(JavaThread::current()); } // Preload classes from a list, populate the shared spaces and dump to a @@ -946,6 +937,7 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS HeapShared::init_for_dumping(CHECK); ArchiveHeapWriter::init(); if (CDSConfig::is_dumping_full_module_graph()) { + ClassLoaderDataShared::ensure_module_entry_tables_exist(); HeapShared::reset_archived_object_states(CHECK); } @@ -1134,11 +1126,8 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { _relocation_delta = static_mapinfo->relocation_delta(); _requested_base_address = static_mapinfo->requested_base_address(); if (dynamic_mapped) { - FileMapInfo::set_shared_path_table(dynamic_mapinfo); // turn AutoCreateSharedArchive off if successfully mapped AutoCreateSharedArchive = false; - } else { - FileMapInfo::set_shared_path_table(static_mapinfo); } } else { set_shared_metaspace_range(nullptr, nullptr, nullptr); @@ -1641,7 +1630,7 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped return result; } - if (!mapinfo->validate_shared_path_table()) { + if (!mapinfo->validate_class_location()) { unmap_archive(mapinfo); return MAP_ARCHIVE_OTHER_FAILURE; } diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index 173713e341a..2e985b72310 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/cdsConfig.hpp" #include "cds/unregisteredClasses.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.inline.hpp" diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index fa003756685..3ca1ec237e8 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -22,9 +22,9 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" -#include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.inline.hpp" @@ -158,12 +158,6 @@ ClassPathEntry* ClassLoader::_jrt_entry = nullptr; ClassPathEntry* volatile ClassLoader::_first_append_entry_list = nullptr; ClassPathEntry* volatile ClassLoader::_last_append_entry = nullptr; -#if INCLUDE_CDS -ClassPathEntry* ClassLoader::_app_classpath_entries = nullptr; -ClassPathEntry* ClassLoader::_last_app_classpath_entry = nullptr; -ClassPathEntry* ClassLoader::_module_path_entries = nullptr; -ClassPathEntry* ClassLoader::_last_module_path_entry = nullptr; -#endif // helper routines #if INCLUDE_CDS @@ -301,12 +295,9 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* return nullptr; } -ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name, - bool is_boot_append, bool from_class_path_attr, bool multi_release) : ClassPathEntry() { +ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() { _zip = zip; _zip_name = copy_path(zip_name); - _from_class_path_attr = from_class_path_attr; - _multi_release = multi_release; } ClassPathZipEntry::~ClassPathZipEntry() { @@ -463,14 +454,6 @@ bool ClassPathImageEntry::is_modules_image() const { return true; } -#if INCLUDE_CDS -void ClassLoader::exit_with_path_failure(const char* error, const char* message) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure"); - vm_exit_during_cds_dumping(error, message); -} -#endif - ModuleClassPathList::ModuleClassPathList(Symbol* module_name) { _module_name = module_name; _module_first_entry = nullptr; @@ -533,57 +516,6 @@ void ClassLoader::setup_bootstrap_search_path(JavaThread* current) { setup_bootstrap_search_path_impl(current, bootcp); } -#if INCLUDE_CDS -void ClassLoader::setup_app_search_path(JavaThread* current, const char *class_path) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - - ResourceMark rm(current); - ClasspathStream cp_stream(class_path); - - while (cp_stream.has_next()) { - const char* path = cp_stream.get_next(); - update_class_path_entry_list(current, path, /* check_for_duplicates */ true, - /* is_boot_append */ false, /* from_class_path_attr */ false); - } -} - -void ClassLoader::add_to_module_path_entries(const char* path, - ClassPathEntry* entry) { - assert(entry != nullptr, "ClassPathEntry should not be nullptr"); - assert(CDSConfig::is_dumping_archive(), "sanity"); - - // The entry does not exist, add to the list - if (_module_path_entries == nullptr) { - assert(_last_module_path_entry == nullptr, "Sanity"); - _module_path_entries = _last_module_path_entry = entry; - } else { - _last_module_path_entry->set_next(entry); - _last_module_path_entry = entry; - } -} - -// Add a module path to the _module_path_entries list. -void ClassLoader::setup_module_search_path(JavaThread* current, const char* path) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - struct stat st; - if (os::stat(path, &st) != 0) { - tty->print_cr("os::stat error %d (%s). CDS dump aborted (path was \"%s\").", - errno, os::errno_name(errno), path); - vm_exit_during_initialization(); - } - // File or directory found - ClassPathEntry* new_entry = nullptr; - new_entry = create_class_path_entry(current, path, &st, - false /*is_boot_append */, false /* from_class_path_attr */); - if (new_entry != nullptr) { - // ClassLoaderExt::process_module_table() filters out non-jar entries before calling this function. - assert(new_entry->is_jar_file(), "module path entry %s is not a jar file", new_entry->name()); - add_to_module_path_entries(path, new_entry); - } -} - -#endif // INCLUDE_CDS - void ClassLoader::close_jrt_image() { // Not applicable for exploded builds if (!ClassLoader::has_jrt_entry()) return; @@ -616,7 +548,7 @@ void ClassLoader::setup_patch_mod_entries() { struct stat st; if (os::stat(path, &st) == 0) { // File or directory found - ClassPathEntry* new_entry = create_class_path_entry(current, path, &st, false, false); + ClassPathEntry* new_entry = create_class_path_entry(current, path, &st); // If the path specification is valid, enter it into this module's list if (new_entry != nullptr) { module_cpl->add_to_list(new_entry); @@ -690,8 +622,7 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch } else { // Every entry on the boot class path after the initial base piece, // which is set by os::set_boot_path(), is considered an appended entry. - update_class_path_entry_list(current, path, /* check_for_duplicates */ false, - /* is_boot_append */ true, /* from_class_path_attr */ false); + update_class_path_entry_list(current, path); } } } @@ -722,7 +653,7 @@ void ClassLoader::add_to_exploded_build_list(JavaThread* current, Symbol* module struct stat st; if (os::stat(path, &st) == 0) { // Directory found - ClassPathEntry* new_entry = create_class_path_entry(current, path, &st, false, false); + ClassPathEntry* new_entry = create_class_path_entry(current, path, &st); // If the path specification is valid, enter it into this module's list. // There is no need to check for duplicate modules in the exploded entry list, @@ -748,10 +679,7 @@ jzfile* ClassLoader::open_zip_file(const char* canonical_path, char** error_msg, } ClassPathEntry* ClassLoader::create_class_path_entry(JavaThread* current, - const char *path, const struct stat* st, - bool is_boot_append, - bool from_class_path_attr, - bool is_multi_release) { + const char *path, const struct stat* st) { ClassPathEntry* new_entry = nullptr; if ((st->st_mode & S_IFMT) == S_IFREG) { ResourceMark rm(current); @@ -764,11 +692,8 @@ ClassPathEntry* ClassLoader::create_class_path_entry(JavaThread* current, char* error_msg = nullptr; jzfile* zip = open_zip_file(canonical_path, &error_msg, current); if (zip != nullptr && error_msg == nullptr) { - new_entry = new ClassPathZipEntry(zip, path, is_boot_append, from_class_path_attr, is_multi_release); + new_entry = new ClassPathZipEntry(zip, path); } else { -#if INCLUDE_CDS - ClassLoaderExt::set_has_non_jar_in_classpath(); -#endif return nullptr; } log_info(class, path)("opened: %s", path); @@ -784,7 +709,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(JavaThread* current, // Create a class path zip entry for a given path (return null if not found // or zip/JAR file cannot be opened) -ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path, bool is_boot_append) { +ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { // check for a regular file struct stat st; if (os::stat(path, &st) == 0) { @@ -797,7 +722,7 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path, bo jzfile* zip = open_zip_file(canonical_path, &error_msg, thread); if (zip != nullptr && error_msg == nullptr) { // create using canonical path - return new ClassPathZipEntry(zip, canonical_path, is_boot_append, false, false); + return new ClassPathZipEntry(zip, canonical_path); } } } @@ -820,70 +745,20 @@ void ClassLoader::add_to_boot_append_entries(ClassPathEntry *new_entry) { } } -// Record the path entries specified in -cp during dump time. The recorded -// information will be used at runtime for loading the archived app classes. -// -// Note that at dump time, ClassLoader::_app_classpath_entries are NOT used for -// loading app classes. Instead, the app class are loaded by the -// jdk/internal/loader/ClassLoaders$AppClassLoader instance. -bool ClassLoader::add_to_app_classpath_entries(JavaThread* current, - ClassPathEntry* entry, - bool check_for_duplicates) { -#if INCLUDE_CDS - assert(entry != nullptr, "ClassPathEntry should not be nullptr"); - ClassPathEntry* e = _app_classpath_entries; - if (check_for_duplicates) { - while (e != nullptr) { - if (strcmp(e->name(), entry->name()) == 0 && - e->from_class_path_attr() == entry->from_class_path_attr()) { - // entry already exists - return false; - } - e = e->next(); - } - } - - // The entry does not exist, add to the list - if (_app_classpath_entries == nullptr) { - assert(_last_app_classpath_entry == nullptr, "Sanity"); - _app_classpath_entries = _last_app_classpath_entry = entry; - } else { - _last_app_classpath_entry->set_next(entry); - _last_app_classpath_entry = entry; - } - - if (entry->is_jar_file()) { - ClassLoaderExt::process_jar_manifest(current, entry); - } -#endif - return true; -} - // Returns true IFF the file/dir exists and the entry was successfully created. -bool ClassLoader::update_class_path_entry_list(JavaThread* current, - const char *path, - bool check_for_duplicates, - bool is_boot_append, - bool from_class_path_attr) { +bool ClassLoader::update_class_path_entry_list(JavaThread* current, const char *path) { struct stat st; if (os::stat(path, &st) == 0) { // File or directory found ClassPathEntry* new_entry = nullptr; - new_entry = create_class_path_entry(current, path, &st, is_boot_append, from_class_path_attr); + new_entry = create_class_path_entry(current, path, &st); if (new_entry == nullptr) { return false; } // Do not reorder the bootclasspath which would break get_system_package(). // Add new entry to linked list - if (is_boot_append) { - add_to_boot_append_entries(new_entry); - } else { - if (!add_to_app_classpath_entries(current, new_entry, check_for_duplicates)) { - // new_entry is not saved, free it now - delete new_entry; - } - } + add_to_boot_append_entries(new_entry); return true; } else { return false; @@ -1318,63 +1193,61 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, int classpath_index = -1; PackageEntry* pkg_entry = ik->package(); - if (FileMapInfo::get_number_of_shared_paths() > 0) { + if (!AOTClassLocationConfig::dumptime_is_ready()) { + // The shared path table is set up after module system initialization. + // The path table contains no entry before that. Any classes loaded prior + // to the setup of the shared path table must be from the modules image. + assert(stream->from_boot_loader_modules_image(), "stream must be loaded by boot loader from modules image"); + classpath_index = 0; + } else { // Save the path from the file: protocol or the module name from the jrt: protocol // if no protocol prefix is found, path is the same as stream->source(). This path // must be valid since the class has been successfully parsed. const char* path = ClassLoader::uri_to_path(src); assert(path != nullptr, "sanity"); - for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { - SharedClassPathEntry* ent = FileMapInfo::shared_path(i); - // A shared path has been validated during its creation in ClassLoader::create_class_path_entry(), - // it must be valid here. - assert(ent->name() != nullptr, "sanity"); - // If the path (from the class stream source) is the same as the shared - // class or module path, then we have a match. - // src may come from the App/Platform class loaders, which would canonicalize - // the file name. We cannot use strcmp to check for equality against ent->name(). - // We must use os::same_files (which is faster than canonicalizing ent->name()). - if (os::same_files(ent->name(), path)) { + AOTClassLocationConfig::dumptime_iterate([&] (AOTClassLocation* cl) { + int i = cl->index(); + // for index 0 and the stream->source() is the modules image or has the jrt: protocol. + // The class must be from the runtime modules image. + if (cl->is_modules_image() && (stream->from_boot_loader_modules_image() || string_starts_with(src, "jrt:"))) { + classpath_index = i; + } else if (os::same_files(cl->path(), path)) { + // If the path (from the class stream source) is the same as the shared + // class or module path, then we have a match. + // src may come from the App/Platform class loaders, which would canonicalize + // the file name. We cannot use strcmp to check for equality against cs->path(). + // We must use os::same_files (which is faster than canonicalizing cs->path()). + // null pkg_entry and pkg_entry in an unnamed module implies the class // is from the -cp or boot loader append path which consists of -Xbootclasspath/a // and jvmti appended entries. if ((pkg_entry == nullptr) || (pkg_entry->in_unnamed_module())) { // Ensure the index is within the -cp range before assigning // to the classpath_index. - if (SystemDictionary::is_system_class_loader(loader) && - (i >= ClassLoaderExt::app_class_paths_start_index()) && - (i < ClassLoaderExt::app_module_paths_start_index())) { + if (SystemDictionary::is_system_class_loader(loader) && cl->from_app_classpath()) { classpath_index = i; - break; } else { - if ((i >= 1) && - (i < ClassLoaderExt::app_class_paths_start_index())) { + if (cl->from_boot_classpath()) { // The class must be from boot loader append path which consists of // -Xbootclasspath/a and jvmti appended entries. assert(loader == nullptr, "sanity"); classpath_index = i; - break; } } } else { // A class from a named module from the --module-path. Ensure the index is // within the --module-path range before assigning to the classpath_index. - if ((pkg_entry != nullptr) && !(pkg_entry->in_unnamed_module()) && (i > 0)) { - if (i >= ClassLoaderExt::app_module_paths_start_index() && - i < FileMapInfo::get_number_of_shared_paths()) { - classpath_index = i; - break; - } + if ((pkg_entry != nullptr) && !(pkg_entry->in_unnamed_module()) && cl->from_module_path()) { + classpath_index = i; } } } - // for index 0 and the stream->source() is the modules image or has the jrt: protocol. - // The class must be from the runtime modules image. - if (i == 0 && (stream->from_boot_loader_modules_image() || string_starts_with(src, "jrt:"))) { - classpath_index = i; - break; + if (classpath_index >= 0) { + return false; // quit iterating + } else { + return true; // Keep iterating } - } + }); // No path entry found for this class: most likely a shared class loaded by the // user defined classloader. @@ -1384,13 +1257,6 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, SystemDictionaryShared::set_shared_class_misc_info(ik, (ClassFileStream*)stream); return; } - } else { - // The shared path table is set up after module system initialization. - // The path table contains no entry before that. Any classes loaded prior - // to the setup of the shared path table must be from the modules image. - assert(stream->from_boot_loader_modules_image(), "stream must be loaded by boot loader from modules image"); - assert(FileMapInfo::get_number_of_shared_paths() == 0, "shared path table must not have been setup"); - classpath_index = 0; } const char* const class_name = ik->name()->as_C_string(); @@ -1431,7 +1297,7 @@ void ClassLoader::record_hidden_class(InstanceKlass* ik) { } else { // Generated invoker classes. if (classloader_type == ClassLoader::APP_LOADER) { - ik->set_shared_classpath_index(ClassLoaderExt::app_class_paths_start_index()); + ik->set_shared_classpath_index(AOTClassLocationConfig::dumptime()->app_cp_start_index()); } else { ik->set_shared_classpath_index(0); } @@ -1540,34 +1406,6 @@ bool ClassLoader::is_module_observable(const char* module_name) { return (*JImageFindResource)(JImage_file, module_name, jimage_version, "module-info.class", &size) != 0; } -#if INCLUDE_CDS -void ClassLoader::initialize_shared_path(JavaThread* current) { - if (CDSConfig::is_dumping_archive()) { - ClassLoaderExt::setup_search_paths(current); - } -} - -void ClassLoader::initialize_module_path(TRAPS) { - if (CDSConfig::is_dumping_archive()) { - ClassLoaderExt::setup_module_paths(THREAD); - FileMapInfo::allocate_shared_path_table(CHECK); - } -} - -// Helper function used by CDS code to get the number of module path -// entries during shared classpath setup time. -int ClassLoader::num_module_path_entries() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - int num_entries = 0; - ClassPathEntry* e= ClassLoader::_module_path_entries; - while (e != nullptr) { - num_entries ++; - e = e->next(); - } - return num_entries; -} -#endif - jlong ClassLoader::classloader_time_ms() { return UsePerfData ? Management::ticks_to_ms(_perf_accumulated_time->get_value()) : -1; diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index 8eb6593f07a..7827b6066e5 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.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 @@ -58,10 +58,6 @@ public: virtual bool is_modules_image() const { return false; } virtual bool is_jar_file() const { return false; } - virtual bool is_multi_release_jar() const { return false; } - virtual void set_multi_release_jar() {} - // Is this entry created from the "Class-path" attribute from a JAR Manifest? - virtual bool from_class_path_attr() const { return false; } virtual const char* name() const = 0; virtual JImageFile* jimage() const { return nullptr; } virtual void close_jimage() {} @@ -92,15 +88,10 @@ class ClassPathZipEntry: public ClassPathEntry { private: jzfile* _zip; // The zip archive const char* _zip_name; // Name of zip archive - bool _from_class_path_attr; // From the "Class-path" attribute of a jar file - bool _multi_release; // multi-release jar public: bool is_jar_file() const { return true; } - bool is_multi_release_jar() const { return _multi_release; } - void set_multi_release_jar() { _multi_release = true; } - bool from_class_path_attr() const { return _from_class_path_attr; } const char* name() const { return _zip_name; } - ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr, bool multi_release); + ClassPathZipEntry(jzfile* zip, const char* zip_name); virtual ~ClassPathZipEntry(); u1* open_entry(JavaThread* current, const char* name, jint* filesize, bool nul_terminate); ClassFileStream* open_stream(JavaThread* current, const char* name); @@ -226,22 +217,7 @@ class ClassLoader: AllStatic { // Last entry in linked list of appended ClassPathEntry instances static ClassPathEntry* volatile _last_append_entry; - // Info used by CDS - CDS_ONLY(static ClassPathEntry* _app_classpath_entries;) - CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;) - CDS_ONLY(static ClassPathEntry* _module_path_entries;) - CDS_ONLY(static ClassPathEntry* _last_module_path_entry;) - CDS_ONLY(static void setup_app_search_path(JavaThread* current, const char* class_path);) - CDS_ONLY(static void setup_module_search_path(JavaThread* current, const char* path);) - static bool add_to_app_classpath_entries(JavaThread* current, - ClassPathEntry* entry, - bool check_for_duplicates); - CDS_ONLY(static void add_to_module_path_entries(const char* path, - ClassPathEntry* entry);) - public: - CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;}) - CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;}) static bool has_bootclasspath_append() { return first_append_entry() != nullptr; } @@ -263,10 +239,7 @@ class ClassLoader: AllStatic { static void* zip_library_handle(); static jzfile* open_zip_file(const char* canonical_path, char** error_msg, JavaThread* thread); static ClassPathEntry* create_class_path_entry(JavaThread* current, - const char *path, const struct stat* st, - bool is_boot_append, - bool from_class_path_attr, - bool is_multi_release = false); + const char *path, const struct stat* st); // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library @@ -276,10 +249,7 @@ class ClassLoader: AllStatic { static PackageEntry* get_package_entry(Symbol* pkg_name, ClassLoaderData* loader_data); static int crc32(int crc, const char* buf, int len); static bool update_class_path_entry_list(JavaThread* current, - const char *path, - bool check_for_duplicates, - bool is_boot_append, - bool from_class_path_attr); + const char *path); static void print_bootclasspath(); // Timing @@ -363,8 +333,6 @@ class ClassLoader: AllStatic { // Initialization static void initialize(TRAPS); static void classLoader_init2(JavaThread* current); - CDS_ONLY(static void initialize_shared_path(JavaThread* current);) - CDS_ONLY(static void initialize_module_path(TRAPS);) static int compute_Object_vtable(); @@ -373,22 +341,6 @@ class ClassLoader: AllStatic { static bool is_in_patch_mod_entries(Symbol* module_name); #if INCLUDE_CDS - // Sharing dump and restore - - // Helper function used by CDS code to get the number of boot classpath - // entries during shared classpath setup time. - static int num_boot_classpath_entries(); - - static ClassPathEntry* get_next_boot_classpath_entry(ClassPathEntry* e); - - // Helper function used by CDS code to get the number of app classpath - // entries during shared classpath setup time. - static int num_app_classpath_entries(); - - // Helper function used by CDS code to get the number of module path - // entries during shared classpath setup time. - static int num_module_path_entries(); - static void exit_with_path_failure(const char* error, const char* message); static char* uri_to_path(const char* uri); static void record_result(JavaThread* current, InstanceKlass* ik, const ClassFileStream* stream, bool redefined); @@ -419,7 +371,7 @@ class ClassLoader: AllStatic { static void add_to_boot_append_entries(ClassPathEntry* new_entry); // creates a class path zip entry (returns null if JAR file cannot be opened) - static ClassPathZipEntry* create_class_path_zip_entry(const char *apath, bool is_boot_append); + static ClassPathZipEntry* create_class_path_zip_entry(const char *path); static bool string_ends_with(const char* str, const char* str_to_find); diff --git a/src/hotspot/share/classfile/classLoader.inline.hpp b/src/hotspot/share/classfile/classLoader.inline.hpp index 7f158a4c854..ec3993b089e 100644 --- a/src/hotspot/share/classfile/classLoader.inline.hpp +++ b/src/hotspot/share/classfile/classLoader.inline.hpp @@ -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 @@ -27,7 +27,6 @@ #include "classfile/classLoader.hpp" -#include "cds/cdsConfig.hpp" #include "runtime/atomic.hpp" // Next entry in class path @@ -58,44 +57,4 @@ inline ClassPathEntry* ClassLoader::classpath_entry(int n) { } } -#if INCLUDE_CDS - -// Helper function used by CDS code to get the number of boot classpath -// entries during shared classpath setup time. - -inline int ClassLoader::num_boot_classpath_entries() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - assert(has_jrt_entry(), "must have a java runtime image"); - int num_entries = 1; // count the runtime image - ClassPathEntry* e = first_append_entry(); - while (e != nullptr) { - num_entries ++; - e = e->next(); - } - return num_entries; -} - -inline ClassPathEntry* ClassLoader::get_next_boot_classpath_entry(ClassPathEntry* e) { - if (e == ClassLoader::_jrt_entry) { - return first_append_entry(); - } else { - return e->next(); - } -} - -// Helper function used by CDS code to get the number of app classpath -// entries during shared classpath setup time. -inline int ClassLoader::num_app_classpath_entries() { - assert(CDSConfig::is_dumping_archive(), "sanity"); - int num_entries = 0; - ClassPathEntry* e= ClassLoader::_app_classpath_entries; - while (e != nullptr) { - num_entries ++; - e = e->next(); - } - return num_entries; -} - -#endif // INCLUDE_CDS - #endif // SHARE_CLASSFILE_CLASSLOADER_INLINE_HPP diff --git a/src/hotspot/share/classfile/classLoaderDataShared.cpp b/src/hotspot/share/classfile/classLoaderDataShared.cpp index 16a16b3a16f..5cfe2df61b1 100644 --- a/src/hotspot/share/classfile/classLoaderDataShared.cpp +++ b/src/hotspot/share/classfile/classLoaderDataShared.cpp @@ -27,10 +27,12 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoaderDataShared.hpp" #include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" #include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "logging/log.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/safepoint.hpp" #if INCLUDE_CDS_JAVA_HEAP @@ -143,6 +145,21 @@ static ClassLoaderData* java_system_loader_data_or_null() { return ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_system_loader()); } +// ModuleEntryTables (even if empty) are required for iterate_symbols() to scan the +// platform/system loaders inside the CDS safepoint, but the tables can be created only +// when outside of safepoints. Let's do that now. +void ClassLoaderDataShared::ensure_module_entry_tables_exist() { + assert(!SafepointSynchronize::is_at_safepoint(), "sanity"); + ensure_module_entry_table_exists(SystemDictionary::java_platform_loader()); + ensure_module_entry_table_exists(SystemDictionary::java_system_loader()); +} + +void ClassLoaderDataShared::ensure_module_entry_table_exists(oop class_loader) { + Handle h_loader(JavaThread::current(), class_loader); + ModuleEntryTable* met = Modules::get_module_entry_table(h_loader); + assert(met != nullptr, "sanity"); +} + void ClassLoaderDataShared::iterate_symbols(MetaspaceClosure* closure) { assert(CDSConfig::is_dumping_full_module_graph(), "must be"); _archived_boot_loader_data.iterate_symbols (null_class_loader_data(), closure); diff --git a/src/hotspot/share/classfile/classLoaderDataShared.hpp b/src/hotspot/share/classfile/classLoaderDataShared.hpp index 957c705afde..b802f751030 100644 --- a/src/hotspot/share/classfile/classLoaderDataShared.hpp +++ b/src/hotspot/share/classfile/classLoaderDataShared.hpp @@ -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 @@ -34,7 +34,9 @@ class SerializeClosure; class ClassLoaderDataShared : AllStatic { static bool _full_module_graph_loaded; + static void ensure_module_entry_table_exists(oop class_loader); public: + static void ensure_module_entry_tables_exist(); static void allocate_archived_tables(); static void iterate_symbols(MetaspaceClosure* closure); static void init_archived_tables(); diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index d3d098e9a02..3a6fd0d933c 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" @@ -51,14 +52,6 @@ #include "utilities/checkedCast.hpp" #include "utilities/stringUtils.hpp" -jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index; -jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index; -jshort ClassLoaderExt::_max_used_path_index = 0; -int ClassLoaderExt::_num_module_paths = 0; -bool ClassLoaderExt::_has_app_classes = false; -bool ClassLoaderExt::_has_platform_classes = false; -bool ClassLoaderExt::_has_non_jar_in_classpath = false; - void ClassLoaderExt::append_boot_classpath(ClassPathEntry* new_entry) { if (CDSConfig::is_using_archive()) { warning("Sharing is only supported for boot loader classes because bootstrap classpath has been appended"); @@ -70,245 +63,10 @@ void ClassLoaderExt::append_boot_classpath(ClassPathEntry* new_entry) { ClassLoader::add_to_boot_append_entries(new_entry); } -void ClassLoaderExt::setup_app_search_path(JavaThread* current) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - int start_index = ClassLoader::num_boot_classpath_entries(); - _app_class_paths_start_index = checked_cast(start_index); - char* app_class_path = os::strdup_check_oom(Arguments::get_appclasspath(), mtClass); - - if (strcmp(app_class_path, ".") == 0) { - // This doesn't make any sense, even for AppCDS, so let's skip it. We - // don't want to throw an error here because -cp "." is usually assigned - // by the launcher when classpath is not specified. - trace_class_path("app loader class path (skipped)=", app_class_path); - } else { - trace_class_path("app loader class path=", app_class_path); - ClassLoader::setup_app_search_path(current, app_class_path); - } - - os::free(app_class_path); -} - int ClassLoaderExt::compare_module_names(const char** p1, const char** p2) { return strcmp(*p1, *p2); } -void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met) { - ResourceMark rm(current); - GrowableArray* module_paths = new GrowableArray(5); - - class ModulePathsGatherer : public ModuleClosure { - JavaThread* _current; - GrowableArray* _module_paths; - public: - ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : - _current(current), _module_paths(module_paths) {} - void do_module(ModuleEntry* m) { - char* uri = m->location()->as_C_string(); - if (strncmp(uri, "file:", 5) == 0) { - char* path = ClassLoader::uri_to_path(uri); - extract_jar_files_from_path(path, _module_paths); - } - } - }; - - ModulePathsGatherer gatherer(current, module_paths); - { - MutexLocker ml(Module_lock); - met->modules_do(&gatherer); - } - - // Sort the module paths before storing into CDS archive for simpler - // checking at runtime. - module_paths->sort(compare_module_names); - - for (int i = 0; i < module_paths->length(); i++) { - ClassLoader::setup_module_search_path(current, module_paths->at(i)); - } -} - -void ClassLoaderExt::setup_module_paths(JavaThread* current) { - assert(CDSConfig::is_dumping_archive(), "sanity"); - int start_index = ClassLoader::num_boot_classpath_entries() + - ClassLoader::num_app_classpath_entries(); - _app_module_paths_start_index = checked_cast(start_index); - Handle system_class_loader (current, SystemDictionary::java_system_loader()); - ModuleEntryTable* met = Modules::get_module_entry_table(system_class_loader); - process_module_table(current, met); -} - -bool ClassLoaderExt::has_jar_suffix(const char* filename) { - // In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix. - // Performing the same check here. - const char* dot = strrchr(filename, '.'); - if (dot != nullptr && strcmp(dot + 1, "jar") == 0) { - return true; - } - return false; -} - -void ClassLoaderExt::extract_jar_files_from_path(const char* path, GrowableArray* module_paths) { - DIR* dirp = os::opendir(path); - if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) { - module_paths->append(path); - } else { - if (dirp != nullptr) { - struct dirent* dentry; - while ((dentry = os::readdir(dirp)) != nullptr) { - const char* file_name = dentry->d_name; - if (has_jar_suffix(file_name)) { - size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1; - char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len); - int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name); - assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string"); - module_paths->append(full_name); - } - } - os::closedir(dirp); - } - } -} - -char* ClassLoaderExt::read_manifest(JavaThread* current, ClassPathEntry* entry, - jint *manifest_size, bool clean_text) { - const char* name = "META-INF/MANIFEST.MF"; - char* manifest; - jint size; - - assert(entry->is_jar_file(), "must be"); - manifest = (char*) ((ClassPathZipEntry*)entry )->open_entry(current, name, &size, true); - - if (manifest == nullptr) { // No Manifest - *manifest_size = 0; - return nullptr; - } - - - if (clean_text) { - // See http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#JAR%20Manifest - // (1): replace all CR/LF and CR with LF - StringUtils::replace_no_expand(manifest, "\r\n", "\n"); - - // (2) remove all new-line continuation (remove all "\n " substrings) - StringUtils::replace_no_expand(manifest, "\n ", ""); - } - - *manifest_size = (jint)strlen(manifest); - return manifest; -} - -char* ClassLoaderExt::get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size) { - const char* tag = "Class-Path: "; - const int tag_len = (int)strlen(tag); - char* found = nullptr; - char* line_start = manifest; - char* end = manifest + manifest_size; - - assert(*end == 0, "must be nul-terminated"); - - while (line_start < end) { - char* line_end = strchr(line_start, '\n'); - if (line_end == nullptr) { - // JAR spec require the manifest file to be terminated by a new line. - break; - } - if (strncmp(tag, line_start, tag_len) == 0) { - if (found != nullptr) { - // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java - // If duplicated entries are found, the last one is used. - log_warning(cds)("Warning: Duplicate name in Manifest: %s.\n" - "Ensure that the manifest does not have duplicate entries, and\n" - "that blank lines separate individual sections in both your\n" - "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, jar_path); - } - found = line_start + tag_len; - assert(found <= line_end, "sanity"); - *line_end = '\0'; - } - line_start = line_end + 1; - } - return found; -} - -void ClassLoaderExt::process_jar_manifest(JavaThread* current, ClassPathEntry* entry) { - ResourceMark rm(current); - jint manifest_size; - char* manifest = read_manifest(current, entry, &manifest_size); - - if (manifest == nullptr) { - return; - } - - if (strstr(manifest, "Extension-List:") != nullptr) { - vm_exit_during_cds_dumping(err_msg("-Xshare:dump does not support Extension-List in JAR manifest: %s", entry->name())); - } - - if (strstr(manifest, "Multi-Release: true") != nullptr) { - entry->set_multi_release_jar(); - } - - char* cp_attr = get_class_path_attr(entry->name(), manifest, manifest_size); - - if (cp_attr != nullptr && strlen(cp_attr) > 0) { - trace_class_path("found Class-Path: ", cp_attr); - - char sep = os::file_separator()[0]; - const char* dir_name = entry->name(); - const char* dir_tail = strrchr(dir_name, sep); -#ifdef _WINDOWS - // On Windows, we also support forward slash as the file separator when locating entries in the classpath entry. - const char* dir_tail2 = strrchr(dir_name, '/'); - if (dir_tail == nullptr) { - dir_tail = dir_tail2; - } else if (dir_tail2 != nullptr && dir_tail2 > dir_tail) { - dir_tail = dir_tail2; - } -#endif - int dir_len; - if (dir_tail == nullptr) { - dir_len = 0; - } else { - dir_len = pointer_delta_as_int(dir_tail, dir_name) + 1; - } - - // Split the cp_attr by spaces, and add each file - char* file_start = cp_attr; - char* end = file_start + strlen(file_start); - - while (file_start < end) { - char* file_end = strchr(file_start, ' '); - if (file_end != nullptr) { - *file_end = 0; - file_end += 1; - } else { - file_end = end; - } - - size_t name_len = strlen(file_start); - if (name_len > 0) { - ResourceMark rm(current); - size_t libname_len = dir_len + name_len; - char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1); - int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start); - assert((size_t)n == libname_len, "Unexpected number of characters in string"); - if (ClassLoader::update_class_path_entry_list(current, libname, true, false, true /* from_class_path_attr */)) { - trace_class_path("library = ", libname); - } else { - trace_class_path("library (non-existent) = ", libname); - FileMapInfo::record_non_existent_class_path_entry(libname); - } - } - - file_start = file_end; - } - } - return; -} - -void ClassLoaderExt::setup_search_paths(JavaThread* current) { - ClassLoaderExt::setup_app_search_path(current); -} - void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* result, bool redefined) { assert(CDSConfig::is_dumping_archive(), "sanity"); @@ -317,14 +75,12 @@ void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* resu s2 classloader_type = ClassLoader::BOOT_LOADER; if (SystemDictionary::is_system_class_loader(loader)) { classloader_type = ClassLoader::APP_LOADER; - ClassLoaderExt::set_has_app_classes(); + AOTClassLocationConfig::dumptime_set_has_app_classes(); } else if (SystemDictionary::is_platform_class_loader(loader)) { classloader_type = ClassLoader::PLATFORM_LOADER; - ClassLoaderExt::set_has_platform_classes(); - } - if (classpath_index > ClassLoaderExt::max_used_path_index()) { - ClassLoaderExt::set_max_used_path_index(classpath_index); + AOTClassLocationConfig::dumptime_set_has_platform_classes(); } + AOTClassLocationConfig::dumptime_update_max_used_index(classpath_index); result->set_shared_classpath_index(classpath_index); result->set_shared_class_loader_type(classloader_type); #if INCLUDE_CDS_JAVA_HEAP @@ -334,7 +90,7 @@ void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* resu // loaders are always loaded from known locations (jimage, classpath or modulepath), // so classpath_index should always be >= 0. // The only exception is when a java agent is used during dump time (for testing - // purposes only). If a class is transformed by the agent, the CodeSource of + // purposes only). If a class is transformed by the agent, the AOTClassLocation of // this class may point to an unknown location. This may break heap object archiving, // which requires all the boot classes to be from known locations. This is an // uncommon scenario (even in test cases). Let's simply disable heap object archiving. diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index ce0013b9d49..86bd5cce7ba 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -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 @@ -34,99 +34,13 @@ class ClassListParser; class ClassLoaderExt: public ClassLoader { // AllStatic public: #if INCLUDE_CDS -private: - enum SomeConstants { - max_classpath_index = 0x7fff - }; - - static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size); - static void setup_app_search_path(JavaThread* current); // Only when -Xshare:dump - static void process_module_table(JavaThread* current, ModuleEntryTable* met); - // index of first app JAR in shared classpath entry table - static jshort _app_class_paths_start_index; - // index of first modular JAR in shared modulepath entry table - static jshort _app_module_paths_start_index; - // the largest path index being used during CDS dump time - static jshort _max_used_path_index; - // number of module paths - static int _num_module_paths; - - static bool _has_app_classes; - static bool _has_platform_classes; - static bool _has_non_jar_in_classpath; - - static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text); - static bool has_jar_suffix(const char* filename); - public: - static void process_jar_manifest(JavaThread* current, ClassPathEntry* entry); - // Called by JVMTI code to add boot classpath + static void append_boot_classpath(ClassPathEntry* new_entry); - static void setup_search_paths(JavaThread* current); - static void setup_module_paths(JavaThread* current); - static void extract_jar_files_from_path(const char* path, GrowableArray* module_paths); static int compare_module_names(const char** p1, const char** p2); - - static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size) { - // Remove all the new-line continuations (which wrap long lines at 72 characters, see - // http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#JAR%20Manifest), so - // that the manifest is easier to parse. - return read_manifest(current, entry, manifest_size, true); - } - static char* read_raw_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size) { - // Do not remove new-line continuations, so we can easily pass it as an argument to - // java.util.jar.Manifest.getManifest() at run-time. - return read_manifest(current, entry, manifest_size, false); - } - - static jshort app_class_paths_start_index() { return _app_class_paths_start_index; } - - static jshort app_module_paths_start_index() { return _app_module_paths_start_index; } - - static jshort max_used_path_index() { return _max_used_path_index; } - - static int num_module_paths() { return _num_module_paths; } - - static void set_max_used_path_index(jshort used_index) { - _max_used_path_index = used_index; - } - - static void init_paths_start_index(jshort app_start) { - _app_class_paths_start_index = app_start; - } - - static void init_app_module_paths_start_index(jshort module_start) { - _app_module_paths_start_index = module_start; - } - - static void init_num_module_paths(int num_module_paths) { - _num_module_paths = num_module_paths; - } - - static bool is_boot_classpath(int classpath_index) { - return classpath_index < _app_class_paths_start_index; - } - - static bool has_platform_or_app_classes() { - return _has_app_classes || _has_platform_classes; - } - - static bool has_non_jar_in_classpath() { - return _has_non_jar_in_classpath; - } - static void record_result(const s2 classpath_index, InstanceKlass* result, bool redefined); - static void set_has_app_classes() { - _has_app_classes = true; - } - static void set_has_platform_classes() { - _has_platform_classes = true; - } - static void set_has_non_jar_in_classpath() { - _has_non_jar_in_classpath = true; - } #endif // INCLUDE_CDS }; diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index a0f9afdc982..55363d7f41f 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -22,10 +22,10 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" -#include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -61,7 +61,7 @@ void ModuleEntry::set_location(Symbol* location) { if (location != nullptr) { location->increment_refcount(); CDS_ONLY(if (CDSConfig::is_using_archive()) { - _shared_path_index = FileMapInfo::get_module_shared_path_index(location); + _shared_path_index = AOTClassLocationConfig::runtime()->get_module_shared_path_index(_location); }); } } @@ -483,7 +483,7 @@ void ModuleEntry::init_as_archived_entry() { set_archived_reads(write_growable_array(reads())); _loader_data = nullptr; // re-init at runtime - _shared_path_index = FileMapInfo::get_module_shared_path_index(_location); + _shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location); if (name() != nullptr) { _name = ArchiveBuilder::get_buffered_symbol(_name); ArchivePtrMarker::mark_pointer((address*)&_name); diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 1943869dbb1..22ccb4e4b04 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -26,7 +26,6 @@ #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/cdsConfig.hpp" -#include "cds/filemap.hpp" #include "cds/heapShared.hpp" #include "classfile/altHashing.hpp" #include "classfile/compactHashtable.hpp" diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 24273fed12f..68f9556099f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/cdsConfig.hpp" #include "cds/heapShared.hpp" #include "classfile/classFileParser.hpp" @@ -962,14 +963,14 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name, int scp_index = ik->shared_classpath_index(); assert(!ik->is_shared_unregistered_class(), "this function should be called for built-in classes only"); assert(scp_index >= 0, "must be"); - SharedClassPathEntry* scp_entry = FileMapInfo::shared_path(scp_index); + const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(scp_index); if (!Universe::is_module_initialized()) { - assert(scp_entry != nullptr, "must be"); + assert(cl != nullptr, "must be"); // At this point, no modules have been defined yet. KlassSubGraphInfo::check_allowed_klass() // has restricted the classes can be loaded at this step to be only: - // [1] scp_entry->is_modules_image(): classes in java.base, or, + // [1] cs->is_modules_image(): classes in java.base, or, // [2] HeapShared::is_a_test_class_in_unnamed_module(ik): classes in bootstrap/unnamed module - assert(scp_entry->is_modules_image() || HeapShared::is_a_test_class_in_unnamed_module(ik), + assert(cl->is_modules_image() || HeapShared::is_a_test_class_in_unnamed_module(ik), "only these classes can be loaded before the module system is initialized"); assert(class_loader.is_null(), "sanity"); return true; @@ -986,7 +987,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name, ModuleEntry* mod_entry = (pkg_entry == nullptr) ? nullptr : pkg_entry->module(); bool should_be_in_named_module = (mod_entry != nullptr && mod_entry->is_named()); - bool was_archived_from_named_module = scp_entry->in_named_module(); + bool was_archived_from_named_module = !cl->has_unnamed_module(); bool visible; if (was_archived_from_named_module) { @@ -1587,6 +1588,9 @@ void SystemDictionary::initialize(TRAPS) { PlaceholderTable::initialize(); #if INCLUDE_CDS SystemDictionaryShared::initialize(); + if (CDSConfig::is_dumping_archive()) { + AOTClassLocationConfig::dumptime_init(THREAD); + } #endif // Resolve basic classes vmClasses::resolve_all(CHECK); diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index ae834ec9a72..b67dcd43e4d 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.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 @@ -314,7 +314,6 @@ class MetaspaceObj { f(ConstantPoolCache) \ f(Annotations) \ f(MethodCounters) \ - f(SharedClassPathEntry) \ f(RecordComponent) #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 9ea021713fc..e7631f9dfe3 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -166,9 +166,9 @@ class Klass : public Metadata { uint8_t _hash_slot; private: - // This is an index into FileMapHeader::_shared_path_table[], to - // associate this class with the JAR file where it's loaded from during - // dump time. If a class is not loaded from the shared archive, this field is + // This is an index into AOTClassLocationConfig::class_locations(), to + // indicate the AOTClassLocation where this class is loaded from during + // dump time. If a class is not loaded from the AOT cache, this field is // -1. s2 _shared_class_path_index; diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 98b1b796813..aedd56817bf 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -667,7 +667,7 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) { // terminating the VM so we check one more time. // create the zip entry - ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, true); + ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); if (zip_entry == nullptr) { return JVMTI_ERROR_ILLEGAL_ARGUMENT; } @@ -709,7 +709,7 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) { // create the zip entry (which will open the zip file and hence // check that the segment is indeed a zip file). - ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment, false); + ClassPathZipEntry* zip_entry = ClassLoader::create_class_path_zip_entry(segment); if (zip_entry == nullptr) { return JVMTI_ERROR_ILLEGAL_ARGUMENT; } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index b3f70592f6f..420d6ab39d9 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -24,7 +24,6 @@ #include "cds/cds_globals.hpp" #include "cds/cdsConfig.hpp" -#include "cds/filemap.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/moduleEntry.hpp" diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 4a0e859a692..006f1be112a 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -799,15 +799,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { initialize_class(vmSymbols::jdk_internal_vm_Continuation(), CHECK_JNI_ERR); } -#if INCLUDE_CDS - // capture the module path info from the ModuleEntryTable - ClassLoader::initialize_module_path(THREAD); - if (HAS_PENDING_EXCEPTION) { - java_lang_Throwable::print(PENDING_EXCEPTION, tty); - vm_exit_during_initialization("ClassLoader::initialize_module_path() failed unexpectedly"); - } -#endif - if (NativeHeapTrimmer::enabled()) { NativeHeapTrimmer::initialize(); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/BootClassPathMismatch.java b/test/hotspot/jtreg/runtime/cds/appcds/BootClassPathMismatch.java index 5190f1f72e4..798275be4e7 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/BootClassPathMismatch.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/BootClassPathMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, 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 @@ -60,6 +60,11 @@ public class BootClassPathMismatch { // this test is not applicable to dynamic archive since // there is no class to be archived in the top archive test.testBootClassPathMatchWithAppend(); + + // this test is not applicable to dynamic archive since + // there is no class path (-cp) specified at dyanmic archive + // creation. + test.testBootClassPathAppend(); } test.testBootClassPathMatch(); test.testBootClassPathMismatchTwoJars(); @@ -235,6 +240,22 @@ public class BootClassPathMismatch { .assertAbnormalExit(mismatchMessage); } + /* Archive contains Hello class with only hello.jar in bootclasspath at dump time. + * + * No error - bootclasspath can be appended during runtime if no -cp is specified. + */ + public void testBootClassPathAppend() throws Exception { + String appJar = JarBuilder.getOrCreateHelloJar(); + String jar2 = ClassFileInstaller.writeJar("jar2.jar", "pkg/C2"); + String jars = appJar + File.pathSeparator + jar2; + String appClasses[] = {"Hello", "pkg/C2"}; + TestCommon.dump( + null, appClasses, "-Xbootclasspath/a:" + appJar); + TestCommon.run( + "-Xbootclasspath/a:" + jars, "Hello") + .assertNormalExit(); + } + private static void copyHelloToNewDir() throws Exception { String classDir = CDSTestUtils.getOutputDir(); String dstDir = classDir + File.separator + "newdir"; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java b/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java index df47e6bebc8..569ba8d20f7 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.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,19 +71,13 @@ public class ClassPathAttr { TestCommon.testDump(cp, classlist); - TestCommon.run( - "-cp", cp, - "CpAttr1") - .assertNormalExit(); - - // Logging test for class+path. TestCommon.run( "-Xlog:class+path", "-cp", cp, "CpAttr1") .assertNormalExit(output -> { - output.shouldMatch("checking shared classpath entry: .*cpattr2.jar"); - output.shouldMatch("checking shared classpath entry: .*cpattr3.jar"); + output.shouldMatch("Checking .*cpattr2.jar.*from JAR manifest ClassPath attribute"); + output.shouldMatch("Checking .*cpattr3.jar.*from JAR manifest ClassPath attribute"); }); // Test handling of forward slash ('/') file separator when locating entries @@ -117,8 +111,8 @@ public class ClassPathAttr { "-cp", newCp, "CpAttr1") .assertNormalExit(output -> { - output.shouldMatch("checking shared classpath entry: .*cpattr2.jar"); - output.shouldMatch("checking shared classpath entry: .*cpattr3.jar"); + output.shouldMatch("Checking .*cpattr2.jar.*from JAR manifest ClassPath attribute"); + output.shouldMatch("Checking .*cpattr3.jar.*from JAR manifest ClassPath attribute"); }); // Go one directory up. @@ -150,8 +144,8 @@ public class ClassPathAttr { "-cp", newCp, "CpAttr1") .assertNormalExit(output -> { - output.shouldMatch("checking shared classpath entry: .*cpattr2.jar"); - output.shouldMatch("checking shared classpath entry: .*cpattr3.jar"); + output.shouldMatch("Checking .*cpattr2.jar.*from JAR manifest ClassPath attribute"); + output.shouldMatch("Checking .*cpattr3.jar.*from JAR manifest ClassPath attribute"); }); } } @@ -163,6 +157,7 @@ public class ClassPathAttr { TestCommon.testDump(cp, classlist); TestCommon.run( + "-Xlog:class+path", "-cp", cp, "CpAttr1") .assertNormalExit(); @@ -183,7 +178,7 @@ public class ClassPathAttr { "-cp", cp, "CpAttr6") .assertNormalExit(output -> { - output.shouldMatch("should be non-existent: .*cpattrX.jar"); + output.shouldMatch("Checking .*cpattrX.jar.* not-exist"); }); // Now make nonExistPath exist. CDS still loads, but archived non-system classes will not be used. @@ -198,11 +193,10 @@ public class ClassPathAttr { result.assertAbnormalExit(output -> { output.shouldMatch("CDS archive has aot-linked classes. It cannot be used because the file .*cpattrX.jar exists"); }); - } else { - result.assertNormalExit(output -> { - output.shouldMatch("Archived non-system classes are disabled because the file .*cpattrX.jar exists"); - }); + result.assertAbnormalExit(output -> { + output.shouldMatch("cpattrX.jar.* must not exist"); + }); } } @@ -233,8 +227,8 @@ public class ClassPathAttr { "-cp", cp, "Hello") .assertAbnormalExit(output -> { - output.shouldMatch(".*APP classpath mismatch, actual: -Djava.class.path=.*cpattr1.jar.*cpattr2.jar.*hello.jar") - .shouldContain("Unable to use shared archive."); + output.shouldMatch("app classpath .* does not match: expected .*hello.jar.* got .*cpattr2.jar") + .shouldContain("Unable to use shared archive."); }); // Run with different -cp cpattr2.jar:hello.jar. App classpath mismatch should be detected. @@ -243,8 +237,8 @@ public class ClassPathAttr { "-cp", cp, "Hello") .assertAbnormalExit(output -> { - output.shouldMatch(".*APP classpath mismatch, actual: -Djava.class.path=.*cpattr2.jar.*hello.jar") - .shouldContain("Unable to use shared archive."); + output.shouldMatch("app classpath .* does not match: expected .*cpattr1.jar.* got .*cpattr2.jar") + .shouldContain("Unable to use shared archive."); }); // Dumping with -cp cpattr1.jar:cpattr2.jar:hello.jar diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommonAppClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/CommonAppClasspath.java index 9dff6f3a2af..18045994ea8 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/CommonAppClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/CommonAppClasspath.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 @@ -41,7 +41,7 @@ import jdk.test.lib.cds.CDSTestUtils; public class CommonAppClasspath { private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); - private static final String failedMessage = "APP classpath mismatch"; + private static final String failedMessage = "Archived app classpath validation: failed"; private static final String successMessage1 = "Hello source: shared objects file"; private static final String successMessage2 = "HelloMore source: shared objects file"; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java index 7f2af4bdcab..38717310aac 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.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 @@ -54,7 +54,7 @@ public class NonExistClasspath { } static void doTest(String appJar, boolean bootcp) throws Exception { - final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch"; + final String errorMessage3 = (bootcp ? "boot" : "app") + " classpath validation: failed"; (new File(nonExistPath)).delete(); String classPath = nonExistPath + File.pathSeparator + appJar; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java b/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java index 6794b3987b6..c0dce14ab82 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/PrintSharedArchiveAndExit.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 @@ -58,9 +58,10 @@ public class PrintSharedArchiveAndExit { public static void main(String[] args) throws Exception { String appJar = JarBuilder.getOrCreateHelloJar(); String appJar2 = JarBuilder.build("PrintSharedArchiveAndExit-more", "HelloMore"); - String cp = appJar + File.pathSeparator + appJar2; - String lastCheckMsg = "checking shared classpath entry: " + appJar2; // the last JAR to check + String firstCheckShortMsg = "Checking 'hello.jar' file"; // the first JAR to check (without directory prefix) + String firstCheckMsg = "Checking '" + appJar + "' file"; // the first JAR to check + String lastCheckMsg = "Checking '" + appJar2 + "' file"; // the last JAR to check TestCommon.testDump(cp, TestCommon.list("Hello", "HelloMore")); @@ -99,7 +100,7 @@ public class PrintSharedArchiveAndExit { TestCommon.run( "-cp", ".", "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "Run time APP classpath is shorter than the one at dump time: .")); + .ifNoMappingFailure(output -> check(output, 1, true, firstCheckShortMsg, "app classpath has fewer elements than expected")); log("Use an invalid App CP -- all the JAR paths should be checked.\n" + "Non-existing jar files will be ignored."); @@ -107,28 +108,27 @@ public class PrintSharedArchiveAndExit { TestCommon.run( "-cp", invalidCP, "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg)); + .ifNoMappingFailure(output -> check(output, 0, true, firstCheckShortMsg)); log("Changed modification time of hello.jar -- all the JAR paths should be checked"); (new File(appJar)).setLastModified(System.currentTimeMillis() + 2000); TestCommon.run( "-cp", cp, "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "Timestamp mismatch")); + .ifNoMappingFailure(output -> check(output, 1, true, firstCheckMsg, "timestamp has changed")); log("Even if hello.jar is out of date, we should still be able to print the dictionary."); TestCommon.run( "-cp", cp, "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "java.lang.Object")); - + .ifNoMappingFailure(output -> check(output, 1, true, firstCheckMsg, "java.lang.Object")); log("Remove hello.jar -- all the JAR paths should be checked"); (new File(appJar)).delete(); TestCommon.run( "-cp", cp, "-XX:+PrintSharedArchiveAndExit") - .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "Required classpath entry does not exist: " + appJar)); + .ifNoMappingFailure(output -> check(output, 1, true, firstCheckMsg, "Required classpath entry does not exist: " + appJar)); log("Execution with major errors -- with 'major' errors like the JSA file\n" + "is missing, we should stop immediately to avoid crashing the JVM."); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 2aa4bafdf12..090df514966 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.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 @@ -268,15 +268,5 @@ public class SharedArchiveConsistency { baseArchiveNameOffset = CDSArchiveUtils.baseArchiveNameOffset(copiedJsa); System.out.println("new baseArchiveNameOffset = " + baseArchiveNameOffset); testAndCheck(verifyExecArgs); - - // modify _common_app_classpath_size - String wrongCommonAppClasspathOffset = startNewArchive("wrongCommonAppClasspathOffset"); - copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, wrongCommonAppClasspathOffset); - int commonAppClasspathPrefixSize = CDSArchiveUtils.commonAppClasspathPrefixSize(copiedJsa); - System.out.println(" commonAppClasspathPrefixSize = " + commonAppClasspathPrefixSize); - CDSArchiveUtils.writeData(copiedJsa, CDSArchiveUtils.offsetCommonAppClasspathPrefixSize(), commonAppClasspathPrefixSize * 2); - commonAppClasspathPrefixSize = CDSArchiveUtils.commonAppClasspathPrefixSize(copiedJsa); - System.out.println("new commonAppClasspathPrefixSize = " + commonAppClasspathPrefixSize); - testAndCheck(verifyExecArgs); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java index 55d036fec42..c79aca564b5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, 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 @@ -88,9 +88,12 @@ public class TraceLongClasspath { // Dump an archive with a specified JAR file in -classpath TestCommon.testDump(dumpCP, TestCommon.list("Hello")); - // Then try to execute the archive with a different classpath and with -Xlog:class+path. - // The diagnostic "expecting" app classpath trace should show the entire classpath (excluding any non-existent dump-time paths). - String recordedCP = dummyJar + ps + appJar; + TestCommon.run( + "-Xlog:class+path", "-Xlog:cds", + "-cp", dumpCP, + "Hello") + .assertNormalExit(); + TestCommon.run( "-Xlog:class+path", "-Xlog:cds", "-cp", appJar, @@ -98,9 +101,6 @@ public class TraceLongClasspath { .assertAbnormalExit(output -> { output.shouldContain("Unable to use shared archive"); output.shouldContain("shared class paths mismatch"); - // the "expecting" app classpath from -Xlog:class+path should not - // be truncated - output.shouldContain(recordedCP); }); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/WrongClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/WrongClasspath.java index 9fb88e0b00c..f9594b9d64d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/WrongClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/WrongClasspath.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 @@ -109,6 +109,6 @@ public class WrongClasspath { output = TestCommon.execAuto( "-cp", jars, "Hello"); output.shouldMatch("This file is not the one used while building the shared archive file:.*jar2.jar") - .shouldMatch(".warning..cds.*jar2.jar timestamp has changed."); + .shouldMatch(".warning..cds.*jar2.jar.*timestamp has changed"); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java index 00bd63fa3d4..ea95a2c8711 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.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 @@ -150,22 +150,6 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { appJar, mainClass, isAuto ? 0 : 1, "Base archive name is damaged"); - startTest("5a. Modify common app classpath size"); - String wrongCommonAppClasspathOffset = getNewArchiveName("wrongCommonAppClasspathOffset"); - copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongCommonAppClasspathOffset); - int commonAppClasspathPrefixSize = CDSArchiveUtils.commonAppClasspathPrefixSize(copiedJsa); - CDSArchiveUtils.writeData(copiedJsa, CDSArchiveUtils.offsetCommonAppClasspathPrefixSize(), -1); - runTwo(baseArchiveName, wrongCommonAppClasspathOffset, - appJar, mainClass, isAuto ? 0 : 1, - "common app classpath prefix len < 0"); - - startTest("5b. Modify common app classpath size, run with -XX:-VerifySharedSpaces"); - VERIFY_CRC = true; - runTwo(baseArchiveName, modTop, - appJar, mainClass, isAuto ? 0 : 1, - "Header checksum verification failed"); - VERIFY_CRC = false; - startTest("6. Make base archive name not terminated with '\0'"); String wrongBaseName = getNewArchiveName("wrongBaseName"); copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/WrongTopClasspath.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/WrongTopClasspath.java index 54c5e66ab18..af8f3acb5e9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/WrongTopClasspath.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/WrongTopClasspath.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 @@ -112,6 +112,6 @@ public class WrongTopClasspath extends DynamicArchiveTestBase { .assertNormalExit(output -> { output.shouldContain(topArchiveMsg); output.shouldMatch("This file is not the one used while building the shared archive file:.*GenericTestApp.jar"); - output.shouldMatch(".warning..cds.*GenericTestApp.jar timestamp has changed.");}); + output.shouldMatch(".warning..cds.*GenericTestApp.jar.*timestamp has changed");}); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java index fe777142046..e5ead078696 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.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 @@ -226,29 +226,30 @@ public class ModulePathAndFMG { "-m", MAIN_MODULE); TestCommon.checkDump(output); - tty("5. run with CDS on, without the extra module specified in dump time, should pass"); + tty("5. run with CDS on, without the extra module specified in dump time, should fail"); TestCommon.runWithModules(prefix, null, // --upgrade-module-path libsDir.toString(), // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_DISABLED) - .shouldContain(OPTIMIZE_ENABLED) - .shouldNotContain(FMG_DISABLED) - .shouldContain(FMG_ENABLED) + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); + tty("6. run with CDS on, with the extra module specified in dump time"); TestCommon.runWithModules(prefix, null, // --upgrade-module-path extraModulePath, // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_ENABLED) - .shouldContain(OPTIMIZE_DISABLED) - .shouldNotContain(FMG_ENABLED) - .shouldContain(FMG_DISABLED) + out.shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldNotContain(FMG_DISABLED) .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); @@ -262,16 +263,16 @@ public class ModulePathAndFMG { extraJarPath, "-m", MAIN_MODULE); TestCommon.checkDump(output); - tty("7. run with CDS on, without the extra module specified in dump time, should pass"); + tty("7. run with CDS on, without the extra module specified in dump time, should fail"); TestCommon.runWithModules(prefix, null, // --upgrade-module-path modularJarPath, // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_DISABLED) - .shouldContain(OPTIMIZE_ENABLED) - .shouldNotContain(FMG_DISABLED) - .shouldContain(FMG_ENABLED) + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); @@ -282,10 +283,10 @@ public class ModulePathAndFMG { extraJarPath, // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_ENABLED) - .shouldContain(OPTIMIZE_DISABLED) - .shouldNotContain(FMG_ENABLED) - .shouldContain(FMG_DISABLED) + out.shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldNotContain(FMG_DISABLED) .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); @@ -295,10 +296,10 @@ public class ModulePathAndFMG { extraModulePath, // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_ENABLED) - .shouldContain(OPTIMIZE_DISABLED) - .shouldNotContain(FMG_ENABLED) - .shouldContain(FMG_DISABLED) + out.shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldNotContain(FMG_DISABLED) .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index fd76df92ef6..f616b22ef38 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.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 @@ -53,7 +53,6 @@ public class CDSArchiveUtils { private static int offsetCrc; // offset of GenericCDSFileMapHeader::_crc private static int offsetVersion; // offset of GenericCDSFileMapHeader::_version private static int offsetHeaderSize; // offset of GenericCDSFileMapHeader::_header_size - private static int offsetCommonAppClasspathPrefixSize;// offset of GenericCDSFileMapHeader::_common_app_classpath_size private static int offsetBaseArchiveNameOffset;// offset of GenericCDSFileMapHeader::_base_archive_name_offset private static int offsetBaseArchiveNameSize; // offset of GenericCDSFileMapHeader::_base_archive_name_size private static int offsetJvmIdent; // offset of FileMapHeader::_jvm_ident @@ -91,7 +90,6 @@ public class CDSArchiveUtils { offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc"); offsetVersion = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_version"); offsetHeaderSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_header_size"); - offsetCommonAppClasspathPrefixSize = wb.getCDSOffsetForName("FileMapHeader::_common_app_classpath_prefix_size"); offsetBaseArchiveNameOffset = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_offset"); offsetBaseArchiveNameSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_size"); offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident"); @@ -130,7 +128,6 @@ public class CDSArchiveUtils { public static int offsetCrc() { return offsetCrc; } public static int offsetVersion() { return offsetVersion; } public static int offsetHeaderSize() { return offsetHeaderSize; } - public static int offsetCommonAppClasspathPrefixSize() { return offsetCommonAppClasspathPrefixSize; } public static int offsetBaseArchiveNameOffset() { return offsetBaseArchiveNameOffset; } public static int offsetBaseArchiveNameSize() { return offsetBaseArchiveNameSize; } public static int offsetJvmIdent() { return offsetJvmIdent; } @@ -159,10 +156,6 @@ public class CDSArchiveUtils { return alignUpWithAlignment(size); } - public static int commonAppClasspathPrefixSize(File jsaFile) throws Exception { - return (int)readInt(jsaFile, offsetCommonAppClasspathPrefixSize, 4); - } - public static int baseArchiveNameOffset(File jsaFile) throws Exception { return (int)readInt(jsaFile, offsetBaseArchiveNameOffset, 4); } From 39cb493c365778a1e3a6e753b49d8664733a3e26 Mon Sep 17 00:00:00 2001 From: Rajat Mahajan Date: Mon, 24 Feb 2025 20:21:20 +0000 Subject: [PATCH 101/587] 8348106: Catch C++ exception in Java_sun_awt_windows_WTaskbarPeer_setOverlayIcon Reviewed-by: abhiscxk, aivanov, azvegint, serb, dmarkov --- .../windows/native/libawt/windows/awt_Taskbar.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Taskbar.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Taskbar.cpp index 19a6fd743b4..f45265d586c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Taskbar.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Taskbar.cpp @@ -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 @@ -126,9 +126,13 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WTaskbarPeer_flashWindow JNIEXPORT void JNICALL Java_sun_awt_windows_WTaskbarPeer_setOverlayIcon (JNIEnv *env, jobject, jlong window, jintArray buf, jint w, jint h) { + TRY; + HICON icon = CreateIconFromRaster(env, buf, w, h); m_Taskbar->SetOverlayIcon((HWND)window, icon, NULL); ::DestroyIcon(icon); + + CATCH_BAD_ALLOC; } #ifdef __cplusplus } From 990d40e98da2ceb3261096eaa55550565af58fc1 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Mon, 24 Feb 2025 22:57:03 +0000 Subject: [PATCH 102/587] 8350476: Fix typo introduced in JDK-8350147 Reviewed-by: jnimeh, jpai --- src/java.base/share/classes/javax/crypto/KEM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index 0486e48615a..f19d3306266 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -65,7 +65,7 @@ import java.util.Objects; * new shared secret and key encapsulation message. *

* - * Example operation using a ficticious {@code KEM} algorithm {@code ABC}: + * Example operation using a fictitious {@code KEM} algorithm {@code ABC}: * {@snippet lang = java: * // Receiver side * KeyPairGenerator g = KeyPairGenerator.getInstance("ABC"); From a6cc37fdbe77ff3c1bd8e2332f67f48e3850e56b Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 25 Feb 2025 05:38:39 +0000 Subject: [PATCH 103/587] 8349888: AOTMode=create crashes with EpsilonGC Reviewed-by: shade, kvn --- src/hotspot/share/cds/classListParser.cpp | 8 ++ .../LambdaInExcludedClass.java | 103 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/LambdaInExcludedClass.java diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 9a5ac12b475..e0c008678ca 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -846,6 +846,14 @@ void ClassListParser::parse_constant_pool_tag() { } } + if (SystemDictionaryShared::should_be_excluded(ik)) { + if (log_is_enabled(Warning, cds, resolve)) { + ResourceMark rm; + log_warning(cds, resolve)("Cannot aot-resolve constants for %s because it is excluded", ik->external_name()); + } + return; + } + if (preresolve_class) { AOTConstantPoolResolver::preresolve_class_cp_entries(THREAD, ik, &preresolve_list); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/LambdaInExcludedClass.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/LambdaInExcludedClass.java new file mode 100644 index 00000000000..9ed2524bff1 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/LambdaInExcludedClass.java @@ -0,0 +1,103 @@ +/* + * 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=static Lambda expressions in excluded classes shouldn't be resolved during the assembly phase. + * @bug 8349888 + * @requires vm.cds.supports.aot.class.linking + * @requires vm.gc.Epsilon + * @comment work around JDK-8345635 + * @requires !vm.jvmci.enabled + * @library /test/jdk/lib/testlibrary /test/lib + * @build LambdaInExcludedClass + * @run driver jdk.test.lib.helpers.ClassFileInstaller LambdaInExcludedClassApp + * @run driver LambdaInExcludedClass STATIC + */ + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class LambdaInExcludedClass { + static final String mainClass = "LambdaInExcludedClassApp"; + + public static void main(String[] args) throws Exception { + Tester t = new Tester(); + t.run(args); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + // Using "." as the classpath allows the LambdaInExcludedClassApp to be loaded in + // the assembly phase, but this class will be excluded from the AOT cache. + return "."; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xmx128m", + "-XX:+AOTClassLinking", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseEpsilonGC", + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.DUMP_STATIC) { + out.shouldContain("Skipping LambdaInExcludedClassApp: Unsupported location"); + out.shouldContain("Cannot aot-resolve constants for LambdaInExcludedClassApp because it is excluded"); + } else { + out.shouldContain("Hello LambdaInExcludedClassApp"); + } + } + } +} + +class LambdaInExcludedClassApp { + public static void main(String args[]) throws Exception { + // LambdaInExcludedClassApp is excluded, so aot-linking of lambda call sites + // should not happen for this class. Otherwise Epsilon GC may crash due + // to 8349888. + Runnable r = LambdaInExcludedClassApp::doit; + r.run(); + } + + static void doit() { + System.out.println("Hello LambdaInExcludedClassApp"); + } +} From e1081cffcbec6020bf4cbec9f795b59b6ec1e9ef Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 25 Feb 2025 06:12:39 +0000 Subject: [PATCH 104/587] 8348536: Remove remain SIZE_FORMAT usage after JDK-8347990 Reviewed-by: dholmes, kbarrett --- test/hotspot/gtest/metaspace/test_blocktree.cpp | 2 +- test/hotspot/gtest/metaspace/test_metaspace_misc.cpp | 10 +++++----- test/hotspot/gtest/nmt/test_nmt_totals.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/gtest/metaspace/test_blocktree.cpp b/test/hotspot/gtest/metaspace/test_blocktree.cpp index c0dae895b2a..6d1e8d2884d 100644 --- a/test/hotspot/gtest/metaspace/test_blocktree.cpp +++ b/test/hotspot/gtest/metaspace/test_blocktree.cpp @@ -143,7 +143,7 @@ static void test_find_nearest_fit_with_tree(const size_t sizes[], size_t request EXPECT_0(real_size); } - LOG(SIZE_FORMAT ": %zu.", request_size, real_size); + LOG("%zu: %zu.", request_size, real_size); } diff --git a/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp b/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp index da0ea656ed7..7793bdddf7c 100644 --- a/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp @@ -74,11 +74,11 @@ TEST_VM(metaspace, chunklevel_utils) { // These tests seem to be really basic, but it is amazing what one can // break accidentally... - LOG(SIZE_FORMAT, MAX_CHUNK_BYTE_SIZE); - LOG(SIZE_FORMAT, MIN_CHUNK_BYTE_SIZE); - LOG(SIZE_FORMAT, MIN_CHUNK_WORD_SIZE); - LOG(SIZE_FORMAT, MAX_CHUNK_WORD_SIZE); - LOG(SIZE_FORMAT, MAX_CHUNK_BYTE_SIZE); + LOG("%zu", MAX_CHUNK_BYTE_SIZE); + LOG("%zu", MIN_CHUNK_BYTE_SIZE); + LOG("%zu", MIN_CHUNK_WORD_SIZE); + LOG("%zu", MAX_CHUNK_WORD_SIZE); + LOG("%zu", MAX_CHUNK_BYTE_SIZE); LOG("%u", (unsigned)ROOT_CHUNK_LEVEL); LOG("%u", (unsigned)HIGHEST_CHUNK_LEVEL); LOG("%u", (unsigned)LOWEST_CHUNK_LEVEL); diff --git a/test/hotspot/gtest/nmt/test_nmt_totals.cpp b/test/hotspot/gtest/nmt/test_nmt_totals.cpp index d3fb62654c2..61c591fa0bb 100644 --- a/test/hotspot/gtest/nmt/test_nmt_totals.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_totals.cpp @@ -65,7 +65,7 @@ static totals_t get_totals() { EXPECT_LE(t_real.s, t_expected.s + leeway_s); \ EXPECT_GE(t_real.ovrh, t_expected.ovrh - (leeway_n * sizeof(MallocHeader))); \ EXPECT_LE(t_real.ovrh, t_expected.ovrh + (leeway_n * sizeof(MallocHeader))); \ - LOG("Deviation: n=" SSIZE_FORMAT ", s=" SSIZE_FORMAT ", ovrh=" SSIZE_FORMAT, \ + LOG("Deviation: n=%zd, s=%zd, ovrh=%zd", \ (ssize_t)t_real.n - (ssize_t)t_expected.n, \ (ssize_t)t_real.s - (ssize_t)t_expected.s, \ (ssize_t)t_real.ovrh - (ssize_t)t_expected.ovrh); \ From ab86a13519a50c5d8a05c493594e6bda329133f4 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Tue, 25 Feb 2025 08:18:52 +0000 Subject: [PATCH 105/587] 8350548: java.lang.classfile package javadoc has errors Reviewed-by: liach --- .../share/classes/java/lang/classfile/package-info.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 b5d79ff6e7e..a966a6d8269 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 @@ -368,13 +368,13 @@ *

* or lift the code transform into the class transform directly: * {@snippet lang=java : - * ClassTransform ct = ClassTransform.transformingMethodBodiess(fooToBar); + * ClassTransform ct = ClassTransform.transformingMethodBodies(fooToBar); * } *

* and then transform the classfile: * {@snippet lang=java : * var cc = ClassFile.of(); - * byte[] newBytes = cc.transform(cc.parse(bytes), ct); + * byte[] newBytes = cc.transformClass(cc.parse(bytes), ct); * } *

* This is much more concise (and less error-prone) than the equivalent @@ -393,7 +393,7 @@ * * {@snippet lang=java : * var cc = ClassFile.of(); - * byte[] newBytes = cc.transform(cc.parse(bytes), + * byte[] newBytes = cc.transformClass(cc.parse(bytes), * ClassTransform.transformingMethods( * MethodTransform.transformingCode( * fooToBar.andThen(instrumentCalls)))); From d551dacaef938cea0cad10047b79a0a7a26dcacb Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 25 Feb 2025 08:19:56 +0000 Subject: [PATCH 106/587] 8350103: Test containers/systemd/SystemdMemoryAwarenessTest.java fails on Linux ppc64le SLES15 SP6 Co-authored-by: Severin Gehwolf Reviewed-by: sgehwolf, asteiner --- .../containers/systemd/SystemdMemoryAwarenessTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java b/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java index 2c06d48bb1c..ba77ce1c6e9 100644 --- a/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java +++ b/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2024, 2025, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,14 +68,14 @@ public class SystemdMemoryAwarenessTest { OutputAnalyzer out = SystemdTestUtils.buildAndRunSystemdJava(opts); out.shouldHaveExitValue(0) - .shouldContain("Hello Systemd") - .shouldContain(String.format("Memory Limit is: %d", (expectedMemLimit * MB))); + .shouldContain("Hello Systemd"); try { + out.shouldContain(String.format("Memory Limit is: %d", (expectedMemLimit * MB))); out.shouldContain("OSContainer::active_processor_count: " + coreLimit); } catch (RuntimeException e) { - // CPU delegation needs to be enabled when run as user on cg v2 + // CPU/memory delegation needs to be enabled when run as user on cg v2 if (SystemdTestUtils.RUN_AS_USER) { - String hint = "When run as user on cg v2 cpu delegation needs to be configured!"; + String hint = "When run as user on cg v2 cpu/memory delegation needs to be configured!"; throw new SkippedException(hint); } throw e; From aa70f0ae8be0bbc80e9d002bf02d0278c8e31bf8 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 25 Feb 2025 10:57:22 +0000 Subject: [PATCH 107/587] 8347348: Clarify that the HTTP server in jdk.httpserver module is not a full featured server Reviewed-by: michaelm, dfuchs --- src/jdk.httpserver/share/classes/module-info.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java index 23e04405ee8..15e9e2cc36d 100644 --- a/src/jdk.httpserver/share/classes/module-info.java +++ b/src/jdk.httpserver/share/classes/module-info.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 @@ -101,6 +101,14 @@ * socket option on all incoming connections. * * + * @apiNote The API and SPI in this module are designed and implemented to support a minimal + * HTTP server and simple HTTP semantics primarily. + * + * @implNote The default implementation of the HTTP server provided in this module is intended + * for simple usages like local testing, development, and debugging. Accordingly, the design + * and implementation of the server does not intend to be a full-featured, high performance + * HTTP server. + * * @toolGuide jwebserver * * @uses com.sun.net.httpserver.spi.HttpServerProvider From a9c9f7f0cbb2f2395fef08348bf867ffa8875d73 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 25 Feb 2025 11:14:20 +0000 Subject: [PATCH 108/587] 8192647: GClocker induced GCs can starve threads requiring memory leading to OOME Reviewed-by: tschatzl, iwalulya, egahlin --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- .../gc/parallel/parallelScavengeHeap.cpp | 73 +------ .../gc/parallel/parallelScavengeHeap.hpp | 4 +- src/hotspot/share/gc/parallel/psOldGen.cpp | 3 - .../share/gc/parallel/psParallelCompact.cpp | 4 - .../share/gc/parallel/psVMOperations.cpp | 8 +- .../share/gc/serial/defNewGeneration.cpp | 12 - src/hotspot/share/gc/serial/serialHeap.cpp | 101 +-------- src/hotspot/share/gc/serial/serialHeap.hpp | 8 +- .../share/gc/serial/serialVMOperations.cpp | 6 +- .../share/gc/serial/tenuredGeneration.cpp | 3 - src/hotspot/share/gc/shared/collectedHeap.cpp | 39 +--- src/hotspot/share/gc/shared/gcCause.cpp | 3 - src/hotspot/share/gc/shared/gcCause.hpp | 1 - src/hotspot/share/gc/shared/gcLocker.cpp | 205 +++++++----------- src/hotspot/share/gc/shared/gcLocker.hpp | 137 +++--------- .../share/gc/shared/gcLocker.inline.hpp | 47 ++-- src/hotspot/share/gc/shared/gcTrace.hpp | 15 -- src/hotspot/share/gc/shared/gcTraceSend.cpp | 46 ---- .../share/gc/shared/gcVMOperations.cpp | 18 +- .../share/gc/shared/gcVMOperations.hpp | 6 - src/hotspot/share/gc/shared/gc_globals.hpp | 5 - src/hotspot/share/jfr/metadata/metadata.xml | 5 - src/hotspot/share/prims/downcallLinker.cpp | 1 - src/hotspot/share/prims/jni.cpp | 1 - src/hotspot/share/prims/whitebox.cpp | 11 - src/hotspot/share/runtime/javaThread.hpp | 3 + src/hotspot/share/runtime/mutexLocker.cpp | 2 - src/hotspot/share/runtime/mutexLocker.hpp | 1 - src/hotspot/share/runtime/safepoint.cpp | 3 - src/hotspot/share/runtime/sharedRuntime.cpp | 1 - .../sun/jvm/hotspot/gc/shared/GCCause.java | 1 - src/jdk.jfr/share/conf/jfr/default.jfc | 6 - src/jdk.jfr/share/conf/jfr/profile.jfc | 6 - test/hotspot/jtreg/ProblemList.txt | 3 - .../TestExcessGCLockerCollections.java | 180 --------------- .../TestGCCauseWithParallelOld.java | 3 +- .../gc/collection/TestGCCauseWithSerial.java | 3 +- .../event/gc/detailed/TestGCLockerEvent.java | 133 ------------ test/lib/jdk/test/lib/jfr/EventNames.java | 1 - test/lib/jdk/test/whitebox/WhiteBox.java | 4 - 41 files changed, 171 insertions(+), 943 deletions(-) delete mode 100644 test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java delete mode 100644 test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 3f84349b90b..6cd4cd07dd8 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1873,7 +1873,7 @@ bool G1CollectedHeap::try_collect(GCCause::Cause cause, return try_collect_concurrently(cause, counters_before.total_collections(), counters_before.old_marking_cycles_started()); - } else if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc + } else if (cause == GCCause::_wb_young_gc DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) { // Schedule a standard evacuation pause. We're setting word_size diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index dc6a3ca565f..24cc30e1918 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -188,6 +188,7 @@ void ParallelScavengeHeap::post_initialize() { PSPromotionManager::initialize(); ScavengableNMethods::initialize(&_is_scavengable); + GCLocker::initialize(); } void ParallelScavengeHeap::update_counters() { @@ -288,7 +289,6 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, uint loop_count = 0; uint gc_count = 0; - uint gclocker_stalled_count = 0; while (result == nullptr) { // We don't want to have multiple collections for a single filled generation. @@ -318,37 +318,10 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, return result; } } - - if (gclocker_stalled_count > GCLockerRetryAllocationCount) { - return nullptr; - } - - // Failed to allocate without a gc. - if (GCLocker::is_active_and_needs_gc()) { - // If this thread is not in a jni critical section, we stall - // the requestor until the critical section has cleared and - // GC allowed. When the critical section clears, a GC is - // initiated by the last thread exiting the critical section; so - // we retry the allocation sequence from the beginning of the loop, - // rather than causing more, now probably unnecessary, GC attempts. - JavaThread* jthr = JavaThread::current(); - if (!jthr->in_critical()) { - MutexUnlocker mul(Heap_lock); - GCLocker::stall_until_clear(); - gclocker_stalled_count += 1; - continue; - } else { - if (CheckJNICalls) { - fatal("Possible deadlock due to allocating while" - " in jni critical section"); - } - return nullptr; - } - } } - if (result == nullptr) { - // Generate a VM operation + assert(result == nullptr, "inv"); + { VM_ParallelCollectForAllocation op(size, is_tlab, gc_count); VMThread::execute(&op); @@ -358,13 +331,6 @@ HeapWord* ParallelScavengeHeap::mem_allocate_work(size_t size, if (op.prologue_succeeded()) { assert(is_in_or_null(op.result()), "result not in heap"); - // If GC was locked out during VM operation then retry allocation - // and/or stall as necessary. - if (op.gc_locked()) { - assert(op.result() == nullptr, "must be null if gc_locked() is true"); - continue; // retry and/or stall as necessary - } - // Exit the loop if the gc time limit has been exceeded. // The allocation must have failed above ("result" guarding // this path is null) and the most recent collection has exceeded the @@ -416,8 +382,8 @@ HeapWord* ParallelScavengeHeap::allocate_old_gen_and_record(size_t size) { } HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) { - if (!should_alloc_in_eden(size) || GCLocker::is_active_and_needs_gc()) { - // Size is too big for eden, or gc is locked out. + if (!should_alloc_in_eden(size)) { + // Size is too big for eden. return allocate_old_gen_and_record(size); } @@ -425,9 +391,6 @@ HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) { } void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { - if (GCLocker::check_active_before_gc()) { - return; - } PSParallelCompact::invoke(clear_all_soft_refs); } @@ -446,11 +409,6 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t HeapWord* result = nullptr; - GCLocker::check_active_before_gc(); - if (GCLocker::is_active_and_needs_gc()) { - return expand_heap_and_allocate(size, is_tlab); - } - // If young-gen can handle this allocation, attempt young-gc firstly. bool should_run_young_gc = is_tlab || should_alloc_in_eden(size); collect_at_safepoint(!should_run_young_gc); @@ -544,10 +502,6 @@ void ParallelScavengeHeap::collect(GCCause::Cause cause) { full_gc_count = total_full_collections(); } - if (GCLocker::should_discard(cause, gc_count)) { - return; - } - while (true) { VM_ParallelGCCollect op(gc_count, full_gc_count, cause); VMThread::execute(&op); @@ -562,22 +516,9 @@ void ParallelScavengeHeap::collect(GCCause::Cause cause) { return; } } - - if (GCLocker::is_active_and_needs_gc()) { - // If GCLocker is active, wait until clear before retrying. - GCLocker::stall_until_clear(); - } } } -void ParallelScavengeHeap::try_collect_at_safepoint(bool full) { - assert(SafepointSynchronize::is_at_safepoint(), "precondition"); - if (GCLocker::check_active_before_gc()) { - return; - } - collect_at_safepoint(full); -} - bool ParallelScavengeHeap::must_clear_all_soft_refs() { return _gc_cause == GCCause::_metadata_GC_clear_soft_refs || _gc_cause == GCCause::_wb_full_gc; @@ -889,11 +830,11 @@ GrowableArray ParallelScavengeHeap::memory_pools() { } void ParallelScavengeHeap::pin_object(JavaThread* thread, oop obj) { - GCLocker::lock_critical(thread); + GCLocker::enter(thread); } void ParallelScavengeHeap::unpin_object(JavaThread* thread, oop obj) { - GCLocker::unlock_critical(thread); + GCLocker::exit(thread); } void ParallelScavengeHeap::update_parallel_worker_threads_cpu_time() { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index b4151f9b8fa..ef9a4b4d5a1 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -95,8 +95,6 @@ class ParallelScavengeHeap : public CollectedHeap { void update_parallel_worker_threads_cpu_time(); - void collect_at_safepoint(bool full); - bool must_clear_all_soft_refs(); HeapWord* allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) override; @@ -198,7 +196,7 @@ public: // Support for System.gc() void collect(GCCause::Cause cause) override; - void try_collect_at_safepoint(bool full); + void collect_at_safepoint(bool full); void ensure_parsability(bool retire_tlabs) override; void resize_all_tlabs() override; diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index 8eadc833ac7..0a95a55b648 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -217,9 +217,6 @@ bool PSOldGen::expand(size_t bytes) { success = expand_to_reserved(); } - if (success && GCLocker::is_active_and_needs_gc()) { - log_debug(gc)("Garbage collection disabled, expanded heap instead"); - } return success; } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 90f4d6367bd..9f51aba080e 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -993,10 +993,6 @@ 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"); - if (GCLocker::check_active_before_gc()) { - return false; - } - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCIdMark gc_id_mark; diff --git a/src/hotspot/share/gc/parallel/psVMOperations.cpp b/src/hotspot/share/gc/parallel/psVMOperations.cpp index 674e51bf6d2..4873853a3dd 100644 --- a/src/hotspot/share/gc/parallel/psVMOperations.cpp +++ b/src/hotspot/share/gc/parallel/psVMOperations.cpp @@ -43,14 +43,10 @@ void VM_ParallelCollectForAllocation::doit() { GCCauseSetter gccs(heap, _gc_cause); _result = heap->satisfy_failed_allocation(_word_size, _is_tlab); - - if (_result == nullptr && GCLocker::is_active_and_needs_gc()) { - set_gc_locked(); - } } static bool is_cause_full(GCCause::Cause cause) { - return (cause != GCCause::_gc_locker) && (cause != GCCause::_wb_young_gc) + return (cause != GCCause::_wb_young_gc) DEBUG_ONLY(&& (cause != GCCause::_scavenge_alot)); } @@ -64,5 +60,5 @@ void VM_ParallelGCCollect::doit() { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCauseSetter gccs(heap, _gc_cause); - heap->try_collect_at_safepoint(_full); + heap->collect_at_safepoint(_full); } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index c5c1b67d5cf..8ad42bc702d 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -367,18 +367,6 @@ bool DefNewGeneration::expand(size_t bytes) { SpaceMangler::mangle_region(mangle_region); } - // Do not attempt an expand-to-the reserve size. The - // request should properly observe the maximum size of - // the generation so an expand-to-reserve should be - // unnecessary. Also a second call to expand-to-reserve - // value potentially can cause an undue expansion. - // For example if the first expand fail for unknown reasons, - // but the second succeeds and expands the heap to its maximum - // value. - if (GCLocker::is_active()) { - log_debug(gc)("Garbage collection disabled, expanded heap instead"); - } - return success; } diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 2408a41a87b..fcf57909a03 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -101,6 +101,7 @@ SerialHeap::SerialHeap() : _old_pool(nullptr) { _young_manager = new GCMemoryManager("Copy"); _old_manager = new GCMemoryManager("MarkSweepCompact"); + GCLocker::initialize(); } void SerialHeap::initialize_serviceability() { @@ -167,11 +168,11 @@ void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { } void SerialHeap::pin_object(JavaThread* thread, oop obj) { - GCLocker::lock_critical(thread); + GCLocker::enter(thread); } void SerialHeap::unpin_object(JavaThread* thread, oop obj) { - GCLocker::unlock_critical(thread); + GCLocker::exit(thread); } jint SerialHeap::initialize() { @@ -282,12 +283,10 @@ size_t SerialHeap::max_capacity() const { // Return true if any of the following is true: // . the allocation won't fit into the current young gen heap -// . gc locker is occupied (jni critical section) // . 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)) - || GCLocker::is_active_and_needs_gc() || _is_heap_almost_full; } @@ -306,14 +305,11 @@ HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { return result; } -HeapWord* SerialHeap::mem_allocate_work(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, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { - + 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)) { @@ -337,45 +333,6 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, return result; } - if (GCLocker::is_active_and_needs_gc()) { - if (is_tlab) { - return nullptr; // Caller will retry allocating individual object. - } - if (!is_maximal_no_gc()) { - // Try and expand heap to satisfy request. - result = expand_heap_and_allocate(size, is_tlab); - // Result could be null if we are out of space. - if (result != nullptr) { - return result; - } - } - - if (gclocker_stalled_count > GCLockerRetryAllocationCount) { - return nullptr; // We didn't get to do a GC and we didn't get any memory. - } - - // If this thread is not in a jni critical section, we stall - // the requestor until the critical section has cleared and - // GC allowed. When the critical section clears, a GC is - // initiated by the last thread exiting the critical section; so - // we retry the allocation sequence from the beginning of the loop, - // rather than causing more, now probably unnecessary, GC attempts. - JavaThread* jthr = JavaThread::current(); - if (!jthr->in_critical()) { - MutexUnlocker mul(Heap_lock); - // Wait for JNI critical section to be exited - GCLocker::stall_until_clear(); - gclocker_stalled_count += 1; - continue; - } else { - if (CheckJNICalls) { - fatal("Possible deadlock due to allocating while" - " in jni critical section"); - } - return nullptr; - } - } - // Read the gc count while the heap lock is held. gc_count_before = total_collections(); } @@ -384,10 +341,6 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, VMThread::execute(&op); if (op.prologue_succeeded()) { result = op.result(); - if (op.gc_locked()) { - assert(result == nullptr, "must be null if gc_locked() is true"); - continue; // Retry and/or stall as necessary. - } assert(result == nullptr || is_in_reserved(result), "result not in heap"); @@ -397,8 +350,8 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, // Give a warning if we seem to be looping forever. if ((QueuedAllocationWarningCount > 0) && (try_count % QueuedAllocationWarningCount == 0)) { - log_warning(gc, ergo)("SerialHeap::mem_allocate_work retries %d times," - " size=%zu %s", try_count, size, is_tlab ? "(TLAB)" : ""); + log_warning(gc, ergo)("SerialHeap::mem_allocate_work retries %d times," + " size=%zu %s", try_count, size, is_tlab ? "(TLAB)" : ""); } } } @@ -517,16 +470,6 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { HeapWord* result = nullptr; - GCLocker::check_active_before_gc(); - if (GCLocker::is_active_and_needs_gc()) { - // GC locker is active; instead of a collection we will attempt - // to expand the heap, if there's room for expansion. - if (!is_maximal_no_gc()) { - result = expand_heap_and_allocate(size, is_tlab); - } - return result; // Could be null if we are out of space. - } - // If young-gen can handle this allocation, attempt young-gc firstly. bool should_run_young_gc = _young_gen->should_allocate(size, is_tlab); collect_at_safepoint(!should_run_young_gc); @@ -550,7 +493,7 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { { UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted const bool clear_all_soft_refs = true; - do_full_collection_no_gc_locker(clear_all_soft_refs); + do_full_collection(clear_all_soft_refs); } result = attempt_allocation(size, is_tlab, false /* first_only */); @@ -632,14 +575,6 @@ void SerialHeap::scan_evacuated_objs(YoungGenScanClosure* young_cl, guarantee(young_gen()->promo_failure_scan_is_complete(), "Failed to finish scan"); } -void SerialHeap::try_collect_at_safepoint(bool full) { - assert(SafepointSynchronize::is_at_safepoint(), "precondition"); - if (GCLocker::check_active_before_gc()) { - return; - } - collect_at_safepoint(full); -} - void SerialHeap::collect_at_safepoint(bool full) { assert(!GCLocker::is_active(), "precondition"); bool clear_soft_refs = must_clear_all_soft_refs(); @@ -651,7 +586,7 @@ void SerialHeap::collect_at_safepoint(bool full) { } // Upgrade to Full-GC if young-gc fails } - do_full_collection_no_gc_locker(clear_soft_refs); + do_full_collection(clear_soft_refs); } // public collection interfaces @@ -669,12 +604,7 @@ void SerialHeap::collect(GCCause::Cause cause) { full_gc_count_before = total_full_collections(); } - if (GCLocker::should_discard(cause, gc_count_before)) { - return; - } - bool should_run_young_gc = (cause == GCCause::_wb_young_gc) - || (cause == GCCause::_gc_locker) DEBUG_ONLY(|| (cause == GCCause::_scavenge_alot)); while (true) { @@ -683,7 +613,6 @@ void SerialHeap::collect(GCCause::Cause cause) { full_gc_count_before, cause); VMThread::execute(&op); - if (!GCCause::is_explicit_full_gc(cause)) { return; } @@ -695,22 +624,10 @@ void SerialHeap::collect(GCCause::Cause cause) { return; } } - - if (GCLocker::is_active_and_needs_gc()) { - // If GCLocker is active, wait until clear before retrying. - GCLocker::stall_until_clear(); - } } } void SerialHeap::do_full_collection(bool clear_all_soft_refs) { - if (GCLocker::check_active_before_gc()) { - return; - } - do_full_collection_no_gc_locker(clear_all_soft_refs); -} - -void SerialHeap::do_full_collection_no_gc_locker(bool clear_all_soft_refs) { IsSTWGCActiveMark gc_active_mark; SvcGCMarker sgcm(SvcGCMarker::FULL); GCIdMark gc_id_mark; diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 28ab7905bbc..754f6741cfe 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -108,9 +108,6 @@ private: bool first_only); void do_full_collection(bool clear_all_soft_refs) override; - void do_full_collection_no_gc_locker(bool clear_all_soft_refs); - - void collect_at_safepoint(bool full); // Does the "cause" of GC indicate that // we absolutely __must__ clear soft refs? @@ -147,7 +144,7 @@ public: HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab); // Callback from VM_SerialGCCollect. - void try_collect_at_safepoint(bool full); + void collect_at_safepoint(bool full); // Perform a full collection of the heap; intended for use in implementing // "System.gc". This implies as full a collection as the CollectedHeap @@ -257,8 +254,7 @@ private: // Try to allocate space by expanding the heap. HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - HeapWord* mem_allocate_work(size_t size, - bool is_tlab); + HeapWord* mem_allocate_work(size_t size, bool is_tlab); MemoryPool* _eden_pool; MemoryPool* _survivor_pool; diff --git a/src/hotspot/share/gc/serial/serialVMOperations.cpp b/src/hotspot/share/gc/serial/serialVMOperations.cpp index 445f5959fe0..ef9ce4e425d 100644 --- a/src/hotspot/share/gc/serial/serialVMOperations.cpp +++ b/src/hotspot/share/gc/serial/serialVMOperations.cpp @@ -30,14 +30,10 @@ void VM_SerialCollectForAllocation::doit() { GCCauseSetter gccs(gch, _gc_cause); _result = gch->satisfy_failed_allocation(_word_size, _tlab); assert(_result == nullptr || gch->is_in_reserved(_result), "result not in heap"); - - if (_result == nullptr && GCLocker::is_active_and_needs_gc()) { - set_gc_locked(); - } } void VM_SerialGCCollect::doit() { SerialHeap* gch = SerialHeap::heap(); GCCauseSetter gccs(gch, _gc_cause); - gch->try_collect_at_safepoint(_full); + gch->collect_at_safepoint(_full); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index c793f138de0..22c4808a0bd 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -100,9 +100,6 @@ bool TenuredGeneration::expand(size_t bytes, size_t expand_bytes) { if (!success) { success = grow_to_reserved(); } - if (success && GCLocker::is_active_and_needs_gc()) { - log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); - } return success; } diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index d78e1f0822e..fba95931703 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -29,7 +29,7 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/gcLocker.inline.hpp" +#include "gc/shared/gcLocker.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/gcTrace.hpp" @@ -350,36 +350,10 @@ MetaWord* CollectedHeap::satisfy_failed_metadata_allocation(ClassLoaderData* loa return result; } - if (GCLocker::is_active_and_needs_gc()) { - // If the GCLocker is active, just expand and allocate. - // If that does not succeed, wait if this thread is not - // in a critical section itself. - result = loader_data->metaspace_non_null()->expand_and_allocate(word_size, mdtype); - if (result != nullptr) { - return result; - } - JavaThread* jthr = JavaThread::current(); - if (!jthr->in_critical()) { - // Wait for JNI critical section to be exited - GCLocker::stall_until_clear(); - // The GC invoked by the last thread leaving the critical - // section will be a young collection and a full collection - // is (currently) needed for unloading classes so continue - // to the next iteration to get a full GC. - continue; - } else { - if (CheckJNICalls) { - fatal("Possible deadlock due to allocating while" - " in jni critical section"); - } - return nullptr; - } - } - { // Need lock to get self consistent gc_count's MutexLocker ml(Heap_lock); - gc_count = Universe::heap()->total_collections(); - full_gc_count = Universe::heap()->total_full_collections(); + gc_count = total_collections(); + full_gc_count = total_full_collections(); } // Generate a VM operation @@ -389,13 +363,8 @@ MetaWord* CollectedHeap::satisfy_failed_metadata_allocation(ClassLoaderData* loa gc_count, full_gc_count, GCCause::_metadata_GC_threshold); - VMThread::execute(&op); - // If GC was locked out, try again. Check before checking success because the - // prologue could have succeeded and the GC still have been locked out. - if (op.gc_locked()) { - continue; - } + VMThread::execute(&op); if (op.prologue_succeeded()) { return op.result(); diff --git a/src/hotspot/share/gc/shared/gcCause.cpp b/src/hotspot/share/gc/shared/gcCause.cpp index f972aeccbc4..51ce73861e0 100644 --- a/src/hotspot/share/gc/shared/gcCause.cpp +++ b/src/hotspot/share/gc/shared/gcCause.cpp @@ -41,9 +41,6 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _jvmti_force_gc: return "JvmtiEnv ForceGarbageCollection"; - case _gc_locker: - return "GCLocker Initiated GC"; - case _heap_inspection: return "Heap Inspection Initiated GC"; diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index 347e32be86a..bd819e8f5c9 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -47,7 +47,6 @@ class GCCause : public AllStatic { _scavenge_alot, _allocation_profiler, _jvmti_force_gc, - _gc_locker, _heap_inspection, _heap_dump, _wb_young_gc, diff --git a/src/hotspot/share/gc/shared/gcLocker.cpp b/src/hotspot/share/gc/shared/gcLocker.cpp index 6344ba80d43..aa13209a37a 100644 --- a/src/hotspot/share/gc/shared/gcLocker.cpp +++ b/src/hotspot/share/gc/shared/gcLocker.cpp @@ -29,15 +29,13 @@ #include "memory/universe.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/safepoint.hpp" +#include "utilities/spinYield.hpp" #include "runtime/threadSMR.hpp" #include "utilities/ticks.hpp" -volatile jint GCLocker::_jni_lock_count = 0; -volatile bool GCLocker::_needs_gc = false; -unsigned int GCLocker::_total_collections = 0; - // GCLockerTimingDebugLogger tracks specific timing information for GC lock waits. class GCLockerTimingDebugLogger : public StackObj { const char* _log_message; @@ -46,7 +44,9 @@ class GCLockerTimingDebugLogger : public StackObj { public: GCLockerTimingDebugLogger(const char* log_message) : _log_message(log_message) { assert(_log_message != nullptr, "GC locker debug message must be set."); - _start = Ticks::now(); + if (log_is_enabled(Debug, gc, jni)) { + _start = Ticks::now(); + } } ~GCLockerTimingDebugLogger() { @@ -59,138 +59,89 @@ public: } }; -#ifdef ASSERT -volatile jint GCLocker::_debug_jni_lock_count = 0; -#endif +Monitor* GCLocker::_lock; +volatile bool GCLocker::_is_gc_request_pending; +DEBUG_ONLY(uint64_t GCLocker::_verify_in_cr_count;) + +void GCLocker::initialize() { + assert(Heap_lock != nullptr, "inv"); + _lock = Heap_lock; + _is_gc_request_pending = false; + + DEBUG_ONLY(_verify_in_cr_count = 0;) +} + +bool GCLocker::is_active() { + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); /* empty */) { + if (cur->in_critical_atomic()) { + return true; + } + } + return false; +} + +void GCLocker::block() { + assert(_lock->is_locked(), "precondition"); + assert(Atomic::load(&_is_gc_request_pending) == false, "precondition"); + + GCLockerTimingDebugLogger logger("Thread blocked to start GC."); + + Atomic::store(&_is_gc_request_pending, true); + + // The _is_gc_request_pending and _jni_active_critical (inside + // in_critical_atomic()) variables form a Dekker duality. On the GC side, the + // _is_gc_request_pending is set and _jni_active_critical is subsequently + // loaded. For Java threads, the opposite is true, just like a Dekker lock. + // That's why there is a fence to order the accesses involved in the Dekker + // synchronization. + OrderAccess::fence(); + + JavaThread* java_thread = JavaThread::current(); + ThreadBlockInVM tbivm(java_thread); + + // Wait for threads leaving critical section + SpinYield spin_yield; + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); /* empty */) { + while (cur->in_critical_atomic()) { + spin_yield.wait(); + } + } #ifdef ASSERT -void GCLocker::verify_critical_count() { - if (SafepointSynchronize::is_at_safepoint()) { - assert(!needs_gc() || _debug_jni_lock_count == _jni_lock_count, "must agree"); - int count = 0; - // Count the number of threads with critical operations in progress - JavaThreadIteratorWithHandle jtiwh; - for (; JavaThread *thr = jtiwh.next(); ) { - if (thr->in_critical()) { - count++; - } - } - if (_jni_lock_count != count) { - log_error(gc, verify)("critical counts don't match: %d != %d", _jni_lock_count, count); - jtiwh.rewind(); - for (; JavaThread *thr = jtiwh.next(); ) { - if (thr->in_critical()) { - log_error(gc, verify)(PTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical()); - } - } - } - assert(_jni_lock_count == count, "must be equal"); - } -} - -// In debug mode track the locking state at all times -void GCLocker::increment_debug_jni_lock_count() { - assert(_debug_jni_lock_count >= 0, "bad value"); - Atomic::inc(&_debug_jni_lock_count); -} - -void GCLocker::decrement_debug_jni_lock_count() { - assert(_debug_jni_lock_count > 0, "bad value"); - Atomic::dec(&_debug_jni_lock_count); -} + // Matching the storestore in GCLocker::exit. + OrderAccess::loadload(); + assert(Atomic::load(&_verify_in_cr_count) == 0, "inv"); #endif - -void GCLocker::log_debug_jni(const char* msg) { - Log(gc, jni) log; - if (log.is_debug()) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - log.debug("%s Thread \"%s\" %d locked.", msg, Thread::current()->name(), _jni_lock_count); - } } -bool GCLocker::is_at_safepoint() { - return SafepointSynchronize::is_at_safepoint(); +void GCLocker::unblock() { + assert(_lock->is_locked(), "precondition"); + assert(Atomic::load(&_is_gc_request_pending) == true, "precondition"); + + Atomic::store(&_is_gc_request_pending, false); } -bool GCLocker::check_active_before_gc() { - assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint"); - if (is_active() && !_needs_gc) { - verify_critical_count(); - _needs_gc = true; - GCLockerTracer::start_gc_locker(_jni_lock_count); - log_debug_jni("Setting _needs_gc."); - } - return is_active(); -} +void GCLocker::enter_slow(JavaThread* current_thread) { + assert(current_thread == JavaThread::current(), "Must be this thread"); -void GCLocker::stall_until_clear() { - assert(!JavaThread::current()->in_critical(), "Would deadlock"); - MonitorLocker ml(JNICritical_lock); - - if (needs_gc()) { - GCLockerTracer::inc_stall_count(); - log_debug_jni("Allocation failed. Thread stalled by JNI critical section."); - GCLockerTimingDebugLogger logger("Thread stalled by JNI critical section."); - // Wait for _needs_gc to be cleared - while (needs_gc()) { - ml.wait(); - } - } -} - -bool GCLocker::should_discard(GCCause::Cause cause, uint total_collections) { - return (cause == GCCause::_gc_locker) && - (_total_collections != total_collections); -} - -void GCLocker::jni_lock(JavaThread* thread) { - assert(!thread->in_critical(), "shouldn't currently be in a critical region"); - MonitorLocker ml(JNICritical_lock); - // Block entering threads if there's a pending GC request. - if (needs_gc()) { - log_debug_jni("Blocking thread as there is a pending GC request"); - GCLockerTimingDebugLogger logger("Thread blocked to enter critical region."); - while (needs_gc()) { - // There's at least one thread that has not left the critical region (CR) - // completely. When that last thread (no new threads can enter CR due to the - // blocking) exits CR, it calls `jni_unlock`, which sets `_needs_gc` - // to false and wakes up all blocked threads. - // We would like to assert #threads in CR to be > 0, `_jni_lock_count > 0` - // in the code, but it's too strong; it's possible that the last thread - // has called `jni_unlock`, but not yet finished the call, e.g. initiating - // a GCCause::_gc_locker GC. - ml.wait(); - } - } - thread->enter_critical(); - _jni_lock_count++; - increment_debug_jni_lock_count(); -} - -void GCLocker::jni_unlock(JavaThread* thread) { - assert(thread->in_last_critical(), "should be exiting critical region"); - MutexLocker mu(JNICritical_lock); - _jni_lock_count--; - decrement_debug_jni_lock_count(); - log_debug_jni("Thread exiting critical region."); - thread->exit_critical(); - if (needs_gc() && !is_active_internal()) { - // We're the last thread out. Request a GC. - // Capture the current total collections, to allow detection of - // other collections that make this one unnecessary. The value of - // total_collections() is only changed at a safepoint, so there - // must not be a safepoint between the lock becoming inactive and - // getting the count, else there may be unnecessary GCLocker GCs. - _total_collections = Universe::heap()->total_collections(); - GCLockerTracer::report_gc_locker(); + GCLockerTimingDebugLogger logger("Thread blocked to enter critical region."); + while (true) { { - // Must give up the lock while at a safepoint - MutexUnlocker munlock(JNICritical_lock); - log_debug_jni("Last thread exiting. Performing GC after exiting critical section."); - Universe::heap()->collect(GCCause::_gc_locker); + // There is a pending gc request and _lock is locked. Wait for the + // completion of a gc. It's enough to do an empty locker section. + MutexLocker locker(_lock); } - _needs_gc = false; - JNICritical_lock->notify_all(); + + current_thread->enter_critical(); + + // Same as fast path. + OrderAccess::fence(); + + if (!Atomic::load(&_is_gc_request_pending)) { + return; + } + + current_thread->exit_critical(); } } diff --git a/src/hotspot/share/gc/shared/gcLocker.hpp b/src/hotspot/share/gc/shared/gcLocker.hpp index e567d0c1f16..33d10f0eecd 100644 --- a/src/hotspot/share/gc/shared/gcLocker.hpp +++ b/src/hotspot/share/gc/shared/gcLocker.hpp @@ -27,126 +27,43 @@ #include "gc/shared/gcCause.hpp" #include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" +#include "runtime/mutex.hpp" -class JavaThread; - -// The direct lock/unlock calls do not force a collection if an unlock -// decrements the count to zero. Avoid calling these if at all possible. +// GCLocker provides synchronization between the garbage collector (GC) and +// threads using JNI critical APIs. When threads enter a critical region (CR), +// certain GC implementations may suspend garbage collection until all such +// threads have exited. +// +// Threads that need to trigger a GC should use the `block()` and `unblock()` +// APIs. `block()` will block the caller and prevent new threads from entering +// the CR. +// +// Threads entering or exiting a CR must call the `enter` and `exit` APIs to +// ensure proper synchronization with the GC. class GCLocker: public AllStatic { - private: - // The _jni_lock_count keeps track of the number of threads that are - // currently in a critical region. It's only kept up to date when - // _needs_gc is true. The current value is computed during - // safepointing and decremented during the slow path of GCLocker - // unlocking. - static volatile jint _jni_lock_count; // number of jni active instances. - static volatile bool _needs_gc; // heap is filling, we need a GC - static uint _total_collections; // value for _gc_locker collection + static Monitor* _lock; + static volatile bool _is_gc_request_pending; #ifdef ASSERT - // This lock count is updated for all operations and is used to - // validate the jni_lock_count that is computed during safepoints. - static volatile jint _debug_jni_lock_count; + // Debug-only: to track the number of java threads in critical-region. + static uint64_t _verify_in_cr_count; #endif + static void enter_slow(JavaThread* current_thread); - // At a safepoint, visit all threads and count the number of active - // critical sections. This is used to ensure that all active - // critical sections are exited before a new one is started. - static void verify_critical_count() NOT_DEBUG_RETURN; +public: + static void initialize(); - static void jni_lock(JavaThread* thread); - static void jni_unlock(JavaThread* thread); + // To query current GCLocker state. Can become outdated if called outside a safepoint. + static bool is_active(); - static bool is_active_internal() { - verify_critical_count(); - return _jni_lock_count > 0; - } + // For use by Java threads requesting GC. + static void block(); + static void unblock(); - static void log_debug_jni(const char* msg); - - static bool is_at_safepoint(); - - public: - // Accessors - static bool is_active() { - assert(GCLocker::is_at_safepoint(), "only read at safepoint"); - return is_active_internal(); - } - static bool needs_gc() { return _needs_gc; } - - // Shorthand - static bool is_active_and_needs_gc() { - // Use is_active_internal since _needs_gc can change from true to - // false outside of a safepoint, triggering the assert in - // is_active. - return needs_gc() && is_active_internal(); - } - - // In debug mode track the locking state at all times - static void increment_debug_jni_lock_count() NOT_DEBUG_RETURN; - static void decrement_debug_jni_lock_count() NOT_DEBUG_RETURN; - - // Set the current lock count - static void set_jni_lock_count(int count) { - _jni_lock_count = count; - verify_critical_count(); - } - - // Sets _needs_gc if is_active() is true. Returns is_active(). - static bool check_active_before_gc(); - - // Return true if the designated collection is a GCLocker request - // that should be discarded. Returns true if cause == GCCause::_gc_locker - // and the given total collection value indicates a collection has been - // done since the GCLocker request was made. - static bool should_discard(GCCause::Cause cause, uint total_collections); - - // Stalls the caller (who should not be in a jni critical section) - // until needs_gc() clears. Note however that needs_gc() may be - // set at a subsequent safepoint and/or cleared under the - // JNICritical_lock, so the caller may not safely assert upon - // return from this method that "!needs_gc()" since that is - // not a stable predicate. - static void stall_until_clear(); - - // The following two methods are used for JNI critical regions. - // If we find that we failed to perform a GC because the GCLocker - // was active, arrange for one as soon as possible by allowing - // all threads in critical regions to complete, but not allowing - // other critical regions to be entered. The reasons for that are: - // 1) a GC request won't be starved by overlapping JNI critical - // region activities, which can cause unnecessary OutOfMemory errors. - // 2) even if allocation requests can still be satisfied before GC locker - // becomes inactive, for example, in tenured generation possibly with - // heap expansion, those allocations can trigger lots of safepointing - // attempts (ineffective GC attempts) and require Heap_lock which - // slow down allocations tremendously. - // - // Note that critical regions can be nested in a single thread, so - // we must allow threads already in critical regions to continue. - // - // JNI critical regions are the only participants in this scheme - // because they are, by spec, well bounded while in a critical region. - // - // Each of the following two method is split into a fast path and a - // slow path. JNICritical_lock is only grabbed in the slow path. - // _needs_gc is initially false and every java thread will go - // through the fast path, which simply increments or decrements the - // current thread's critical count. When GC happens at a safepoint, - // GCLocker::is_active() is checked. Since there is no safepoint in - // the fast path of lock_critical() and unlock_critical(), there is - // no race condition between the fast path and GC. After _needs_gc - // is set at a safepoint, every thread will go through the slow path - // after the safepoint. Since after a safepoint, each of the - // following two methods is either entered from the method entry and - // falls into the slow path, or is resumed from the safepoints in - // the method, which only exist in the slow path. So when _needs_gc - // is set, the slow path is always taken, till _needs_gc is cleared. - inline static void lock_critical(JavaThread* thread); - inline static void unlock_critical(JavaThread* thread); + // For use by Java threads entering/leaving critical-region. + inline static void enter(JavaThread* current_thread); + inline static void exit(JavaThread* current_thread); }; #endif // SHARE_GC_SHARED_GCLOCKER_HPP diff --git a/src/hotspot/share/gc/shared/gcLocker.inline.hpp b/src/hotspot/share/gc/shared/gcLocker.inline.hpp index 82cc4bb5442..357b788ce52 100644 --- a/src/hotspot/share/gc/shared/gcLocker.inline.hpp +++ b/src/hotspot/share/gc/shared/gcLocker.inline.hpp @@ -29,30 +29,39 @@ #include "runtime/javaThread.inline.hpp" -void GCLocker::lock_critical(JavaThread* thread) { - if (!thread->in_critical()) { - if (needs_gc()) { - // jni_lock call calls enter_critical under the lock so that the - // global lock count and per thread count are in agreement. - jni_lock(thread); - return; +void GCLocker::enter(JavaThread* current_thread) { + assert(current_thread == JavaThread::current(), "Must be this thread"); + + if (!current_thread->in_critical()) { + current_thread->enter_critical(); + + // Matching the fence in GCLocker::block. + OrderAccess::fence(); + + if (Atomic::load(&_is_gc_request_pending)) { + current_thread->exit_critical(); + // slow-path + enter_slow(current_thread); } - increment_debug_jni_lock_count(); + + DEBUG_ONLY(Atomic::add(&_verify_in_cr_count, (uint64_t)1);) + } else { + current_thread->enter_critical(); } - thread->enter_critical(); } -void GCLocker::unlock_critical(JavaThread* thread) { - if (thread->in_last_critical()) { - if (needs_gc()) { - // jni_unlock call calls exit_critical under the lock so that - // the global lock count and per thread count are in agreement. - jni_unlock(thread); - return; - } - decrement_debug_jni_lock_count(); +void GCLocker::exit(JavaThread* current_thread) { + assert(current_thread == JavaThread::current(), "Must be this thread"); + +#ifdef ASSERT + if (current_thread->in_last_critical()) { + Atomic::add(&_verify_in_cr_count, (uint64_t)-1); + // Matching the loadload in GCLocker::block. + OrderAccess::storestore(); } - thread->exit_critical(); +#endif + + current_thread->exit_critical(); } #endif // SHARE_GC_SHARED_GCLOCKER_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 9c747e139df..6a47e54090f 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -212,19 +212,4 @@ class DefNewTracer : public YoungGCTracer, public CHeapObj { DefNewTracer() : YoungGCTracer(DefNew) {} }; -class GCLockerTracer : public AllStatic { -#if INCLUDE_JFR -private: - static Ticks _needs_gc_start_timestamp; - static volatile jint _jni_lock_count; - static volatile jint _stall_count; -#endif - - static bool is_started() NOT_JFR_RETURN_(false); - -public: - static void start_gc_locker(jint jni_lock_count) NOT_JFR_RETURN(); - static void inc_stall_count() NOT_JFR_RETURN(); - static void report_gc_locker() NOT_JFR_RETURN(); -}; #endif // SHARE_GC_SHARED_GCTRACE_HPP diff --git a/src/hotspot/share/gc/shared/gcTraceSend.cpp b/src/hotspot/share/gc/shared/gcTraceSend.cpp index 14e64e110b7..e244930079f 100644 --- a/src/hotspot/share/gc/shared/gcTraceSend.cpp +++ b/src/hotspot/share/gc/shared/gcTraceSend.cpp @@ -358,49 +358,3 @@ void GCTracer::send_phase_events(TimePartitions* time_partitions) const { phase->accept(&phase_reporter); } } - -#if INCLUDE_JFR -Ticks GCLockerTracer::_needs_gc_start_timestamp; -volatile jint GCLockerTracer::_jni_lock_count = 0; -volatile jint GCLockerTracer::_stall_count = 0; - -bool GCLockerTracer::is_started() { - return _needs_gc_start_timestamp != Ticks(); -} - -void GCLockerTracer::start_gc_locker(const jint jni_lock_count) { - assert(SafepointSynchronize::is_at_safepoint(), "sanity"); - assert(!is_started(), "sanity"); - assert(_jni_lock_count == 0, "sanity"); - assert(_stall_count == 0, "sanity"); - if (EventGCLocker::is_enabled()) { - _needs_gc_start_timestamp.stamp(); - _jni_lock_count = jni_lock_count; - } -} - -void GCLockerTracer::inc_stall_count() { - if (is_started()) { - _stall_count++; - } -} - -void GCLockerTracer::report_gc_locker() { - if (is_started()) { - EventGCLocker event(UNTIMED); - if (event.should_commit()) { - event.set_starttime(_needs_gc_start_timestamp); - event.set_endtime(_needs_gc_start_timestamp); - event.set_lockCount(_jni_lock_count); - event.set_stallCount(_stall_count); - event.commit(); - } - // reset - _needs_gc_start_timestamp = Ticks(); - _jni_lock_count = 0; - _stall_count = 0; - - assert(!is_started(), "sanity"); - } -} -#endif diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 85c452a6f89..b28007962d3 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -85,19 +85,11 @@ void VM_GC_Operation::notify_gc_end() { // Allocations may fail in several threads at about the same time, // resulting in multiple gc requests. We only want to do one of them. -// In case a GC locker is active and the need for a GC is already signaled, -// we want to skip this GC attempt altogether, without doing a futile -// safepoint operation. bool VM_GC_Operation::skip_operation() const { bool skip = (_gc_count_before != Universe::heap()->total_collections()); if (_full && skip) { skip = (_full_gc_count_before != Universe::heap()->total_full_collections()); } - if (!skip && GCLocker::is_active_and_needs_gc()) { - skip = Universe::heap()->is_maximal_no_gc(); - assert(!(skip && (_gc_cause == GCCause::_gc_locker)), - "GCLocker cannot be active when initiating GC"); - } return skip; } @@ -122,6 +114,9 @@ bool VM_GC_Operation::doit_prologue() { Heap_lock->unlock(); _prologue_succeeded = false; } else { + if (UseSerialGC || UseParallelGC) { + GCLocker::block(); + } _prologue_succeeded = true; } return _prologue_succeeded; @@ -129,6 +124,9 @@ bool VM_GC_Operation::doit_prologue() { void VM_GC_Operation::doit_epilogue() { + if (UseSerialGC || UseParallelGC) { + GCLocker::unblock(); + } // GC thread root traversal likely used OopMapCache a lot, which // might have created lots of old entries. Trigger the cleanup now. OopMapCache::try_trigger_cleanup(); @@ -259,10 +257,6 @@ void VM_CollectForMetadataAllocation::doit() { } log_debug(gc)("After Metaspace GC failed to allocate size %zu", _size); - - if (GCLocker::is_active_and_needs_gc()) { - set_gc_locked(); - } } VM_CollectForAllocation::VM_CollectForAllocation(size_t word_size, uint gc_count_before, GCCause::Cause cause) diff --git a/src/hotspot/share/gc/shared/gcVMOperations.hpp b/src/hotspot/share/gc/shared/gcVMOperations.hpp index e9281198fdf..5893986a70d 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.hpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.hpp @@ -108,7 +108,6 @@ class VM_GC_Operation: public VM_GC_Sync_Operation { bool _full; // whether a "full" collection bool _prologue_succeeded; // whether doit_prologue succeeded GCCause::Cause _gc_cause; // the putative cause for this gc op - bool _gc_locked; // will be set if gc was locked virtual bool skip_operation() const; @@ -123,8 +122,6 @@ class VM_GC_Operation: public VM_GC_Sync_Operation { _gc_cause = _cause; - _gc_locked = false; - _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 @@ -148,9 +145,6 @@ class VM_GC_Operation: public VM_GC_Sync_Operation { virtual bool allow_nested_vm_operations() const { return true; } bool prologue_succeeded() const { return _prologue_succeeded; } - void set_gc_locked() { _gc_locked = true; } - bool gc_locked() const { return _gc_locked; } - static void notify_gc_begin(bool full = false); static void notify_gc_end(); }; diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 9086c25ee48..ba29daf2fe1 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -155,11 +155,6 @@ "A System.gc() request invokes a concurrent collection; " \ "(effective only when using concurrent collectors)") \ \ - product(uintx, GCLockerRetryAllocationCount, 2, DIAGNOSTIC, \ - "Number of times to retry allocations when " \ - "blocked by the GC locker") \ - range(0, max_uintx) \ - \ product(uint, ParallelGCBufferWastePct, 10, \ "Wasted fraction of parallel allocation buffer") \ range(0, 100) \ diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index a9eed63f9aa..a4b9bc78900 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1241,11 +1241,6 @@ - - - - - diff --git a/src/hotspot/share/prims/downcallLinker.cpp b/src/hotspot/share/prims/downcallLinker.cpp index 3d9095f8e13..64861439817 100644 --- a/src/hotspot/share/prims/downcallLinker.cpp +++ b/src/hotspot/share/prims/downcallLinker.cpp @@ -22,7 +22,6 @@ */ #include "downcallLinker.hpp" -#include "gc/shared/gcLocker.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 6de84520278..517808a115f 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -40,7 +40,6 @@ #include "classfile/vmSymbols.hpp" #include "compiler/compiler_globals.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "interpreter/linkResolver.hpp" #include "jni.h" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a612a3d55a9..dd5a23f9209 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -45,7 +45,6 @@ #include "compiler/methodMatcher.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/gcConfig.hpp" -#include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/genArguments.hpp" #include "jvm.h" #include "jvmtifiles/jvmtiEnv.hpp" @@ -2649,14 +2648,6 @@ WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o)) return info_string; WB_END -WB_ENTRY(void, WB_LockCritical(JNIEnv* env, jobject wb)) - GCLocker::lock_critical(thread); -WB_END - -WB_ENTRY(void, WB_UnlockCritical(JNIEnv* env, jobject wb)) - GCLocker::unlock_critical(thread); -WB_END - WB_ENTRY(void, WB_PinObject(JNIEnv* env, jobject wb, jobject o)) #if INCLUDE_G1GC if (!UseG1GC) { @@ -2997,8 +2988,6 @@ static JNINativeMethod methods[] = { {CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe}, {CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName}, - {CC"lockCritical", CC"()V", (void*)&WB_LockCritical}, - {CC"unlockCritical", CC"()V", (void*)&WB_UnlockCritical}, {CC"pinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_PinObject}, {CC"unpinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_UnpinObject}, {CC"setVirtualThreadsNotifyJvmtiMode", CC"(Z)Z", (void*)&WB_SetVirtualThreadsNotifyJvmtiMode}, diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 9ae8ae151e7..06dd6d31ea9 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -935,6 +935,9 @@ private: assert(_jni_active_critical >= 0, "JNI critical nesting problem?"); } + // Atomic version; invoked by a thread other than the owning thread. + bool in_critical_atomic() { return Atomic::load(&_jni_active_critical) > 0; } + // Checked JNI: is the programmer required to check for exceptions, if so specify // which function name. Returning to a Java frame should implicitly clear the // pending check, this is done for Native->Java transitions (i.e. user JNI code). diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 0586009f3b8..2733cbcb14c 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -46,7 +46,6 @@ Mutex* CompiledIC_lock = nullptr; Mutex* VMStatistic_lock = nullptr; Mutex* JmethodIdCreation_lock = nullptr; Mutex* JfieldIdCreation_lock = nullptr; -Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; Monitor* JvmtiVTMSTransition_lock = nullptr; @@ -339,7 +338,6 @@ void mutex_init() { #endif MUTEX_DEFL(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock); MUTEX_DEFL(SystemDictionary_lock , PaddedMonitor, Module_lock); - MUTEX_DEFL(JNICritical_lock , PaddedMonitor, AdapterHandlerLibrary_lock); // used for JNI critical regions #if INCLUDE_JVMCI // JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 598612df8f1..aa8850b8b63 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -44,7 +44,6 @@ extern Mutex* CompiledIC_lock; // a lock used to guard compile extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers -extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 495921877d8..e6f3b84945b 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -408,9 +408,6 @@ void SafepointSynchronize::begin() { } #endif // ASSERT - // Update the count of active JNI critical regions - GCLocker::set_jni_lock_count(_current_jni_active_count); - post_safepoint_synchronize_event(sync_event, _safepoint_id, initial_running, diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 53bff3bc7ad..2f29ce9b1fc 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -37,7 +37,6 @@ #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/gcLocker.inline.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "jvm.h" diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java index b301f774390..20fbb2128f0 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java @@ -32,7 +32,6 @@ public enum GCCause { _scavenge_alot ("ScavengeAlot"), _allocation_profiler ("Allocation Profiler"), _jvmti_force_gc ("JvmtiEnv ForceGarbageCollection"), - _gc_locker ("GCLocker Initiated GC"), _heap_inspection ("Heap Inspection Initiated GC"), _heap_dump ("Heap Dump Initiated GC"), _wb_young_gc ("WhiteBox Initiated Young GC"), diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 57016a9bdd0..231ecc494a9 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -898,12 +898,6 @@ 5 s - - true - 1 s - true - - true endChunk diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 1df3af7475f..e7996689354 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -898,12 +898,6 @@ 5 s - - true - 100 ms - true - - true endChunk diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index e8656a74f4b..f9ad5dbd1de 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -96,7 +96,6 @@ gc/TestAlwaysPreTouchBehavior.java#Shenandoah 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#G1 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#Z 8334513 generic-all gc/TestAlwaysPreTouchBehavior.java#Epsilon 8334513 generic-all -gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all gc/shenandoah/oom/TestAllocOutOfMemory.java#large 8344312 linux-ppc64le gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all @@ -170,8 +169,6 @@ vmTestbase/nsk/jvmti/AttachOnDemand/attach045/TestDescription.java 8202971 gener vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 8073470 linux-all vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all -vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all - vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java deleted file mode 100644 index 4560d9477c1..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2019, 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 gc.stress.gclocker; - -/* - * @test TestExcessGCLockerCollections - * @bug 8048556 - * @summary Check for GC Locker initiated GCs that immediately follow another - * GC and so have very little needing to be collected. - * @requires vm.gc != "Z" - * @requires vm.gc != "Epsilon" - * @requires vm.gc != "Shenandoah" - * @requires vm.gc != "G1" - * @requires vm.gc != null - * @library /test/lib - * @modules java.base/jdk.internal.misc - * @run driver/timeout=1000 gc.stress.gclocker.TestExcessGCLockerCollections 300 4 2 - */ - -import java.util.HashMap; -import java.util.Map; - -import java.util.zip.Deflater; - -import java.util.ArrayList; -import java.util.Arrays; - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - -class TestExcessGCLockerCollectionsAux { - static private final int LARGE_MAP_SIZE = 64 * 1024; - - static private final int MAP_ARRAY_LENGTH = 4; - static private final int MAP_SIZE = 1024; - - static private final int BYTE_ARRAY_LENGTH = 128 * 1024; - - static private void println(String str) { System.out.println(str); } - - static private volatile boolean keepRunning = true; - - static Map populateMap(int size) { - Map map = new HashMap(); - for (int i = 0; i < size; i += 1) { - Integer keyInt = Integer.valueOf(i); - String valStr = "value is [" + i + "]"; - map.put(keyInt,valStr); - } - return map; - } - - static private class AllocatingWorker implements Runnable { - private final Object[] array = new Object[MAP_ARRAY_LENGTH]; - private int arrayIndex = 0; - - private void doStep() { - Map map = populateMap(MAP_SIZE); - array[arrayIndex] = map; - arrayIndex = (arrayIndex + 1) % MAP_ARRAY_LENGTH; - } - - public void run() { - while (keepRunning) { - doStep(); - } - } - } - - static private class JNICriticalWorker implements Runnable { - private int count; - - private void doStep() { - byte[] inputArray = new byte[BYTE_ARRAY_LENGTH]; - for (int i = 0; i < inputArray.length; i += 1) { - inputArray[i] = (byte) (count + i); - } - - Deflater deflater = new Deflater(); - deflater.setInput(inputArray); - deflater.finish(); - - byte[] outputArray = new byte[2 * inputArray.length]; - deflater.deflate(outputArray); - - count += 1; - } - - public void run() { - while (keepRunning) { - doStep(); - } - } - } - - static public Map largeMap; - - static public void main(String args[]) { - long durationSec = Long.parseLong(args[0]); - int allocThreadNum = Integer.parseInt(args[1]); - int jniCriticalThreadNum = Integer.parseInt(args[2]); - - println("Running for " + durationSec + " secs"); - - largeMap = populateMap(LARGE_MAP_SIZE); - - println("Starting " + allocThreadNum + " allocating threads"); - for (int i = 0; i < allocThreadNum; i += 1) { - new Thread(new AllocatingWorker()).start(); - } - - println("Starting " + jniCriticalThreadNum + " jni critical threads"); - for (int i = 0; i < jniCriticalThreadNum; i += 1) { - new Thread(new JNICriticalWorker()).start(); - } - - try { - Thread.sleep(durationSec * 1000L); - } catch (InterruptedException e) { - throw new RuntimeException("Test Failure, did not expect an InterruptedException", e); - } - - println("Done."); - keepRunning = false; - } -} - -public class TestExcessGCLockerCollections { - private static final String locker = - "\\[gc\\s*\\] .* \\(GCLocker Initiated GC\\)"; - private static final String ANY_LOCKER = locker + " [1-9][0-9]*M"; - private static final String BAD_LOCKER = locker + " [1-9][0-9]?M"; - - private static final String[] COMMON_OPTIONS = new String[] { - "-Xmx1G", "-Xms1G", "-Xmn256M", "-Xlog:gc,gc+ergo*=debug,gc+ergo+cset=trace:x.log", "-XX:+UnlockDiagnosticVMOptions", "-XX:+VerifyAfterGC"}; - - public static void main(String args[]) throws Exception { - if (args.length < 3) { - System.out.println("usage: TestExcessGCLockerCollectionsAux" + - " " + - " "); - throw new RuntimeException("Invalid arguments"); - } - - ArrayList finalArgs = new ArrayList(); - finalArgs.addAll(Arrays.asList(COMMON_OPTIONS)); - finalArgs.add(TestExcessGCLockerCollectionsAux.class.getName()); - finalArgs.addAll(Arrays.asList(args)); - - // GC and other options obtained from test framework. - OutputAnalyzer output = ProcessTools.executeTestJava(finalArgs); - output.shouldHaveExitValue(0); - //System.out.println("------------- begin stdout ----------------"); - //System.out.println(output.getStdout()); - //System.out.println("------------- end stdout ----------------"); - output.stdoutShouldMatch(ANY_LOCKER); - output.stdoutShouldNotMatch(BAD_LOCKER); - } -} diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java index 785d761f4ee..0e27caf610d 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java @@ -39,8 +39,7 @@ public class TestGCCauseWithParallelOld { String testID = "ParallelOld"; String[] vmFlags = {"-XX:+UseParallelGC"}; String[] gcNames = {GCHelper.gcParallelScavenge, GCHelper.gcParallelOld}; - String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC", - "CodeCache GC Threshold"}; + String[] gcCauses = {"Allocation Failure", "System.gc()", "CodeCache GC Threshold"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java index f8f95070c1c..7701fd36853 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java @@ -39,8 +39,7 @@ public class TestGCCauseWithSerial { String testID = "Serial"; String[] vmFlags = {"-XX:+UseSerialGC"}; String[] gcNames = {GCHelper.gcDefNew, GCHelper.gcSerialOld}; - String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC", - "CodeCache GC Threshold"}; + String[] gcCauses = {"Allocation Failure", "System.gc()", "CodeCache GC Threshold"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java deleted file mode 100644 index 1ad0fbd86b8..00000000000 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2021, Alibaba Group Holding Limited. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 TestGCLockerEvent - * @requires vm.flagless - * @requires vm.hasJFR - * @requires vm.gc.Serial | vm.gc.Parallel - * @requires vm.gc != null - * @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 -Xmx32m -Xms32m -Xmn12m jdk.jfr.event.gc.detailed.TestGCLockerEvent - */ - -package jdk.jfr.event.gc.detailed; - -import static jdk.test.lib.Asserts.assertTrue; - -import java.util.concurrent.CountDownLatch; - -import jdk.jfr.Recording; -import jdk.jfr.consumer.RecordedEvent; -import jdk.test.lib.jfr.EventNames; -import jdk.test.lib.jfr.Events; - -import jdk.test.whitebox.WhiteBox; - -public class TestGCLockerEvent { - - private static final String EVENT_NAME = EventNames.GCLocker; - - private static final int CRITICAL_THREAD_COUNT = 4; - - private static final CountDownLatch LOCK_COUNT_SIGNAL = new CountDownLatch(CRITICAL_THREAD_COUNT); - - private static final CountDownLatch UNLOCK_SIGNAL = new CountDownLatch(1); - - private static final CountDownLatch UNLOCK_COUNT_SIGNAL = new CountDownLatch(CRITICAL_THREAD_COUNT); - - private static final String CRITICAL_THREAD_NAME_PREFIX = "Critical Thread "; - - private static final int STALL_THREAD_COUNT = 8; - - private static final CountDownLatch STALL_COUNT_SIGNAL = new CountDownLatch(STALL_THREAD_COUNT); - - private static final int LOOP = 32; - - private static final int M = 1024 * 1024; - - public static void main(String[] args) throws Exception { - var recording = new Recording(); - recording.enable(EVENT_NAME); - recording.start(); - - startCriticalThreads(); - LOCK_COUNT_SIGNAL.await(); - startStallThreads(); - STALL_COUNT_SIGNAL.await(); - - // Wait threads to be stalled - Thread.sleep(1500); - - UNLOCK_SIGNAL.countDown(); - UNLOCK_COUNT_SIGNAL.await(); - recording.stop(); - - // Verify recording - var all = Events.fromRecording(recording); - Events.hasEvents(all); - var event = all.getFirst(); - - assertTrue(Events.isEventType(event, EVENT_NAME)); - Events.assertField(event, "lockCount").equal(CRITICAL_THREAD_COUNT); - Events.assertField(event, "stallCount").atLeast(STALL_THREAD_COUNT); - assertTrue(event.getThread().getJavaName().startsWith(CRITICAL_THREAD_NAME_PREFIX)); - - recording.close(); - } - - private static void startCriticalThreads() { - for (var i = 0; i < CRITICAL_THREAD_COUNT; i++) { - new Thread(() -> { - try { - WhiteBox.getWhiteBox().lockCritical(); - LOCK_COUNT_SIGNAL.countDown(); - - UNLOCK_SIGNAL.await(); - WhiteBox.getWhiteBox().unlockCritical(); - UNLOCK_COUNT_SIGNAL.countDown(); - } catch (InterruptedException ex) { - } - }, CRITICAL_THREAD_NAME_PREFIX + i).start(); - } - } - - private static void startStallThreads() { - var ts = new Thread[STALL_THREAD_COUNT]; - for (var i = 0; i < STALL_THREAD_COUNT; i++) { - ts[i] = new Thread(() -> { - STALL_COUNT_SIGNAL.countDown(); - for (int j = 0; j < LOOP; j++) { - byte[] bytes = new byte[M]; - } - }); - } - for (Thread t : ts) { - t.start(); - } - } -} - diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 77fe554c9ba..0ef1b5e6d3f 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -151,7 +151,6 @@ public class EventNames { public static final String ZRelocationSetGroup = PREFIX + "ZRelocationSetGroup"; public static final String ZUncommit = PREFIX + "ZUncommit"; public static final String ZUnmap = PREFIX + "ZUnmap"; - public static final String GCLocker = PREFIX + "GCLocker"; public static final String SystemGC = PREFIX + "SystemGC"; public static final String GCCPUTime = PREFIX + "GCCPUTime"; diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 7222c6fedcf..be9bc646ce4 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -786,10 +786,6 @@ public class WhiteBox { public native void waitUnsafe(int time_ms); - public native void lockCritical(); - - public native void unlockCritical(); - public native void pinObject(Object o); public native void unpinObject(Object o); From c413549eb775f4209416c718dc9aa0748144a6b4 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 25 Feb 2025 12:35:54 +0000 Subject: [PATCH 109/587] 8349860: Make Class.isArray(), Class.isInterface() and Class.isPrimitive() non-native Reviewed-by: dlong, rriggs, vlivanov, yzheng, liach --- src/hotspot/share/c1/c1_Canonicalizer.cpp | 11 ----- src/hotspot/share/c1/c1_Compiler.cpp | 1 - src/hotspot/share/c1/c1_LIRGenerator.cpp | 20 --------- src/hotspot/share/c1/c1_LIRGenerator.hpp | 1 - src/hotspot/share/classfile/javaClasses.cpp | 31 ++++++++----- src/hotspot/share/classfile/javaClasses.hpp | 4 +- .../share/classfile/javaClasses.inline.hpp | 8 ++-- src/hotspot/share/classfile/vmIntrinsics.cpp | 3 -- src/hotspot/share/classfile/vmIntrinsics.hpp | 6 --- src/hotspot/share/include/jvm.h | 12 ----- src/hotspot/share/opto/c2compiler.cpp | 3 -- src/hotspot/share/opto/library_call.cpp | 36 --------------- src/hotspot/share/prims/jvm.cpp | 44 +++++++------------ .../share/classes/java/lang/Class.java | 33 +++++++------- .../jdk/internal/reflect/Reflection.java | 2 +- src/java.base/share/native/libjava/Class.c | 3 -- .../ci/runtime/test/TestResolvedJavaType.java | 10 +++-- .../ModuleSetAccessibleTest.java | 2 +- .../TrySetAccessibleTest.java | 2 +- .../reflect/Reflection/Filtering.java | 1 + 20 files changed, 74 insertions(+), 159 deletions(-) diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index 15b21029b68..f5a1d14e694 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -536,17 +536,6 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) { } break; } - case vmIntrinsics::_isPrimitive : { - assert(x->number_of_arguments() == 1, "wrong type"); - - // Class.isPrimitive is known on constant classes: - InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant(); - if (c != nullptr && !c->value()->is_null_object()) { - ciType* t = c->value()->java_mirror_type(); - set_constant(t->is_primitive_type()); - } - break; - } default: break; } diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index a26320589c4..eb7c42e4576 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -155,7 +155,6 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_longBitsToDouble: case vmIntrinsics::_getClass: case vmIntrinsics::_isInstance: - case vmIntrinsics::_isPrimitive: case vmIntrinsics::_currentCarrierThread: case vmIntrinsics::_currentThread: case vmIntrinsics::_scopedValueCache: diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 325b8d193ea..959e49749c5 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1278,25 +1278,6 @@ void LIRGenerator::do_getClass(Intrinsic* x) { LIR_OprFact::address(new LIR_Address(temp, T_OBJECT)), result); } -// java.lang.Class::isPrimitive() -void LIRGenerator::do_isPrimitive(Intrinsic* x) { - assert(x->number_of_arguments() == 1, "wrong type"); - - LIRItem rcvr(x->argument_at(0), this); - rcvr.load_item(); - LIR_Opr temp = new_register(T_METADATA); - LIR_Opr result = rlock_result(x); - - CodeEmitInfo* info = nullptr; - if (x->needs_null_check()) { - info = state_for(x); - } - - __ move(new LIR_Address(rcvr.result(), java_lang_Class::klass_offset(), T_ADDRESS), temp, info); - __ cmp(lir_cond_notEqual, temp, LIR_OprFact::metadataConst(nullptr)); - __ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN); -} - void LIRGenerator::do_getObjectSize(Intrinsic* x) { assert(x->number_of_arguments() == 3, "wrong type"); LIR_Opr result_reg = rlock_result(x); @@ -2914,7 +2895,6 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break; case vmIntrinsics::_isInstance: do_isInstance(x); break; - case vmIntrinsics::_isPrimitive: do_isPrimitive(x); break; case vmIntrinsics::_getClass: do_getClass(x); break; case vmIntrinsics::_getObjectSize: do_getObjectSize(x); break; case vmIntrinsics::_currentCarrierThread: do_currentCarrierThread(x); break; diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index 18997e2dd1a..73bd883a746 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -254,7 +254,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_RegisterFinalizer(Intrinsic* x); void do_isInstance(Intrinsic* x); - void do_isPrimitive(Intrinsic* x); void do_getClass(Intrinsic* x); void do_getObjectSize(Intrinsic* x); void do_currentCarrierThread(Intrinsic* x); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index d6d1f799253..a224ef481b0 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -868,6 +868,7 @@ int java_lang_Class::_classData_offset; int java_lang_Class::_classRedefinedCount_offset; int java_lang_Class::_reflectionData_offset; int java_lang_Class::_modifiers_offset; +int java_lang_Class::_is_primitive_offset; bool java_lang_Class::_offsets_computed = false; GrowableArray* java_lang_Class::_fixup_mirror_list = nullptr; @@ -1062,7 +1063,7 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti set_klass(mirror(), k); // Set the modifiers flag. - int computed_modifiers = k->compute_modifier_flags(); + u2 computed_modifiers = k->compute_modifier_flags(); set_modifiers(mirror(), computed_modifiers); InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); @@ -1272,8 +1273,11 @@ void java_lang_Class::set_protection_domain(oop java_class, oop pd) { void java_lang_Class::set_component_mirror(oop java_class, oop comp_mirror) { assert(_component_mirror_offset != 0, "must be set"); - java_class->obj_field_put(_component_mirror_offset, comp_mirror); - } + assert(java_lang_Class::as_Klass(java_class) != nullptr && + java_lang_Class::as_Klass(java_class)->is_array_klass(), "must be"); + java_class->obj_field_put(_component_mirror_offset, comp_mirror); +} + oop java_lang_Class::component_mirror(oop java_class) { assert(_component_mirror_offset != 0, "must be set"); return java_class->obj_field(_component_mirror_offset); @@ -1347,9 +1351,14 @@ void java_lang_Class::set_source_file(oop java_class, oop source_file) { java_class->obj_field_put(_source_file_offset, source_file); } +void java_lang_Class::set_is_primitive(oop java_class) { + assert(_is_primitive_offset != 0, "must be set"); + java_class->bool_field_put(_is_primitive_offset, true); +} + + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { - // This should be improved by adding a field at the Java level or by - // introducing a new VM klass (see comment in ClassFileParser) + // Mirrors for basic types have a null klass field, which makes them special. oop java_class = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(nullptr, CHECK_NULL); if (type != T_VOID) { Klass* aklass = Universe::typeArrayKlass(type); @@ -1361,6 +1370,7 @@ oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, Basic assert(static_oop_field_count(java_class) == 0, "should have been zeroed by allocation"); #endif set_modifiers(java_class, JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); + set_is_primitive(java_class); return java_class; } @@ -1500,8 +1510,9 @@ oop java_lang_Class::primitive_mirror(BasicType t) { macro(_classData_offset, k, "classData", object_signature, false); \ macro(_reflectionData_offset, k, "reflectionData", java_lang_ref_SoftReference_signature, false); \ macro(_signers_offset, k, "signers", object_array_signature, false); \ - macro(_modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); \ - macro(_protection_domain_offset, k, "protectionDomain", java_security_ProtectionDomain_signature, false); + macro(_modifiers_offset, k, vmSymbols::modifiers_name(), char_signature, false); \ + macro(_protection_domain_offset, k, "protectionDomain", java_security_ProtectionDomain_signature, false); \ + macro(_is_primitive_offset, k, "primitive", bool_signature, false); void java_lang_Class::compute_offsets() { if (_offsets_computed) { @@ -1537,12 +1548,12 @@ void java_lang_Class::set_classRedefinedCount(oop the_class_mirror, int value) { int java_lang_Class::modifiers(oop the_class_mirror) { assert(_modifiers_offset != 0, "offsets should have been initialized"); - return the_class_mirror->int_field(_modifiers_offset); + return the_class_mirror->char_field(_modifiers_offset); } -void java_lang_Class::set_modifiers(oop the_class_mirror, int value) { +void java_lang_Class::set_modifiers(oop the_class_mirror, u2 value) { assert(_modifiers_offset != 0, "offsets should have been initialized"); - the_class_mirror->int_field_put(_modifiers_offset, value); + the_class_mirror->char_field_put(_modifiers_offset, value); } diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 43b358f6c46..37ca22e9295 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -257,6 +257,7 @@ class java_lang_Class : AllStatic { static int _classRedefinedCount_offset; static int _reflectionData_offset; static int _modifiers_offset; + static int _is_primitive_offset; static bool _offsets_computed; @@ -302,6 +303,7 @@ class java_lang_Class : AllStatic { static bool is_instance(oop obj); static bool is_primitive(oop java_class); + static void set_is_primitive(oop java_class); static BasicType primitive_type(oop java_class); static oop primitive_mirror(BasicType t); // JVM_NewArray support @@ -338,7 +340,7 @@ class java_lang_Class : AllStatic { static void set_source_file(oop java_class, oop source_file); static int modifiers(oop java_class); - static void set_modifiers(oop java_class, int value); + static void set_modifiers(oop java_class, u2 value); static size_t oop_size(oop java_class); static void set_oop_size(HeapWord* java_class, size_t size); diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index 6a698e02298..66ecca4bbea 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.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 @@ -293,11 +293,13 @@ inline Klass* java_lang_Class::as_Klass(oop java_class) { inline bool java_lang_Class::is_primitive(oop java_class) { // should assert: - //assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + // assert(java_lang_Class::is_instance(java_class), "must be a Class object"); bool is_primitive = (java_class->metadata_field(_klass_offset) == nullptr); #ifdef ASSERT - if (is_primitive) { + // The heapwalker walks through Classes that have had their Klass pointers removed, so can't assert this. + // assert(is_primitive == java_class->bool_field(_is_primitive_offset), "must match what we told Java"); + if (java_class->bool_field(_is_primitive_offset)) { Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset)); assert(k == nullptr || is_java_primitive(ArrayKlass::cast(k)->element_type()), "Should be either the T_VOID primitive or a java primitive"); diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index aaeb54f0d32..2943f9d4af3 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -256,9 +256,6 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { switch (id) { case vmIntrinsics::_isInstance: case vmIntrinsics::_isAssignableFrom: - case vmIntrinsics::_isInterface: - case vmIntrinsics::_isArray: - case vmIntrinsics::_isPrimitive: case vmIntrinsics::_isHidden: case vmIntrinsics::_getSuperclass: case vmIntrinsics::_Class_cast: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index cf68217ae2c..0c95f6ab410 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -304,12 +304,6 @@ class methodHandle; do_name( isAssignableFrom_name, "isAssignableFrom") \ do_intrinsic(_isInstance, java_lang_Class, isInstance_name, object_boolean_signature, F_RN) \ do_name( isInstance_name, "isInstance") \ - do_intrinsic(_isInterface, java_lang_Class, isInterface_name, void_boolean_signature, F_RN) \ - do_name( isInterface_name, "isInterface") \ - do_intrinsic(_isArray, java_lang_Class, isArray_name, void_boolean_signature, F_RN) \ - do_name( isArray_name, "isArray") \ - do_intrinsic(_isPrimitive, java_lang_Class, isPrimitive_name, void_boolean_signature, F_RN) \ - do_name( isPrimitive_name, "isPrimitive") \ do_intrinsic(_isHidden, java_lang_Class, isHidden_name, void_boolean_signature, F_RN) \ do_name( isHidden_name, "isHidden") \ do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \ diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index c2a1a3f53f6..c1d20387d0d 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -546,21 +546,9 @@ JVM_GetClassInterfaces(JNIEnv *env, jclass cls); JNIEXPORT jboolean JNICALL JVM_IsInterface(JNIEnv *env, jclass cls); -JNIEXPORT jobject JNICALL -JVM_GetProtectionDomain(JNIEnv *env, jclass cls); - -JNIEXPORT jboolean JNICALL -JVM_IsArrayClass(JNIEnv *env, jclass cls); - -JNIEXPORT jboolean JNICALL -JVM_IsPrimitiveClass(JNIEnv *env, jclass cls); - JNIEXPORT jboolean JNICALL JVM_IsHiddenClass(JNIEnv *env, jclass cls); -JNIEXPORT jint JNICALL -JVM_GetClassModifiers(JNIEnv *env, jclass cls); - JNIEXPORT jobjectArray JNICALL JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass); diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index c5b6d5a4895..0a769211c82 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -755,9 +755,6 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_clone: case vmIntrinsics::_isAssignableFrom: case vmIntrinsics::_isInstance: - case vmIntrinsics::_isInterface: - case vmIntrinsics::_isArray: - case vmIntrinsics::_isPrimitive: case vmIntrinsics::_isHidden: case vmIntrinsics::_getSuperclass: case vmIntrinsics::_getClassAccessFlags: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6d4990787d7..6f651db58ce 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -516,9 +516,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isAssignableFrom: return inline_native_subtype_check(); case vmIntrinsics::_isInstance: - case vmIntrinsics::_isInterface: - case vmIntrinsics::_isArray: - case vmIntrinsics::_isPrimitive: case vmIntrinsics::_isHidden: case vmIntrinsics::_getSuperclass: case vmIntrinsics::_getClassAccessFlags: return inline_native_Class_query(intrinsic_id()); @@ -3892,17 +3889,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { prim_return_value = intcon(0); obj = argument(1); break; - case vmIntrinsics::_isInterface: - prim_return_value = intcon(0); - break; - case vmIntrinsics::_isArray: - prim_return_value = intcon(0); - expect_prim = true; // cf. ObjectStreamClass.getClassSignature - break; - case vmIntrinsics::_isPrimitive: - prim_return_value = intcon(1); - expect_prim = true; // obviously - break; case vmIntrinsics::_isHidden: prim_return_value = intcon(0); break; @@ -3971,28 +3957,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { query_value = gen_instanceof(obj, kls, safe_for_replace); break; - case vmIntrinsics::_isInterface: - // (To verify this code sequence, check the asserts in JVM_IsInterface.) - if (generate_interface_guard(kls, region) != nullptr) - // A guard was added. If the guard is taken, it was an interface. - phi->add_req(intcon(1)); - // If we fall through, it's a plain class. - query_value = intcon(0); - break; - - case vmIntrinsics::_isArray: - // (To verify this code sequence, check the asserts in JVM_IsArrayClass.) - if (generate_array_guard(kls, region) != nullptr) - // A guard was added. If the guard is taken, it was an array. - phi->add_req(intcon(1)); - // If we fall through, it's a plain class. - query_value = intcon(0); - break; - - case vmIntrinsics::_isPrimitive: - query_value = intcon(0); // "normal" path produces false - break; - case vmIntrinsics::_isHidden: // (To verify this code sequence, check the asserts in JVM_IsHiddenClass.) if (generate_hidden_class_guard(kls, region) != nullptr) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 33d82045b6e..ccb15485b07 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1187,20 +1187,6 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) JVM_END -JVM_ENTRY(jboolean, JVM_IsInterface(JNIEnv *env, jclass cls)) - oop mirror = JNIHandles::resolve_non_null(cls); - if (java_lang_Class::is_primitive(mirror)) { - return JNI_FALSE; - } - Klass* k = java_lang_Class::as_Klass(mirror); - jboolean result = k->is_interface(); - assert(!result || k->is_instance_klass(), - "all interfaces are instance types"); - // The compiler intrinsic for isInterface tests the - // Klass::_access_flags bits in the same way. - return result; -JVM_END - JVM_ENTRY(jboolean, JVM_IsHiddenClass(JNIEnv *env, jclass cls)) oop mirror = JNIHandles::resolve_non_null(cls); if (java_lang_Class::is_primitive(mirror)) { @@ -1259,18 +1245,6 @@ JVM_ENTRY(jobject, JVM_FindScopedValueBindings(JNIEnv *env, jclass cls)) return nullptr; JVM_END -JVM_ENTRY(jboolean, JVM_IsArrayClass(JNIEnv *env, jclass cls)) - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); - return (k != nullptr) && k->is_array_klass() ? true : false; -JVM_END - - -JVM_ENTRY(jboolean, JVM_IsPrimitiveClass(JNIEnv *env, jclass cls)) - oop mirror = JNIHandles::resolve_non_null(cls); - return (jboolean) java_lang_Class::is_primitive(mirror); -JVM_END - - JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) JvmtiVMObjectAllocEventCollector oam; // ofClass is a reference to a java_lang_Class object. The mirror object @@ -2305,7 +2279,23 @@ JVM_END // The function returns a Klass* of the _scratch_class if the verifier // was invoked in the middle of the class redefinition. // Otherwise it returns its argument value which is the _the_class Klass*. -// Please, refer to the description in the jvmtiThreadSate.hpp. +// Please, refer to the description in the jvmtiThreadState.hpp. + +JVM_ENTRY(jboolean, JVM_IsInterface(JNIEnv *env, jclass cls)) + oop mirror = JNIHandles::resolve_non_null(cls); + if (java_lang_Class::is_primitive(mirror)) { + return JNI_FALSE; + } + Klass* k = java_lang_Class::as_Klass(mirror); + // This isn't necessary since answer is the same since redefinition + // has already checked this matches for the scratch class. + // k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread); + jboolean result = k->is_interface(); + assert(!result || k->is_instance_klass(), + "all interfaces are instance types"); + return result; +JVM_END + JVM_ENTRY(const char*, JVM_GetClassNameUTF(JNIEnv *env, jclass cls)) Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 4607858faa8..d86baaac362 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -236,13 +236,15 @@ public final class Class implements java.io.Serializable, * This constructor is not used and prevents the default constructor being * generated. */ - private Class(ClassLoader loader, Class arrayComponentType, int mods, ProtectionDomain pd) { + private Class(ClassLoader loader, Class arrayComponentType, char mods, ProtectionDomain pd, boolean isPrim) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. + // The following assignments are done directly by the VM without calling this constructor. classLoader = loader; componentType = arrayComponentType; modifiers = mods; protectionDomain = pd; + primitive = isPrim; } /** @@ -790,8 +792,9 @@ public final class Class implements java.io.Serializable, * @return {@code true} if this {@code Class} object represents an interface; * {@code false} otherwise. */ - @IntrinsicCandidate - public native boolean isInterface(); + public boolean isInterface() { + return Modifier.isInterface(modifiers); + } /** @@ -801,8 +804,9 @@ public final class Class implements java.io.Serializable, * {@code false} otherwise. * @since 1.1 */ - @IntrinsicCandidate - public native boolean isArray(); + public boolean isArray() { + return componentType != null; + } /** @@ -843,8 +847,9 @@ public final class Class implements java.io.Serializable, * @since 1.1 * @jls 15.8.2 Class Literals */ - @IntrinsicCandidate - public native boolean isPrimitive(); + public boolean isPrimitive() { + return primitive; + } /** * Returns true if this {@code Class} object represents an annotation @@ -1002,7 +1007,8 @@ public final class Class implements java.io.Serializable, private transient Object classData; // Set by VM private transient Object[] signers; // Read by VM, mutable - private final transient int modifiers; // Set by the VM + private final transient char modifiers; // Set by the VM + private final transient boolean primitive; // Set by the VM if the Class is a primitive type. // package-private Object getClassData() { @@ -1284,15 +1290,12 @@ public final class Class implements java.io.Serializable, * @since 1.1 */ public Class getComponentType() { - // Only return for array types. Storage may be reused for Class for instance types. - if (isArray()) { - return componentType; - } else { - return null; - } + return componentType; } - private final Class componentType; + // The componentType field's null value is the sole indication that the class + // is an array - see isArray(). + private transient final Class componentType; /* * Returns the {@code Class} representing the element type of an array class. diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index e1fe26684c8..5025b81dd10 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -56,7 +56,7 @@ public class Reflection { fieldFilterMap = Map.of( Reflection.class, ALL_MEMBERS, AccessibleObject.class, ALL_MEMBERS, - Class.class, Set.of("classLoader", "classData", "modifiers", "protectionDomain"), + Class.class, Set.of("classLoader", "classData", "modifiers", "protectionDomain", "primitive"), ClassLoader.class, ALL_MEMBERS, Constructor.class, ALL_MEMBERS, Field.class, ALL_MEMBERS, diff --git a/src/java.base/share/native/libjava/Class.c b/src/java.base/share/native/libjava/Class.c index 47eedaa59d9..3ab3e764bff 100644 --- a/src/java.base/share/native/libjava/Class.c +++ b/src/java.base/share/native/libjava/Class.c @@ -56,10 +56,7 @@ static JNINativeMethod methods[] = { {"initClassName", "()" STR, (void *)&JVM_InitClassName}, {"getSuperclass", "()" CLS, NULL}, {"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces}, - {"isInterface", "()Z", (void *)&JVM_IsInterface}, - {"isArray", "()Z", (void *)&JVM_IsArrayClass}, {"isHidden", "()Z", (void *)&JVM_IsHiddenClass}, - {"isPrimitive", "()Z", (void *)&JVM_IsPrimitiveClass}, {"getDeclaredFields0","(Z)[" FLD, (void *)&JVM_GetClassDeclaredFields}, {"getDeclaredMethods0","(Z)[" MHD, (void *)&JVM_GetClassDeclaredMethods}, {"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors}, diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 6450f9e1e29..52b52cf647f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -929,10 +929,12 @@ public class TestResolvedJavaType extends TypeUniverse { return true; } if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class))) { - return f.getName().equals("classLoader") || - f.getName().equals("classData") || - f.getName().equals("modifiers") || - f.getName().equals("protectionDomain"); + String name = f.getName(); + return name.equals("classLoader") || + name.equals("classData") || + name.equals("modifiers") || + name.equals("protectionDomain") || + name.equals("primitive"); } if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Lookup.class))) { return f.getName().equals("allowedModes") || f.getName().equals("lookupClass"); diff --git a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index 08db3265c94..8ee5179ea81 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -148,7 +148,7 @@ public class ModuleSetAccessibleTest { // non-public constructor Constructor ctor - = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, int.class, ProtectionDomain.class); + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, char.class, ProtectionDomain.class, boolean.class); AccessibleObject[] ctors = { ctor }; try { diff --git a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java index d08798c8757..9574afee407 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java @@ -194,7 +194,7 @@ public class TrySetAccessibleTest { // non-public constructor Constructor ctor - = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, int.class, ProtectionDomain.class); + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, char.class, ProtectionDomain.class, boolean.class); AccessibleObject[] ctors = { ctor }; assertFalse(ctor.trySetAccessible()); diff --git a/test/jdk/jdk/internal/reflect/Reflection/Filtering.java b/test/jdk/jdk/internal/reflect/Reflection/Filtering.java index c399b8ff42d..88d7e23ba59 100644 --- a/test/jdk/jdk/internal/reflect/Reflection/Filtering.java +++ b/test/jdk/jdk/internal/reflect/Reflection/Filtering.java @@ -57,6 +57,7 @@ public class Filtering { { Class.class, "classData" }, { Class.class, "modifiers" }, { Class.class, "protectionDomain" }, + { Class.class, "primitive" }, { ClassLoader.class, "parent" }, { Field.class, "clazz" }, { Field.class, "modifiers" }, From 8cfebc41dc8ec7b0d24d9c467b91de82d28b73fc Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 25 Feb 2025 12:54:30 +0000 Subject: [PATCH 110/587] 8350571: Remove mention of Tonga test suite from JMX tests Reviewed-by: cjplummer, lmesnik, sspitsyn --- .../javax/management/MBeanServer/ExceptionFactory.java | 10 +++------- .../javax/management/MBeanServer/ExceptionTest.java | 6 +----- test/jdk/javax/management/mxbean/Utils.java | 6 +----- .../management/query/SupportedQueryTypesTest.java | 6 +----- test/jdk/javax/management/security/Utils.java | 6 +----- 5 files changed, 7 insertions(+), 27 deletions(-) diff --git a/test/jdk/javax/management/MBeanServer/ExceptionFactory.java b/test/jdk/javax/management/MBeanServer/ExceptionFactory.java index 2315edff3fc..a615c5252da 100644 --- a/test/jdk/javax/management/MBeanServer/ExceptionFactory.java +++ b/test/jdk/javax/management/MBeanServer/ExceptionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, 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 @@ -67,12 +67,8 @@ import javax.management.remote.JMXProviderException; import javax.management.remote.JMXServerErrorException; /** - * |----- Original Description Coming From Tonga Original Source Code -------| - * | | - * | That class creates an ArrayList and fill it with an instance of each of | - * | the Exception class of the JMX API. | - * | It's dedicated to use by ExceptionTest. | - * |-------------------------------------------------------------------------| + * This class creates an ArrayList and fills it with an instance of each + * Exception class in the JMX API. Used by ExceptionTest. */ public class ExceptionFactory { diff --git a/test/jdk/javax/management/MBeanServer/ExceptionTest.java b/test/jdk/javax/management/MBeanServer/ExceptionTest.java index bb58e941242..d3550780f0b 100644 --- a/test/jdk/javax/management/MBeanServer/ExceptionTest.java +++ b/test/jdk/javax/management/MBeanServer/ExceptionTest.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 @@ -188,7 +188,6 @@ public class ExceptionTest { return true; } - // Utility inner class coming from JMX Tonga test suite. // Also used by ExceptionFactory. static class Utils { @@ -222,9 +221,6 @@ public class ExceptionTest { } /** - * Reproduces the original parsing and collection of test parameters - * from the DTonga JMX test suite. - * * Collects passed args and returns them in a map(argname, value) structure, * which will be then propagated as necessary to various called methods. */ diff --git a/test/jdk/javax/management/mxbean/Utils.java b/test/jdk/javax/management/mxbean/Utils.java index f77196baa2c..550f11736a1 100644 --- a/test/jdk/javax/management/mxbean/Utils.java +++ b/test/jdk/javax/management/mxbean/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, 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,6 @@ import java.util.Properties; import java.lang.reflect.Method; import javax.management.remote.JMXConnectorServerMBean; -// utility class for MXBean* tests coming from JMX Tonga test suite class Utils { // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property @@ -60,9 +59,6 @@ class Utils { } /** - * Reproduces the original parsing and collection of test parameters - * from the DTonga JMX test suite. - * * Collects passed args and returns them in a map(argname, value) structure, * which will be then propagated as necessary to various called methods. */ diff --git a/test/jdk/javax/management/query/SupportedQueryTypesTest.java b/test/jdk/javax/management/query/SupportedQueryTypesTest.java index 8c254329915..17c720d499e 100644 --- a/test/jdk/javax/management/query/SupportedQueryTypesTest.java +++ b/test/jdk/javax/management/query/SupportedQueryTypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, 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 @@ -287,7 +287,6 @@ public class SupportedQueryTypesTest { } } - // Utility inner class coming from JMX Tonga test suite. private static class Utils { // DEBUG is printed depending on the DEBUG and DEBUG_LEVEL JAVA property @@ -320,9 +319,6 @@ public class SupportedQueryTypesTest { } /** - * Reproduces the original parsing and collection of test parameters - * from the DTonga JMX test suite. - * * Collects passed args and returns them in a map(argname, value) structure, * which will be then propagated as necessary to various called methods. */ diff --git a/test/jdk/javax/management/security/Utils.java b/test/jdk/javax/management/security/Utils.java index c0af037a4d6..afb1a8b1842 100644 --- a/test/jdk/javax/management/security/Utils.java +++ b/test/jdk/javax/management/security/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, 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,7 +28,6 @@ import java.util.StringTokenizer; import java.lang.reflect.Method; import javax.management.remote.JMXConnectorServerMBean; -// utility class for MXBean* tests coming from JMX Tonga test suite class Utils { private static final String SERVER_SIDE_NAME = "-server"; @@ -64,9 +63,6 @@ class Utils { } /** - * Reproduces the original parsing and collection of test parameters - * from the DTonga JMX test suite. - * * Collects passed args and returns them in a map(argname, value) structure, * which will be then propagated as necessary to various called methods. */ From cfeb7d6c964f63184c939f6f0625c6e7f1afdc31 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 25 Feb 2025 13:30:54 +0000 Subject: [PATCH 111/587] 8350497: os::create_thread unify init thread attributes part across UNIX platforms Reviewed-by: dholmes --- src/hotspot/os/aix/os_aix.cpp | 8 ++++++-- src/hotspot/os/bsd/os_bsd.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index bebd1f1a8c1..e452bfdfd7c 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -711,8 +711,12 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // Init thread attributes. pthread_attr_t attr; int rslt = pthread_attr_init(&attr); - guarantee(rslt == 0, "pthread_attr_init has to return 0"); - guarantee(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0, "???"); + if (rslt != 0) { + thread->set_osthread(nullptr); + delete osthread; + return false; + } + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // Make sure we run in 1:1 kernel-user-thread mode. guarantee(pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0, "???"); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b386169138f..c538c54e86f 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -637,7 +637,12 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // init thread attributes pthread_attr_t attr; - pthread_attr_init(&attr); + int rslt = pthread_attr_init(&attr); + if (rslt != 0) { + thread->set_osthread(nullptr); + delete osthread; + return false; + } pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // calculate stack size if it's not specified by caller From 62f39bd6468d1c99bb0d6af6a96972bae96a7588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 25 Feb 2025 14:30:24 +0000 Subject: [PATCH 112/587] 8350636: Potential null-pointer dereference in MallocSiteTable::new_entry Reviewed-by: dholmes --- src/hotspot/share/nmt/mallocSiteTable.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/nmt/mallocSiteTable.cpp b/src/hotspot/share/nmt/mallocSiteTable.cpp index b017e139e24..71e75551e2f 100644 --- a/src/hotspot/share/nmt/mallocSiteTable.cpp +++ b/src/hotspot/share/nmt/mallocSiteTable.cpp @@ -179,7 +179,11 @@ MallocSite* MallocSiteTable::malloc_site(uint32_t marker) { MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key, MemTag mem_tag) { void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT, *hash_entry_allocation_stack(), AllocFailStrategy::RETURN_NULL); - return ::new (p) MallocSiteHashtableEntry(key, mem_tag); + if (p == nullptr) { + return nullptr; + } else { + return ::new (p) MallocSiteHashtableEntry(key, mem_tag); + } } bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) { From b17c0b63a15246967f7cb24ba6089f2ef13e900e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 25 Feb 2025 14:38:19 +0000 Subject: [PATCH 113/587] 8350585: InlineSecondarySupersTest must be guarded on ppc64 by COMPILER2 Reviewed-by: amitkumar, mdoerr --- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 2bdff4c0995..1749447d43b 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -4889,12 +4889,14 @@ void generate_lookup_secondary_supers_table_stub() { // arraycopy stubs used by compilers generate_arraycopy_stubs(); +#ifdef COMPILER2 if (UseSecondarySupersTable) { StubRoutines::_lookup_secondary_supers_table_slow_path_stub = generate_lookup_secondary_supers_table_slow_path_stub(); if (!InlineSecondarySupersTest) { generate_lookup_secondary_supers_table_stub(); } } +#endif // COMPILER2 StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); From 08bc59da9b66c6504a2d2712feebf37cc5eb2d3e Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Tue, 25 Feb 2025 15:18:30 +0000 Subject: [PATCH 114/587] 8138614: (spec str) StringBuffer and StringBuilder methods improperly require "new" String to be returned Reviewed-by: rgiulietti, shade, alanb, rriggs, liach --- .../java/lang/AbstractStringBuilder.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 94c4192ff5e..c2f90e22802 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1027,13 +1027,13 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence } /** - * Returns a new {@code String} that contains a subsequence of + * Returns a {@code String} that contains a subsequence of * characters currently contained in this character sequence. The * substring begins at the specified index and extends to the end of * this sequence. * * @param start The beginning index, inclusive. - * @return The new string. + * @return A string containing the specified subsequence of characters. * @throws StringIndexOutOfBoundsException if {@code start} is * less than zero, or greater than the length of this object. */ @@ -1042,7 +1042,7 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence } /** - * Returns a new character sequence that is a subsequence of this sequence. + * Returns a character sequence that is a subsequence of this sequence. * *

An invocation of this method of the form * @@ -1072,14 +1072,14 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence } /** - * Returns a new {@code String} that contains a subsequence of + * Returns a {@code String} that contains a subsequence of * characters currently contained in this sequence. The * substring begins at the specified {@code start} and * extends to the character at index {@code end - 1}. * * @param start The beginning index, inclusive. * @param end The ending index, exclusive. - * @return The new string. + * @return A string containing the specified subsequence of characters. * @throws StringIndexOutOfBoundsException if {@code start} * or {@code end} are negative or greater than * {@code length()}, or {@code start} is @@ -1602,11 +1602,10 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence /** * Returns a string representing the data in this sequence. - * A new {@code String} object is allocated and initialized to - * contain the character sequence currently represented by this - * object. This {@code String} is then returned. Subsequent + * The {@code String} object that is returned contains the character + * sequence currently represented by this object. Subsequent * changes to this sequence do not affect the contents of the - * {@code String}. + * returned {@code String}. * * @return a string representation of this sequence of characters. */ From 50239716403732fe8af73b4b6f006b6a4b7b22db Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 25 Feb 2025 15:21:07 +0000 Subject: [PATCH 115/587] 8267068: Incomplete @throws javadoc for various javax.crypto.spec classes Reviewed-by: valeriep, jnimeh --- .../javax/crypto/spec/IvParameterSpec.java | 22 ++++++++-------- .../javax/crypto/spec/RC2ParameterSpec.java | 7 ++++-- .../javax/crypto/spec/RC5ParameterSpec.java | 8 +++--- .../javax/crypto/spec/SecretKeySpec.java | 25 +++++++++---------- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java index 6d7fa142c68..a1c7102e8a4 100644 --- a/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.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 @@ -47,30 +47,30 @@ public class IvParameterSpec implements AlgorithmParameterSpec { * * @param iv the buffer with the IV. The contents of the * buffer are copied to protect against subsequent modification. - * @throws NullPointerException if iv is null + * @throws NullPointerException if {@code iv} is {@code null} */ public IvParameterSpec(byte[] iv) { this(iv, 0, iv.length); } /** - * Creates an IvParameterSpec object using the first len - * bytes in iv, beginning at offset + * Creates an IvParameterSpec object using the first {@code len} + * bytes in {@code iv}, beginning at {@code offset} * inclusive, as the IV. * *

The bytes that constitute the IV are those between - * iv[offset] and iv[offset+len-1] inclusive. + * {@code iv[offset]} and {@code iv[offset+len-1]} inclusive. * - * @param iv the buffer with the IV. The first len - * bytes of the buffer beginning at offset inclusive + * @param iv the buffer with the IV. The first {@code len} + * bytes of the buffer beginning at {@code offset} inclusive * are copied to protect against subsequent modification. - * @param offset the offset in iv where the IV + * @param offset the offset in {@code iv} where the IV * starts. * @param len the number of IV bytes. - * @throws IllegalArgumentException if iv is null + * @throws IllegalArgumentException if {@code iv} is {@code null} * or {@code (iv.length - offset < len)} - * @throws ArrayIndexOutOfBoundsException is thrown if offset - * or len index bytes outside the iv. + * @throws ArrayIndexOutOfBoundsException if {@code offset} + * or {@code len} are negative. */ public IvParameterSpec(byte[] iv, int offset, int len) { if (iv == null) { diff --git a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java index 3c2e5a57da6..e37e3872ff2 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.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 @@ -91,7 +91,10 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { * are copied to protect against subsequent modification. * @param offset the offset in {@code iv} where the 8-byte IV * starts. - * @exception IllegalArgumentException if {@code iv} is null. + * @exception IllegalArgumentException if {@code iv} is {@code null} + * or {@code iv.length - offset < 8}. + * @exception ArrayIndexOutOfBoundsException if + * {@code offset} is negative. */ public RC2ParameterSpec(int effectiveKeyBits, byte[] iv, int offset) { this.effectiveKeyBits = effectiveKeyBits; diff --git a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java index 86d128afbf8..644433f3373 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.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 @@ -106,9 +106,9 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { * bytes of the buffer beginning at {@code offset} * inclusive are copied to protect against subsequent modification. * @param offset the offset in {@code iv} where the IV starts. - * @exception IllegalArgumentException if {@code iv} is - * {@code null} or - * {@code (iv.length - offset < 2 * (wordSize / 8))} + * @exception ArrayIndexOutOfBoundsException if {@code offset} is negative. + * @exception IllegalArgumentException if {@code iv} is {@code null} + * or {@code (iv.length - offset < 2 * (wordSize / 8))} */ public RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv, int offset) { diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java index e51b1471a8c..44dbd960a74 100644 --- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java @@ -113,16 +113,16 @@ public class SecretKeySpec implements KeySpec, SecretKey { /** * Constructs a secret key from the given byte array, using the first - * len bytes of key, starting at - * offset inclusive. + * {@code len} bytes of {@code key}, starting at + * {@code offset} inclusive. * *

The bytes that constitute the secret key are - * those between key[offset] and - * key[offset+len-1] inclusive. + * those between {@code key[offset]} and + * {@code key[offset+len-1]} inclusive. * *

This constructor does not check if the given bytes indeed specify a * secret key of the specified algorithm. For example, if the algorithm is - * DES, this constructor does not check if key is 8 bytes + * DES, this constructor does not check if {@code key} is 8 bytes * long, and also does not check for weak or semi-weak keys. * In order for those checks to be performed, an algorithm-specific key * specification class (in this case: @@ -130,10 +130,10 @@ public class SecretKeySpec implements KeySpec, SecretKey { * must be used. * * @param key the key material of the secret key. The first - * len bytes of the array beginning at - * offset inclusive are copied to protect + * {@code len} bytes of the array beginning at + * {@code offset} inclusive are copied to protect * against subsequent modification. - * @param offset the offset in key where the key material + * @param offset the offset in {@code key} where the key material * starts. * @param len the length of the key material. * @param algorithm the name of the secret key algorithm to be associated @@ -142,12 +142,11 @@ public class SecretKeySpec implements KeySpec, SecretKey { * * Java Security Standard Algorithm Names Specification * for information about standard secret key algorithm names. - * @exception IllegalArgumentException if algorithm - * is null or key is null, empty, or too short, + * @exception IllegalArgumentException if {@code algorithm} + * is {@code null} or {@code key} is {@code null}, empty, or too short, * i.e. {@code key.length-offsetoffset or len index bytes outside the - * key. + * @exception ArrayIndexOutOfBoundsException if + * {@code offset} or {@code len} are negative. * * @spec security/standard-names.html Java Security Standard Algorithm Names */ From dea7a9f0d640e5234bafe2157aecd942c71d5de5 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Tue, 25 Feb 2025 16:28:25 +0000 Subject: [PATCH 116/587] 8350516: Update model numbers for ECore-based cpus Reviewed-by: sviswanathan, vaivanov --- src/hotspot/cpu/x86/vm_version_x86.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 788fe2c6586..68fc4380a59 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -928,7 +928,8 @@ void VM_Version::get_processor_features() { // Check if processor has Intel Ecore if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && cpu_family() == 6 && - (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF)) { + (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF || + _model == 0xCC || _model == 0xDD)) { FLAG_SET_DEFAULT(EnableX86ECoreOpts, true); } From c5992ca27b7dddaaaf217b62445fdc48e7eaf240 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Tue, 25 Feb 2025 18:24:42 +0000 Subject: [PATCH 117/587] 8349533: Refactor validator tests shell files to java Reviewed-by: weijun --- .../sun/security/validator/CertReplace.java | 178 +++++++++++++++++- .../jdk/sun/security/validator/certreplace.sh | 88 --------- test/jdk/sun/security/validator/samedn.sh | 86 --------- 3 files changed, 168 insertions(+), 184 deletions(-) delete mode 100644 test/jdk/sun/security/validator/certreplace.sh delete mode 100644 test/jdk/sun/security/validator/samedn.sh diff --git a/test/jdk/sun/security/validator/CertReplace.java b/test/jdk/sun/security/validator/CertReplace.java index e858cc7657c..42885b73e96 100644 --- a/test/jdk/sun/security/validator/CertReplace.java +++ b/test/jdk/sun/security/validator/CertReplace.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 @@ -21,29 +21,186 @@ * questions. */ -/* - * This test is called by certreplace.sh - */ - import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.security.KeyStore; +import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.Arrays; import java.util.ArrayList; import java.util.List; + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.security.CertUtils; +import jdk.test.lib.security.KeyStoreUtils; import sun.security.validator.Validator; +/* + * @test id=certreplace + * @bug 6948803 + * @summary CertPath validation regression caused by SHA1 replacement root and MD2 disable feature + * @library /test/lib + * @modules java.base/sun.security.validator + * + * @run main CertReplace certreplace.jks certreplace.certs + */ + +/* + * @test id=samedn + * @bug 6958869 + * @summary Regression: PKIXValidator fails when multiple trust anchors have same dn + * @library /test/lib + * @modules java.base/sun.security.validator + * + * @run main CertReplace samedn.jks samedn1.certs + * @run main CertReplace samedn.jks samedn2.certs + */ + public class CertReplace { + private static final String SAMEDN_JKS = "samedn.jks"; + private static final String CERTREPLACE_JKS = "certreplace.jks"; + private static final String PASSWORD = "changeit"; + private static final char[] PASSWORD_CHAR_ARR = PASSWORD.toCharArray(); + + /** + * This method creates certs for the Cert Replace test + * + * @throws Exception + */ + private static void certReplace() throws Exception { + + final String ktBaseParameters = "-storepass " + PASSWORD + " " + + "-keypass " + PASSWORD + " " + + "-keystore " + CERTREPLACE_JKS + " " + + "-keyalg rsa "; + + final Path keystoreFilePath = Paths.get(CERTREPLACE_JKS); + Files.deleteIfExists(keystoreFilePath); + + // 1. Generate 3 aliases in a keystore: ca, int, user + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias ca -dname CN=CA -keyalg rsa -sigalg md2withrsa -ext bc"); + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias int -dname CN=Int -keyalg rsa"); + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias user -dname CN=User -keyalg rsa"); + + final KeyStore keyStore = KeyStoreUtils.loadKeyStore(CERTREPLACE_JKS, PASSWORD); + + // 2. Signing: ca -> int -> user + + SecurityTools.keytool(ktBaseParameters + + "-certreq -alias int -file int.req"); + SecurityTools.keytool(ktBaseParameters + + "-gencert -rfc -alias ca -ext bc -infile int.req " + + "-outfile int.cert"); + + //putting the certificate in the keystore + try (final FileInputStream certInputStream = new FileInputStream("int.cert")) { + final Certificate[] certs = new Certificate[]{ + CertUtils.getCertFromStream( + certInputStream + ) + }; + + final PrivateKey privateKey = (PrivateKey) keyStore.getKey("int", PASSWORD_CHAR_ARR); + keyStore.setKeyEntry("int", privateKey, PASSWORD_CHAR_ARR, certs); + keyStore.store(new FileOutputStream(CERTREPLACE_JKS), PASSWORD_CHAR_ARR); + } + + SecurityTools.keytool(ktBaseParameters + + "-certreq -alias user -file user.req"); + SecurityTools.keytool(ktBaseParameters + + "-gencert -rfc -alias int " + + "-infile user.req " + + "-outfile certreplace.certs"); // this will create certreplace.certs which is later appended + + // 3. Create the certchain file + final Path certPath = Paths.get("certreplace.certs"); + + Files.write(certPath, Files.readAllBytes(Path.of("int.cert")), StandardOpenOption.APPEND); + + final String outputCa = SecurityTools.keytool(ktBaseParameters + + "-export -rfc -alias ca").getOutput(); + Files.write(certPath, outputCa.getBytes(), StandardOpenOption.APPEND); + + // 4. Upgrade ca from MD2withRSA to SHA256withRSA, remove other aliases and make this keystore the cacerts file + keyStore.deleteEntry("int"); + keyStore.deleteEntry("user"); + keyStore.store(new FileOutputStream(CERTREPLACE_JKS), PASSWORD_CHAR_ARR); + + SecurityTools.keytool(ktBaseParameters + + "-selfcert -alias ca"); + } + + /** + * This method creates certs for the Same DN test + * + * @throws Exception + */ + private static void sameDn() throws Exception { + + final String ktBaseParameters = "-storepass " + PASSWORD + " " + + "-keypass " + PASSWORD + " " + + "-keystore " + SAMEDN_JKS + " " + + "-keyalg rsa "; + + final Path keystoreFilePath = Paths.get(SAMEDN_JKS); + Files.deleteIfExists(keystoreFilePath); + + // 1. Generate 3 aliases in a keystore: ca1, ca2, user. The CAs' startdate + // is set to one year ago so that they are expired now + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias ca1 -dname CN=CA -keyalg rsa " + + "-sigalg md5withrsa -ext bc -startdate -1y"); + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias ca2 -dname CN=CA -keyalg rsa " + + "-sigalg sha1withrsa -ext bc -startdate -1y"); + SecurityTools.keytool(ktBaseParameters + + "-genkeypair -alias user -dname CN=User -keyalg rsa"); + + // 2. Signing: ca -> user. The startdate is set to 1 minute in the past to ensure the certificate + // is valid at the time of validation and to prevent any issues with timing discrepancies + // Automatically saves the certs to the certs files + + SecurityTools.keytool(ktBaseParameters + + "-certreq -alias user -file user.req"); + SecurityTools.keytool(ktBaseParameters + + "-gencert -rfc -alias ca1 " + + "-startdate -1M -infile user.req -outfile samedn1.certs"); + SecurityTools.keytool(ktBaseParameters + + "-gencert -rfc -alias ca2 " + + "-startdate -1M -infile user.req -outfile samedn2.certs"); + + // 3. Remove user for cacerts + final KeyStore keyStore = KeyStoreUtils.loadKeyStore(SAMEDN_JKS, PASSWORD); + keyStore.deleteEntry("user"); + keyStore.store(new FileOutputStream(CERTREPLACE_JKS), PASSWORD_CHAR_ARR); + } + /** * @param args {cacerts keystore, cert chain} */ public static void main(String[] args) throws Exception { + if (args[0].equals(CERTREPLACE_JKS)) { + certReplace(); + } else if (args[0].equals(SAMEDN_JKS)) { + sameDn(); + } else { + throw new RuntimeException("Not recognised test " + args[0]); + } + KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(new FileInputStream(args[0]), "changeit".toCharArray()); + try (final FileInputStream certInputStream = new FileInputStream(args[0])) { + ks.load(certInputStream, PASSWORD_CHAR_ARR); + } Validator v = Validator.getInstance (Validator.TYPE_PKIX, Validator.VAR_GENERIC, ks); X509Certificate[] chain = createPath(args[1]); @@ -57,9 +214,10 @@ public class CertReplace { public static X509Certificate[] createPath(String chain) throws Exception { CertificateFactory cf = CertificateFactory.getInstance("X.509"); List list = new ArrayList(); - for (Certificate c: cf.generateCertificates( - new FileInputStream(chain))) { - list.add((X509Certificate)c); + try (final FileInputStream certInputStream = new FileInputStream(chain)) { + for (Certificate c : cf.generateCertificates(certInputStream)) { + list.add((X509Certificate) c); + } } return (X509Certificate[]) list.toArray(new X509Certificate[0]); } diff --git a/test/jdk/sun/security/validator/certreplace.sh b/test/jdk/sun/security/validator/certreplace.sh deleted file mode 100644 index 79c97328092..00000000000 --- a/test/jdk/sun/security/validator/certreplace.sh +++ /dev/null @@ -1,88 +0,0 @@ -# -# Copyright (c) 2010, 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 6948803 -# @summary CertPath validation regression caused by SHA1 replacement root -# and MD2 disable feature -# @modules java.base/sun.security.validator -# - -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi -if [ "${TESTJAVA}" = "" ] ; then - JAVAC_CMD=`which javac` - TESTJAVA=`dirname $JAVAC_CMD`/.. - COMPILEJAVA="${TESTJAVA}" -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Windows_* ) - FS="\\" - ;; - * ) - FS="/" - ;; -esac - -KT="$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepass changeit \ - -keypass changeit -keystore certreplace.jks -keyalg rsa" -JAVAC=$COMPILEJAVA${FS}bin${FS}javac -JAVA=$TESTJAVA${FS}bin${FS}java - -rm -rf certreplace.jks 2> /dev/null - -# 1. Generate 3 aliases in a keystore: ca, int, user - -$KT -genkeypair -alias ca -dname CN=CA -keyalg rsa -sigalg md2withrsa -ext bc -$KT -genkeypair -alias int -dname CN=Int -keyalg rsa -$KT -genkeypair -alias user -dname CN=User -keyalg rsa - -# 2. Signing: ca -> int -> user - -$KT -certreq -alias int | $KT -gencert -rfc -alias ca -ext bc \ - | $KT -import -alias int -$KT -certreq -alias user | $KT -gencert -rfc -alias int \ - | $KT -import -alias user - -# 3. Create the certchain file - -$KT -export -alias user -rfc > certreplace.certs -$KT -export -rfc -alias int >> certreplace.certs -$KT -export -rfc -alias ca >> certreplace.certs - -# 4. Upgrade ca from MD2withRSA to SHA256withRSA, remove other aliases and -# make this keystore the cacerts file - -$KT -selfcert -alias ca -$KT -delete -alias int -$KT -delete -alias user - -# 5. Build and run test - -EXTRAOPTS="--add-exports java.base/sun.security.validator=ALL-UNNAMED" -$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java -$JAVA ${TESTVMOPTS} ${TESTJAVAOPTS} ${EXTRAOPTS} CertReplace certreplace.jks certreplace.certs diff --git a/test/jdk/sun/security/validator/samedn.sh b/test/jdk/sun/security/validator/samedn.sh deleted file mode 100644 index 912bbcd40c7..00000000000 --- a/test/jdk/sun/security/validator/samedn.sh +++ /dev/null @@ -1,86 +0,0 @@ -# -# Copyright (c) 2010, 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 6958869 -# @summary regression: PKIXValidator fails when multiple trust anchors -# have same dn -# @modules java.base/sun.security.validator -# - -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi -if [ "${TESTJAVA}" = "" ] ; then - JAVAC_CMD=`which javac` - TESTJAVA=`dirname $JAVAC_CMD`/.. - COMPILEJAVA="${TESTJAVA}" -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Windows_* ) - FS="\\" - ;; - * ) - FS="/" - ;; -esac - -KT="$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepass changeit \ - -keypass changeit -keystore samedn.jks -keyalg rsa" -JAVAC=$COMPILEJAVA${FS}bin${FS}javac -JAVA=$TESTJAVA${FS}bin${FS}java - -rm -rf samedn.jks 2> /dev/null - -# 1. Generate 3 aliases in a keystore: ca1, ca2, user. The CAs' startdate -# is set to one year ago so that they are expired now - -$KT -genkeypair -alias ca1 -dname CN=CA -keyalg rsa -sigalg md5withrsa -ext bc -startdate -1y -$KT -genkeypair -alias ca2 -dname CN=CA -keyalg rsa -sigalg sha1withrsa -ext bc -startdate -1y -$KT -genkeypair -alias user -dname CN=User -keyalg rsa - -# 2. Signing: ca -> user. The startdate is set to 1 minute in the past to ensure the certificate -# is valid at the time of validation and to prevent any issues with timing discrepancies - -$KT -certreq -alias user | $KT -gencert -rfc -alias ca1 -startdate -1M > samedn1.certs -$KT -certreq -alias user | $KT -gencert -rfc -alias ca2 -startdate -1M > samedn2.certs - -# 3. Append the ca file - -$KT -export -rfc -alias ca1 >> samedn1.certs -$KT -export -rfc -alias ca2 >> samedn2.certs - -# 4. Remove user for cacerts - -$KT -delete -alias user - -# 5. Build and run test. Make sure the CA certs are ignored for validity check. -# Check both, one of them might be dropped out of map in old codes. - -EXTRAOPTS="--add-exports java.base/sun.security.validator=ALL-UNNAMED" -$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java -$JAVA ${TESTVMOPTS} ${TESTJAVAOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn1.certs || exit 1 -$JAVA ${TESTVMOPTS} ${TESTJAVAOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn2.certs || exit 2 From 0151b15b7cc077a30b00f2af4a5e3f831d1d92cb Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 25 Feb 2025 19:19:40 +0000 Subject: [PATCH 118/587] 8348367: Remove hotspot_not_fast_compiler and hotspot_slow_compiler test groups Reviewed-by: thartmann, chagedorn --- test/hotspot/jtreg/TEST.groups | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index abbcc90f8c7..f58257da2ef 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -152,24 +152,12 @@ tier1_compiler = \ :tier1_compiler_2 \ :tier1_compiler_3 -hotspot_not_fast_compiler = \ - :hotspot_compiler \ - -:tier1_compiler \ - -:hotspot_slow_compiler - -hotspot_slow_compiler = \ - compiler/codegen/aes \ - compiler/codecache/stress \ - compiler/gcbarriers/PreserveFPRegistersTest.java \ - compiler/memoryinitialization/ZeroTLABTest.java \ - compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java \ - :hotspot_compiler_arraycopy - tier1_compiler_1 = \ compiler/arraycopy/ \ compiler/blackhole/ \ compiler/c1/ \ compiler/c2/ \ + -compiler/arraycopy/stress \ -compiler/c2/Test6850611.java \ -compiler/c2/cr6890943/Test6890943.java \ -compiler/c2/Test6905845.java \ @@ -179,8 +167,7 @@ tier1_compiler_1 = \ -compiler/c2/stemmer \ -compiler/c2/Test6792161.java \ -compiler/c2/Test6603011.java \ - -compiler/c2/Test6912517.java \ - -:hotspot_slow_compiler + -compiler/c2/Test6912517.java tier1_compiler_2 = \ compiler/classUnloading/ \ @@ -197,7 +184,10 @@ tier1_compiler_2 = \ compiler/integerArithmetic/ \ compiler/interpreter/ \ compiler/jvmci/ \ - -:hotspot_slow_compiler + -compiler/classUnloading/methodUnloading/TestOverloadCompileQueues.java \ + -compiler/codecache/stress \ + -compiler/codegen/aes \ + -compiler/gcbarriers/PreserveFPRegistersTest.java tier1_compiler_3 = \ compiler/intrinsics/ \ @@ -221,6 +211,7 @@ tier1_compiler_3 = \ -compiler/intrinsics/bigInteger/TestMultiplyToLen.java \ -compiler/intrinsics/zip/TestAdler32.java \ -compiler/loopopts/Test7052494.java \ + -compiler/memoryinitialization/ZeroTLABTest.java \ -compiler/runtime/Test6826736.java tier2_compiler = \ @@ -230,7 +221,6 @@ tier2_compiler = \ compiler/cha/ \ compiler/controldependency/ \ compiler/conversions/ \ - compiler/codegen/ \ compiler/linkage/ \ compiler/loopstripmining/ \ compiler/loopopts/Test7052494.java \ @@ -248,8 +238,7 @@ tier2_compiler = \ compiler/runtime/Test6826736.java \ compiler/stable/ \ compiler/stringopts/ \ - -:tier1_compiler \ - -:hotspot_slow_compiler + -:tier1_compiler tier3_compiler = \ :hotspot_compiler \ From 829d7a845e18ec483379abf3a3fccb596d899f25 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 25 Feb 2025 19:20:05 +0000 Subject: [PATCH 119/587] 8339889: Several compiler tests ignore vm flags and not marked as flagless Reviewed-by: thartmann --- .../jtreg/compiler/c2/TestReduceAllocationAndHeapDump.java | 4 ++-- test/hotspot/jtreg/compiler/calls/NativeCalls.java | 3 ++- test/hotspot/jtreg/compiler/debug/TestStress.java | 3 ++- .../compiler/inlining/TestDuplicatedLateInliningOutput.java | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndHeapDump.java b/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndHeapDump.java index 9d1e97e253f..e2d45d73161 100644 --- a/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndHeapDump.java +++ b/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndHeapDump.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 @@ -54,7 +54,7 @@ public class TestReduceAllocationAndHeapDump { HeapDumper.class.getName() }; - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(dumperArgs); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(dumperArgs); Process p = pb.start(); OutputAnalyzer out = new OutputAnalyzer(p); diff --git a/test/hotspot/jtreg/compiler/calls/NativeCalls.java b/test/hotspot/jtreg/compiler/calls/NativeCalls.java index d0d3abfb0c4..edb371b765b 100644 --- a/test/hotspot/jtreg/compiler/calls/NativeCalls.java +++ b/test/hotspot/jtreg/compiler/calls/NativeCalls.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -104,7 +105,7 @@ public class NativeCalls { ArrayList command = new ArrayList(v.options); command.addAll(baseOptions); command.add(v.compile); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(command); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(command); OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); System.out.println(analyzer.getOutput()); diff --git a/test/hotspot/jtreg/compiler/debug/TestStress.java b/test/hotspot/jtreg/compiler/debug/TestStress.java index cdeecff91cd..6678d09e649 100644 --- a/test/hotspot/jtreg/compiler/debug/TestStress.java +++ b/test/hotspot/jtreg/compiler/debug/TestStress.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 @@ -32,6 +32,7 @@ import jdk.test.lib.Asserts; * @key stress randomness * @bug 8252219 8256535 8317349 * @requires vm.debug == true & vm.compiler2.enabled + * @requires vm.flagless * @summary Tests that stress compilations with the same seed yield the same * IGVN, CCP, and macro expansion traces. * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java b/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java index ebc5a827ea4..3c8d2c6eba9 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java +++ b/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023, Red Hat and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +28,7 @@ * @summary late inlining output shouldn't produce both failure and success messages * @library /test/lib * @requires vm.compiler2.enabled + * @requires vm.flagless * @run driver compiler.inlining.TestDuplicatedLateInliningOutput */ From d422abc55aa93d8603d29d269dfb3325bd77f34d Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 25 Feb 2025 19:25:18 +0000 Subject: [PATCH 120/587] 8350668: has_extra_module_paths in filemap.cpp may be uninitialized Reviewed-by: ccheung, shade --- src/hotspot/share/cds/filemap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 015032b2d38..7db8e78743e 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -303,7 +303,7 @@ bool FileMapInfo::validate_class_location() { assert(CDSConfig::is_using_archive(), "runtime only"); AOTClassLocationConfig* config = header()->class_location_config(); - bool has_extra_module_paths; + bool has_extra_module_paths = false; if (!config->validate(header()->has_aot_linked_classes(), &has_extra_module_paths)) { if (PrintSharedArchiveAndExit) { MetaspaceShared::set_archive_loading_failed(); From a3188e0406bcd69468de0444038525d3d069699f Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 25 Feb 2025 19:39:00 +0000 Subject: [PATCH 121/587] 8349991: GraphUtils.java can use String.replace() instead of String.replaceAll() Reviewed-by: mcimadamore --- .../classes/com/sun/tools/javac/util/GraphUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java index 3d0aab4b010..8620caf3ee5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/GraphUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -251,9 +251,9 @@ public class GraphUtils { } protected String formatProperties(Properties p) { - return p.toString().replaceAll(",", " ") - .replaceAll("\\{", "[") - .replaceAll("\\}", "]"); + return p.toString().replace(',', ' ') + .replace('{', '[') + .replace('}', ']'); } protected static String wrap(String s) { From b78043fdc64dba62293631ad0cc263029e8dfb1e Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 25 Feb 2025 19:39:21 +0000 Subject: [PATCH 122/587] 8320220: Compilation of cyclic hierarchy causes infinite recursion Reviewed-by: vromero, jlahoda --- .../classes/com/sun/tools/javac/comp/Check.java | 17 ++++++++++++----- .../tools/javac/ClassCycle/ClassCycle4.java | 10 ++++++++++ .../tools/javac/ClassCycle/ClassCycle4.out | 2 ++ 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 test/langtools/tools/javac/ClassCycle/ClassCycle4.java create mode 100644 test/langtools/tools/javac/ClassCycle/ClassCycle4.out 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 dbf66c88f0a..a27bf235e7e 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 @@ -2374,7 +2374,12 @@ public class Check { return; if (seenClasses.contains(c)) { errorFound = true; - noteCyclic(pos, (ClassSymbol)c); + log.error(pos, Errors.CyclicInheritance(c)); + seenClasses.stream() + .filter(s -> !s.type.isErroneous()) + .filter(ClassSymbol.class::isInstance) + .map(ClassSymbol.class::cast) + .forEach(Check.this::handleCyclic); } else if (!c.type.isErroneous()) { try { seenClasses.add(c); @@ -2451,7 +2456,8 @@ public class Check { if ((c.flags_field & ACYCLIC) != 0) return true; if ((c.flags_field & LOCKED) != 0) { - noteCyclic(pos, (ClassSymbol)c); + log.error(pos, Errors.CyclicInheritance(c)); + handleCyclic((ClassSymbol)c); } else if (!c.type.isErroneous()) { try { c.flags_field |= LOCKED; @@ -2478,9 +2484,10 @@ public class Check { return complete; } - /** Note that we found an inheritance cycle. */ - private void noteCyclic(DiagnosticPosition pos, ClassSymbol c) { - log.error(pos, Errors.CyclicInheritance(c)); + /** Handle finding an inheritance cycle on a class by setting + * the class' and its supertypes' types to the error type. + **/ + private void handleCyclic(ClassSymbol c) { for (List l=types.interfaces(c.type); l.nonEmpty(); l=l.tail) l.head = types.createErrorType((ClassSymbol)l.head.tsym, Type.noType); Type st = types.supertype(c.type); diff --git a/test/langtools/tools/javac/ClassCycle/ClassCycle4.java b/test/langtools/tools/javac/ClassCycle/ClassCycle4.java new file mode 100644 index 00000000000..dbe13a1bf9d --- /dev/null +++ b/test/langtools/tools/javac/ClassCycle/ClassCycle4.java @@ -0,0 +1,10 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8320220 + * @summary Fix infinite recursion in cyclic inheritance situation + * @compile/fail/ref=ClassCycle4.out -XDrawDiagnostics ClassCycle4.java + */ + +interface ClassCycle4 extends I1, I2 {} +interface I1 extends ClassCycle4 {} +interface I2 extends ClassCycle4 {} diff --git a/test/langtools/tools/javac/ClassCycle/ClassCycle4.out b/test/langtools/tools/javac/ClassCycle/ClassCycle4.out new file mode 100644 index 00000000000..2e3d28750ab --- /dev/null +++ b/test/langtools/tools/javac/ClassCycle/ClassCycle4.out @@ -0,0 +1,2 @@ +ClassCycle4.java:8:1: compiler.err.cyclic.inheritance: ClassCycle4 +1 error From d4fdc796aac8ece930c28579d285b21acf8e6ddb Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Tue, 25 Feb 2025 19:40:39 +0000 Subject: [PATCH 123/587] 8344981: [REDO] JDK-6672644 JComboBox still scrolling if switch to another window and return back Co-authored-by: Alexander Zvegintsev Reviewed-by: azvegint, psadhukhan, honkar --- .../swing/plaf/basic/BasicScrollBarUI.java | 17 +- .../JComboBox/JComboBoxScrollFocusTest.java | 149 ++++++++++++++++++ 2 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 test/jdk/javax/swing/JComboBox/JComboBoxScrollFocusTest.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java index 60274d766cd..baff1d1b81e 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.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 @@ -1609,6 +1609,11 @@ public class BasicScrollBarUI /** {@inheritDoc} */ public void actionPerformed(ActionEvent e) { + // If scrollbar isn't visible, stop the timer + if (!scrollbar.isShowing()) { + stopScrollTimer(e); + return; + } // If frame is disabled and timer is started in mousePressed // and mouseReleased is not called, then timer will not be stopped // Stop the timer if frame is disabled @@ -1616,9 +1621,7 @@ public class BasicScrollBarUI do { if (parent instanceof JFrame par) { if (!par.isEnabled()) { - ((Timer)e.getSource()).stop(); - buttonListener.handledEvent = false; - scrollbar.setValueIsAdjusting(false); + stopScrollTimer(e); return; } break; @@ -1660,6 +1663,12 @@ public class BasicScrollBarUI } } + private void stopScrollTimer(ActionEvent e) { + ((Timer) e.getSource()).stop(); + buttonListener.handledEvent = false; + scrollbar.setValueIsAdjusting(false); + } + private boolean isMouseLeftOfThumb() { return trackListener.currentMouseX < getThumbBounds().x; } diff --git a/test/jdk/javax/swing/JComboBox/JComboBoxScrollFocusTest.java b/test/jdk/javax/swing/JComboBox/JComboBoxScrollFocusTest.java new file mode 100644 index 00000000000..c7c3ba2f12e --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/JComboBoxScrollFocusTest.java @@ -0,0 +1,149 @@ +/* + * 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.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicComboPopup; + +/* + * @test + * @key headful + * @bug 6672644 + * @summary Tests JComboBox scrollbar behavior when alt-tabbing + * @run main JComboBoxScrollFocusTest + */ + +public class JComboBoxScrollFocusTest { + private static Robot robot; + private static JFrame comboboxFrame; + private static JComboBox combobox; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + try { + SwingUtilities.invokeAndWait(JComboBoxScrollFocusTest::createAndShowGUI); + doTest(); + } finally { + SwingUtilities.invokeAndWait(comboboxFrame::dispose); + } + } + + private static void createAndShowGUI() { + comboboxFrame = new JFrame("JComboBoxScrollFocusTest Test Frame"); + combobox = new JComboBox<>(); + for (int i = 0; i < 100; i++) { + combobox.addItem(String.valueOf(i)); + } + comboboxFrame.add(combobox); + comboboxFrame.setSize(400, 200); + comboboxFrame.setLocationRelativeTo(null); + comboboxFrame.setVisible(true); + } + + static Rectangle getOnScreenBoundsOnEDT(Component component) throws Exception { + robot.waitForIdle(); + FutureTask task = new FutureTask<>(() + -> new Rectangle(component.getLocationOnScreen(), + component.getSize())); + SwingUtilities.invokeLater(task); + return task.get(500, TimeUnit.MILLISECONDS); + } + + private static JScrollBar getScrollBar() { + BasicComboPopup popup = (BasicComboPopup) combobox + .getAccessibleContext().getAccessibleChild(0); + JScrollPane scrollPane = (JScrollPane) popup + .getAccessibleContext().getAccessibleChild(0); + return scrollPane.getVerticalScrollBar(); + } + + private static int getScrollbarValue() throws Exception { + FutureTask task = new FutureTask<>(() -> { + JScrollBar scrollBar = getScrollBar(); + return scrollBar.getValue(); + }); + SwingUtilities.invokeAndWait(task); + + return task.get(500, TimeUnit.MILLISECONDS); + } + + private static void doTest() throws Exception { + robot.waitForIdle(); + robot.delay(500); + + Rectangle rectangle = getOnScreenBoundsOnEDT(combobox); + + Point ptOpenComboboxPopup = new Point(rectangle.x + rectangle.width - 5, + rectangle.y + rectangle.height / 2); + + robot.mouseMove(ptOpenComboboxPopup.x, ptOpenComboboxPopup.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + + JScrollBar scrollBar = getScrollBar(); + + // Start scrolling + Rectangle scrollbarBounds = getOnScreenBoundsOnEDT(scrollBar); + robot.mouseMove(scrollbarBounds.x + scrollbarBounds.width / 2, + scrollbarBounds.y + scrollbarBounds.height - 5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + + robot.delay(1000); + + if (getScrollbarValue() == 0) { + throw new RuntimeException("The scrollbar is not scrolling"); + } + + // closing popup by moving focus to the main window + comboboxFrame.requestFocus(); + robot.waitForIdle(); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.waitForIdle(); + robot.delay(500); + + // open popup again + robot.mouseMove(ptOpenComboboxPopup.x, ptOpenComboboxPopup.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + + if (getScrollbarValue() != 0) { + throw new RuntimeException("The scroll bar is scrolling"); + } + } +} From 2efb0336e0c257c34f9e49a50cbad1704691582e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 21:53:24 +0000 Subject: [PATCH 124/587] 8350601: Miscellaneous updates to jpackage test lib Reviewed-by: almatvee --- .../jdk/jpackage/test/TKitTest.java | 146 +++++++++++++++++- .../jdk/jpackage/test/AdditionalLauncher.java | 17 +- .../jdk/jpackage/test/JPackageCommand.java | 11 +- .../helpers/jdk/jpackage/test/TKit.java | 105 +++++++++---- .../jpackage/share/AppImagePackageTest.java | 2 +- 5 files changed, 227 insertions(+), 54 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java index 4cddb1eb912..f7f76a209cc 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.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 @@ -26,19 +26,24 @@ import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; public class TKitTest extends JUnitAdapter { - public static Collection assertTestsData() { + public static Collection test() { List data = new ArrayList<>(); var assertFunc = MethodCallConfig.build("assertTrue", boolean.class, String.class); @@ -57,6 +62,12 @@ public class TKitTest extends JUnitAdapter { data.addAll(List.of(assertFunc.args(7, 7).pass().expectLog("assertEquals(7)").createForMessage("Owl"))); data.addAll(List.of(assertFunc.args(7, 10).fail().expectLog("Expected [7]. Actual [10]").createForMessage("Owl"))); + assertFunc = MethodCallConfig.build("assertEquals", boolean.class, boolean.class, String.class); + data.addAll(List.of(assertFunc.args(true, true).pass().expectLog("assertEquals(true)").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(false, false).pass().expectLog("assertEquals(false)").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(true, false).fail().expectLog("Expected [true]. Actual [false]").createForMessage("Emu"))); + data.addAll(List.of(assertFunc.args(false, true).fail().expectLog("Expected [false]. Actual [true]").createForMessage("Emu"))); + assertFunc = MethodCallConfig.build("assertNotEquals", String.class, String.class, String.class); data.addAll(List.of(assertFunc.args("a", "b").pass().expectLog("assertNotEquals(a, b)").createForMessage("Tit"))); data.addAll(List.of(assertFunc.args("a", "a").fail().expectLog("Unexpected [a] value").createForMessage("Tit"))); @@ -65,6 +76,12 @@ public class TKitTest extends JUnitAdapter { data.addAll(List.of(assertFunc.args(7, 10).pass().expectLog("assertNotEquals(7, 10)").createForMessage("Duck"))); data.addAll(List.of(assertFunc.args(7, 7).fail().expectLog("Unexpected [7] value").createForMessage("Duck"))); + assertFunc = MethodCallConfig.build("assertNotEquals", boolean.class, boolean.class, String.class); + data.addAll(List.of(assertFunc.args(true, false).pass().expectLog("assertNotEquals(true, false)").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(false, true).pass().expectLog("assertNotEquals(false, true)").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(true, true).fail().expectLog("Unexpected [true] value").createForMessage("Sparrow"))); + data.addAll(List.of(assertFunc.args(false, false).fail().expectLog("Unexpected [false] value").createForMessage("Sparrow"))); + assertFunc = MethodCallConfig.build("assertNull", Object.class, String.class); data.addAll(List.of(assertFunc.args((Object) null).pass().expectLog("assertNull()").createForMessage("Ibis"))); data.addAll(List.of(assertFunc.args("v").fail().expectLog("Unexpected not null value [v]").createForMessage("Ibis"))); @@ -186,13 +203,136 @@ public class TKitTest extends JUnitAdapter { } @Test - @ParameterSupplier("assertTestsData") + @ParameterSupplier public void test(MethodCallConfig methodCall) { runAssertWithExpectedLogOutput(() -> { methodCall.method.invoke(null, methodCall.args); }, methodCall.expectFail, methodCall.expectLog); } + @Test + @ParameterSupplier("testCreateTempPath") + public void testCreateTempFile(CreateTempTestSpec testSpec) throws Throwable { + testSpec.test(TKit::createTempFile, TKit::assertFileExists); + } + + @Test + @ParameterSupplier("testCreateTempPath") + public void testCreateTempDirectory(CreateTempTestSpec testSpec) throws Throwable { + testSpec.test(TKit::createTempDirectory, TKit::assertDirectoryEmpty); + } + + record CreateTempTestSpec(String role, Path expectedPath, List existingFiles, + Class expectedExceptionClass) { + + CreateTempTestSpec { + Objects.requireNonNull(existingFiles); + if ((expectedExceptionClass == null) == (expectedPath == null)) { + throw new IllegalArgumentException("Only one of `expectedPath` and `expectedExceptionClass` should be set"); + } + } + + void test(ThrowingFunction createTempPath, Consumer assertTempPathExists) throws Throwable { + for (var existingFile : existingFiles) { + existingFile = TKit.workDir().resolve(existingFile); + + Files.createDirectories(existingFile.getParent()); + Files.createFile(existingFile); + } + + if (expectedExceptionClass != null) { + try { + createTempPath.apply(role); + TKit.assertUnexpected("Exception expected"); + } catch (Exception ex) { + TKit.assertTrue(expectedExceptionClass.isInstance(ex), + String.format("Check exception [%s] is instance of %s", ex, expectedExceptionClass)); + } + } else { + final var tempPath = createTempPath.apply(role); + + assertTempPathExists.accept(tempPath); + TKit.assertTrue(tempPath.startsWith(TKit.workDir()), "Check temp path created in the work directory"); + + final var relativeTempPath = TKit.workDir().relativize(tempPath); + TKit.assertTrue(expectedPath.equals(relativeTempPath), + String.format("Check [%s]=[%s]", expectedPath, relativeTempPath)); + } + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append("role=").append(role); + if (expectedPath != null) { + sb.append("; expected=").append(expectedPath); + } + if (!existingFiles.isEmpty()) { + sb.append("; exits=").append(existingFiles); + } + if (expectedExceptionClass != null) { + sb.append("; exception=").append(expectedExceptionClass); + } + return sb.toString(); + } + + static Builder role(String role) { + return new Builder(role); + } + + final static class Builder { + + private Builder(String role) { + this.role = role; + } + + CreateTempTestSpec create() { + return new CreateTempTestSpec(role, expectedPath, existingFiles, expectedExceptionClass); + } + + Builder expectedPath(String v) { + expectedPath = Optional.of(v).map(Path::of).orElse(null); + return this; + } + + Builder existingFiles(String ...v) { + existingFiles.addAll(Stream.of(v).map(Path::of).toList()); + return this; + } + + Builder expectedExceptionClass(Class v) { + expectedExceptionClass = v; + return this; + } + + private final String role; + private Path expectedPath; + private final List existingFiles = new ArrayList<>(); + private Class expectedExceptionClass; + } + } + + public static Collection testCreateTempPath() { + return Stream.of( + CreateTempTestSpec.role("foo").expectedPath("foo"), + CreateTempTestSpec.role("foo.b").expectedPath("foo.b"), + CreateTempTestSpec.role("foo").expectedPath("foo-0").existingFiles("foo"), + CreateTempTestSpec.role("foo.b").expectedPath("foo-0.b").existingFiles("foo.b"), + CreateTempTestSpec.role("foo..b").expectedPath("foo.-0.b").existingFiles("foo..b"), + CreateTempTestSpec.role("a.b.c.d").expectedPath("a.b.c-0.d").existingFiles("a.b.c.d"), + CreateTempTestSpec.role("foo").expectedPath("foo-1").existingFiles("foo", "foo-0"), + CreateTempTestSpec.role("foo/bar/buz").expectedPath("foo/bar/buz"), + CreateTempTestSpec.role("foo/bar/buz").expectedPath("foo/bar/buz-0").existingFiles("foo/bar/buz"), + CreateTempTestSpec.role("foo/bar/buz.tmp").expectedPath("foo/bar/buz-0.tmp").existingFiles("foo/bar/buz.tmp"), + CreateTempTestSpec.role("foo/bar").expectedPath("foo/bar-0").existingFiles("foo/bar/buz"), + CreateTempTestSpec.role(Path.of("").toAbsolutePath().toString()).expectedExceptionClass(IllegalArgumentException.class), + CreateTempTestSpec.role(null).expectedExceptionClass(NullPointerException.class), + CreateTempTestSpec.role("").expectedExceptionClass(IllegalArgumentException.class) + ).map(CreateTempTestSpec.Builder::create).map(testSpec -> { + return new Object[] { testSpec }; + }).toList(); + } + private static void runAssertWithExpectedLogOutput(ThrowingRunnable action, boolean expectFail, String... expectLogStrings) { runWithExpectedLogOutput(() -> { 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 03914759f16..5089dc0c602 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -186,21 +186,10 @@ public class AdditionalLauncher { return Optional.of(shell[0]).get(); } - private void initialize(JPackageCommand cmd) { - Path propsFile = TKit.workDir().resolve(name + ".properties"); - if (Files.exists(propsFile)) { - // File with the given name exists, pick another name that - // will not reference existing file. - try { - propsFile = TKit.createTempFile(propsFile); - TKit.deleteIfExists(propsFile); - } catch (IOException ex) { - rethrowUnchecked(ex); - } - } + private void initialize(JPackageCommand cmd) throws IOException { + final Path propsFile = TKit.createTempFile(name + ".properties"); - cmd.addArguments("--add-launcher", String.format("%s=%s", name, - propsFile)); + cmd.addArguments("--add-launcher", String.format("%s=%s", name, propsFile)); List> properties = new ArrayList<>(); if (defaultArguments != null) { 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 418d7377ec6..6fc5cfad3f9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -252,11 +252,7 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand setInputToEmptyDirectory() { if (Files.exists(inputDir())) { - try { - setArgumentValue("--input", TKit.createTempDirectory("input")); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + setArgumentValue("--input", TKit.createTempDirectory("input")); } return this; } @@ -841,6 +837,11 @@ public class JPackageCommand extends CommandArguments { TKit.assertFileExists(cmd.appLauncherCfgPath(null)); } }), + MAIN_JAR_FILE(cmd -> { + Optional.ofNullable(cmd.getArgumentValue("--main-jar", () -> null)).ifPresent(mainJar -> { + TKit.assertFileExists(cmd.appLayout().appDirectory().resolve(mainJar)); + }); + }), RUNTIME_DIRECTORY(cmd -> { TKit.assertDirectoryExists(cmd.appRuntimeDirectory()); if (TKit.isOSX()) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index d3473952cf8..f10415b5e97 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -22,18 +22,21 @@ */ package jdk.jpackage.test; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static java.util.stream.Collectors.toSet; + import java.io.Closeable; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.io.UncheckedIOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardWatchEventKinds; import java.nio.file.StandardCopyOption; -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; @@ -58,13 +61,13 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingRunnable; import jdk.jpackage.internal.util.function.ThrowingSupplier; +import jdk.jpackage.internal.util.function.ThrowingUnaryOperator; public final class TKit { @@ -288,9 +291,17 @@ public final class TKit { } } - private static final String TEMP_FILE_PREFIX = null; + private static Path createUniquePath(String defaultName) { + return createUniquePath(defaultName, workDir()); + } + + private static Path createUniquePath(String defaultName, Path basedir) { + Objects.requireNonNull(defaultName); + Objects.requireNonNull(basedir); + if (defaultName.isEmpty()) { + throw new IllegalArgumentException(); + } - private static Path createUniqueFileName(String defaultName) { final String[] nameComponents; int separatorIdx = defaultName.lastIndexOf('.'); @@ -304,7 +315,6 @@ public final class TKit { separatorIdx + 1)}; } - final Path basedir = workDir(); int i = 0; for (; i < 100; ++i) { Path path = basedir.resolve(String.join(".", nameComponents)); @@ -320,32 +330,42 @@ public final class TKit { baseName, i)); } - public static Path createTempDirectory(String role) throws IOException { - if (role == null) { - return Files.createTempDirectory(workDir(), TEMP_FILE_PREFIX); + public static Path createTempDirectory(String role) { + return createTempDirectory(Path.of(role)); + } + + public static Path createTempDirectory(Path role) { + return createTempPath(role, Files::createDirectory); + } + + public static Path createTempFile(String role) { + return createTempFile(Path.of(role)); + } + + public static Path createTempFile(Path role) { + return createTempPath(role, Files::createFile); + } + + private static Path createTempPath(Path templatePath, ThrowingUnaryOperator createPath) { + if (templatePath.isAbsolute()) { + throw new IllegalArgumentException(); + } + final Path basedir; + if (templatePath.getNameCount() > 1) { + basedir = workDir().resolve(templatePath.getParent()); + } else { + basedir = workDir(); } - return Files.createDirectory(createUniqueFileName(role)); - } - public static Path createTempFile(Path templateFile) throws - IOException { - return Files.createFile(createUniqueFileName( - templateFile.getFileName().toString())); - } + final var path = createUniquePath(templatePath.getFileName().toString(), basedir); - public static Path withTempFile(Path templateFile, - ThrowingConsumer action) { - final Path tempFile = ThrowingSupplier.toSupplier(() -> createTempFile( - templateFile)).get(); - boolean keepIt = true; try { - ThrowingConsumer.toConsumer(action).accept(tempFile); - keepIt = false; - return tempFile; - } finally { - if (tempFile != null && !keepIt) { - ThrowingRunnable.toRunnable(() -> Files.deleteIfExists(tempFile)).run(); - } + Files.createDirectories(path.getParent()); + return createPath.apply(path); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } catch (Throwable t) { + throw ExceptionBox.rethrowUnchecked(t); } } @@ -509,7 +529,7 @@ public final class TKit { public static Path createRelativePathCopy(final Path file) { Path fileCopy = ThrowingSupplier.toSupplier(() -> { - Path localPath = createTempFile(file); + Path localPath = createTempFile(file.getFileName()); Files.copy(file, localPath, StandardCopyOption.REPLACE_EXISTING); return localPath; }).get().toAbsolutePath().normalize(); @@ -609,6 +629,29 @@ public final class TKit { actual), msg)); } + public static void assertEquals(boolean expected, boolean actual, String msg) { + currentTest.notifyAssert(); + if (expected != actual) { + error(concatMessages(String.format( + "Expected [%s]. Actual [%s]", expected, actual), + msg)); + } + + traceAssert(concatMessages(String.format("assertEquals(%s)", expected), msg)); + } + + public static void assertNotEquals(boolean expected, boolean actual, String msg) { + currentTest.notifyAssert(); + if (expected == actual) { + error(concatMessages(String.format("Unexpected [%s] value", actual), + msg)); + } + + traceAssert(concatMessages(String.format("assertNotEquals(%s, %s)", expected, + actual), msg)); + } + + public static void assertEquals(String expected, String actual, String msg) { currentTest.notifyAssert(); if ((actual != null && !actual.equals(expected)) @@ -703,7 +746,7 @@ public final class TKit { assertDirectoryExists(path, Optional.of(true)); } - public static void assertDirectoryExists(Path path, Optional isEmptyCheck) { + private static void assertDirectoryExists(Path path, Optional isEmptyCheck) { assertPathExists(path, true); boolean isDirectory = Files.isDirectory(path); if (isEmptyCheck.isEmpty() || !isDirectory) { diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 030cca50f14..fc545cc1f55 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -73,7 +73,7 @@ public class AppImagePackageTest { public static void testEmpty(boolean withIcon) throws IOException { final String name = "EmptyAppImagePackageTest"; final String imageName = name + (TKit.isOSX() ? ".app" : ""); - Path appImageDir = TKit.createTempDirectory(null).resolve(imageName); + Path appImageDir = TKit.createTempDirectory("appimage").resolve(imageName); Files.createDirectories(appImageDir.resolve("bin")); Path libDir = Files.createDirectories(appImageDir.resolve("lib")); From 267d69bed6265ec2820f17eb7534ec64d80ad093 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Feb 2025 22:49:26 +0000 Subject: [PATCH 125/587] 8326447: jpackage creates Windows installers that cannot be signed Reviewed-by: almatvee --- src/jdk.jpackage/share/man/jpackage.md | 6 + .../jdk/jpackage/internal/WinExeBundler.java | 12 +- .../resources/WinResources.properties | 3 +- .../jpackage/test/LauncherIconVerifier.java | 195 +----------- .../test/WinExecutableIconVerifier.java | 290 ++++++++++++++++++ .../resources/read-executable-icon.ps1 | 54 ++++ .../windows/WinInstallerResourceTest.java | 102 ++++++ 7 files changed, 463 insertions(+), 199 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java create mode 100644 test/jdk/tools/jpackage/resources/read-executable-icon.ps1 create mode 100644 test/jdk/tools/jpackage/windows/WinInstallerResourceTest.java diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md index edc76f7caff..61b671579da 100644 --- a/src/jdk.jpackage/share/man/jpackage.md +++ b/src/jdk.jpackage/share/man/jpackage.md @@ -686,6 +686,12 @@ jpackage will lookup files by specific names in the resource directory. : A Windows Script File (WSF) to run after building embedded MSI installer for EXE installer +`installer.exe` + +: Executable wrapper for MSI installer + + Default resource is *msiwrapper.exe* + ### Resource directory files considered only when running on macOS: diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index cc2e9298e99..04838fe6b87 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.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 @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.OverridableResource.createResource; + import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -129,9 +131,11 @@ public class WinExeBundler extends AbstractBundler { // Copy template msi wrapper next to msi file final Path exePath = PathUtils.replaceSuffix(msi, ".exe"); - try (InputStream is = OverridableResource.readDefault(EXE_WRAPPER_NAME)) { - Files.copy(is, exePath); - } + + createResource(EXE_WRAPPER_NAME, params) + .setCategory(I18N.getString("resource.installer-exe")) + .setPublicName("installer.exe") + .saveToFile(exePath); new ExecutableRebrander().addAction((resourceLock) -> { // Embed msi in msi wrapper exe. diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 506ffa59ed6..91fc8806e10 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -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 @@ -41,6 +41,7 @@ resource.shortcutpromptdlg-wix-file=Shortcut prompt dialog WiX project file resource.installdirnotemptydlg-wix-file=Not empty install directory dialog WiX project file resource.launcher-as-service-wix-file=Service installer WiX project file resource.wix-src-conv=XSLT stylesheet converting WiX sources from WiX v3 to WiX v4 format +resource.installer-exe=installer executable error.no-wix-tools=Can not find WiX tools. Was looking for WiX v3 light.exe and candle.exe or WiX v4/v5 wix.exe and none was found error.no-wix-tools.advice=Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index 05510461c16..a5eb24980ae 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -23,15 +23,9 @@ package jdk.jpackage.test; -import java.awt.image.BufferedImage; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; -import javax.imageio.ImageIO; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; public final class LauncherIconVerifier { public LauncherIconVerifier() { @@ -68,7 +62,7 @@ public final class LauncherIconVerifier { if (TKit.isWindows()) { TKit.assertPathExists(iconPath, false); - WinIconVerifier.instance.verifyLauncherIcon(cmd, launcherName, + WinExecutableIconVerifier.verifyLauncherIcon(cmd, launcherName, expectedIcon, expectedDefault); } else if (expectedDefault) { TKit.assertPathExists(iconPath, true); @@ -83,193 +77,6 @@ public final class LauncherIconVerifier { } } - private static class WinIconVerifier { - - void verifyLauncherIcon(JPackageCommand cmd, String launcherName, - Path expectedIcon, boolean expectedDefault) { - TKit.withTempDirectory("icons", tmpDir -> { - Path launcher = cmd.appLauncherPath(launcherName); - Path iconWorkDir = tmpDir.resolve(launcher.getFileName()); - Path iconContainer = iconWorkDir.resolve("container.exe"); - Files.createDirectories(iconContainer.getParent()); - Files.copy(getDefaultAppLauncher(expectedIcon == null - && !expectedDefault), iconContainer); - if (expectedIcon != null) { - Executor.tryRunMultipleTimes(() -> { - setIcon(expectedIcon, iconContainer); - }, 3, 5); - } - - Path extractedExpectedIcon = extractIconFromExecutable( - iconWorkDir, iconContainer, "expected"); - Path extractedActualIcon = extractIconFromExecutable(iconWorkDir, - launcher, "actual"); - - TKit.trace(String.format( - "Check icon file [%s] of %s launcher is a copy of source icon file [%s]", - extractedActualIcon, - Optional.ofNullable(launcherName).orElse("main"), - extractedExpectedIcon)); - - if (Files.mismatch(extractedExpectedIcon, extractedActualIcon) - != -1) { - // On Windows11 .NET API extracting icons from executables - // produce slightly different output for the same icon. - // To workaround it, compare pixels of images and if the - // number of off pixels is below a threshold, assume - // equality. - BufferedImage expectedImg = ImageIO.read( - extractedExpectedIcon.toFile()); - BufferedImage actualImg = ImageIO.read( - extractedActualIcon.toFile()); - - int w = expectedImg.getWidth(); - int h = expectedImg.getHeight(); - - TKit.assertEquals(w, actualImg.getWidth(), - "Check expected and actual icons have the same width"); - TKit.assertEquals(h, actualImg.getHeight(), - "Check expected and actual icons have the same height"); - - int diffPixelCount = 0; - - for (int i = 0; i != w; ++i) { - for (int j = 0; j != h; ++j) { - int expectedRGB = expectedImg.getRGB(i, j); - int actualRGB = actualImg.getRGB(i, j); - - if (expectedRGB != actualRGB) { - TKit.trace(String.format( - "Images mismatch at [%d, %d] pixel", i, - j)); - diffPixelCount++; - } - } - } - - double threshold = 0.1; - TKit.assertTrue(((double) diffPixelCount) / (w * h) - < threshold, - String.format( - "Check the number of mismatched pixels [%d] of [%d] is < [%f] threshold", - diffPixelCount, (w * h), threshold)); - } - }); - } - - private WinIconVerifier() { - try { - executableRebranderClass = Class.forName( - "jdk.jpackage.internal.ExecutableRebrander"); - - lockResource = executableRebranderClass.getDeclaredMethod( - "lockResource", String.class); - // Note: this reflection call requires - // --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED - lockResource.setAccessible(true); - - unlockResource = executableRebranderClass.getDeclaredMethod( - "unlockResource", long.class); - unlockResource.setAccessible(true); - - iconSwapWrapper = executableRebranderClass.getDeclaredMethod( - "iconSwapWrapper", long.class, String.class); - iconSwapWrapper.setAccessible(true); - } catch (ClassNotFoundException | NoSuchMethodException - | SecurityException ex) { - throw rethrowUnchecked(ex); - } - } - - private Path extractIconFromExecutable(Path outputDir, Path executable, - String label) { - // Run .NET code to extract icon from the given executable. - // ExtractAssociatedIcon() will succeed even if the target file - // is locked (by an antivirus). It will output a default icon - // in case of error. To prevent this "fail safe" behavior we try - // lock the target file with Open() call. If the attempt - // fails ExtractAssociatedIcon() is not called and the script exits - // with the exit code that will be trapped - // inside of Executor.executeAndRepeatUntilExitCode() method that - // will keep running the script until it succeeds or the number of - // allowed attempts is exceeded. - - Path extractedIcon = outputDir.resolve(label + ".bmp"); - String script = String.join(";", - String.format( - "try { [System.io.File]::Open('%s', 'Open', 'Read', 'None') } catch { exit 100 }", - executable.toAbsolutePath().normalize()), - "[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')", - String.format( - "[System.Drawing.Icon]::ExtractAssociatedIcon('%s').ToBitmap().Save('%s', [System.Drawing.Imaging.ImageFormat]::Bmp)", - executable.toAbsolutePath().normalize(), - extractedIcon.toAbsolutePath().normalize())); - - Executor.of("powershell", "-NoLogo", "-NoProfile", "-Command", - script).executeAndRepeatUntilExitCode(0, 5, 10); - - return extractedIcon; - } - - private Path getDefaultAppLauncher(boolean noIcon) { - // Create app image with the sole purpose to get the default app launcher - Path defaultAppOutputDir = TKit.workDir().resolve(String.format( - "out-%d", ProcessHandle.current().pid())); - JPackageCommand cmd = JPackageCommand.helloAppImage().setFakeRuntime().setArgumentValue( - "--dest", defaultAppOutputDir); - - String launcherName; - if (noIcon) { - launcherName = "no-icon"; - new AdditionalLauncher(launcherName).setNoIcon().applyTo(cmd); - } else { - launcherName = null; - } - - if (!Files.isExecutable(cmd.appLauncherPath(launcherName))) { - cmd.execute(); - } - return cmd.appLauncherPath(launcherName); - } - - private void setIcon(Path iconPath, Path launcherPath) { - TKit.trace(String.format("Set icon of [%s] launcher to [%s] file", - launcherPath, iconPath)); - try { - launcherPath.toFile().setWritable(true, true); - try { - long lock = 0; - try { - lock = (Long) lockResource.invoke(null, new Object[]{ - launcherPath.toAbsolutePath().normalize().toString()}); - if (lock == 0) { - throw new RuntimeException(String.format( - "Failed to lock [%s] executable", - launcherPath)); - } - iconSwapWrapper.invoke(null, new Object[]{lock, - iconPath.toAbsolutePath().normalize().toString()}); - } finally { - if (lock != 0) { - unlockResource.invoke(null, new Object[]{lock}); - } - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw rethrowUnchecked(ex); - } - } finally { - launcherPath.toFile().setWritable(false, true); - } - } - - static final WinIconVerifier instance = new WinIconVerifier(); - - private final Class executableRebranderClass; - private final Method lockResource; - private final Method unlockResource; - private final Method iconSwapWrapper; - } - private String launcherName; private Path expectedIcon; private boolean expectedDefault; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java new file mode 100644 index 00000000000..5110259e6f3 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinExecutableIconVerifier.java @@ -0,0 +1,290 @@ +/* + * 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.test; + +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import javax.imageio.ImageIO; + +public final class WinExecutableIconVerifier { + + static void verifyLauncherIcon(JPackageCommand cmd, String launcherName, + Path expectedIcon, boolean expectedDefault) { + Objects.requireNonNull(cmd); + INSTANCE.verifyExecutablesHaveSameIcon(new Input() { + @Override + public Path executableWithExpectedIcon(Path iconWorkDir) throws IOException { + final var iconContainer = iconWorkDir.resolve("container.exe"); + Files.createDirectories(iconContainer.getParent()); + Files.copy(INSTANCE.getDefaultAppLauncher(expectedIcon == null + && !expectedDefault), iconContainer); + if (expectedIcon != null) { + Executor.tryRunMultipleTimes(() -> { + INSTANCE.setIcon(expectedIcon, iconContainer); + }, 3, 5); + } + return iconContainer; + } + + @Override + public Path executableWithActualIcon(Path iconWorkDir) { + return cmd.appLauncherPath(launcherName); + } + + @Override + public void trace(Path extractedActualIcon, Path extractedExpectedIcon) { + TKit.trace(String.format( + "Check icon file [%s] of %s launcher is a copy of source icon file [%s]", + extractedActualIcon, + Optional.ofNullable(launcherName).orElse("main"), + extractedExpectedIcon)); + } + }); + } + + public static void verifyExecutablesHaveSameIcon(Path executableWithExpectedIcon, + Path executableWithActualIcon) { + Objects.requireNonNull(executableWithExpectedIcon); + Objects.requireNonNull(executableWithActualIcon); + INSTANCE.verifyExecutablesHaveSameIcon(new Input() { + @Override + public Path executableWithExpectedIcon(Path iconWorkDir) { + return executableWithExpectedIcon; + } + + @Override + public Path executableWithActualIcon(Path iconWorkDir) { + return executableWithActualIcon; + } + + @Override + public void trace(Path extractedActualIcon, Path extractedExpectedIcon) { + TKit.trace(String.format( + "Check icon file [%s] extracted from [%s] executable is a copy of icon file [%s] extracted from [%s] executable", + extractedActualIcon, executableWithActualIcon, + extractedExpectedIcon, executableWithExpectedIcon)); + } + }); + } + + private interface Input { + Path executableWithExpectedIcon(Path iconWorkDir) throws IOException; + Path executableWithActualIcon(Path iconWorkDir) throws IOException; + void trace(Path extractedActualIcon, Path extractedExpectedIcon); + } + + private void verifyExecutablesHaveSameIcon(Input input) { + + Objects.requireNonNull(input); + + TKit.withTempDirectory("icons", iconWorkDir -> { + + final var executableWithExpectedIcon = input.executableWithExpectedIcon(iconWorkDir); + final var executableWithActualIcon = input.executableWithActualIcon(iconWorkDir); + + if (Files.isSameFile(executableWithExpectedIcon, executableWithActualIcon)) { + throw new IllegalArgumentException("Supply different files for icon comparison"); + } + + Path extractedExpectedIcon = extractIconFromExecutable( + iconWorkDir, executableWithExpectedIcon, "expected"); + Path extractedActualIcon = extractIconFromExecutable(iconWorkDir, + executableWithActualIcon, "actual"); + + input.trace(extractedActualIcon, extractedExpectedIcon); + + // If executable doesn't have an icon, icon file will be empty. + // Both icon files must be empty or not empty. + // If only one icon file is empty executables have different icons. + final var expectedIconIsEmpty = isFileEmpty(extractedExpectedIcon); + final var actualIconIsEmpty = isFileEmpty(extractedActualIcon); + + TKit.assertTrue(expectedIconIsEmpty == actualIconIsEmpty, + "Check both icon files are empty or not empty"); + + if (!expectedIconIsEmpty && Files.mismatch(extractedExpectedIcon, extractedActualIcon) != -1) { + // On Windows11 .NET API extracting icons from executables + // produce slightly different output for the same icon. + // To workaround it, compare pixels of images and if the + // number of off pixels is below a threshold, assume + // equality. + BufferedImage expectedImg = ImageIO.read( + extractedExpectedIcon.toFile()); + BufferedImage actualImg = ImageIO.read( + extractedActualIcon.toFile()); + + int w = expectedImg.getWidth(); + int h = expectedImg.getHeight(); + + TKit.assertEquals(w, actualImg.getWidth(), + "Check expected and actual icons have the same width"); + TKit.assertEquals(h, actualImg.getHeight(), + "Check expected and actual icons have the same height"); + + int diffPixelCount = 0; + + for (int i = 0; i != w; ++i) { + for (int j = 0; j != h; ++j) { + int expectedRGB = expectedImg.getRGB(i, j); + int actualRGB = actualImg.getRGB(i, j); + + if (expectedRGB != actualRGB) { + TKit.trace(String.format( + "Images mismatch at [%d, %d] pixel", i, + j)); + diffPixelCount++; + } + } + } + + double threshold = 0.1; + TKit.assertTrue(((double) diffPixelCount) / (w * h) + < threshold, + String.format( + "Check the number of mismatched pixels [%d] of [%d] is < [%f] threshold", + diffPixelCount, (w * h), threshold)); + } + }); + } + + private WinExecutableIconVerifier() { + try { + executableRebranderClass = Class.forName( + "jdk.jpackage.internal.ExecutableRebrander"); + + lockResource = executableRebranderClass.getDeclaredMethod( + "lockResource", String.class); + // Note: this reflection call requires + // --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED + lockResource.setAccessible(true); + + unlockResource = executableRebranderClass.getDeclaredMethod( + "unlockResource", long.class); + unlockResource.setAccessible(true); + + iconSwap = executableRebranderClass.getDeclaredMethod( + "iconSwap", long.class, String.class); + iconSwap.setAccessible(true); + } catch (ClassNotFoundException | NoSuchMethodException + | SecurityException ex) { + throw rethrowUnchecked(ex); + } + } + + private Path extractIconFromExecutable(Path outputDir, Path executable, + String extractedIconFilename) { + + Objects.requireNonNull(outputDir); + Objects.requireNonNull(executable); + Objects.requireNonNull(extractedIconFilename); + + Path extractedIcon = outputDir.resolve(extractedIconFilename + ".bmp"); + + Executor.of("powershell", "-NoLogo", "-NoProfile", "-ExecutionPolicy", "Unrestricted", + "-File", EXTRACT_ICON_PS1.toString(), + "-InputExecutable", executable.toAbsolutePath().normalize().toString(), + "-OutputIcon", extractedIcon.toAbsolutePath().normalize().toString() + ).executeAndRepeatUntilExitCode(0, 5, 10); + + return extractedIcon; + } + + private Path getDefaultAppLauncher(boolean noIcon) { + // Create app image with the sole purpose to get the default app launcher + Path defaultAppOutputDir = TKit.workDir().resolve(String.format( + "out-%d", ProcessHandle.current().pid())); + JPackageCommand cmd = JPackageCommand.helloAppImage().setFakeRuntime().setArgumentValue( + "--dest", defaultAppOutputDir); + + String launcherName; + if (noIcon) { + launcherName = "no-icon"; + new AdditionalLauncher(launcherName).setNoIcon().applyTo(cmd); + } else { + launcherName = null; + } + + if (!Files.isExecutable(cmd.appLauncherPath(launcherName))) { + cmd.execute(); + } + return cmd.appLauncherPath(launcherName); + } + + private void setIcon(Path iconPath, Path executable) { + Objects.requireNonNull(iconPath); + Objects.requireNonNull(executable); + + try { + executable.toFile().setWritable(true, true); + try { + long lock = 0; + try { + lock = (Long) lockResource.invoke(null, new Object[]{ + executable.toAbsolutePath().normalize().toString()}); + if (lock == 0) { + throw new RuntimeException(String.format( + "Failed to lock [%s] executable", + executable)); + } + var exitCode = (Integer) iconSwap.invoke(null, new Object[]{ + lock, + iconPath.toAbsolutePath().normalize().toString()}); + if (exitCode != 0) { + throw new RuntimeException(String.format( + "Failed to swap icon of [%s] executable", + executable)); + } + } finally { + if (lock != 0) { + unlockResource.invoke(null, new Object[]{lock}); + } + } + } catch (IllegalAccessException | InvocationTargetException ex) { + throw rethrowUnchecked(ex); + } + } finally { + executable.toFile().setWritable(false, true); + } + } + + private static boolean isFileEmpty(Path file) { + return file.toFile().length() == 0; + } + + private final Class executableRebranderClass; + private final Method lockResource; + private final Method unlockResource; + private final Method iconSwap; + + private static final WinExecutableIconVerifier INSTANCE = new WinExecutableIconVerifier(); + + private static final Path EXTRACT_ICON_PS1 = TKit.TEST_SRC_ROOT.resolve(Path.of("resources/read-executable-icon.ps1")).normalize(); +} diff --git a/test/jdk/tools/jpackage/resources/read-executable-icon.ps1 b/test/jdk/tools/jpackage/resources/read-executable-icon.ps1 new file mode 100644 index 00000000000..55effdc4708 --- /dev/null +++ b/test/jdk/tools/jpackage/resources/read-executable-icon.ps1 @@ -0,0 +1,54 @@ +# +# 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. +# + +param ( + # Path to input executable file. + [Parameter(Mandatory=$true)] + [string]$InputExecutable, + + # Path to BMP file where to save an icon extracted from the input executable. + [Parameter(Mandatory=$true)] + [string]$OutputIcon +) + +Add-Type -AssemblyName 'System.Drawing' + +$Shell32MethodDefinitions = @' +[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] +public static extern uint ExtractIconEx(string szFileName, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons); +'@ +$Shell32 = Add-Type -MemberDefinition $Shell32MethodDefinitions -Name 'Shell32' -Namespace 'Win32' -PassThru + +$IconHandleArray = New-Object IntPtr[] 1 # Allocate IntPtr[1] to recieve HICON +$IconCount = $Shell32::ExtractIconEx($InputExecutable, 0, $IconHandleArray, $null, 1); +if ($IconCount -eq [uint32]::MaxValue) { + Write-Error "Failed to read icon." + exit 100 +} elseif ($IconCount -ne 0) { + # Executable has an icon. + $Icon = [System.Drawing.Icon]::FromHandle($IconHandleArray[0]); + $Icon.ToBitmap().Save($OutputIcon, [System.Drawing.Imaging.ImageFormat]::Bmp) +} else { + # Execeutable doesn't have an icon. Empty output icon file. + $null = New-Item -Force $OutputIcon -ItemType File +} diff --git a/test/jdk/tools/jpackage/windows/WinInstallerResourceTest.java b/test/jdk/tools/jpackage/windows/WinInstallerResourceTest.java new file mode 100644 index 00000000000..bb2008bbda7 --- /dev/null +++ b/test/jdk/tools/jpackage/windows/WinInstallerResourceTest.java @@ -0,0 +1,102 @@ +/* + * 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 + * 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 static jdk.jpackage.test.WinExecutableIconVerifier.verifyExecutablesHaveSameIcon; + +import java.nio.file.Files; +import java.nio.file.Path; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; + +/** + * Test for installer exe from the resource directory. + */ + +/* + * @test + * @summary jpackage with installer exe from the resource directory + * @library /test/jdk/tools/jpackage/helpers + * @key jpackagePlatformPackage + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror WinInstallerResourceTest.java + * @requires (os.family == "windows") + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=WinInstallerResourceTest + */ +public class WinInstallerResourceTest { + + @Test + public void test() { + createPackageTest("dummy") + .addInitializer(JPackageCommand::setFakeRuntime) + .addInitializer(cmd -> { + // Create exe installer using the default installer exe resource and a custom icon. + cmd.addArguments("--icon", iconPath("icon")); + }) + .addBundleVerifier(cmd -> { + final var exeInstaller = cmd.outputBundle(); + + createPackageTest("InstallerResTest") + .addInitializer(cmd2 -> { + cmd2.setArgumentValue("--runtime-image", cmd.getArgumentValue("--runtime-image")); + }) + .addInitializer(cmd2 -> { + // + // Create an exe installer using the exe installer created in the first jpackage run. + // + + // The exe installer created in the first jpackage run has a custom icon. + // Configure the second jpackage run to use the default icon. + // This will prevent jpackage from editing icon in the exe installer. + // Copy the exe installer created in the first jpackage run into the + // resource directory for the second jpackage run. + // If jpackage will pick an exe installer resource from the resource directory, + // the output exe installer should have the same icon as + // the exe installer produced in the first jpackage run. + final var resourceDir = TKit.createTempDirectory("resources"); + Files.copy(exeInstaller, resourceDir.resolve("installer.exe")); + cmd2.addArguments("--resource-dir", resourceDir); + }) + .addBundleVerifier(cmd2 -> { + verifyExecutablesHaveSameIcon(exeInstaller, cmd2.outputBundle()); + }).run(Action.CREATE); + }).run(Action.CREATE); + } + + private PackageTest createPackageTest(String name) { + return new PackageTest() + .ignoreBundleOutputDir() + .forTypes(PackageType.WIN_EXE) + .configureHelloApp() + .addInitializer(cmd -> cmd.setArgumentValue("--name", name)); + } + + private static Path iconPath(String name) { + return TKit.TEST_SRC_ROOT.resolve(Path.of("resources", name + + TKit.ICON_SUFFIX)); + } +} From 86024ebdb0f06517925c03e52246fbda0bad8f7c Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 25 Feb 2025 22:56:25 +0000 Subject: [PATCH 126/587] 8348426: Generate binary file for -XX:AOTMode=record -XX:AOTConfiguration=file Reviewed-by: ccheung, asmehra, kvn, iveresov --- src/hotspot/share/cds/aotClassLocation.cpp | 10 +- src/hotspot/share/cds/archiveBuilder.cpp | 5 +- src/hotspot/share/cds/archiveUtils.hpp | 16 +- src/hotspot/share/cds/archiveUtils.inline.hpp | 37 +++- src/hotspot/share/cds/cdsConfig.cpp | 169 +++++++++++++----- src/hotspot/share/cds/cdsConfig.hpp | 37 +++- src/hotspot/share/cds/cds_globals.hpp | 6 +- src/hotspot/share/cds/cppVtables.cpp | 42 ++++- src/hotspot/share/cds/dumpTimeClassInfo.cpp | 10 +- src/hotspot/share/cds/dynamicArchive.cpp | 5 +- src/hotspot/share/cds/filemap.cpp | 159 +++++++++++----- src/hotspot/share/cds/filemap.hpp | 3 + src/hotspot/share/cds/finalImageRecipes.cpp | 167 +++++++++++++++++ src/hotspot/share/cds/finalImageRecipes.hpp | 76 ++++++++ src/hotspot/share/cds/heapShared.cpp | 7 +- src/hotspot/share/cds/heapShared.hpp | 1 + src/hotspot/share/cds/lambdaFormInvokers.cpp | 4 + src/hotspot/share/cds/metaspaceShared.cpp | 97 +++++++--- src/hotspot/share/cds/runTimeClassInfo.hpp | 21 ++- src/hotspot/share/classfile/moduleEntry.cpp | 8 +- .../share/classfile/systemDictionary.cpp | 4 + .../classfile/systemDictionaryShared.cpp | 94 ++++++++-- .../classfile/systemDictionaryShared.hpp | 11 +- src/hotspot/share/include/cds.h | 1 + src/hotspot/share/memory/metaspace.cpp | 1 - src/hotspot/share/oops/constantPool.cpp | 5 + src/hotspot/share/oops/instanceKlass.cpp | 1 + src/hotspot/share/runtime/arguments.cpp | 16 +- src/hotspot/share/runtime/java.cpp | 5 + src/hotspot/share/runtime/threads.cpp | 6 +- test/hotspot/jtreg/TEST.groups | 2 +- .../runtime/cds/ArchiveDoesNotExist.java | 4 +- .../jtreg/runtime/cds/appcds/AOTFlags.java | 118 ++++++++++-- .../AOTLoaderConstraintsTest.java | 104 +++++++++++ .../cds/appcds/aotClassLinking/BootClass.java | 30 ++++ .../aotClassLinking/BulkLoaderTest.java | 20 +++ .../cds/appcds/applications/JavacBench.java | 11 +- .../dynamicArchive/ArchiveConsistency.java | 6 +- .../TestAutoCreateSharedArchive.java | 6 +- .../TestAutoCreateSharedArchiveUpgrade.java | 4 +- .../DumpingWithJavaAgent.java | 7 +- test/lib/jdk/test/lib/cds/CDSAppTester.java | 67 ++++++- 42 files changed, 1185 insertions(+), 218 deletions(-) create mode 100644 src/hotspot/share/cds/finalImageRecipes.cpp create mode 100644 src/hotspot/share/cds/finalImageRecipes.hpp create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTLoaderConstraintsTest.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BootClass.java diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 8d453fe1773..c083213b933 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -989,8 +989,14 @@ bool AOTClassLocationConfig::validate(bool has_aot_linked_classes, bool* has_ext const char* hint_msg = log_is_enabled(Info, class, path) ? "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; if (RequireSharedSpaces && !PrintSharedArchiveAndExit) { - log_error(cds)("%s%s", mismatch_msg, hint_msg); - MetaspaceShared::unrecoverable_loading_error(); + if (CDSConfig::is_dumping_final_static_archive()) { + log_error(cds)("class path and/or module path are not compatible with the " + "ones specified when the AOTConfiguration file was recorded%s", hint_msg); + vm_exit_during_initialization("Unable to use create AOT cache.", nullptr); + } else { + log_error(cds)("%s%s", mismatch_msg, hint_msg); + MetaspaceShared::unrecoverable_loading_error(); + } } else { log_warning(cds)("%s%s", mismatch_msg, hint_msg); } diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index afd2d909595..21e97457a87 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -507,9 +507,8 @@ 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 (MetaspaceShared::is_shared_static(bottom)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_shared_static(bottom)) { // The bottom class is in the static archive so it's clearly not excluded. - assert(CDSConfig::is_dumping_dynamic_archive(), "sanity"); return false; } else if (bottom->is_instance_klass()) { return SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(bottom)); @@ -521,7 +520,7 @@ bool ArchiveBuilder::is_excluded(Klass* klass) { ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) { address obj = ref->obj(); - if (MetaspaceShared::is_in_shared_metaspace(obj)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(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 a10117e9f9a..59146547aca 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.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 @@ -255,11 +255,23 @@ public: }; class ArchiveUtils { + template static Array* archive_non_ptr_array(GrowableArray* tmp_array); + template static Array* archive_ptr_array(GrowableArray* tmp_array); + public: static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF; static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN; static bool has_aot_initialized_mirror(InstanceKlass* src_ik); - template static Array* archive_array(GrowableArray* tmp_array); + + template ::value)> + static Array* archive_array(GrowableArray* tmp_array) { + return archive_non_ptr_array(tmp_array); + } + + template ::value)> + static Array* archive_array(GrowableArray* tmp_array) { + return archive_ptr_array(tmp_array); + } // 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()). diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 537b3d1670c..9388bca18c7 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.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 @@ -28,6 +28,8 @@ #include "cds/archiveUtils.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" @@ -52,13 +54,40 @@ inline bool SharedDataRelocator::do_bit(size_t offset) { // Returns the address of an Array that's allocated in the ArchiveBuilder "buffer" space. template -Array* ArchiveUtils::archive_array(GrowableArray* tmp_array) { +Array* ArchiveUtils::archive_non_ptr_array(GrowableArray* tmp_array) { + ArchiveBuilder* builder = ArchiveBuilder::current(); + Array* archived_array = ArchiveBuilder::new_ro_array(tmp_array->length()); for (int i = 0; i < tmp_array->length(); i++) { archived_array->at_put(i, tmp_array->at(i)); - if (std::is_pointer::value) { + } + + return archived_array; +} + +// Returns the address of an Array that's allocated in the ArchiveBuilder "buffer" space. +// All pointers in tmp_array must point to: +// - a buffered object; or +// - a source object that has been archived; or +// - (only when dumping dynamic archive) an object in the static archive. +template +Array* ArchiveUtils::archive_ptr_array(GrowableArray* tmp_array) { + ArchiveBuilder* builder = ArchiveBuilder::current(); + const bool is_dynamic_dump = CDSConfig::is_dumping_dynamic_archive(); + + Array* archived_array = ArchiveBuilder::new_ro_array(tmp_array->length()); + for (int i = 0; i < tmp_array->length(); i++) { + T ptr = tmp_array->at(i); + if (!builder->is_in_buffer_space(ptr)) { + if (is_dynamic_dump && MetaspaceShared::is_in_shared_metaspace(ptr)) { + // We have a pointer that lives in the dynamic archive but points into + // the static archive. + } else { + ptr = builder->get_buffered_addr(ptr); + } + } + archived_array->at_put(i, ptr); ArchivePtrMarker::mark_pointer(archived_array->adr_at(i)); - } } return archived_array; diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 564298fa5c8..1bb842af953 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -40,6 +40,8 @@ #include "utilities/formatBuffer.hpp" bool CDSConfig::_is_dumping_static_archive = false; +bool CDSConfig::_is_dumping_preimage_static_archive = false; +bool CDSConfig::_is_dumping_final_static_archive = false; bool CDSConfig::_is_dumping_dynamic_archive = false; bool CDSConfig::_is_using_optimized_module_handling = true; bool CDSConfig::_is_dumping_full_module_graph = true; @@ -47,6 +49,7 @@ bool CDSConfig::_is_using_full_module_graph = true; bool CDSConfig::_has_aot_linked_classes = false; bool CDSConfig::_has_archived_invokedynamic = false; bool CDSConfig::_old_cds_flags_used = false; +bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; char* CDSConfig::_default_archive_path = nullptr; @@ -64,7 +67,7 @@ int CDSConfig::get_status() { } void CDSConfig::initialize() { - if (is_dumping_static_archive()) { + if (is_dumping_static_archive() && !is_dumping_final_static_archive()) { if (RequireSharedSpaces) { warning("Cannot dump shared archive while using shared archive"); } @@ -210,6 +213,7 @@ void CDSConfig::init_shared_archive_paths() { warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); AutoCreateSharedArchive = false; } + log_error(cds)("Not a valid %s (%s)", new_aot_flags_used() ? "AOT cache" : "archive", SharedArchiveFile); Arguments::no_shared_spaces("invalid archive"); } } else if (base_archive_path == nullptr) { @@ -333,7 +337,11 @@ bool CDSConfig::has_unsupported_runtime_module_options() { if (RequireSharedSpaces) { warning("CDS is disabled when the %s option is specified.", option); } else { - log_info(cds)("CDS is disabled when the %s option is specified.", option); + if (new_aot_flags_used()) { + log_warning(cds)("AOT cache is disabled when the %s option is specified.", option); + } else { + log_info(cds)("CDS is disabled when the %s option is specified.", option); + } } return true; } @@ -343,7 +351,7 @@ bool CDSConfig::has_unsupported_runtime_module_options() { #define CHECK_ALIAS(f) check_flag_alias(FLAG_IS_DEFAULT(f), #f) void CDSConfig::check_flag_alias(bool alias_is_default, const char* alias_name) { - if (_old_cds_flags_used && !alias_is_default) { + if (old_cds_flags_used() && !alias_is_default) { vm_exit_during_initialization(err_msg("Option %s cannot be used at the same time with " "-Xshare:on, -Xshare:auto, -Xshare:off, -Xshare:dump, " "DumpLoadedClassList, SharedClassListFile, or SharedArchiveFile", @@ -351,7 +359,7 @@ void CDSConfig::check_flag_alias(bool alias_is_default, const char* alias_name) } } -void CDSConfig::check_flag_aliases() { +void CDSConfig::check_aot_flags() { if (!FLAG_IS_DEFAULT(DumpLoadedClassList) || !FLAG_IS_DEFAULT(SharedClassListFile) || !FLAG_IS_DEFAULT(SharedArchiveFile)) { @@ -363,30 +371,16 @@ void CDSConfig::check_flag_aliases() { CHECK_ALIAS(AOTMode); if (FLAG_IS_DEFAULT(AOTCache) && FLAG_IS_DEFAULT(AOTConfiguration) && FLAG_IS_DEFAULT(AOTMode)) { - // Aliases not used. + // AOTCache/AOTConfiguration/AOTMode not used. return; + } else { + _new_aot_flags_used = true; } if (FLAG_IS_DEFAULT(AOTMode) || strcmp(AOTMode, "auto") == 0 || strcmp(AOTMode, "on") == 0) { - if (!FLAG_IS_DEFAULT(AOTConfiguration)) { - vm_exit_during_initialization("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create"); - } - - if (!FLAG_IS_DEFAULT(AOTCache)) { - assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); - FLAG_SET_ERGO(SharedArchiveFile, AOTCache); - } - - UseSharedSpaces = true; - if (FLAG_IS_DEFAULT(AOTMode) || (strcmp(AOTMode, "auto") == 0)) { - RequireSharedSpaces = false; - } else { - assert(strcmp(AOTMode, "on") == 0, "already checked"); - RequireSharedSpaces = true; - } + check_aotmode_auto_or_on(); } else if (strcmp(AOTMode, "off") == 0) { - UseSharedSpaces = false; - RequireSharedSpaces = false; + check_aotmode_off(); } else { // AOTMode is record or create if (FLAG_IS_DEFAULT(AOTConfiguration)) { @@ -394,32 +388,78 @@ void CDSConfig::check_flag_aliases() { } if (strcmp(AOTMode, "record") == 0) { - if (!FLAG_IS_DEFAULT(AOTCache)) { - vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record"); - } - - assert(FLAG_IS_DEFAULT(DumpLoadedClassList), "already checked"); - FLAG_SET_ERGO(DumpLoadedClassList, AOTConfiguration); - UseSharedSpaces = false; - RequireSharedSpaces = false; + check_aotmode_record(); } else { assert(strcmp(AOTMode, "create") == 0, "checked by AOTModeConstraintFunc"); - if (FLAG_IS_DEFAULT(AOTCache)) { - vm_exit_during_initialization("AOTCache must be specified when using -XX:AOTMode=create"); - } - - assert(FLAG_IS_DEFAULT(SharedClassListFile), "already checked"); - FLAG_SET_ERGO(SharedClassListFile, AOTConfiguration); - assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); - FLAG_SET_ERGO(SharedArchiveFile, AOTCache); - - CDSConfig::enable_dumping_static_archive(); + check_aotmode_create(); } } } +void CDSConfig::check_aotmode_off() { + UseSharedSpaces = false; + RequireSharedSpaces = false; +} + +void CDSConfig::check_aotmode_auto_or_on() { + if (!FLAG_IS_DEFAULT(AOTConfiguration)) { + vm_exit_during_initialization("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create"); + } + + if (!FLAG_IS_DEFAULT(AOTCache)) { + assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); + FLAG_SET_ERGO(SharedArchiveFile, AOTCache); + } + + UseSharedSpaces = true; + if (FLAG_IS_DEFAULT(AOTMode) || (strcmp(AOTMode, "auto") == 0)) { + RequireSharedSpaces = false; + } else { + assert(strcmp(AOTMode, "on") == 0, "already checked"); + RequireSharedSpaces = true; + } +} + +void CDSConfig::check_aotmode_record() { + if (!FLAG_IS_DEFAULT(AOTCache)) { + vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record"); + } + + assert(FLAG_IS_DEFAULT(DumpLoadedClassList), "already checked"); + assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); + FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration); + FLAG_SET_ERGO(DumpLoadedClassList, nullptr); + UseSharedSpaces = false; + RequireSharedSpaces = false; + _is_dumping_static_archive = true; + _is_dumping_preimage_static_archive = true; + + // At VM exit, the module graph may be contaminated with program states. + // We will rebuild the module graph when dumping the CDS final image. + disable_heap_dumping(); +} + +void CDSConfig::check_aotmode_create() { + if (FLAG_IS_DEFAULT(AOTCache)) { + vm_exit_during_initialization("AOTCache must be specified when using -XX:AOTMode=create"); + } + + assert(FLAG_IS_DEFAULT(SharedArchiveFile), "already checked"); + + _is_dumping_final_static_archive = true; + FLAG_SET_ERGO(SharedArchiveFile, AOTConfiguration); + UseSharedSpaces = true; + RequireSharedSpaces = true; + + if (!FileMapInfo::is_preimage_static_archive(AOTConfiguration)) { + vm_exit_during_initialization("Must be a valid AOT configuration generated by the current JVM", AOTConfiguration); + } + + CDSConfig::enable_dumping_static_archive(); +} + bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) { - check_flag_aliases(); + check_aot_flags(); if (!FLAG_IS_DEFAULT(AOTMode)) { // Using any form of the new AOTMode switch enables enhanced optimizations. @@ -435,7 +475,9 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla } if (is_dumping_static_archive()) { - if (!mode_flag_cmd_line) { + if (is_dumping_preimage_static_archive()) { + // Don't tweak execution mode + } else if (!mode_flag_cmd_line) { // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive. // // If your classlist is large and you don't care about deterministic dumping, you can use @@ -499,6 +541,20 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla return true; } +bool CDSConfig::is_dumping_classic_static_archive() { + return _is_dumping_static_archive && + !is_dumping_preimage_static_archive() && + !is_dumping_final_static_archive(); +} + +bool CDSConfig::is_dumping_preimage_static_archive() { + return _is_dumping_preimage_static_archive; +} + +bool CDSConfig::is_dumping_final_static_archive() { + return _is_dumping_final_static_archive; +} + bool CDSConfig::allow_only_single_java_thread() { // See comments in JVM_StartThread() return is_dumping_static_archive(); @@ -534,6 +590,26 @@ bool CDSConfig::current_thread_is_vm_or_dumper() { return t != nullptr && (t->is_VM_thread() || t == _dumper_thread); } +const char* CDSConfig::type_of_archive_being_loaded() { + if (is_dumping_final_static_archive()) { + return "AOT configuration file"; + } else if (new_aot_flags_used()) { + return "AOT cache"; + } else { + return "shared archive file"; + } +} + +const char* CDSConfig::type_of_archive_being_written() { + if (is_dumping_preimage_static_archive()) { + return "AOT configuration file"; + } else if (new_aot_flags_used()) { + return "AOT cache"; + } else { + return "shared archive file"; + } +} + // If an incompatible VM options is found, return a text message that explains why static const char* check_options_incompatible_with_dumping_heap() { #if INCLUDE_CDS_JAVA_HEAP @@ -574,12 +650,11 @@ bool CDSConfig::are_vm_options_incompatible_with_dumping_heap() { bool CDSConfig::is_dumping_heap() { - if (!is_dumping_static_archive() // heap dump is not supported in dynamic dump + if (!(is_dumping_classic_static_archive() || is_dumping_final_static_archive()) || are_vm_options_incompatible_with_dumping_heap() || _disable_heap_dumping) { return false; } - return true; } @@ -627,7 +702,9 @@ void CDSConfig::stop_using_full_module_graph(const char* reason) { } bool CDSConfig::is_dumping_aot_linked_classes() { - if (is_dumping_dynamic_archive()) { + if (is_dumping_preimage_static_archive()) { + return false; + } else if (is_dumping_dynamic_archive()) { return is_using_full_module_graph() && AOTClassLinking; } else if (is_dumping_static_archive()) { return is_dumping_full_module_graph() && AOTClassLinking; diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index c2dc2b41a93..d9f5a593098 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -34,6 +34,8 @@ class JavaThread; class CDSConfig : public AllStatic { #if INCLUDE_CDS static bool _is_dumping_static_archive; + static bool _is_dumping_preimage_static_archive; + static bool _is_dumping_final_static_archive; static bool _is_dumping_dynamic_archive; static bool _is_using_optimized_module_handling; static bool _is_dumping_full_module_graph; @@ -46,6 +48,7 @@ class CDSConfig : public AllStatic { static char* _dynamic_archive_path; static bool _old_cds_flags_used; + static bool _new_aot_flags_used; static bool _disable_heap_dumping; static JavaThread* _dumper_thread; @@ -57,7 +60,11 @@ class CDSConfig : public AllStatic { static void init_shared_archive_paths(); static void check_flag_alias(bool alias_is_default, const char* alias_name); - static void check_flag_aliases(); + static void check_aot_flags(); + static void check_aotmode_off(); + static void check_aotmode_auto_or_on(); + static void check_aotmode_record(); + static void check_aotmode_create(); public: // Used by jdk.internal.misc.CDS.getCDSConfigStatus(); @@ -71,11 +78,14 @@ public: static void initialize() NOT_CDS_RETURN; static void set_old_cds_flags_used() { CDS_ONLY(_old_cds_flags_used = true); } static bool old_cds_flags_used() { return CDS_ONLY(_old_cds_flags_used) NOT_CDS(false); } + static bool new_aot_flags_used() { return CDS_ONLY(_new_aot_flags_used) NOT_CDS(false); } static void check_internal_module_property(const char* key, const char* value) NOT_CDS_RETURN; static void check_incompatible_property(const char* key, const char* value) NOT_CDS_RETURN; static void check_unsupported_dumping_module_options() NOT_CDS_RETURN; static bool has_unsupported_runtime_module_options() NOT_CDS_RETURN_(false); static bool check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) NOT_CDS_RETURN_(true); + static const char* type_of_archive_being_loaded(); + static const char* type_of_archive_being_written(); // --- Basic CDS features @@ -88,6 +98,30 @@ public: static bool is_dumping_static_archive() { return CDS_ONLY(_is_dumping_static_archive) NOT_CDS(false); } static void enable_dumping_static_archive() { CDS_ONLY(_is_dumping_static_archive = true); } + // A static CDS archive can be dumped in three modes: + // + // "classic" - This is the traditional CDS workflow of + // "java -Xshare:dump -XX:SharedClassListFile=file.txt". + // + // "preimage" - This happens when we execute the JEP 483 training run, e.g: + // "java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconfig -cp app.jar App" + // The above command writes app.aotconfig as a "CDS preimage". This + // is a binary file that contains all the classes loaded during the + // training run, plus profiling data (e.g., the resolved constant pool entries). + // + // "final" - This happens when we execute the JEP 483 assembly phase, e.g: + // "java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconfig -XX:AOTCache=app.aot -cp app.jar" + // The above command loads all classes from app.aotconfig, perform additional linking, + // and writes app.aot as a "CDS final image" file. + // + // The main structural difference between "preimage" and "final" is that the preimage + // - has a different magic number (0xcafea07c) + // - does not have any archived Java heap objects + // - does not have aot-linked classes + static bool is_dumping_classic_static_archive() NOT_CDS_RETURN_(false); + static bool is_dumping_preimage_static_archive() NOT_CDS_RETURN_(false); + static bool is_dumping_final_static_archive() NOT_CDS_RETURN_(false); + // dynamic_archive static bool is_dumping_dynamic_archive() { return CDS_ONLY(_is_dumping_dynamic_archive) NOT_CDS(false); } static void enable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = true); } @@ -135,7 +169,6 @@ public: static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN; static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN; - // Some CDS functions assume that they are called only within a single-threaded context. I.e., // they are called from: // - The VM thread (e.g., inside VM_PopulateDumpSharedSpace) diff --git a/src/hotspot/share/cds/cds_globals.hpp b/src/hotspot/share/cds/cds_globals.hpp index 811740cfbcb..bb9ffe2044b 100644 --- a/src/hotspot/share/cds/cds_globals.hpp +++ b/src/hotspot/share/cds/cds_globals.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 @@ -105,7 +105,9 @@ constraint(AOTModeConstraintFunc, AtParse) \ \ product(ccstr, AOTConfiguration, nullptr, \ - "Configuration information used by CreateAOTCache") \ + "The configuration file written by -XX:AOTMode=record, and " \ + "loaded by -XX:AOTMode=create. This file contains profiling data "\ + "for deciding what contents should be added to AOTCache. ") \ \ product(ccstr, AOTCache, nullptr, \ "Cache for improving start up and warm up") \ diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 39849571015..b8243cedf6d 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -189,12 +189,22 @@ enum ClonedVtableKind { _num_cloned_vtable_kinds }; -// This is a map of all the original vtptrs. E.g., for +// _orig_cpp_vtptrs and _archived_cpp_vtptrs are used for type checking in +// CppVtables::get_archived_vtable(). +// +// _orig_cpp_vtptrs is a map of all the original vtptrs. E.g., for // ConstantPool *cp = new (...) ConstantPool(...) ; // a dynamically allocated constant pool // the following holds true: -// _orig_cpp_vtptrs[ConstantPool_Kind] == ((intptr_t**)cp)[0] -static intptr_t* _orig_cpp_vtptrs[_num_cloned_vtable_kinds]; +// _orig_cpp_vtptrs[ConstantPool_Kind] == ((intptr_t**)cp)[0] +// +// _archived_cpp_vtptrs is a map of all the vptprs used by classes in a preimage. E.g., for +// InstanceKlass* k = a class loaded from the preimage; +// ConstantPool* cp = k->constants(); +// the following holds true: +// _archived_cpp_vtptrs[ConstantPool_Kind] == ((intptr_t**)cp)[0] static bool _orig_cpp_vtptrs_inited = false; +static intptr_t* _orig_cpp_vtptrs[_num_cloned_vtable_kinds]; +static intptr_t* _archived_cpp_vtptrs[_num_cloned_vtable_kinds]; template void CppVtableCloner::init_orig_cpp_vtptr(int kind) { @@ -212,15 +222,27 @@ void CppVtableCloner::init_orig_cpp_vtptr(int kind) { // _index[InstanceKlass_Kind]->cloned_vtable() == ((intptr_t**)ik)[0] static CppVtableInfo* _index[_num_cloned_vtable_kinds]; -// Vtables are all fixed offsets from ArchiveBuilder::current()->mapped_base() -// E.g. ConstantPool is at offset 0x58. We can archive these offsets in the -// RO region and use them to alculate their location at runtime without storing -// the pointers in the RW region +// This marks the location in the archive where _index[0] is stored. This location +// will be stored as FileMapHeader::_cloned_vtables_offset into the archive header. +// Serviceability Agent uses this information to determine the vtables of +// archived Metadata objects. char* CppVtables::_vtables_serialized_base = nullptr; void CppVtables::dumptime_init(ArchiveBuilder* builder) { assert(CDSConfig::is_dumping_static_archive(), "cpp tables are only dumped into static archive"); + if (CDSConfig::is_dumping_final_static_archive()) { + // When dumping final archive, _index[kind] at this point is in the preimage. + // Remember these vtable pointers in _archived_cpp_vtptrs, as _index[kind] will now be rewritten + // to point to the runtime vtable data. + for (int i = 0; i < _num_cloned_vtable_kinds; i++) { + assert(_index[i] != nullptr, "must have been restored by CppVtables::serialize()"); + _archived_cpp_vtptrs[i] = _index[i]->cloned_vtable(); + } + } else { + memset(_archived_cpp_vtptrs, 0, sizeof(_archived_cpp_vtptrs)); + } + CPP_VTABLE_TYPES_DO(ALLOCATE_AND_INITIALIZE_VTABLE); size_t cpp_tables_size = builder->rw_region()->top() - builder->rw_region()->base(); @@ -267,7 +289,8 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob break; default: for (kind = 0; kind < _num_cloned_vtable_kinds; kind ++) { - if (vtable_of((Metadata*)obj) == _orig_cpp_vtptrs[kind]) { + if (vtable_of((Metadata*)obj) == _orig_cpp_vtptrs[kind] || + vtable_of((Metadata*)obj) == _archived_cpp_vtptrs[kind]) { break; } } @@ -295,5 +318,6 @@ void CppVtables::zero_archived_vtables() { bool CppVtables::is_valid_shared_method(const Method* m) { assert(MetaspaceShared::is_in_shared_metaspace(m), "must be"); - return vtable_of(m) == _index[Method_Kind]->cloned_vtable(); + 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 18136d6eeec..94a0f14ff1f 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -66,9 +66,9 @@ void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* na GrowableArray* vcflags_array = _verifier_constraint_flags; char c = 0; - c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0; - c |= from_is_array ? SystemDictionaryShared::FROM_IS_ARRAY : 0; - c |= from_is_object ? SystemDictionaryShared::FROM_IS_OBJECT : 0; + c |= from_field_is_protected ? RunTimeClassInfo::FROM_FIELD_IS_PROTECTED : 0; + c |= from_is_array ? RunTimeClassInfo::FROM_IS_ARRAY : 0; + c |= from_is_object ? RunTimeClassInfo::FROM_IS_OBJECT : 0; vcflags_array->append(c); if (log_is_enabled(Trace, cds, verification)) { @@ -142,7 +142,7 @@ bool DumpTimeClassInfo::is_builtin() { } DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { - assert(!k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "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(!k->is_shared(), "Do not call with shared classes"); + assert(CDSConfig::is_dumping_final_static_archive() || !k->is_shared(), "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 4ccf23ff91c..095b443af66 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -388,8 +388,9 @@ public: void doit() { ResourceMark rm; if (AllowArchivingWithJavaAgent) { - log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " - "for testing purposes only and should not be used in a production environment"); + log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + "for testing purposes only and should not be used in a production environment", + CDSConfig::type_of_archive_being_loaded()); } AOTClassLocationConfig::dumptime_check_nonempty_dirs(); _builder.doit(); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 7db8e78743e..8a7e66c19e4 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -151,6 +151,13 @@ FileMapInfo::~FileMapInfo() { } } +void FileMapInfo::free_current_info() { + assert(CDSConfig::is_dumping_final_static_archive(), "only supported in this mode"); + assert(_current_info != nullptr, "sanity"); + delete _current_info; + assert(_current_info == nullptr, "sanity"); // Side effect expected from the above "delete" operator. +} + void FileMapInfo::populate_header(size_t core_region_alignment) { assert(_header == nullptr, "Sanity check"); size_t c_header_size; @@ -191,7 +198,13 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, set_header_size((unsigned int)header_size); set_base_archive_name_offset((unsigned int)base_archive_name_offset); set_base_archive_name_size((unsigned int)base_archive_name_size); - set_magic(CDSConfig::is_dumping_dynamic_archive() ? CDS_DYNAMIC_ARCHIVE_MAGIC : CDS_ARCHIVE_MAGIC); + if (CDSConfig::is_dumping_dynamic_archive()) { + set_magic(CDS_DYNAMIC_ARCHIVE_MAGIC); + } else if (CDSConfig::is_dumping_preimage_static_archive()) { + set_magic(CDS_PREIMAGE_ARCHIVE_MAGIC); + } else { + set_magic(CDS_ARCHIVE_MAGIC); + } set_version(CURRENT_CDS_ARCHIVE_VERSION); if (!info->is_static() && base_archive_name_size != 0) { @@ -386,7 +399,7 @@ public: assert(_archive_name != nullptr, "Archive name is null"); _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { - log_info(cds)("Specified shared archive not found (%s)", _archive_name); + log_info(cds)("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); return false; } return initialize(_fd); @@ -397,30 +410,32 @@ public: assert(_archive_name != nullptr, "Archive name is null"); assert(fd != -1, "Archive must be opened already"); // First read the generic header so we know the exact size of the actual header. + const char* file_type = CDSConfig::type_of_archive_being_loaded(); GenericCDSFileMapHeader gen_header; size_t size = sizeof(GenericCDSFileMapHeader); os::lseek(fd, 0, SEEK_SET); size_t n = ::read(fd, (void*)&gen_header, (unsigned int)size); if (n != size) { - log_warning(cds)("Unable to read generic CDS file map header from shared archive"); + log_warning(cds)("Unable to read generic CDS file map header from %s", file_type); return false; } if (gen_header._magic != CDS_ARCHIVE_MAGIC && - gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - log_warning(cds)("The shared archive file has a bad magic number: %#x", gen_header._magic); + gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC && + gen_header._magic != CDS_PREIMAGE_ARCHIVE_MAGIC) { + log_warning(cds)("The %s has a bad magic number: %#x", file_type, gen_header._magic); return false; } if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) { - log_warning(cds)("Cannot handle shared archive file version 0x%x. Must be at least 0x%x.", - gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION); + log_warning(cds)("Cannot handle %s version 0x%x. Must be at least 0x%x.", + file_type, gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION); return false; } if (gen_header._version != CURRENT_CDS_ARCHIVE_VERSION) { - log_warning(cds)("The shared archive file version 0x%x does not match the required version 0x%x.", - gen_header._version, CURRENT_CDS_ARCHIVE_VERSION); + log_warning(cds)("The %s version 0x%x does not match the required version 0x%x.", + file_type, gen_header._version, CURRENT_CDS_ARCHIVE_VERSION); } size_t filelen = os::lseek(fd, 0, SEEK_END); @@ -435,7 +450,7 @@ public: os::lseek(fd, 0, SEEK_SET); n = ::read(fd, (void*)_header, (unsigned int)size); if (n != size) { - log_warning(cds)("Unable to read actual CDS file map header from shared archive"); + log_warning(cds)("Unable to read file map header from %s", file_type); return false; } @@ -462,6 +477,18 @@ public: return _base_archive_name; } + bool is_static_archive() const { + return _header->_magic == CDS_ARCHIVE_MAGIC; + } + + bool is_dynamic_archive() const { + return _header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC; + } + + bool is_preimage_static_archive() const { + return _header->_magic == CDS_PREIMAGE_ARCHIVE_MAGIC; + } + private: bool check_header_crc() const { if (VerifySharedSpaces) { @@ -487,7 +514,8 @@ public: name_offset, name_size); return false; } - if (_header->_magic == CDS_ARCHIVE_MAGIC) { + + if (is_static_archive() || is_preimage_static_archive()) { if (name_offset != 0) { log_warning(cds)("static shared archive must have zero _base_archive_name_offset"); return false; @@ -497,7 +525,7 @@ public: return false; } } else { - assert(_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC, "must be"); + assert(is_dynamic_archive(), "must be"); if ((name_size == 0 && name_offset != 0) || (name_size != 0 && name_offset == 0)) { // If either is zero, both must be zero. This indicates that we are using the default base archive. @@ -545,7 +573,12 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, return false; } GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); - if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { + switch (header->_magic) { + case CDS_PREIMAGE_ARCHIVE_MAGIC: + return false; // This is a binary config file, not a proper archive + case CDS_DYNAMIC_ARCHIVE_MAGIC: + break; + default: assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be"); if (AutoCreateSharedArchive) { log_warning(cds)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name); @@ -563,6 +596,14 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, return true; } +bool FileMapInfo::is_preimage_static_archive(const char* file) { + FileHeaderHelper file_helper(file, false); + if (!file_helper.initialize()) { + return false; + } + return file_helper.is_preimage_static_archive(); +} + // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { @@ -573,9 +614,17 @@ bool FileMapInfo::init_from_file(int fd) { } GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header(); + const char* file_type = CDSConfig::type_of_archive_being_loaded(); if (_is_static) { - if (gen_header->_magic != CDS_ARCHIVE_MAGIC) { - log_warning(cds)("Not a base shared archive: %s", _full_path); + if ((gen_header->_magic == CDS_ARCHIVE_MAGIC) || + (gen_header->_magic == CDS_PREIMAGE_ARCHIVE_MAGIC && CDSConfig::is_dumping_final_static_archive())) { + // Good + } else { + if (CDSConfig::new_aot_flags_used()) { + log_warning(cds)("Not a valid %s %s", file_type, _full_path); + } else { + log_warning(cds)("Not a base shared archive: %s", _full_path); + } return false; } } else { @@ -597,7 +646,7 @@ bool FileMapInfo::init_from_file(int fd) { if (header()->version() != CURRENT_CDS_ARCHIVE_VERSION) { log_info(cds)("_version expected: 0x%x", CURRENT_CDS_ARCHIVE_VERSION); log_info(cds)(" actual: 0x%x", header()->version()); - log_warning(cds)("The shared archive file has the wrong version."); + log_warning(cds)("The %s has the wrong version.", file_type); return false; } @@ -609,7 +658,7 @@ bool FileMapInfo::init_from_file(int fd) { log_info(cds)("_header_size: " UINT32_FORMAT, header_size); log_info(cds)("base_archive_name_size: " UINT32_FORMAT, header()->base_archive_name_size()); log_info(cds)("base_archive_name_offset: " UINT32_FORMAT, header()->base_archive_name_offset()); - log_warning(cds)("The shared archive file has an incorrect header size."); + log_warning(cds)("The %s has an incorrect header size.", file_type); return false; } } @@ -626,8 +675,8 @@ bool FileMapInfo::init_from_file(int fd) { if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) { log_info(cds)("_jvm_ident expected: %s", expected_ident); log_info(cds)(" actual: %s", actual_ident); - log_warning(cds)("The shared archive file was created by a different" - " version or build of HotSpot"); + log_warning(cds)("The %s was created by a different" + " version or build of HotSpot", file_type); return false; } @@ -638,7 +687,7 @@ bool FileMapInfo::init_from_file(int fd) { for (int i = 0; i < MetaspaceShared::n_regions; i++) { FileMapRegion* r = region_at(i); if (r->file_offset() > len || len - r->file_offset() < r->used()) { - log_warning(cds)("The shared archive file has been truncated."); + log_warning(cds)("The %s has been truncated.", file_type); return false; } } @@ -658,18 +707,21 @@ bool FileMapInfo::open_for_read() { if (_file_open) { return true; } - log_info(cds)("trying to map %s", _full_path); + const char* file_type = CDSConfig::type_of_archive_being_loaded(); + const char* info = CDSConfig::is_dumping_final_static_archive() ? + "AOTConfiguration file " : ""; + log_info(cds)("trying to map %s%s", info, _full_path); int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); if (fd < 0) { if (errno == ENOENT) { - log_info(cds)("Specified shared archive not found (%s)", _full_path); + log_info(cds)("Specified %s not found (%s)", file_type, _full_path); } else { - log_warning(cds)("Failed to open shared archive file (%s)", + log_warning(cds)("Failed to open %s (%s)", file_type, os::strerror(errno)); } return false; } else { - log_info(cds)("Opened archive %s.", _full_path); + log_info(cds)("Opened %s %s.", file_type, _full_path); } _fd = fd; @@ -682,20 +734,25 @@ bool FileMapInfo::open_for_read() { void FileMapInfo::open_for_write() { LogMessage(cds) msg; if (msg.is_info()) { - msg.info("Dumping shared data to file: "); + if (CDSConfig::is_dumping_preimage_static_archive()) { + msg.info("Writing binary AOTConfiguration file: "); + } else { + msg.info("Dumping shared data to file: "); + } msg.info(" %s", _full_path); } #ifdef _WINDOWS // On Windows, need WRITE permission to remove the file. - chmod(_full_path, _S_IREAD | _S_IWRITE); + chmod(_full_path, _S_IREAD | _S_IWRITE); #endif // Use remove() to delete the existing file because, on Unix, this will // allow processes that have it open continued access to the file. remove(_full_path); - int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); + int mode = CDSConfig::is_dumping_preimage_static_archive() ? 0666 : 0444; + int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, mode); if (fd < 0) { - log_error(cds)("Unable to create shared archive file %s: (%s).", _full_path, + log_error(cds)("Unable to create %s %s: (%s).", CDSConfig::type_of_archive_being_written(), _full_path, os::strerror(errno)); MetaspaceShared::writing_error(); return; @@ -951,7 +1008,14 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { // If the shared archive is corrupted, close it and remove it. close(); remove(_full_path); - MetaspaceShared::writing_error("Unable to write to shared archive file."); + + if (CDSConfig::is_dumping_preimage_static_archive()) { + MetaspaceShared::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."); + } else { + MetaspaceShared::writing_error("Unable to write to shared archive."); + } } _file_offset += nbytes; } @@ -1793,15 +1857,16 @@ int FileMapHeader::compute_crc() { // This function should only be called during run time with UseSharedSpaces enabled. bool FileMapHeader::validate() { + const char* file_type = CDSConfig::type_of_archive_being_loaded(); if (_obj_alignment != ObjectAlignmentInBytes) { - log_info(cds)("The shared archive file's ObjectAlignmentInBytes of %d" + log_info(cds)("The %s's ObjectAlignmentInBytes of %d" " does not equal the current ObjectAlignmentInBytes of %d.", - _obj_alignment, ObjectAlignmentInBytes); + file_type, _obj_alignment, ObjectAlignmentInBytes); return false; } if (_compact_strings != CompactStrings) { - log_info(cds)("The shared archive file's CompactStrings setting (%s)" - " does not equal the current CompactStrings setting (%s).", + log_info(cds)("The %s's CompactStrings setting (%s)" + " does not equal the current CompactStrings setting (%s).", file_type, _compact_strings ? "enabled" : "disabled", CompactStrings ? "enabled" : "disabled"); return false; @@ -1825,8 +1890,8 @@ bool FileMapHeader::validate() { if (!_verify_local && BytecodeVerificationLocal) { // we cannot load boot classes, so there's no point of using the CDS archive - log_info(cds)("The shared archive file's BytecodeVerificationLocal setting (%s)" - " does not equal the current BytecodeVerificationLocal setting (%s).", + log_info(cds)("The %s's BytecodeVerificationLocal setting (%s)" + " does not equal the current BytecodeVerificationLocal setting (%s).", file_type, _verify_local ? "enabled" : "disabled", BytecodeVerificationLocal ? "enabled" : "disabled"); return false; @@ -1837,8 +1902,8 @@ bool FileMapHeader::validate() { if (_has_platform_or_app_classes && !_verify_remote // we didn't verify the archived platform/app classes && BytecodeVerificationRemote) { // but we want to verify all loaded platform/app classes - log_info(cds)("The shared archive file was created with less restrictive " - "verification setting than the current setting."); + log_info(cds)("The %s was created with less restrictive " + "verification setting than the current setting.", file_type); // Pretend that we didn't have any archived platform/app classes, so they won't be loaded // by SystemDictionaryShared. _has_platform_or_app_classes = false; @@ -1850,32 +1915,32 @@ bool FileMapHeader::validate() { // while AllowArchivingWithJavaAgent is set during the current run. if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) { log_warning(cds)("The setting of the AllowArchivingWithJavaAgent is different " - "from the setting in the shared archive."); + "from the setting in the %s.", file_type); return false; } if (_allow_archiving_with_java_agent) { - log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " - "for testing purposes only and should not be used in a production environment"); + log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + "for testing purposes only and should not be used in a production environment", file_type); } - log_info(cds)("Archive was created with UseCompressedOops = %d, UseCompressedClassPointers = %d, UseCompactObjectHeaders = %d", - compressed_oops(), compressed_class_pointers(), compact_headers()); + log_info(cds)("The %s was created with UseCompressedOops = %d, UseCompressedClassPointers = %d, UseCompactObjectHeaders = %d", + file_type, compressed_oops(), compressed_class_pointers(), compact_headers()); if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) { - log_warning(cds)("Unable to use shared archive.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " - "different from runtime, CDS will be disabled."); + log_warning(cds)("Unable to use %s.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " + "different from runtime, CDS will be disabled.", file_type); return false; } if (compact_headers() != UseCompactObjectHeaders) { - log_warning(cds)("Unable to use shared archive.\nThe shared archive file's UseCompactObjectHeaders setting (%s)" - " does not equal the current UseCompactObjectHeaders setting (%s).", + log_warning(cds)("Unable to use %s.\nThe %s's UseCompactObjectHeaders setting (%s)" + " does not equal the current UseCompactObjectHeaders setting (%s).", file_type, file_type, _compact_headers ? "enabled" : "disabled", UseCompactObjectHeaders ? "enabled" : "disabled"); return false; } - if (!_use_optimized_module_handling) { + if (!_use_optimized_module_handling && !CDSConfig::is_dumping_final_static_archive()) { CDSConfig::stop_using_optimized_module_handling(); log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling"); } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 22f70635e17..25550d76d2a 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -270,12 +270,15 @@ public: FileMapHeader *header() const { return _header; } static bool get_base_archive_name_from_header(const char* archive_name, char** base_archive_name); + static bool is_preimage_static_archive(const char* file); + bool init_from_file(int fd); void log_paths(const char* msg, int start_idx, int end_idx); FileMapInfo(const char* full_apth, bool is_static); ~FileMapInfo(); + static void free_current_info(); // Accessors int compute_header_crc() const { return header()->compute_crc(); } diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp new file mode 100644 index 00000000000..55855679a1c --- /dev/null +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -0,0 +1,167 @@ +/* + * 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 "cds/aotConstantPoolResolver.hpp" +#include "cds/archiveBuilder.hpp" +#include "cds/archiveUtils.inline.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/finalImageRecipes.hpp" +#include "classfile/classLoader.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/systemDictionaryShared.hpp" +#include "classfile/vmClasses.hpp" +#include "memory/oopFactory.hpp" +#include "memory/resourceArea.hpp" +#include "oops/constantPool.inline.hpp" +#include "runtime/handles.inline.hpp" + +static FinalImageRecipes* _final_image_recipes = nullptr; + +void* FinalImageRecipes::operator new(size_t size) throw() { + return ArchiveBuilder::current()->ro_region_alloc(size); +} + +void FinalImageRecipes::record_recipes_impl() { + assert(CDSConfig::is_dumping_preimage_static_archive(), "must be"); + ResourceMark rm; + GrowableArray* klasses = ArchiveBuilder::current()->klasses(); + + // Record the indys that have been resolved in the training run. These indys will be + // resolved during the final image assembly. + + GrowableArray tmp_indy_klasses; + GrowableArray*> tmp_indy_cp_indices; + int total_indys_to_resolve = 0; + for (int i = 0; i < klasses->length(); i++) { + Klass* k = klasses->at(i); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + GrowableArray indices; + + if (ik->constants()->cache() != nullptr) { + Array* tmp_indy_entries = ik->constants()->cache()->resolved_indy_entries(); + if (tmp_indy_entries != nullptr) { + for (int i = 0; i < tmp_indy_entries->length(); i++) { + ResolvedIndyEntry* rie = tmp_indy_entries->adr_at(i); + int cp_index = rie->constant_pool_index(); + if (rie->is_resolved()) { + indices.append(cp_index); + } + } + } + } + + if (indices.length() > 0) { + tmp_indy_klasses.append(ArchiveBuilder::current()->get_buffered_addr(ik)); + tmp_indy_cp_indices.append(ArchiveUtils::archive_array(&indices)); + total_indys_to_resolve += indices.length(); + } + } + } + + _all_klasses = ArchiveUtils::archive_array(klasses); + ArchivePtrMarker::mark_pointer(&_all_klasses); + + assert(tmp_indy_klasses.length() == tmp_indy_cp_indices.length(), "must be"); + if (tmp_indy_klasses.length() > 0) { + _indy_klasses = ArchiveUtils::archive_array(&tmp_indy_klasses); + _indy_cp_indices = ArchiveUtils::archive_array(&tmp_indy_cp_indices); + + ArchivePtrMarker::mark_pointer(&_indy_klasses); + ArchivePtrMarker::mark_pointer(&_indy_cp_indices); + } + log_info(cds)("%d indies in %d classes will be resolved in final CDS image", total_indys_to_resolve, tmp_indy_klasses.length()); +} + +void FinalImageRecipes::load_all_classes(TRAPS) { + assert(CDSConfig::is_dumping_final_static_archive(), "sanity"); + Handle class_loader(THREAD, SystemDictionary::java_system_loader()); + for (int i = 0; i < _all_klasses->length(); i++) { + Klass* k = _all_klasses->at(i); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + if (!ik->is_shared_unregistered_class() && !ik->is_hidden()) { + Klass* actual = SystemDictionary::resolve_or_fail(ik->name(), class_loader, true, CHECK); + if (actual != ik) { + ResourceMark rm(THREAD); + log_error(cds)("Unable to resolve class from CDS archive: %s", ik->external_name()); + log_error(cds)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); + log_error(cds)("Please check if your VM command-line is the same as in the training run"); + MetaspaceShared::unrecoverable_writing_error(); + } + assert(ik->is_loaded(), "must be"); + ik->link_class(CHECK); + } + } + } +} + +void FinalImageRecipes::apply_recipes_for_invokedynamic(TRAPS) { + assert(CDSConfig::is_dumping_final_static_archive(), "must be"); + + if (CDSConfig::is_dumping_invokedynamic() && _indy_klasses != nullptr) { + assert(_indy_cp_indices != nullptr, "must be"); + for (int i = 0; i < _indy_klasses->length(); i++) { + InstanceKlass* ik = _indy_klasses->at(i); + ConstantPool* cp = ik->constants(); + Array* cp_indices = _indy_cp_indices->at(i); + GrowableArray preresolve_list(cp->length(), cp->length(), false); + for (int j = 0; j < cp_indices->length(); j++) { + preresolve_list.at_put(cp_indices->at(j), true); + } + AOTConstantPoolResolver::preresolve_indy_cp_entries(THREAD, ik, &preresolve_list); + } + } +} + +void FinalImageRecipes::record_recipes() { + _final_image_recipes = new FinalImageRecipes(); + _final_image_recipes->record_recipes_impl(); +} + +void FinalImageRecipes::apply_recipes(TRAPS) { + assert(CDSConfig::is_dumping_final_static_archive(), "must be"); + if (_final_image_recipes != nullptr) { + _final_image_recipes->apply_recipes_impl(THREAD); + if (HAS_PENDING_EXCEPTION) { + log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), + java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); + log_error(cds)("Please check if your VM command-line is the same as in the training run"); + MetaspaceShared::unrecoverable_writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail"); + } + } + + // Set it to null as we don't need to write this table into the final image. + _final_image_recipes = nullptr; +} + +void FinalImageRecipes::apply_recipes_impl(TRAPS) { + load_all_classes(CHECK); + apply_recipes_for_invokedynamic(CHECK); +} + +void FinalImageRecipes::serialize(SerializeClosure* soc) { + soc->do_ptr((void**)&_final_image_recipes); +} diff --git a/src/hotspot/share/cds/finalImageRecipes.hpp b/src/hotspot/share/cds/finalImageRecipes.hpp new file mode 100644 index 00000000000..f07d9787af9 --- /dev/null +++ b/src/hotspot/share/cds/finalImageRecipes.hpp @@ -0,0 +1,76 @@ +/* + * 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_CDS_FINALIMAGERECIPES_HPP +#define SHARE_CDS_FINALIMAGERECIPES_HPP + +#include "oops/oopsHierarchy.hpp" +#include "utilities/exceptions.hpp" + +class InstanceKlass; +class Klass; + +template class GrowableArray; +template class Array; + +// This class is used for transferring information from the AOTConfiguration file (aka the "preimage") +// to the JVM that creates the AOTCache (aka the "final image"). +// - The recipes are recorded when CDSConfig::is_dumping_preimage_static_archive() is true. +// - The recipes are applied when CDSConfig::is_dumping_final_static_archive() is true. +// The following information are recorded: +// - The list of all classes that are stored in the AOTConfiguration file. +// - The list of all classes that require AOT resolution of invokedynamic call sites. +class FinalImageRecipes { + // A list of all the archived classes from the preimage. We want to transfer all of these + // into the final image. + Array* _all_klasses; + + // The classes who have resolved at least one indy CP entry during the training run. + // _indy_cp_indices[i] is a list of all resolved CP entries for _indy_klasses[i]. + Array* _indy_klasses; + Array*>* _indy_cp_indices; + + FinalImageRecipes() : _indy_klasses(nullptr), _indy_cp_indices(nullptr) {} + + void* operator new(size_t size) throw(); + + // Called when dumping preimage + void record_recipes_impl(); + + // Called when dumping final image + void apply_recipes_impl(TRAPS); + void load_all_classes(TRAPS); + void apply_recipes_for_invokedynamic(TRAPS); + +public: + static void serialize(SerializeClosure* soc); + + // Called when dumping preimage + static void record_recipes(); + + // Called when dumping final image + static void apply_recipes(TRAPS); +}; + +#endif // SHARE_CDS_FINALIMAGERECIPES_HPP diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 5aa456ea438..c95a358de5f 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -401,6 +401,11 @@ objArrayOop HeapShared::scratch_resolved_references(ConstantPool* src) { return (objArrayOop)_scratch_references_table->get_oop(src); } +void HeapShared::init_dumping() { + _scratch_java_mirror_table = new (mtClass)MetaspaceObjToOopHandleTable(); + _scratch_references_table = new (mtClass)MetaspaceObjToOopHandleTable(); +} + void HeapShared::init_scratch_objects(TRAPS) { for (int i = T_BOOLEAN; i < T_VOID+1; i++) { BasicType bt = (BasicType)i; @@ -409,8 +414,6 @@ void HeapShared::init_scratch_objects(TRAPS) { _scratch_basic_type_mirrors[i] = OopHandle(Universe::vm_global(), m); } } - _scratch_java_mirror_table = new (mtClass)MetaspaceObjToOopHandleTable(); - _scratch_references_table = new (mtClass)MetaspaceObjToOopHandleTable(); } // Given java_mirror that represents a (primitive or reference) type T, diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 11250f1a35c..ba2fe5be775 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -405,6 +405,7 @@ private: static void write_heap(ArchiveHeapInfo* heap_info) NOT_CDS_JAVA_HEAP_RETURN; static objArrayOop scratch_resolved_references(ConstantPool* src); static void add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) NOT_CDS_JAVA_HEAP_RETURN; + static void init_dumping() NOT_CDS_JAVA_HEAP_RETURN; static void init_scratch_objects(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void init_box_classes(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static bool is_heap_region(int idx) { diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index ee3e9cff782..fc1917086f3 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -263,4 +263,8 @@ void LambdaFormInvokers::read_static_archive_invokers() { void LambdaFormInvokers::serialize(SerializeClosure* soc) { soc->do_ptr(&_static_archive_invokers); + if (soc->reading() && CDSConfig::is_dumping_final_static_archive()) { + LambdaFormInvokers::read_static_archive_invokers(); + _static_archive_invokers = nullptr; + } } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index b95d524cb1d..2e5ebff456e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -39,6 +39,7 @@ #include "cds/dumpAllocStats.hpp" #include "cds/dynamicArchive.hpp" #include "cds/filemap.hpp" +#include "cds/finalImageRecipes.hpp" #include "cds/heapShared.hpp" #include "cds/lambdaFormInvokers.hpp" #include "cds/metaspaceShared.hpp" @@ -489,6 +490,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { HeapShared::serialize_tables(soc); SystemDictionaryShared::serialize_dictionary_headers(soc); AOTLinkedClassBulkLoader::serialize(soc, true); + FinalImageRecipes::serialize(soc); InstanceMirrorKlass::serialize_offsets(soc); // Dump/restore well known classes (pointers) @@ -609,6 +611,9 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& SystemDictionaryShared::write_to_archive(); cl_config = AOTClassLocationConfig::dumptime()->write_to_archive(); AOTClassLinker::write_to_archive(); + if (CDSConfig::is_dumping_preimage_static_archive()) { + FinalImageRecipes::record_recipes(); + } MetaspaceShared::write_method_handle_intrinsics(); // Write lambform lines into archive @@ -624,7 +629,9 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& } void VM_PopulateDumpSharedSpace::doit() { - guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); + if (!CDSConfig::is_dumping_final_static_archive()) { + guarantee(!CDSConfig::is_using_archive(), "We should not be using an archive when we dump"); + } DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); @@ -679,7 +686,13 @@ void VM_PopulateDumpSharedSpace::doit() { CppVtables::zero_archived_vtables(); // Write the archive file - const char* static_archive = CDSConfig::static_archive_path(); + const char* static_archive; + if (CDSConfig::is_dumping_final_static_archive()) { + static_archive = AOTCache; + FileMapInfo::free_current_info(); + } else { + static_archive = CDSConfig::static_archive_path(); + } assert(static_archive != nullptr, "SharedArchiveFile not set?"); _map_info = new FileMapInfo(static_archive, true); _map_info->populate_header(MetaspaceShared::core_region_alignment()); @@ -743,7 +756,7 @@ bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) { void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { AOTClassLinker::initialize(); - if (!jcmd_request) { + if (!jcmd_request && !CDSConfig::is_dumping_final_static_archive()) { LambdaFormInvokers::regenerate_holder_classes(CHECK); } @@ -778,6 +791,10 @@ void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) { // Class linking includes verification which may load more classes. // Keep scanning until we have linked no more classes. } + + if (CDSConfig::is_dumping_final_static_archive()) { + FinalImageRecipes::apply_recipes(CHECK); + } } void MetaspaceShared::prepare_for_dumping() { @@ -804,13 +821,18 @@ void MetaspaceShared::preload_and_dump(TRAPS) { } } - if (!CDSConfig::old_cds_flags_used()) { - // The JLI launcher only recognizes the "old" -Xshare:dump flag. - // When the new -XX:AOTMode=create flag is used, we can't return - // to the JLI launcher, as the launcher will fail when trying to - // run the main class, which is not what we want. - tty->print_cr("AOTCache creation is complete: %s", AOTCache); - vm_exit(0); + if (CDSConfig::new_aot_flags_used()) { + if (CDSConfig::is_dumping_preimage_static_archive()) { + tty->print_cr("AOTConfiguration recorded: %s", AOTConfiguration); + vm_exit(0); + } else { + // The JLI launcher only recognizes the "old" -Xshare:dump flag. + // When the new -XX:AOTMode=create flag is used, we can't return + // to the JLI launcher, as the launcher will fail when trying to + // run the main class, which is not what we want. + tty->print_cr("AOTCache creation is complete: %s", AOTCache); + vm_exit(0); + } } } @@ -910,12 +932,34 @@ void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { } void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) { - preload_classes(CHECK); + if (CDSConfig::is_dumping_classic_static_archive()) { + // We are running with -Xshare:dump + preload_classes(CHECK); - if (SharedArchiveConfigFile) { - log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile); - read_extra_data(THREAD, SharedArchiveConfigFile); - log_info(cds)("Reading extra data: done."); + if (SharedArchiveConfigFile) { + log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile); + read_extra_data(THREAD, SharedArchiveConfigFile); + log_info(cds)("Reading extra data: done."); + } + } + + if (CDSConfig::is_dumping_preimage_static_archive()) { + log_info(cds)("Reading lambda form invokers from JDK default classlist ..."); + char default_classlist[JVM_MAXPATHLEN]; + get_default_classlist(default_classlist, sizeof(default_classlist)); + struct stat statbuf; + if (os::stat(default_classlist, &statbuf) == 0) { + ClassListParser::parse_classlist(default_classlist, + ClassListParser::_parse_lambda_forms_invokers_only, CHECK); + } + } + + if (CDSConfig::is_dumping_final_static_archive()) { + if (ExtraSharedClassListFile) { + log_info(cds)("Loading extra classes from %s ...", ExtraSharedClassListFile); + ClassListParser::parse_classlist(ExtraSharedClassListFile, + ClassListParser::_parse_all, CHECK); + } } // Rewrite and link classes @@ -993,8 +1037,8 @@ bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* builder->write_archive(map_info, heap_info); if (AllowArchivingWithJavaAgent) { - log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " - "for testing purposes only and should not be used in a production environment"); + log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + "for testing purposes only and should not be used in a production environment", CDSConfig::type_of_archive_being_loaded()); } return true; } @@ -1004,7 +1048,13 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { ExceptionMark em(current); JavaThread* THREAD = current; // For exception macros. assert(CDSConfig::is_dumping_archive(), "sanity"); - if (!ik->is_shared() && ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() && + + if (ik->is_shared() && !CDSConfig::is_dumping_final_static_archive()) { + assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); + return false; + } + + if (ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() && !SystemDictionaryShared::has_class_failed_verification(ik)) { bool saved = BytecodeVerificationLocal; if (ik->is_shared_unregistered_class() && ik->class_loader() == nullptr) { @@ -1072,11 +1122,18 @@ bool MetaspaceShared::is_shared_static(void* p) { // - 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) { - log_error(cds)("An error has occurred while processing the shared archive file."); + log_error(cds)("An error has occurred while processing the %s.", CDSConfig::type_of_archive_being_loaded()); if (message != nullptr) { log_error(cds)("%s", message); } - vm_exit_during_initialization("Unable to use shared archive.", nullptr); + + if (CDSConfig::is_dumping_final_static_archive()) { + vm_exit_during_initialization("Must be a valid AOT configuration generated by the current JVM", AOTConfiguration); + } else if (CDSConfig::new_aot_flags_used()) { + vm_exit_during_initialization("Unable to use AOT cache.", nullptr); + } else { + vm_exit_during_initialization("Unable to use shared archive.", nullptr); + } } // This function is called when the JVM is unable to write the specified CDS archive due to an diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index ca60e11736d..8ad2efcbccb 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.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 @@ -41,7 +41,13 @@ class Method; class Symbol; class RunTimeClassInfo { -public: + public: + enum : char { + FROM_FIELD_IS_PROTECTED = 1 << 0, + FROM_IS_ARRAY = 1 << 1, + FROM_IS_OBJECT = 1 << 2 + }; + struct CrcInfo { int _clsfile_size; int _clsfile_crc32; @@ -202,6 +208,17 @@ public: return verifier_constraint_flags()[i]; } + bool from_field_is_protected(int i) { + return (verifier_constraint_flag(i) & FROM_FIELD_IS_PROTECTED) != 0; + } + + bool from_is_array(int i) { + return (verifier_constraint_flag(i) & FROM_IS_ARRAY) != 0; + } + bool from_is_object(int i) { + return (verifier_constraint_flag(i) & FROM_IS_OBJECT) != 0; + } + int num_enum_klass_static_fields(int i) const { return enum_klass_static_fields_addr()->_num; } diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 55363d7f41f..18f2abfd5f4 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -413,7 +413,13 @@ ModuleEntry* ModuleEntry::allocate_archived_entry() const { _archive_modules_entries->put(this, archived_entry); DEBUG_ONLY(_num_archived_module_entries++); - assert(archived_entry->shared_protection_domain() == nullptr, "never set during -Xshare:dump"); + if (CDSConfig::is_dumping_final_static_archive()) { + OopHandle null_handle; + archived_entry->_shared_pd = null_handle; + } else { + assert(archived_entry->shared_protection_domain() == nullptr, "never set during -Xshare:dump"); + } + // Clear handles and restore at run time. Handles cannot be archived. OopHandle null_handle; archived_entry->_module = null_handle; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 68f9556099f..811ba12a1e9 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1177,6 +1177,10 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData // notify a class loaded from shared object ClassLoadingService::notify_class_loaded(ik, true /* shared class */); + + if (CDSConfig::is_dumping_final_static_archive()) { + SystemDictionaryShared::init_dumptime_info_from_preimage(ik); + } } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index b8e24bb2caa..2f7887c2d46 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotClassLocation.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/archiveUtils.hpp" @@ -193,23 +194,20 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( // k must not be a shared class. DumpTimeClassInfo* SystemDictionaryShared::get_info(InstanceKlass* k) { MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); - assert(!k->is_shared(), "sanity"); return get_info_locked(k); } DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) { assert_lock_strong(DumpTimeTable_lock); - assert(!k->is_shared(), "sanity"); DumpTimeClassInfo* info = _dumptime_table->get_info(k); assert(info != nullptr, "must be"); return info; } bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClassInfo* info) { - if (MetaspaceShared::is_in_shared_metaspace(k)) { + if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(k)) { // We have reached a super type that's already in the base archive. Treat it // as "not excluded". - assert(CDSConfig::is_dumping_dynamic_archive(), "must be"); return false; } @@ -277,6 +275,11 @@ bool SystemDictionaryShared::is_hidden_lambda_proxy(InstanceKlass* ik) { } bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { + if (CDSConfig::is_dumping_final_static_archive() && k->is_shared_unregistered_class() + && k->is_shared()) { + return false; // Do not exclude: unregistered classes are passed from preimage to final image. + } + if (k->is_in_error_state()) { return warn_excluded(k, "In error state"); } @@ -329,6 +332,10 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { // 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()) { + // When dumping the final static archive, we will unconditionally load and link all + // classes from tje preimage. We don't want to get a VerifyError when linking this class. + return warn_excluded(k, "Unlinked class not supported by AOTConfiguration"); } } else { if (!k->can_be_verified_at_dumptime()) { @@ -497,6 +504,9 @@ void SystemDictionaryShared::initialize() { _dumptime_table = new (mtClass) DumpTimeSharedClassTable; _dumptime_lambda_proxy_class_dictionary = new (mtClass) DumpTimeLambdaProxyClassDictionary; + if (CDSConfig::is_dumping_heap()) { + HeapShared::init_dumping(); + } } } @@ -537,6 +547,18 @@ 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_linking_constraints_from_preimage(k); + + if (SystemDictionary::is_platform_class_loader(k->class_loader())) { + AOTClassLocationConfig::dumptime_set_has_platform_classes(); + } else if (SystemDictionary::is_system_class_loader(k->class_loader())) { + AOTClassLocationConfig::dumptime_set_has_app_classes(); + } +} + // Check if a class or any of its supertypes has been redefined. bool SystemDictionaryShared::has_been_redefined(InstanceKlass* k) { if (k->has_been_redefined()) { @@ -723,7 +745,10 @@ void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) { assert_lock_strong(DumpTimeTable_lock); auto do_klass = [&] (InstanceKlass* k, DumpTimeClassInfo& info) { - if (k->is_loader_alive() && !info.is_excluded()) { + if (CDSConfig::is_dumping_final_static_archive() && !k->is_loaded()) { + assert(k->is_shared_unregistered_class(), "must be"); + info.metaspace_pointers_do(it); + } else if (k->is_loader_alive() && !info.is_excluded()) { info.metaspace_pointers_do(it); } }; @@ -795,6 +820,10 @@ void SystemDictionaryShared::add_lambda_proxy_class(InstanceKlass* caller_ik, // There's no need to remember them in a separate table. return; } + if (CDSConfig::is_dumping_preimage_static_archive()) { + // Information about lambda proxies are recorded in FinalImageRecipes. + return; + } assert(caller_ik->class_loader() == lambda_ik->class_loader(), "mismatched class loader"); assert(caller_ik->class_loader_data() == lambda_ik->class_loader_data(), "mismatched class loader data"); @@ -832,6 +861,10 @@ InstanceKlass* SystemDictionaryShared::get_shared_lambda_proxy_class(InstanceKla Symbol* method_type, Method* member_method, Symbol* instantiated_method_type) { + if (CDSConfig::is_dumping_final_static_archive()) { + return nullptr; + } + assert(caller_ik != nullptr, "sanity"); assert(invoked_name != nullptr, "sanity"); assert(invoked_type != nullptr, "sanity"); @@ -956,7 +989,7 @@ InstanceKlass* SystemDictionaryShared::prepare_shared_lambda_proxy_class(Instanc void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass, TRAPS) { - assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); + assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); RunTimeClassInfo* record = RunTimeClassInfo::get_for(klass); int length = record->num_verifier_constraints(); @@ -965,21 +998,16 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass RunTimeClassInfo::RTVerifierConstraint* vc = record->verifier_constraint_at(i); Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); - char c = record->verifier_constraint_flag(i); if (log_is_enabled(Trace, cds, verification)) { ResourceMark rm(THREAD); log_trace(cds, verification)("check_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); + name->as_klass_external_name(), record->verifier_constraint_flag(i)); } - bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false; - bool from_is_array = (c & SystemDictionaryShared::FROM_IS_ARRAY) ? true : false; - bool from_is_object = (c & SystemDictionaryShared::FROM_IS_OBJECT) ? true : false; - - bool ok = VerificationType::resolve_and_check_assignability(klass, name, - from_name, from_field_is_protected, from_is_array, from_is_object, CHECK); + bool ok = VerificationType::resolve_and_check_assignability(klass, name, from_name, + record->from_field_is_protected(i), record->from_is_array(i), record->from_is_object(i), CHECK); if (!ok) { ResourceMark rm(THREAD); stringStream ss; @@ -995,6 +1023,24 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass } } +void SystemDictionaryShared::copy_verification_constraints_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 + + int length = rt_info->num_verifier_constraints(); + if (length > 0) { + for (int i = 0; i < length; i++) { + RunTimeClassInfo::RTVerifierConstraint* vc = rt_info->verifier_constraint_at(i); + Symbol* name = vc->name(); + Symbol* from_name = vc->from_name(); + + dt_info->add_verification_constraint(klass, name, from_name, + rt_info->from_field_is_protected(i), rt_info->from_is_array(i), rt_info->from_is_object(i)); + } + } +} + static oop get_class_loader_by(char type) { if (type == (char)ClassLoader::BOOT_LOADER) { return (oop)nullptr; @@ -1066,7 +1112,7 @@ void SystemDictionaryShared::record_linking_constraint(Symbol* name, InstanceKla // returns true IFF there's no need to re-initialize the i/v-tables for klass for // the purpose of checking class loader constraints. bool SystemDictionaryShared::check_linking_constraints(Thread* current, InstanceKlass* klass) { - assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); + assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); LogTarget(Info, class, loader, constraints) log; if (klass->is_shared_boot_class()) { // No class loader constraint check performed for boot classes. @@ -1112,6 +1158,24 @@ bool SystemDictionaryShared::check_linking_constraints(Thread* current, Instance return false; } +void SystemDictionaryShared::copy_linking_constraints_from_preimage(InstanceKlass* klass) { + assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); + JavaThread* current = JavaThread::current(); + if (klass->is_shared_platform_class() || klass->is_shared_app_class()) { + RunTimeClassInfo* rt_info = RunTimeClassInfo::get_for(klass); // from preimage + + if (rt_info->num_loader_constraints() > 0) { + for (int i = 0; i < rt_info->num_loader_constraints(); i++) { + RunTimeClassInfo::RTLoaderConstraint* lc = rt_info->loader_constraint_at(i); + Symbol* name = lc->constraint_name(); + Handle loader1(current, get_class_loader_by(lc->_loader_type1)); + Handle loader2(current, get_class_loader_by(lc->_loader_type2)); + record_linking_constraint(name, klass, loader1, loader2); + } + } + } +} + bool SystemDictionaryShared::is_supported_invokedynamic(BootstrapInfo* bsi) { LogTarget(Debug, cds, lambda) log; if (bsi->arg_values() == nullptr || !bsi->arg_values()->is_objArray()) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 41e3d9c9716..7286bdad3fd 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -152,13 +152,6 @@ class SystemDictionaryShared: public SystemDictionary { void print_table_statistics(const char* prefix, outputStream* st); }; -public: - enum : char { - FROM_FIELD_IS_PROTECTED = 1 << 0, - FROM_IS_ARRAY = 1 << 1, - FROM_IS_OBJECT = 1 << 2 - }; - private: static DumpTimeSharedClassTable* _dumptime_table; @@ -199,6 +192,9 @@ private: static InstanceKlass* retrieve_lambda_proxy_class(const RunTimeLambdaProxyClassInfo* info) NOT_CDS_RETURN_(nullptr); DEBUG_ONLY(static bool _class_loading_may_happen;) + static void copy_verification_constraints_from_preimage(InstanceKlass* klass); + static void copy_linking_constraints_from_preimage(InstanceKlass* klass); + public: static bool is_registered_lambda_proxy_class(InstanceKlass* ik); static bool is_hidden_lambda_proxy(InstanceKlass* ik); @@ -229,6 +225,7 @@ public: static void initialize() NOT_CDS_RETURN; static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN; + static void init_dumptime_info_from_preimage(InstanceKlass* k) NOT_CDS_RETURN; static void handle_class_unloading(InstanceKlass* k) NOT_CDS_RETURN; static Dictionary* boot_loader_dictionary() { diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index 16d9d74e398..2a80dd68abd 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -38,6 +38,7 @@ #define NUM_CDS_REGIONS 4 // this must be the same as MetaspaceShared::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 +#define CDS_PREIMAGE_ARCHIVE_MAGIC 0xcafea07c #define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13 #define CURRENT_CDS_ARCHIVE_VERSION 18 diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index c1fc0bf669b..99d1d027db0 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -716,7 +716,6 @@ void Metaspace::global_initialize() { metaspace::ChunkHeaderPool::initialize(); if (CDSConfig::is_dumping_static_archive()) { - assert(!CDSConfig::is_using_archive(), "sanity"); MetaspaceShared::initialize_for_static_dump(); } diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 8aba2bb2ba3..ee53e43c327 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -454,6 +454,11 @@ void ConstantPool::restore_unshareable_info(TRAPS) { } } } + + if (CDSConfig::is_dumping_final_static_archive() && resolved_references() != nullptr) { + objArrayOop scratch_references = oopFactory::new_objArray(vmClasses::Object_klass(), resolved_references()->length(), CHECK); + HeapShared::add_scratch_resolved_references(this, scratch_references); + } } void ConstantPool::remove_unshareable_info() { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 9e3f73596e2..fb1b84b826a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2707,6 +2707,7 @@ void InstanceKlass::remove_unshareable_info() { } init_shared_package_entry(); _dep_context_last_cleaned = 0; + DEBUG_ONLY(_shared_class_load_count = 0); remove_unshareable_flags(); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 420d6ab39d9..ab05cbeb891 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1365,11 +1365,19 @@ void Arguments::set_mode_flags(Mode mode) { // incompatible command line options were chosen. void Arguments::no_shared_spaces(const char* message) { if (RequireSharedSpaces) { - jio_fprintf(defaultStream::error_stream(), - "Class data sharing is inconsistent with other specified options.\n"); - vm_exit_during_initialization("Unable to use shared archive", message); + log_error(cds)("%s is incompatible with other specified options.", + CDSConfig::new_aot_flags_used() ? "AOT cache" : "CDS"); + if (CDSConfig::new_aot_flags_used()) { + vm_exit_during_initialization("Unable to use AOT cache", message); + } else { + vm_exit_during_initialization("Unable to use shared archive", message); + } } else { - log_info(cds)("Unable to use shared archive: %s", message); + if (CDSConfig::new_aot_flags_used()) { + log_warning(cds)("Unable to use AOT cache: %s", message); + } else { + log_info(cds)("Unable to use shared archive: %s", message); + } UseSharedSpaces = false; } } diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index d6dda04e053..b2c24169505 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -23,6 +23,7 @@ */ #include "cds/cds_globals.hpp" +#include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" #include "cds/dynamicArchive.hpp" #include "classfile/classLoader.hpp" @@ -440,6 +441,10 @@ void before_exit(JavaThread* thread, bool halt) { #if INCLUDE_CDS ClassListWriter::write_resolved_constants(); + + if (CDSConfig::is_dumping_preimage_static_archive()) { + MetaspaceShared::preload_and_dump(thread); + } #endif // Hang forever on exit if we're reporting an error. diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 006f1be112a..32859bf2718 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -853,7 +853,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { _vm_complete = true; #endif - if (CDSConfig::is_dumping_static_archive()) { + if (CDSConfig::is_dumping_classic_static_archive()) { + // Classic -Xshare:dump, aka "old workflow" + MetaspaceShared::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); } diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index f58257da2ef..c71f5e2dfc9 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -405,6 +405,7 @@ hotspot_cds_only = \ hotspot_appcds_dynamic = \ runtime/cds/appcds/ \ + -runtime/cds/appcds/aotClassLinking \ -runtime/cds/appcds/applications \ -runtime/cds/appcds/cacheObject \ -runtime/cds/appcds/complexURI \ @@ -423,7 +424,6 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/jvmti/redefineClasses/OldClassAndRedefineClass.java \ -runtime/cds/appcds/lambdaForm/DefaultClassListLFInvokers.java \ -runtime/cds/appcds/methodHandles \ - -runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java \ -runtime/cds/appcds/sharedStrings \ -runtime/cds/appcds/resolvedConstants \ -runtime/cds/appcds/ArchiveRelocationTest.java \ diff --git a/test/hotspot/jtreg/runtime/cds/ArchiveDoesNotExist.java b/test/hotspot/jtreg/runtime/cds/ArchiveDoesNotExist.java index d8cf5816a1c..57e9269d8d1 100644 --- a/test/hotspot/jtreg/runtime/cds/ArchiveDoesNotExist.java +++ b/test/hotspot/jtreg/runtime/cds/ArchiveDoesNotExist.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, 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 @@ -50,7 +50,7 @@ public class ArchiveDoesNotExist { // -Xshare=on OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); CDSTestUtils.checkMappingFailure(out); - out.shouldContain("Specified shared archive not found") + out.shouldContain("Specified shared archive file not found") .shouldHaveExitValue(1); // -Xshare=auto diff --git a/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java index 98ff155abfa..aeb0476346d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/AOTFlags.java @@ -49,17 +49,21 @@ public class AOTFlags { } static void positiveTests() throws Exception { - // (1) Training Run + //---------------------------------------------------------------------- + printTestCase("Training Run"); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=record", "-XX:AOTConfiguration=" + aotConfigFile, + "-Xlog:cds=debug", "-cp", appJar, helloClass); OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "train"); out.shouldContain("Hello World"); + out.shouldContain("AOTConfiguration recorded: " + aotConfigFile); out.shouldHaveExitValue(0); - // (2) Assembly Phase (AOTClassLinking unspecified -> should be enabled by default) + //---------------------------------------------------------------------- + printTestCase("Assembly Phase (AOTClassLinking unspecified -> should be enabled by default)"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=create", "-XX:AOTConfiguration=" + aotConfigFile, @@ -71,18 +75,20 @@ public class AOTFlags { out.shouldMatch("cds.*hello[.]aot"); out.shouldHaveExitValue(0); - // (3) Production Run with AOTCache + //---------------------------------------------------------------------- + printTestCase("Production Run with AOTCache"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "-Xlog:cds", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain("Using AOT-linked classes: true (static archive: has aot-linked classes)"); - out.shouldContain("Opened archive hello.aot."); + out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); - // (4) AOTMode=off + //---------------------------------------------------------------------- + printTestCase("AOTMode=off"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "--show-version", @@ -91,11 +97,12 @@ public class AOTFlags { "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldNotContain(", sharing"); - out.shouldNotContain("Opened archive hello.aot."); + out.shouldNotContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); - // (5) AOTMode=auto + //---------------------------------------------------------------------- + printTestCase("AOTMode=auto"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "--show-version", @@ -104,11 +111,12 @@ public class AOTFlags { "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain(", sharing"); - out.shouldContain("Opened archive hello.aot."); + out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); - // (6) AOTMode=on + //---------------------------------------------------------------------- + printTestCase("AOTMode=on"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "--show-version", @@ -117,11 +125,12 @@ public class AOTFlags { "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain(", sharing"); - out.shouldContain("Opened archive hello.aot."); + out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); - // (7) Assembly Phase with -XX:-AOTClassLinking + //---------------------------------------------------------------------- + printTestCase("Assembly Phase with -XX:-AOTClassLinking"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=create", "-XX:-AOTClassLinking", @@ -134,20 +143,22 @@ public class AOTFlags { out.shouldMatch("cds.*hello[.]aot"); out.shouldHaveExitValue(0); - // (8) Production Run with AOTCache, which was created with -XX:-AOTClassLinking + //---------------------------------------------------------------------- + printTestCase("Production Run with AOTCache, which was created with -XX:-AOTClassLinking"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "-Xlog:cds", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain("Using AOT-linked classes: false (static archive: no aot-linked classes)"); - out.shouldContain("Opened archive hello.aot."); + out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); out.shouldHaveExitValue(0); } static void negativeTests() throws Exception { - // (1) Mixing old and new options + //---------------------------------------------------------------------- + printTestCase("Mixing old and new options"); String mixOldNewErrSuffix = " cannot be used at the same time with -Xshare:on, -Xshare:auto, " + "-Xshare:off, -Xshare:dump, DumpLoadedClassList, SharedClassListFile, " + "or SharedArchiveFile"; @@ -169,7 +180,8 @@ public class AOTFlags { out.shouldContain("Option AOTCache" + mixOldNewErrSuffix); out.shouldNotHaveExitValue(0); - // (2) Use AOTConfiguration without AOTMode + //---------------------------------------------------------------------- + printTestCase("Use AOTConfiguration without AOTMode"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTConfiguration=" + aotConfigFile, "-cp", appJar, helloClass); @@ -178,7 +190,8 @@ public class AOTFlags { out.shouldContain("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create"); out.shouldNotHaveExitValue(0); - // (3) Use AOTMode without AOTConfiguration + //---------------------------------------------------------------------- + printTestCase("Use AOTMode without AOTConfiguration"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=record", "-cp", appJar, helloClass); @@ -194,7 +207,8 @@ public class AOTFlags { out.shouldContain("-XX:AOTMode=create cannot be used without setting AOTConfiguration"); out.shouldNotHaveExitValue(0); - // (4) Bad AOTMode + //---------------------------------------------------------------------- + printTestCase("Bad AOTMode"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=foo", "-cp", appJar, helloClass); @@ -203,7 +217,8 @@ public class AOTFlags { out.shouldContain("Unrecognized value foo for AOTMode. Must be one of the following: off, record, create, auto, on"); out.shouldNotHaveExitValue(0); - // (5) AOTCache specified with -XX:AOTMode=record + //---------------------------------------------------------------------- + printTestCase("AOTCache specified with -XX:AOTMode=record"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=record", "-XX:AOTConfiguration=" + aotConfigFile, @@ -214,7 +229,8 @@ public class AOTFlags { out.shouldContain("AOTCache must not be specified when using -XX:AOTMode=record"); out.shouldNotHaveExitValue(0); - // (5) AOTCache not specified with -XX:AOTMode=create + //---------------------------------------------------------------------- + printTestCase("AOTCache not specified with -XX:AOTMode=create"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTMode=create", "-XX:AOTConfiguration=" + aotConfigFile, @@ -224,5 +240,69 @@ public class AOTFlags { out.shouldContain("AOTCache must be specified when using -XX:AOTMode=create"); out.shouldNotHaveExitValue(0); + //---------------------------------------------------------------------- + printTestCase("No such config file"); + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=create", + "-XX:AOTConfiguration=no-such-file", + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar, helloClass); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Must be a valid AOT configuration generated by the current JVM: no-such-file"); + out.shouldNotHaveExitValue(0); + + //---------------------------------------------------------------------- + printTestCase("AOTConfiguration file cannot be used as a CDS archive"); + + // first make sure we have a valid aotConfigFile + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, helloClass); + + out = CDSTestUtils.executeAndLog(pb, "train"); + out.shouldHaveExitValue(0); + + // Cannot use this config file as a AOT cache + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=on", + "-XX:AOTCache=" + aotConfigFile, + "-cp", appJar, helloClass); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Not a valid AOT cache (hello.aotconfig)"); + out.shouldNotHaveExitValue(0); + + // Cannot use this config file as a CDS archive + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xshare:on", + "-XX:SharedArchiveFile=" + aotConfigFile, + "-cp", appJar, helloClass); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("Not a valid archive (hello.aotconfig)"); + out.shouldNotHaveExitValue(0); + + //---------------------------------------------------------------------- + printTestCase("Classpath mismatch when creating archive"); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", "noSuchJar.jar"); + + out = CDSTestUtils.executeAndLog(pb, "neg"); + out.shouldContain("class path and/or module path are not compatible with the ones " + + "specified when the AOTConfiguration file was recorded"); + out.shouldContain("Unable to use create AOT cache"); + out.shouldHaveExitValue(1); + } + + static int testNum = 0; + static void printTestCase(String s) { + System.out.println("vvvvvvv TEST CASE " + testNum + ": " + s + " starts here vvvvvvv"); + testNum++; } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTLoaderConstraintsTest.java new file mode 100644 index 00000000000..63be2038907 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTLoaderConstraintsTest.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 Make sure loader constraints are passed from AOT preimage to final image. + * @bug 8348426 + * @requires vm.cds.supports.aot.class.linking + * @comment work around JDK-8345635 + * @requires !vm.jvmci.enabled + * @library /test/jdk/lib/testlibrary /test/lib + * @build AOTLoaderConstraintsTest BootClass + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar BootClass + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar AOTLoaderConstraintsTestApp.jar AOTLoaderConstraintsTestApp AppClass + * @run driver AOTLoaderConstraintsTest AOT + */ + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class AOTLoaderConstraintsTest { + static final String appJar = ClassFileInstaller.getJarPath("AOTLoaderConstraintsTestApp.jar"); + static final String mainClass = "AOTLoaderConstraintsTestApp"; + + public static void main(String[] args) throws Exception { + Tester t = new Tester(); + t.run(args); + } + + 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[] { + "-Xbootclasspath/a:boot.jar", + "-Xlog:class+loader+constraints=debug", + "-Xlog:class+path=debug", + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + switch (runMode) { + case RunMode.ASSEMBLY: // JEP 485 + binary AOTConfiguration -- should load AppClass from preimage + case RunMode.PRODUCTION: + out.shouldContain("CDS add loader constraint for class AppClass symbol java/lang/String loader[0] 'app' loader[1] 'bootstrap'"); + } + } + } +} + +class AOTLoaderConstraintsTestApp { + public static void main(String args[]) throws Exception { + AppClass obj = new AppClass(); + obj.func("Hello"); + } +} + +class AppClass extends BootClass { + @Override + public void func(String s) { + // This method overrides BootClass, which is loaded by the boot loader. + // AppClass is loaded by the app loader. To make sure that you cannot use + // type masquerade attacks, we need to add a loader constraint that says: + // app and boot loaders must resolve the symbol "java/lang/String" to the same type. + super.func(s + " From AppClass"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BootClass.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BootClass.java new file mode 100644 index 00000000000..40c22772c86 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BootClass.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. + * + */ + +// This is a test class to be loaded by the boot loader. +public class BootClass { + public void func(String s) { + System.out.println(s); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index c4648bd2eb3..9db886e20a5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -53,6 +53,19 @@ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. BulkLoaderTest DYNAMIC */ +/* + * @test id=aot + * @requires vm.cds.supports.aot.class.linking + * @comment work around JDK-8345635 + * @requires !vm.jvmci.enabled + * @library /test/jdk/lib/testlibrary /test/lib + * @build InitiatingLoaderTester BadOldClassA BadOldClassB + * @build BulkLoaderTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar BulkLoaderTestApp.jar BulkLoaderTestApp MyUtil InitiatingLoaderTester + * BadOldClassA BadOldClassB + * @run driver BulkLoaderTest AOT + */ + import java.io.File; import java.lang.StackWalker.StackFrame; import java.util.List; @@ -122,6 +135,13 @@ public class BulkLoaderTest { mainClass, }; } + + @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"); + } + } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java index a95119f1a47..332f2fc909e 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.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 @@ -40,6 +40,15 @@ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. JavacBench DYNAMIC */ +/* + * @test id=aot + * @requires vm.cds.supports.aot.class.linking + * @summary Run JavacBenchApp with AOT cache (JEP 483) + * @requires vm.cds + * @library /test/lib + * @run driver JavacBench AOT + */ + import jdk.test.lib.cds.CDSAppTester; import jdk.test.lib.helpers.ClassFileInstaller; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java index ea95a2c8711..ef0df473a98 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java @@ -188,7 +188,7 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { nonExistBaseFile.delete(); runTwo(nonExistBase, topArchiveName, appJar, mainClass, isAuto ? 0 : 1, - "Specified shared archive not found (" + nonExistBase + ")"); + "Specified shared archive file not found (" + nonExistBase + ")"); startTest("9. Non-exist top archive"); String nonExistTop = "non-exist-top.jsa"; @@ -196,11 +196,11 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { nonExistTopFile.delete(); runTwo(baseArchiveName, nonExistTop, appJar, mainClass, isAuto ? 0 : 1, - "Specified shared archive not found (" + nonExistTop + ")"); + "Specified shared archive file not found (" + nonExistTop + ")"); startTest("10. nost-exist-base and non-exist-top"); runTwo(nonExistBase, nonExistTop, appJar, mainClass, isAuto ? 0 : 1, - "Specified shared archive not found (" + nonExistBase + ")"); + "Specified shared archive file not found (" + nonExistBase + ")"); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java index 493d5fa5665..c8a04027a3d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.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 @@ -663,7 +663,7 @@ public class TestAutoCreateSharedArchive extends DynamicArchiveTestBase { "-cp", appJar, mainAppClass) .assertNormalExit(output -> { - output.shouldContain("Specified shared archive not found (" + nonExistTop + ")") + output.shouldContain("Specified shared archive file not found (" + nonExistTop + ")") .shouldContain(HELLO_WORLD) .shouldContain("Dumping shared data to file:"); }); @@ -688,7 +688,7 @@ public class TestAutoCreateSharedArchive extends DynamicArchiveTestBase { "-cp", appJar, mainAppClass) .assertNormalExit(output -> { - output.shouldContain("Specified shared archive not found (" + nonExistBase + ")") + output.shouldContain("Specified shared archive file not found (" + nonExistBase + ")") .shouldContain(HELLO_WORLD) .shouldNotContain("Dumping shared data to file:"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java index 88697496ac6..852fa1823a1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.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 @@ -162,7 +162,7 @@ public class TestAutoCreateSharedArchiveUpgrade { } static void assertJSANotFound(OutputAnalyzer output) { - output.shouldContain("Specified shared archive not found"); + output.shouldContain("Specified shared archive file not found"); } static void assertCreatedJSA(OutputAnalyzer output) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java index 7d68fdf0fc8..54cb3fb23fb 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.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 @@ -48,13 +48,12 @@ public class DumpingWithJavaAgent { }; public static String warningMessages[] = { - "This archive was created with AllowArchivingWithJavaAgent", + "This shared archive file was created with AllowArchivingWithJavaAgent", "It should be used for testing purposes only and should not be used in a production environment", }; public static String errorMessage = - "The setting of the AllowArchivingWithJavaAgent is different from the setting in the shared archive."; - + "The setting of the AllowArchivingWithJavaAgent is different from the setting in the shared archive file."; public static String diagnosticOption = "-XX:+AllowArchivingWithJavaAgent"; diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index 3a2fc1e1f69..7b4ad6eb5c4 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.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 @@ -40,8 +40,12 @@ abstract public class CDSAppTester { private final String name; private final String classListFile; private final String classListFileLog; + private final String aotConfigurationFile; + private final String aotConfigurationFileLog; private final String staticArchiveFile; private final String staticArchiveFileLog; + private final String aotCacheFile; + private final String aotCacheFileLog; private final String dynamicArchiveFile; private final String dynamicArchiveFileLog; private final String tempBaseArchiveFile; @@ -56,8 +60,12 @@ abstract public class CDSAppTester { this.name = name; classListFile = name() + ".classlist"; classListFileLog = classListFile + ".log"; + aotConfigurationFile = name() + ".aotconfig"; + aotConfigurationFileLog = aotConfigurationFile + ".log"; staticArchiveFile = name() + ".static.jsa"; staticArchiveFileLog = staticArchiveFile + ".log"; + aotCacheFile = name() + ".aot"; + aotCacheFileLog = aotCacheFile + ".log"; dynamicArchiveFile = name() + ".dynamic.jsa"; dynamicArchiveFileLog = dynamicArchiveFile + ".log"; tempBaseArchiveFile = name() + ".temp-base.jsa"; @@ -74,13 +82,15 @@ abstract public class CDSAppTester { private enum Workflow { STATIC, // classic -Xshare:dump workflow DYNAMIC, // classic -XX:ArchiveClassesAtExit + AOT, // JEP 483 Ahead-of-Time Class Loading & Linking } public enum RunMode { - CLASSLIST, - DUMP_STATIC, - DUMP_DYNAMIC, - PRODUCTION; + TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=create -XX:AOTConfiguration} + DUMP_STATIC, // -Xshare:dump + DUMP_DYNAMIC, // -XX:ArchiveClassesArExit + ASSEMBLY, // JEP 483 + PRODUCTION; // Running with the CDS archive produced from the above steps public boolean isStaticDump() { return this == DUMP_STATIC; @@ -126,6 +136,10 @@ abstract public class CDSAppTester { return workflow == Workflow.DYNAMIC; } + public final boolean isAOTWorkflow() { + return workflow == Workflow.AOT; + } + private String logToFile(String logFile, String... logTags) { StringBuilder sb = new StringBuilder("-Xlog:"); String prefix = ""; @@ -163,8 +177,20 @@ abstract public class CDSAppTester { return output; } + private OutputAnalyzer recordAOTConfiguration() throws Exception { + RunMode runMode = RunMode.TRAINING; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigurationFile, + "-cp", classpath(runMode), + logToFile(aotConfigurationFileLog, + "class+load=debug")); + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, aotConfigurationFile, aotConfigurationFileLog); + } + private OutputAnalyzer createClassList() throws Exception { - RunMode runMode = RunMode.CLASSLIST; + RunMode runMode = RunMode.TRAINING; String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), "-Xshare:off", "-XX:DumpLoadedClassList=" + classListFile, @@ -192,6 +218,23 @@ abstract public class CDSAppTester { return executeAndCheck(cmdLine, runMode, staticArchiveFile, staticArchiveFileLog); } + private OutputAnalyzer createAOTCache() throws Exception { + RunMode runMode = RunMode.ASSEMBLY; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:cds", + "-Xlog:cds+heap=error", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigurationFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", classpath(runMode), + logToFile(aotCacheFileLog, + "cds=debug", + "cds+class=debug", + "cds+heap=warning", + "cds+resolve=debug")); + return executeAndCheck(cmdLine, runMode, aotCacheFile, aotCacheFileLog); + } + // Creating a dynamic CDS archive (with -XX:ArchiveClassesAtExit=.jsa) requires that the current // JVM process is using a static archive (which is usually the default CDS archive included in the JDK). // However, if the JDK doesn't include a default CDS archive that's compatible with the set of @@ -264,6 +307,8 @@ abstract public class CDSAppTester { cmdLine = StringArrayUtils.concat(cmdLine, "-Xshare:on", "-XX:SharedArchiveFile=" + staticArchiveFile); } else if (isDynamicWorkflow()) { cmdLine = StringArrayUtils.concat(cmdLine, "-Xshare:on", "-XX:SharedArchiveFile=" + dynamicArchiveFile); + } else if (isAOTWorkflow()) { + cmdLine = StringArrayUtils.concat(cmdLine, "-XX:AOTMode=on", "-XX:AOTCache=" + aotCacheFile); } if (extraVmArgs != null) { @@ -296,6 +341,8 @@ abstract public class CDSAppTester { runStaticWorkflow(); } else if (args[0].equals("DYNAMIC")) { runDynamicWorkflow(); + } else if (args[0].equals("AOT")) { + runAOTWorkflow(); } else { throw new RuntimeException(err); } @@ -314,4 +361,12 @@ abstract public class CDSAppTester { dumpDynamicArchive(); productionRun(); } + + // See JEP 485 + private void runAOTWorkflow() throws Exception { + this.workflow = Workflow.AOT; + recordAOTConfiguration(); + createAOTCache(); + productionRun(); + } } From c8a521fddac9d42fe93ea9b3ab89e804bc48bf4e Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 25 Feb 2025 23:03:18 +0000 Subject: [PATCH 127/587] 8345213: JVM Prefers /etc/timezone Over /etc/localtime on Debian 12 Reviewed-by: joehw, jpai, alanb --- .../unix/native/libjava/TimeZone_md.c | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c index bc55f099bd9..cd253edde60 100644 --- a/src/java.base/unix/native/libjava/TimeZone_md.c +++ b/src/java.base/unix/native/libjava/TimeZone_md.c @@ -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 @@ -46,7 +46,6 @@ #define fileclose fclose #if defined(__linux__) || defined(_ALLBSD_SOURCE) -static const char *ETC_TIMEZONE_FILE = "/etc/timezone"; static const char *ZONEINFO_DIR = "/usr/share/zoneinfo"; static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime"; #else @@ -248,40 +247,13 @@ getPlatformTimeZoneID() { struct stat statbuf; char *tz = NULL; - FILE *fp; int fd; char *buf; size_t size; int res; -#if defined(__linux__) /* - * Try reading the /etc/timezone file for Debian distros. There's - * no spec of the file format available. This parsing assumes that - * there's one line of an Olson tzid followed by a '\n', no - * leading or trailing spaces, no comments. - */ - if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) { - char line[256]; - - if (fgets(line, sizeof(line), fp) != NULL) { - char *p = strchr(line, '\n'); - if (p != NULL) { - *p = '\0'; - } - if (strlen(line) > 0) { - tz = strdup(line); - } - } - (void) fclose(fp); - if (tz != NULL) { - return tz; - } - } -#endif /* defined(__linux__) */ - - /* - * Next, try /etc/localtime to find the zone ID. + * Try /etc/localtime to find the zone ID. */ RESTARTABLE(lstat(DEFAULT_ZONEINFO_FILE, &statbuf), res); if (res == -1) { From 037e47112bdf2fa2324f7c58198f6d433f17d9fd Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Tue, 25 Feb 2025 23:49:52 +0000 Subject: [PATCH 128/587] 8350666: cmp-baseline builds fail after JDK-8280682 Reviewed-by: iklam --- src/hotspot/share/cds/aotClassLocation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index c083213b933..656d7551b03 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -270,7 +270,7 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa cs->_manifest_length = manifest_length; cs->_check_time = check_time; cs->_from_cpattr = from_cpattr; - cs->_timestamp = timestamp; + cs->_timestamp = check_time ? timestamp : 0; cs->_filesize = filesize; cs->_file_type = type; cs->_group = group; From f529bf712d8946584999dfc98abea60c22c97167 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Wed, 26 Feb 2025 09:07:07 +0000 Subject: [PATCH 129/587] 8350483: AArch64: turn on signum intrinsics by default on Ampere CPUs Reviewed-by: aph --- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 874f8a380ae..bca39ae9db2 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -161,6 +161,9 @@ void VM_Version::initialize() { (_model == CPU_MODEL_AMPERE_1A || _model == CPU_MODEL_AMPERE_1B)) { FLAG_SET_DEFAULT(CodeEntryAlignment, 32); } + if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) { + FLAG_SET_DEFAULT(UseSignumIntrinsic, true); + } } // ThunderX From a70eba8e4212c2c7125475f69b3952197e7a8ce3 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 26 Feb 2025 09:51:56 +0000 Subject: [PATCH 130/587] 8330174: Protection zone for easier detection of accidental zero-nKlass use Co-authored-by: Ioi Lam Reviewed-by: iklam, rkennke --- src/hotspot/share/cds/archiveBuilder.cpp | 17 +- src/hotspot/share/cds/archiveBuilder.hpp | 13 +- src/hotspot/share/cds/archiveUtils.cpp | 55 ++--- src/hotspot/share/cds/dynamicArchive.cpp | 1 - src/hotspot/share/cds/filemap.hpp | 2 +- src/hotspot/share/cds/metaspaceShared.cpp | 92 +++++--- src/hotspot/share/cds/metaspaceShared.hpp | 1 + src/hotspot/share/include/cds.h | 5 +- src/hotspot/share/memory/metaspace.cpp | 41 ++-- src/hotspot/share/oops/compressedKlass.cpp | 29 ++- src/hotspot/share/oops/compressedKlass.hpp | 11 +- .../share/oops/compressedKlass.inline.hpp | 6 +- src/hotspot/share/prims/whitebox.cpp | 12 ++ src/hotspot/share/runtime/os.cpp | 6 + .../AccessZeroNKlassHitsProtectionZone.java | 203 ++++++++++++++++++ test/lib/jdk/test/whitebox/WhiteBox.java | 4 +- 16 files changed, 400 insertions(+), 98 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 21e97457a87..f093b9d8070 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -153,7 +153,6 @@ void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) { ArchiveBuilder::ArchiveBuilder() : _current_dump_region(nullptr), _buffer_bottom(nullptr), - _num_dump_regions_used(0), _requested_static_archive_bottom(nullptr), _requested_static_archive_top(nullptr), _requested_dynamic_archive_bottom(nullptr), @@ -161,6 +160,7 @@ ArchiveBuilder::ArchiveBuilder() : _mapped_static_archive_bottom(nullptr), _mapped_static_archive_top(nullptr), _buffer_to_requested_delta(0), + _pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive. _rw_region("rw", MAX_SHARED_DELTA), _ro_region("ro", MAX_SHARED_DELTA), _ptrmap(mtClassShared), @@ -323,9 +323,14 @@ address ArchiveBuilder::reserve_buffer() { _shared_rs = rs; _buffer_bottom = buffer_bottom; - _current_dump_region = &_rw_region; - _num_dump_regions_used = 1; - _current_dump_region->init(&_shared_rs, &_shared_vs); + + if (CDSConfig::is_dumping_static_archive()) { + _current_dump_region = &_pz_region; + _current_dump_region->init(&_shared_rs, &_shared_vs); + } else { + _current_dump_region = &_rw_region; + _current_dump_region->init(&_shared_rs, &_shared_vs); + } ArchivePtrMarker::initialize(&_ptrmap, &_shared_vs); @@ -366,7 +371,8 @@ address ArchiveBuilder::reserve_buffer() { 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(). - rw_region()->allocate(16); + _pz_region.allocate(MetaspaceShared::protection_zone_size()); + start_dump_region(&_rw_region); } return buffer_bottom; @@ -544,7 +550,6 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref void ArchiveBuilder::start_dump_region(DumpRegion* next) { current_dump_region()->pack(next); _current_dump_region = next; - _num_dump_regions_used ++; } char* ArchiveBuilder::ro_strdup(const char* s) { diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index e3efedd46f1..5913ae29c78 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.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. * 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,7 +96,6 @@ class ArchiveBuilder : public StackObj { protected: DumpRegion* _current_dump_region; address _buffer_bottom; // for writing the contents of rw/ro regions - int _num_dump_regions_used; // These are the addresses where we will request the static and dynamic archives to be // mapped at run time. If the request fails (due to ASLR), we will map the archives at @@ -210,6 +209,12 @@ private: ReservedSpace _shared_rs; VirtualSpace _shared_vs; + // The "pz" region is used only during static dumps to reserve an unused space between SharedBaseAddress and + // the bottom of the rw region. During runtime, this space will be filled with a reserved area that disallows + // read/write/exec, so we can track for bad CompressedKlassPointers encoding. + // Note: this region does NOT exist in the cds archive. + DumpRegion _pz_region; + DumpRegion _rw_region; DumpRegion _ro_region; @@ -270,9 +275,6 @@ private: protected: virtual void iterate_roots(MetaspaceClosure* it) = 0; - - static const int _total_dump_regions = 2; - void start_dump_region(DumpRegion* next); public: @@ -367,6 +369,7 @@ public: void remember_embedded_pointer_in_enclosing_obj(MetaspaceClosure::Ref* ref); static void serialize_dynamic_archivable_items(SerializeClosure* soc); + DumpRegion* pz_region() { return &_pz_region; } DumpRegion* rw_region() { return &_rw_region; } DumpRegion* ro_region() { return &_ro_region; } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 90eefd13d46..7e04b6227f2 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -73,34 +73,39 @@ void ArchivePtrMarker::initialize(CHeapBitMap* ptrmap, VirtualSpace* vs) { } void ArchivePtrMarker::initialize_rw_ro_maps(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap) { - address* rw_bottom = (address*)ArchiveBuilder::current()->rw_region()->base(); - address* ro_bottom = (address*)ArchiveBuilder::current()->ro_region()->base(); + address* buff_bottom = (address*)ArchiveBuilder::current()->buffer_bottom(); + address* rw_bottom = (address*)ArchiveBuilder::current()->rw_region()->base(); + address* ro_bottom = (address*)ArchiveBuilder::current()->ro_region()->base(); + + // The bit in _ptrmap that cover the very first word in the rw/ro regions. + size_t rw_start = rw_bottom - buff_bottom; + size_t ro_start = ro_bottom - buff_bottom; + + // The number of bits used by the rw/ro ptrmaps. We might have lots of zero + // bits at the bottom and top of rrw/ro ptrmaps, but these zeros will be + // removed by FileMapInfo::write_bitmap_region(). + size_t rw_size = ArchiveBuilder::current()->rw_region()->used() / sizeof(address); + size_t ro_size = ArchiveBuilder::current()->ro_region()->used() / sizeof(address); + + // The last (exclusive) bit in _ptrmap that covers the rw/ro regions. + // Note: _ptrmap is dynamically expanded only when an actual pointer is written, so + // it may not be as large as we want. + size_t rw_end = MIN2(rw_start + rw_size, _ptrmap->size()); + size_t ro_end = MIN2(ro_start + ro_size, _ptrmap->size()); + + rw_ptrmap->initialize(rw_size); + ro_ptrmap->initialize(ro_size); + + for (size_t rw_bit = rw_start; rw_bit < rw_end; rw_bit++) { + rw_ptrmap->at_put(rw_bit - rw_start, _ptrmap->at(rw_bit)); + } + + for(size_t ro_bit = ro_start; ro_bit < ro_end; ro_bit++) { + ro_ptrmap->at_put(ro_bit - ro_start, _ptrmap->at(ro_bit)); + } _rw_ptrmap = rw_ptrmap; _ro_ptrmap = ro_ptrmap; - - size_t rw_size = ArchiveBuilder::current()->rw_region()->used() / sizeof(address); - size_t ro_size = ArchiveBuilder::current()->ro_region()->used() / sizeof(address); - // ro_start is the first bit in _ptrmap that covers the pointer that would sit at ro_bottom. - // E.g., if rw_bottom = (address*)100 - // ro_bottom = (address*)116 - // then for 64-bit platform: - // ro_start = ro_bottom - rw_bottom = (116 - 100) / sizeof(address) = 2; - size_t ro_start = ro_bottom - rw_bottom; - - // Note: ptrmap is big enough only to cover the last pointer in ro_region. - // See ArchivePtrMarker::compact() - _rw_ptrmap->initialize(rw_size); - _ro_ptrmap->initialize(_ptrmap->size() - ro_start); - - for (size_t rw_bit = 0; rw_bit < _rw_ptrmap->size(); rw_bit++) { - _rw_ptrmap->at_put(rw_bit, _ptrmap->at(rw_bit)); - } - - for(size_t ro_bit = ro_start; ro_bit < _ptrmap->size(); ro_bit++) { - _ro_ptrmap->at_put(ro_bit-ro_start, _ptrmap->at(ro_bit)); - } - assert(_ptrmap->size() - ro_start == _ro_ptrmap->size(), "must be"); } void ArchivePtrMarker::mark_pointer(address* ptr_loc) { diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 095b443af66..bcec4146aeb 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -170,7 +170,6 @@ public: post_dump(); - assert(_num_dump_regions_used == _total_dump_regions, "must be"); verify_universe("After CDS dynamic dump"); } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 25550d76d2a..52e8827a69a 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -400,7 +400,7 @@ public: // The offset of the (exclusive) end of the last core region in this archive, relative to SharedBaseAddress size_t mapping_end_offset() const { return last_core_region()->mapping_end_offset(); } - char* mapped_base() const { return first_core_region()->mapped_base(); } + char* mapped_base() const { return header()->mapped_base_address(); } char* mapped_end() const { return last_core_region()->mapped_end(); } // Non-zero if the archive needs to be mapped a non-default location due to ASLR. diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 2e5ebff456e..e8866336b7a 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -147,6 +147,10 @@ size_t MetaspaceShared::core_region_alignment() { return os::cds_core_region_alignment(); } +size_t MetaspaceShared::protection_zone_size() { + return os::cds_core_region_alignment(); +} + static bool shared_base_valid(char* shared_base) { // We check user input for SharedBaseAddress at dump time. @@ -1280,6 +1284,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File ReservedSpace total_space_rs, archive_space_rs, class_space_rs; MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; + size_t prot_zone_size = 0; char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo, use_requested_addr, @@ -1291,14 +1296,29 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File log_debug(cds)("Failed to reserve spaces (use_requested_addr=%u)", (unsigned)use_requested_addr); } else { + if (Metaspace::using_class_space()) { + prot_zone_size = protection_zone_size(); +#ifdef ASSERT + // Before mapping the core regions into the newly established address space, we mark + // start and the end of the future protection zone with canaries. That way we easily + // catch mapping errors (accidentally mapping data into the future protection zone). + os::commit_memory(mapped_base_address, prot_zone_size, false); + *(mapped_base_address) = 'P'; + *(mapped_base_address + prot_zone_size - 1) = 'P'; +#endif + } + #ifdef ASSERT // Some sanity checks after reserving address spaces for archives // and class space. assert(archive_space_rs.is_reserved(), "Sanity"); if (Metaspace::using_class_space()) { + assert(archive_space_rs.base() == mapped_base_address && + archive_space_rs.size() > protection_zone_size(), + "Archive space must lead and include the protection zone"); // Class space must closely follow the archive space. Both spaces // must be aligned correctly. - assert(class_space_rs.is_reserved(), + assert(class_space_rs.is_reserved() && class_space_rs.size() > 0, "A class space should have been reserved"); assert(class_space_rs.base() >= archive_space_rs.end(), "class space should follow the cds archive space"); @@ -1311,8 +1331,9 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File } #endif // ASSERT - log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", - p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size()); + log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes%s", + p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size(), + (prot_zone_size > 0 ? " (includes protection zone)" : "")); log_info(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size()); @@ -1384,38 +1405,40 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File if (result == MAP_ARCHIVE_SUCCESS) { SharedBaseAddress = (size_t)mapped_base_address; #ifdef _LP64 - if (Metaspace::using_class_space()) { - // Set up ccs in metaspace. - Metaspace::initialize_class_space(class_space_rs); + if (Metaspace::using_class_space()) { + assert(*(mapped_base_address) == 'P' && + *(mapped_base_address + prot_zone_size - 1) == 'P', + "Protection zone was overwritten?"); - // Set up compressed Klass pointer encoding: the encoding range must - // cover both archive and class space. - address cds_base = (address)static_mapinfo->mapped_base(); - address ccs_end = (address)class_space_rs.end(); - assert(ccs_end > cds_base, "Sanity check"); - if (INCLUDE_CDS_JAVA_HEAP || UseCompactObjectHeaders) { - // The CDS archive may contain narrow Klass IDs that were precomputed at archive generation time: - // - every archived java object header (only if INCLUDE_CDS_JAVA_HEAP) - // - every archived Klass' prototype (only if +UseCompactObjectHeaders) - // - // In order for those IDs to still be valid, we need to dictate base and shift: base should be the - // mapping start, shift the shift used at archive generation time. - address precomputed_narrow_klass_base = cds_base; - const int precomputed_narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift(); - CompressedKlassPointers::initialize_for_given_encoding( - cds_base, ccs_end - cds_base, // Klass range - precomputed_narrow_klass_base, precomputed_narrow_klass_shift // precomputed encoding, see ArchiveBuilder - ); - } else { - // Let JVM freely chose encoding base and shift - CompressedKlassPointers::initialize ( - cds_base, ccs_end - cds_base // Klass range - ); - } - // map_or_load_heap_region() compares the current narrow oop and klass encodings - // with the archived ones, so it must be done after all encodings are determined. - static_mapinfo->map_or_load_heap_region(); - } + // Set up ccs in metaspace. + Metaspace::initialize_class_space(class_space_rs); + + // Set up compressed Klass pointer encoding: the encoding range must + // cover both archive and class space. + const address encoding_base = (address)mapped_base_address; + const address klass_range_start = encoding_base + prot_zone_size; + const size_t klass_range_size = (address)class_space_rs.end() - klass_range_start; + if (INCLUDE_CDS_JAVA_HEAP || UseCompactObjectHeaders) { + // The CDS archive may contain narrow Klass IDs that were precomputed at archive generation time: + // - every archived java object header (only if INCLUDE_CDS_JAVA_HEAP) + // - every archived Klass' prototype (only if +UseCompactObjectHeaders) + // + // In order for those IDs to still be valid, we need to dictate base and shift: base should be the + // mapping start (including protection zone), shift should be the shift used at archive generation time. + CompressedKlassPointers::initialize_for_given_encoding( + klass_range_start, klass_range_size, + encoding_base, ArchiveBuilder::precomputed_narrow_klass_shift() // precomputed encoding, see ArchiveBuilder + ); + } else { + // Let JVM freely chose encoding base and shift + CompressedKlassPointers::initialize(klass_range_start, klass_range_size); + } + CompressedKlassPointers::establish_protection_zone(encoding_base, prot_zone_size); + + // map_or_load_heap_region() compares the current narrow oop and klass encodings + // with the archived ones, so it must be done after all encodings are determined. + static_mapinfo->map_or_load_heap_region(); + } #endif // _LP64 log_info(cds)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); log_info(cds)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); @@ -1497,7 +1520,6 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma const size_t archive_space_alignment = core_region_alignment(); // Size and requested location of the archive_space_rs (for both static and dynamic archives) - assert(static_mapinfo->mapping_base_offset() == 0, "Must be"); size_t archive_end_offset = (dynamic_mapinfo == nullptr) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset(); size_t archive_space_size = align_up(archive_end_offset, archive_space_alignment); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 6d5f273041a..27df816833c 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -139,6 +139,7 @@ public: // Alignment for the 2 core CDS regions (RW/RO) only. // (Heap region alignments are decided by GC). static size_t core_region_alignment(); + static size_t protection_zone_size(); static void rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik); // print loaded classes names to file. static void dump_loaded_classes(const char* file_name, TRAPS); diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index 2a80dd68abd..8819e4c00be 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -70,7 +70,10 @@ typedef struct CDSFileMapRegion { size_t _ptrmap_offset; // Bitmap for relocating native pointer fields in archived heap objects. // (The base address is the bottom of the BM region). size_t _ptrmap_size_in_bits; - char* _mapped_base; // Actually mapped address (null if this region is not mapped). + 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 + // static archive) is is mapped. bool _in_reserved_space; // Is this region in a ReservedSpace } CDSFileMapRegion; diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 99d1d027db0..2566c61188f 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. - * Copyright (c) 2023, 2024, Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, 2025, Red Hat, 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 @@ -37,6 +37,7 @@ #include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/commitLimiter.hpp" #include "memory/metaspace/internalStats.hpp" +#include "memory/metaspace/metachunk.hpp" #include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/metaspaceReporter.hpp" @@ -804,29 +805,37 @@ void Metaspace::global_initialize() { // Set up compressed class pointer encoding. // In CDS=off mode, we give the JVM some leeway to choose a favorable base/shift combination. CompressedKlassPointers::initialize((address)rs.base(), rs.size()); + + // After narrowKlass encoding scheme is decided: if the encoding base points to class space start, + // establish a protection zone. Accidentally decoding a zero nKlass ID and then using it will result + // in an immediate segmentation fault instead of a delayed error much later. + if (CompressedKlassPointers::base() == (address)rs.base()) { + // Let the protection zone be a whole commit granule. Otherwise, buddy allocator may later place neighboring + // chunks in the same granule, see that the granule is not yet committed, and commit it, which would replace + // the protection mapping and make the zone readable. + // Alternatively, we could commit the chunk right now, but that is a tiny bit more fiddly, since we are not + // fully set up yet at this point. + const size_t protzone_size = metaspace::Settings::commit_granule_bytes(); // granule size >= page size + const size_t protzone_wordsize = protzone_size / BytesPerWord; + const metaspace::chunklevel_t lvl = metaspace::chunklevel::level_fitting_word_size(protzone_wordsize); + metaspace::Metachunk* const chunk = MetaspaceContext::context_class()->cm()->get_chunk(lvl); + const address protzone = (address) chunk->base(); + assert(protzone == (address)rs.base(), "The very first chunk should be located at the class space start?"); + assert(chunk->word_size() == protzone_wordsize, "Weird chunk size"); + CompressedKlassPointers::establish_protection_zone(protzone, protzone_size); + } else { + assert(CompressedKlassPointers::base() == nullptr, "Zero-based encoding expected"); + } + } -#endif +#endif // _LP64 // Initialize non-class virtual space list, and its chunk manager: MetaspaceContext::initialize_nonclass_space_context(); _tracer = new MetaspaceTracer(); - // We must prevent the very first address of the ccs from being used to store - // metadata, since that address would translate to a narrow pointer of 0, and the - // VM does not distinguish between "narrow 0 as in null" and "narrow 0 as in start - // of ccs". - // Before Elastic Metaspace that did not happen due to the fact that every Metachunk - // had a header and therefore could not allocate anything at offset 0. -#ifdef _LP64 - if (using_class_space()) { - // The simplest way to fix this is to allocate a tiny dummy chunk right at the - // start of ccs and do not use it for anything. - MetaspaceContext::context_class()->cm()->get_chunk(metaspace::chunklevel::HIGHEST_CHUNK_LEVEL); - } -#endif - #ifdef _LP64 if (UseCompressedClassPointers) { // Note: "cds" would be a better fit but keep this for backward compatibility. diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index fc8c0513ca0..1e00571ef60 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -42,6 +42,7 @@ address CompressedKlassPointers::_klass_range_start = nullptr; address CompressedKlassPointers::_klass_range_end = nullptr; narrowKlass CompressedKlassPointers::_lowest_valid_narrow_klass_id = (narrowKlass)-1; narrowKlass CompressedKlassPointers::_highest_valid_narrow_klass_id = (narrowKlass)-1; +size_t CompressedKlassPointers::_protection_zone_size = 0; #ifdef _LP64 @@ -162,11 +163,6 @@ void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t vm_exit_during_initialization(ss.base()); } - // Note: While it would be technically valid for the encoding base to precede the start of the Klass range, - // we never do this here. This is used at CDS runtime to re-instate the scheme used to precompute the - // narrow Klass IDs in the archive, and the requested base should point to the start of the Klass range. - assert(requested_base == addr, "Invalid requested base"); - // Remember Klass range: _klass_range_start = addr; _klass_range_end = addr + len; @@ -304,9 +300,32 @@ void CompressedKlassPointers::print_mode(outputStream* st) { st->print_cr("Klass Range: " RANGE2FMT, RANGE2FMTARGS(_klass_range_start, _klass_range_end)); st->print_cr("Klass ID Range: [%u - %u) (%u)", _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id + 1, _highest_valid_narrow_klass_id + 1 - _lowest_valid_narrow_klass_id); + if (_protection_zone_size > 0) { + st->print_cr("Protection zone: " RANGEFMT, RANGEFMTARGS(_base, _protection_zone_size)); + } else { + st->print_cr("No protection zone."); + } } else { st->print_cr("UseCompressedClassPointers off"); } } +// Protect a zone a the start of the encoding range +void CompressedKlassPointers::establish_protection_zone(address addr, size_t size) { + assert(_protection_zone_size == 0, "just once"); + assert(addr == base(), "Protection zone not at start of encoding range?"); + assert(size > 0 && is_aligned(size, os::vm_page_size()), "Protection zone not page sized"); + const bool rc = os::protect_memory((char*)addr, size, os::MEM_PROT_NONE, false); + assert(rc, "Failed to protect the Class space protection zone"); + log_info(metaspace)("%s Narrow Klass Protection zone " RANGEFMT, + (rc ? "Established" : "FAILED to establish "), + RANGEFMTARGS(addr, size)); + _protection_zone_size = size; +} + +bool CompressedKlassPointers::is_in_protection_zone(address addr) { + return _protection_zone_size > 0 ? + (addr >= base() && addr < base() + _protection_zone_size) : false; +} + #endif // _LP64 diff --git a/src/hotspot/share/oops/compressedKlass.hpp b/src/hotspot/share/oops/compressedKlass.hpp index dd54c8130eb..4ce644d9cef 100644 --- a/src/hotspot/share/oops/compressedKlass.hpp +++ b/src/hotspot/share/oops/compressedKlass.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 @@ -134,6 +134,8 @@ class CompressedKlassPointers : public AllStatic { static narrowKlass _lowest_valid_narrow_klass_id; static narrowKlass _highest_valid_narrow_klass_id; + // Protection zone size (0 if not set up) + static size_t _protection_zone_size; // Helper function for common cases. static char* reserve_address_space_X(uintptr_t from, uintptr_t to, size_t size, size_t alignment, bool aslr); @@ -231,6 +233,7 @@ public: static bool is_null(narrowKlass v) { return v == 0; } // Versions without asserts + static inline Klass* decode_not_null_without_asserts(narrowKlass v); static inline Klass* decode_without_asserts(narrowKlass v); static inline Klass* decode_not_null(narrowKlass v); static inline Klass* decode(narrowKlass v); @@ -258,6 +261,12 @@ public: is_aligned(addr, klass_alignment_in_bytes()); } + // Protect a zone a the start of the encoding range + static void establish_protection_zone(address addr, size_t size); + + // Returns true if address points into protection zone (for error reporting) + static bool is_in_protection_zone(address addr); + #if defined(AARCH64) && !defined(ZERO) // Check that with the given base, shift and range, aarch64 code can encode and decode the klass pointer. static bool check_klass_decode_mode(address base, int shift, const size_t range); diff --git a/src/hotspot/share/oops/compressedKlass.inline.hpp b/src/hotspot/share/oops/compressedKlass.inline.hpp index 7c5da48a494..94a78ed1894 100644 --- a/src/hotspot/share/oops/compressedKlass.inline.hpp +++ b/src/hotspot/share/oops/compressedKlass.inline.hpp @@ -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 @@ -40,6 +40,10 @@ inline narrowKlass CompressedKlassPointers::encode_not_null_without_asserts(Klas return (narrowKlass)(pointer_delta(k, narrow_base, 1) >> shift); } +inline Klass* CompressedKlassPointers::decode_not_null_without_asserts(narrowKlass v) { + return decode_not_null_without_asserts(v, base(), shift()); +} + inline Klass* CompressedKlassPointers::decode_without_asserts(narrowKlass v) { return is_null(v) ? nullptr : decode_not_null_without_asserts(v, base(), shift()); } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index dd5a23f9209..84fa9d06a1c 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -325,6 +325,17 @@ WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o)) *(vs.low_boundary() - rhs.noaccess_prefix() / 2 )); WB_END +WB_ENTRY(void, WB_DecodeNKlassAndAccessKlass(JNIEnv* env, jobject o, jint nKlass)) + assert(UseCompressedClassPointers, "Should only call for UseCompressedClassPointers"); + const narrowKlass nk = (narrowKlass)nKlass; + const Klass* const k = CompressedKlassPointers::decode_not_null_without_asserts(nKlass); + printf("WB_DecodeNKlassAndAccessKlass: nk %u k " PTR_FORMAT "\n", nk, p2i(k)); + printf("Will attempt to crash now...\n"); + fflush(stdout); // flush now - we will crash below + // Access k by calling a virtual function - will result in loading the vtable from *k + k->print_on(tty); +WB_END + static jint wb_stress_virtual_space_resize(size_t reserved_space_size, size_t magnitude, size_t iterations) { size_t granularity = os::vm_allocation_granularity(); @@ -2733,6 +2744,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetCompressedOopsMaxHeapSize}, {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes }, {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea}, + {CC"decodeNKlassAndAccessKlass",CC"(I)V", (void*)&WB_DecodeNKlassAndAccessKlass}, {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, #if INCLUDE_CDS {CC"getCDSOffsetForName0", CC"(Ljava/lang/String;)I", (void*)&WB_GetCDSOffsetForName}, diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index d266b632ed1..efff891c72f 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1291,6 +1291,12 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { bool accessible = is_readable_pointer(addr); + // Check if addr points into the narrow Klass protection zone + if (UseCompressedClassPointers && CompressedKlassPointers::is_in_protection_zone(addr)) { + st->print_cr(PTR_FORMAT " points into nKlass protection zone", p2i(addr)); + return; + } + // Check if addr is a JNI handle. if (align_down((intptr_t)addr, sizeof(intptr_t)) != 0 && accessible) { if (JNIHandles::is_global_handle((jobject) addr)) { diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java new file mode 100644 index 00000000000..2e70c1d8786 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * 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=no_coh_no_cds + * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone + * @library /test/lib + * @requires vm.bits == 64 & vm.debug == true + * @requires vm.flagless + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver AccessZeroNKlassHitsProtectionZone no_coh_no_cds + */ + +/* + * @test id=no_coh_cds + * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone + * @requires vm.bits == 64 & vm.debug == true & vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver AccessZeroNKlassHitsProtectionZone no_coh_cds + */ + +/* + * @test id=coh_no_cds + * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone + * @requires vm.bits == 64 & vm.debug == true & vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver AccessZeroNKlassHitsProtectionZone coh_no_cds + */ + +/* + * @test id=coh_cds + * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone + * @requires vm.bits == 64 & vm.debug == true & vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver AccessZeroNKlassHitsProtectionZone coh_cds + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.regex.Pattern; + +// Test that dereferencing a Klass that is the result of a narrowKlass=0 will give us immediate crashes +// that hit the protection zone at encoding base. +public class AccessZeroNKlassHitsProtectionZone { + + private static OutputAnalyzer run_test(boolean COH, boolean CDS, String forceBaseString) throws IOException, SkippedException { + ArrayList args = new ArrayList<>(); + args.add("-Xbootclasspath/a:."); + args.add("-XX:+UnlockDiagnosticVMOptions"); + args.add("-XX:+WhiteBoxAPI"); + args.add("-XX:CompressedClassSpaceSize=128m"); + args.add("-Xmx128m"); + args.add("-XX:-CreateCoredumpOnCrash"); + args.add("-Xlog:metaspace*"); + if (COH) { + args.add("-XX:+UnlockExperimentalVMOptions"); + args.add("-XX:+UseCompactObjectHeaders"); + } + if (CDS) { + args.add("-Xshare:on"); + } else { + args.add("-Xshare:off"); + args.add("-XX:CompressedClassSpaceBaseAddress=" + forceBaseString); + } + args.add(AccessZeroNKlassHitsProtectionZone.class.getName()); + args.add("runwb"); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args.toArray(new String[0])); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.reportDiagnosticSummary(); + return output; + } + + private static void run_test(boolean COH, boolean CDS) throws IOException, SkippedException { + // Notes: + // We want to enforce zero-based encoding, to test the protection page in that case. For zero-based encoding, + // protection page is at address zero, no need to test that. + // If CDS is on, we never use zero-based, forceBase is ignored. + // If CDS is off, we use forceBase to (somewhat) reliably force the encoding base to beyond 32G, + // in order to prevent zero-based encoding. Since that may fail, we try several times. + OutputAnalyzer output = null; + long forceBase = -1; + if (CDS) { + output = run_test(COH, CDS, ""); + } else { + long g4 = 0x1_0000_0000L; + long start = g4 * 8; // 32g + long step = g4; + long end = start + step * 16; + for (forceBase = start; forceBase < end; forceBase += step) { + String thisBaseString = String.format("0x%016X", forceBase).toLowerCase(); + output = run_test(COH, CDS, thisBaseString); + if (output.contains("CompressedClassSpaceBaseAddress=" + thisBaseString + " given, but reserving class space failed.")) { + // try next one + } else if (output.contains("Successfully forced class space address to " + thisBaseString)) { + break; + } else { + throw new RuntimeException("Unexpected"); + } + } + if (forceBase >= end) { + throw new SkippedException("Failed to force ccs to any of the given bases. Skipping test."); + } + } + + // Parse the encoding base from the output. In case of CDS, it depends on ASLR. Even in case of CDS=off, we want + // to double-check it is the force address. + String nKlassBaseString = output.firstMatch("Narrow klass base: 0x([0-9a-f]+)", 1); + if (nKlassBaseString == null) { + throw new RuntimeException("did not find Narrow klass base in log output"); + } + long nKlassBase = Long.valueOf(nKlassBaseString, 16); + + if (!CDS && nKlassBase != forceBase) { + throw new RuntimeException("Weird - we should have mapped at force base"); // .. otherwise we would have skipped out above + } + if (nKlassBase == 0) { + throw new RuntimeException("We should not be running zero-based at this point."); + } + + // Calculate the expected crash address pattern. The precise crash address is unknown, but should be located + // in the lower part of the guard page following the encoding base. We just accept any address matching the + // upper 52 digits (leaving 4K = 12 bits = 4 nibbles of wiggle room) + String expectedCrashAddressString = nKlassBaseString.substring(0, nKlassBaseString.length() - 3); + + // output from whitebox function: Klass* should point to encoding base + output.shouldMatch("WB_DecodeNKlassAndAccessKlass: nk 0 k 0x" + nKlassBaseString); + + // Then, we should have crashed + output.shouldNotHaveExitValue(0); + output.shouldContain("# A fatal error has been detected"); + + // The hs-err file should contain a reference to the nKlass protection zone, like this: + // "RDI=0x0000000800000000 points into nKlass protection zone" + File hsErrFile = HsErrFileUtils.openHsErrFileFromOutput(output); + + ArrayList hsErrPatternList = new ArrayList<>(); + hsErrPatternList.add(Pattern.compile(".*(SIGBUS|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*")); + + hsErrPatternList.add(Pattern.compile(".*siginfo:.*" + expectedCrashAddressString + ".*")); + hsErrPatternList.add(Pattern.compile(".*" + expectedCrashAddressString + ".*points into nKlass protection zone.*")); + Pattern[] hsErrPattern = hsErrPatternList.toArray(new Pattern[0]); + HsErrFileUtils.checkHsErrFileContent(hsErrFile, hsErrPattern, true); + } + + enum Argument { runwb, no_coh_no_cds, no_coh_cds, coh_no_cds, coh_cds }; + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Expecting one argument"); + } + Argument arg = Argument.valueOf(args[0]); + System.out.println(arg); + switch (arg) { + case runwb -> WhiteBox.getWhiteBox().decodeNKlassAndAccessKlass(0); + case no_coh_no_cds -> run_test(false, false); + case no_coh_cds -> run_test(false, true); + case coh_no_cds -> run_test(true, false); + case coh_cds -> run_test(true, true); + } + } +} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index be9bc646ce4..c45aecbced5 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.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 @@ -642,6 +642,8 @@ public class WhiteBox { // Tests on ReservedSpace/VirtualSpace classes public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); public native void readFromNoaccessArea(); + + public native void decodeNKlassAndAccessKlass(int nKlass); public native long getThreadStackSize(); public native long getThreadRemainingStackSize(); From a43104640420fbd82868788ccd8a3a8e938f365a Mon Sep 17 00:00:00 2001 From: "Tagir F. Valeev" Date: Wed, 26 Feb 2025 10:08:29 +0000 Subject: [PATCH 131/587] 8350518: org.openjdk.bench.java.util.TreeMapUpdate.compute fails with "java.lang.IllegalArgumentException: key out of range" Reviewed-by: liach, skuksenko --- test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java b/test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java index 2a5a9cf0bed..b93c3c309c5 100644 --- a/test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java +++ b/test/micro/org/openjdk/bench/java/util/TreeMapUpdate.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 @@ -56,7 +56,7 @@ import java.util.stream.IntStream; @Fork(3) @State(Scope.Thread) public class TreeMapUpdate { - @Param({"TreeMap", "descendingMap", "tailMap"}) + @Param({"TreeMap", "descendingMap", "subMap"}) public String mode; @Param({"10", "1000", "100000"}) @@ -86,8 +86,8 @@ public class TreeMapUpdate { case "descendingMap": transformer = map -> map.descendingMap(); break; - case "tailMap": - transformer = map -> map.tailMap(0, true); + case "subMap": + transformer = comparator ? map -> map.headMap(0, true) : map -> map.tailMap(0, true); break; default: throw new IllegalStateException(mode); From aac9cb4537b13a4af123ae76f29359e851dc4c82 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 26 Feb 2025 10:30:01 +0000 Subject: [PATCH 132/587] 8349906: G1: Improve initial survivor rate for newly used young regions Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index 1eaaf44a1fb..c5c0ca992b0 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -68,13 +68,26 @@ void G1SurvRateGroup::stop_adding_regions() { _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(double, _accum_surv_rate_pred, _num_added_regions, mtGC); _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_predictors, _num_added_regions, mtGC); + // Assume that the prediction for the newly added regions is the same as the + // ones at the (current) end of the array. Particularly predictions at the end + // of this array fairly seldom get updated, so having a better initial value + // that is at least somewhat related to the actual application is preferable. + double new_pred = _stats_arrays_length > 1 + ? _accum_surv_rate_pred[_stats_arrays_length - 1] - _accum_surv_rate_pred[_stats_arrays_length - 2] + : InitialSurvivorRate; + for (size_t i = _stats_arrays_length; i < _num_added_regions; ++i) { // Initialize predictors and accumulated survivor rate predictions. _surv_rate_predictors[i] = new TruncatedSeq(10); - _surv_rate_predictors[i]->add(InitialSurvivorRate); - _accum_surv_rate_pred[i] = ((i == 0) ? 0.0 : _accum_surv_rate_pred[i-1]) + InitialSurvivorRate; + if (i == 0) { + _surv_rate_predictors[i]->add(InitialSurvivorRate); + _accum_surv_rate_pred[i] = 0.0; + } else { + _surv_rate_predictors[i]->add(_surv_rate_predictors[i-1]->last()); + _accum_surv_rate_pred[i] = _accum_surv_rate_pred[i-1] + new_pred; + } } - _last_pred = InitialSurvivorRate; + _last_pred = new_pred; _stats_arrays_length = _num_added_regions; } From a0dd56543219343306aea99b684b5e2cb04c7d76 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 26 Feb 2025 11:31:48 +0000 Subject: [PATCH 133/587] 8350643: G1: Make loop iteration variable type correspond to limit in G1SurvRateGroup Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index c5c0ca992b0..d5fd50c4523 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -46,7 +46,7 @@ void G1SurvRateGroup::reset() { // The call to stop_adding_regions() will use "new" to refill // the _surv_rate_pred array, so we need to make sure to call // "delete". - for (size_t i = 0; i < _stats_arrays_length; ++i) { + for (uint i = 0; i < _stats_arrays_length; ++i) { delete _surv_rate_predictors[i]; } _stats_arrays_length = 0; @@ -76,7 +76,7 @@ void G1SurvRateGroup::stop_adding_regions() { ? _accum_surv_rate_pred[_stats_arrays_length - 1] - _accum_surv_rate_pred[_stats_arrays_length - 2] : InitialSurvivorRate; - for (size_t i = _stats_arrays_length; i < _num_added_regions; ++i) { + for (uint i = _stats_arrays_length; i < _num_added_regions; ++i) { // Initialize predictors and accumulated survivor rate predictions. _surv_rate_predictors[i] = new TruncatedSeq(10); if (i == 0) { @@ -123,7 +123,7 @@ double G1SurvRateGroup::accum_surv_rate_pred(uint age) const { void G1SurvRateGroup::fill_in_last_surv_rates() { if (_num_added_regions > 0) { // conservative double surv_rate = _surv_rate_predictors[_num_added_regions-1]->last(); - for (size_t i = _num_added_regions; i < _stats_arrays_length; ++i) { + for (uint i = _num_added_regions; i < _stats_arrays_length; ++i) { _surv_rate_predictors[i]->add(surv_rate); } } @@ -132,7 +132,7 @@ void G1SurvRateGroup::fill_in_last_surv_rates() { void G1SurvRateGroup::finalize_predictions(const G1Predictions& predictor) { double accum = 0.0; double pred = 0.0; - for (size_t i = 0; i < _stats_arrays_length; ++i) { + for (uint i = 0; i < _stats_arrays_length; ++i) { pred = predictor.predict_in_unit_interval(_surv_rate_predictors[i]); accum += pred; _accum_surv_rate_pred[i] = accum; From 1e18fffee456382c4eeb017b3fad0dc99ccaad35 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 26 Feb 2025 11:49:09 +0000 Subject: [PATCH 134/587] 8328473: StringTable and SymbolTable statistics delay time to safepoint Reviewed-by: shade, eosterlund --- src/hotspot/share/classfile/stringTable.cpp | 22 +++++- src/hotspot/share/classfile/symbolTable.cpp | 34 ++++++--- .../share/utilities/concurrentHashTable.hpp | 16 ++-- .../utilities/concurrentHashTable.inline.hpp | 75 +++++++------------ .../concurrentHashTableTasks.inline.hpp | 46 +++++++++++- 5 files changed, 123 insertions(+), 70 deletions(-) diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 22ccb4e4b04..1076ffb2dd7 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -744,13 +744,29 @@ struct SizeFunc : StackObj { TableStatistics StringTable::get_table_statistics() { static TableStatistics ts; SizeFunc sz; - ts = _local_table->statistics_get(Thread::current(), sz, ts); + + Thread* jt = Thread::current(); + StringTableHash::StatisticsTask sts(_local_table); + if (!sts.prepare(jt)) { + return ts; // return old table statistics + } + { + TraceTime timer("GetStatistics", TRACETIME_LOG(Debug, stringtable, perf)); + while (sts.do_task(jt, sz)) { + sts.pause(jt); + if (jt->is_Java_thread()) { + ThreadBlockInVM tbivm(JavaThread::cast(jt)); + } + sts.cont(jt); + } + } + ts = sts.done(jt); return ts; } void StringTable::print_table_statistics(outputStream* st) { - SizeFunc sz; - _local_table->statistics_to(Thread::current(), sz, st, "StringTable"); + TableStatistics ts = get_table_statistics(); + ts.print(st, "StringTable"); #if INCLUDE_CDS_JAVA_HEAP if (!_shared_table.empty()) { _shared_table.print_table_statistics(st, "Shared String Table"); diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 84c0a5a39de..3cb453aaecb 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -572,23 +572,35 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) { return sym; } -struct SizeFunc : StackObj { - size_t operator()(Symbol* value) { +TableStatistics SymbolTable::get_table_statistics() { + static TableStatistics ts; + auto sz = [&](Symbol* value) { assert(value != nullptr, "expected valid value"); return (value)->size() * HeapWordSize; }; + + Thread* jt = Thread::current(); + SymbolTableHash::StatisticsTask sts(_local_table); + if (!sts.prepare(jt)) { + return ts; // return old table statistics + } + { + TraceTime timer("GetStatistics", TRACETIME_LOG(Debug, symboltable, perf)); + while (sts.do_task(jt, sz)) { + sts.pause(jt); + if (jt->is_Java_thread()) { + ThreadBlockInVM tbivm(JavaThread::cast(jt)); + } + sts.cont(jt); + } + } + ts = sts.done(jt); + return ts; }; -TableStatistics SymbolTable::get_table_statistics() { - static TableStatistics ts; - SizeFunc sz; - ts = _local_table->statistics_get(Thread::current(), sz, ts); - return ts; -} - void SymbolTable::print_table_statistics(outputStream* st) { - SizeFunc sz; - _local_table->statistics_to(Thread::current(), sz, st, "SymbolTable"); + TableStatistics ts = get_table_statistics(); + ts.print(st, "SymbolTable"); if (!_shared_table.empty()) { _shared_table.print_table_statistics(st, "Shared Symbol Table"); diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 402a767c0b8..48166b22126 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -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,9 +56,12 @@ class ConcurrentHashTable : public CHeapObj { _stats_rate->remove(); } } - // Calculate statistics. Item sizes are calculated with VALUE_SIZE_FUNC. + // Calculate statistics. Item sizes are calculated with VALUE_SIZE_FUNC, and accumulated in summary and literal_size. template - TableStatistics statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f); + void internal_statistics_range(Thread* thread, size_t start, size_t stop, + VALUE_SIZE_FUNC& sts_f, NumberSeq& summary, size_t& literal_size); + + TableStatistics internal_statistics_epilog(Thread* thread, NumberSeq summary, size_t literal_size); // This is the internal node structure. // Only constructed with placement new from memory allocated with MemTag of @@ -531,12 +534,6 @@ class ConcurrentHashTable : public CHeapObj { template TableStatistics statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old); - // Writes statistics to the outputStream. Item sizes are calculated with - // VALUE_SIZE_FUNC. - template - void statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, outputStream* st, - const char* table_name); - // Moves all nodes from this table to to_cht with new hash code. // Must be done at a safepoint. void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); @@ -559,6 +556,7 @@ class ConcurrentHashTable : public CHeapObj { public: class BulkDeleteTask; class GrowTask; + class StatisticsTask; class ScanTask; }; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 929d70c74bd..3b6e3fefabf 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -1232,35 +1232,34 @@ inline void ConcurrentHashTable:: template template -inline TableStatistics ConcurrentHashTable:: - statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f) +inline void ConcurrentHashTable:: + internal_statistics_range(Thread* thread, size_t start, size_t stop, + VALUE_SIZE_FUNC& vs_f, NumberSeq& summary, size_t& literal_size) { - constexpr size_t batch_size = 128; - NumberSeq summary; - size_t literal_bytes = 0; - InternalTable* table = get_table(); - size_t num_batches = table->_size / batch_size; - for (size_t batch_start = 0; batch_start < _table->_size; batch_start += batch_size) { - // We batch the use of ScopedCS here as it has been found to be quite expensive to - // invoke it for every single bucket. - size_t batch_end = MIN2(batch_start + batch_size, _table->_size); - ScopedCS cs(thread, this); - for (size_t bucket_it = batch_start; bucket_it < batch_end; bucket_it++) { - size_t count = 0; - Bucket* bucket = table->get_bucket(bucket_it); - if (bucket->have_redirect() || bucket->is_locked()) { - continue; - } - Node* current_node = bucket->first(); - while (current_node != nullptr) { - ++count; - literal_bytes += vs_f(current_node->value()); - current_node = current_node->next(); - } - summary.add((double)count); + // We batch the use of ScopedCS here as it has been found to be quite expensive to + // invoke it for every single bucket. + ScopedCS cs(thread, this); + for (size_t bucket_it = start; bucket_it < stop; bucket_it++) { + size_t count = 0; + Bucket* bucket = _table->get_bucket(bucket_it); + if (bucket->have_redirect() || bucket->is_locked()) { + continue; } + Node* current_node = bucket->first(); + while (current_node != nullptr) { + ++count; + literal_size += vs_f(current_node->value()); + current_node = current_node->next(); + } + summary.add((double)count); } +} +template +inline TableStatistics ConcurrentHashTable:: + internal_statistics_epilog(Thread* thread, NumberSeq summary, size_t literal_bytes) +{ + unlock_resize_lock(thread); if (_stats_rate == nullptr) { return TableStatistics(summary, literal_bytes, sizeof(Bucket), sizeof(Node)); } else { @@ -1276,28 +1275,12 @@ inline TableStatistics ConcurrentHashTable:: if (!try_resize_lock(thread)) { return old; } + InternalTable* table = get_table(); + NumberSeq summary; + size_t literal_bytes = 0; - TableStatistics ts = statistics_calculate(thread, vs_f); - unlock_resize_lock(thread); - - return ts; -} - -template -template -inline void ConcurrentHashTable:: - statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, - outputStream* st, const char* table_name) -{ - if (!try_resize_lock(thread)) { - st->print_cr("statistics unavailable at this moment"); - return; - } - - TableStatistics ts = statistics_calculate(thread, vs_f); - unlock_resize_lock(thread); - - ts.print(st, table_name); + internal_statistics_range(thread, 0, table->_size, vs_f, summary, literal_bytes); + return internal_statistics_epilog(thread, summary, literal_bytes); } template diff --git a/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp b/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp index 44b2f91c3f2..f9808ba6c9c 100644 --- a/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp @@ -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 @@ -229,6 +229,50 @@ class ConcurrentHashTable::GrowTask : } }; +template +class ConcurrentHashTable::StatisticsTask : + public BucketsOperation +{ + NumberSeq _summary; + size_t _literal_bytes; + public: + StatisticsTask(ConcurrentHashTable* cht) : BucketsOperation(cht), _literal_bytes(0) { } + + // Before start prepare must be called. + bool prepare(Thread* thread) { + bool lock = BucketsOperation::_cht->try_resize_lock(thread); + if (!lock) { + return false; + } + + this->setup(thread); + return true; + } + + // Scans part of the table adding to statistics. + template + bool do_task(Thread* thread, VALUE_SIZE_FUNC& sz) { + size_t start, stop; + assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + "Should be locked"); + if (!this->claim(&start, &stop)) { + return false; + } + BucketsOperation::_cht->internal_statistics_range(thread, start, stop, sz, _summary, _literal_bytes); + assert(BucketsOperation::_cht->_resize_lock_owner != nullptr, + "Should be locked"); + return true; + } + + // Must be called after do_task returns false. + TableStatistics done(Thread* thread) { + this->thread_owns_resize_lock(thread); + TableStatistics ts = BucketsOperation::_cht->internal_statistics_epilog(thread, _summary, _literal_bytes); + this->thread_do_not_own_resize_lock(thread); + return ts; + } +}; + template class ConcurrentHashTable::ScanTask : public BucketsOperation From e7d4b360fe27585f1a021fd1d1da1fda7f27a37c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 26 Feb 2025 12:40:53 +0000 Subject: [PATCH 135/587] 8350667: Remove startThread_lock() and _startThread_lock on AIX Reviewed-by: stuefe, jkern --- src/hotspot/os/aix/osThread_aix.cpp | 4 +--- src/hotspot/os/aix/osThread_aix.hpp | 9 --------- src/hotspot/os/aix/os_aix.cpp | 2 ++ 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index 204b271ceee..bbc7cf41e52 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.cpp @@ -37,11 +37,9 @@ OSThread::OSThread() _siginfo(nullptr), _ucontext(nullptr), _expanding_stack(0), - _alt_sig_stack(nullptr), - _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { + _alt_sig_stack(nullptr) { sigemptyset(&_caller_sigmask); } OSThread::~OSThread() { - delete _startThread_lock; } diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp index 771c2c19e45..81c0eafa0f7 100644 --- a/src/hotspot/os/aix/osThread_aix.hpp +++ b/src/hotspot/os/aix/osThread_aix.hpp @@ -114,15 +114,6 @@ class OSThread : public OSThreadBase { void set_alt_sig_stack(address val) { _alt_sig_stack = val; } address alt_sig_stack(void) { return _alt_sig_stack; } - private: - Monitor* _startThread_lock; // sync parent and child in thread creation - - public: - - Monitor* startThread_lock() const { - return _startThread_lock; - } - // Printing uintx thread_id_for_printing() const override { return (uintx)_thread_id; diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index e452bfdfd7c..315c5fde157 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -796,6 +796,8 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // OSThread::thread_id is the pthread id. osthread->set_thread_id(tid); + // child thread synchronization is not done here on AIX, a thread is started in suspended state + return true; } From ea2c92384927a22dd1e1e8676723c7cc720a128b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Wed, 26 Feb 2025 12:51:35 +0000 Subject: [PATCH 136/587] 8323807: Async UL: Add a stalling mode to async UL Reviewed-by: dholmes, aboldtch --- src/hotspot/share/logging/logAsyncWriter.cpp | 143 +++++++++++++----- src/hotspot/share/logging/logAsyncWriter.hpp | 22 ++- .../share/logging/logConfiguration.cpp | 25 ++- .../share/logging/logConfiguration.hpp | 18 ++- src/hotspot/share/runtime/arguments.cpp | 6 +- src/hotspot/share/runtime/globals.hpp | 2 +- src/java.base/share/man/java.md | 10 +- test/hotspot/gtest/logging/test_asynclog.cpp | 19 ++- .../jtreg/runtime/logging/StressAsyncUL.java | 57 +++++++ 9 files changed, 241 insertions(+), 61 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/logging/StressAsyncUL.java diff --git a/src/hotspot/share/logging/logAsyncWriter.cpp b/src/hotspot/share/logging/logAsyncWriter.cpp index 737f001c049..ea5cc5c96ab 100644 --- a/src/hotspot/share/logging/logAsyncWriter.cpp +++ b/src/hotspot/share/logging/logAsyncWriter.cpp @@ -26,45 +26,63 @@ #include "logging/logConfiguration.hpp" #include "logging/logFileOutput.hpp" #include "logging/logFileStreamOutput.hpp" -#include "logging/logHandle.hpp" +#include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" -#include "runtime/os.inline.hpp" -#include "runtime/globals.hpp" +class AsyncLogWriter::Locker : public StackObj { + Thread*& _holder; + PlatformMonitor& _lock; -class AsyncLogWriter::AsyncLogLocker : public StackObj { - static Thread* _holder; public: - static Thread* current_holder() { return _holder; } - AsyncLogLocker() { - assert(_instance != nullptr, "AsyncLogWriter::_lock is unavailable"); - _instance->_lock.lock(); + Locker(Thread*& holder, PlatformMonitor& lock) + : _holder(holder), + _lock(lock) { + _lock.lock(); _holder = Thread::current_or_null(); } - ~AsyncLogLocker() { + ~Locker() { assert(_holder == Thread::current_or_null(), "must be"); _holder = nullptr; - _instance->_lock.unlock(); + _lock.unlock(); + } + + void notify() { + _lock.notify(); } void wait() { Thread* saved_holder = _holder; _holder = nullptr; - _instance->_lock.wait(0/* no timeout */); + _lock.wait(0 /* no timeout */); _holder = saved_holder; } }; -Thread* AsyncLogWriter::AsyncLogLocker::_holder = nullptr; +class AsyncLogWriter::ProducerLocker : public Locker { + static Thread* _holder; +public: + static Thread* current_holder() { return _holder; } + ProducerLocker() : Locker(_holder, _instance->_producer_lock) {} +}; + +class AsyncLogWriter::ConsumerLocker : public Locker { + static Thread* _holder; +public: + static Thread* current_holder() { return _holder; } + ConsumerLocker() : Locker(_holder, _instance->_consumer_lock) {} +}; + +Thread* AsyncLogWriter::ProducerLocker::_holder = nullptr; +Thread* AsyncLogWriter::ConsumerLocker::_holder = nullptr; // LogDecorator::None applies to 'constant initialization' because of its constexpr constructor. const LogDecorations& AsyncLogWriter::None = LogDecorations(LogLevel::Warning, LogTagSetMapping::tagset(), LogDecorators::None); -bool AsyncLogWriter::Buffer::push_back(LogFileStreamOutput* output, const LogDecorations& decorations, const char* msg) { - const size_t len = strlen(msg); +bool AsyncLogWriter::Buffer::push_back(LogFileStreamOutput* output, const LogDecorations& decorations, const char* msg, const size_t msg_len) { + const size_t len = msg_len; const size_t sz = Message::calc_size(len); const bool is_token = output == nullptr; // Always leave headroom for the flush token. Pushing a token must succeed. @@ -80,7 +98,7 @@ bool AsyncLogWriter::Buffer::push_back(LogFileStreamOutput* output, const LogDec } void AsyncLogWriter::Buffer::push_flush_token() { - bool result = push_back(nullptr, AsyncLogWriter::None, ""); + bool result = push_back(nullptr, AsyncLogWriter::None, "", 0); assert(result, "fail to enqueue the flush token."); } @@ -89,22 +107,45 @@ void AsyncLogWriter::enqueue_locked(LogFileStreamOutput* output, const LogDecora // client should use "" instead. assert(msg != nullptr, "enqueuing a null message!"); - if (!_buffer->push_back(output, decorations, msg)) { - bool p_created; - uint32_t* counter = _stats.put_if_absent(output, 0, &p_created); - *counter = *counter + 1; - return; - } + size_t msg_len = strlen(msg); + void* stalled_message = nullptr; + { + ConsumerLocker clocker; + if (_buffer->push_back(output, decorations, msg, msg_len)) { + _data_available = true; + clocker.notify(); + return; + } - _data_available = true; - _lock.notify(); + if (LogConfiguration::async_mode() == LogConfiguration::AsyncMode::Stall) { + size_t size = Message::calc_size(msg_len); + stalled_message = os::malloc(size, mtLogging); + if (stalled_message == nullptr) { + // Out of memory. We bail without any notice. + // Some other part of the system will probably fail later. + return; + } + _stalled_message = new (stalled_message) Message(output, decorations, msg, msg_len); + _data_available = true; + clocker.notify(); + // Note: we still hold the producer lock so cannot race against other threads trying to log a message + while (_stalled_message != nullptr) { + clocker.wait(); + } + } else { + bool p_created; + uint32_t* counter = _stats.put_if_absent(output, 0, &p_created); + *counter = *counter + 1; + } + } // ConsumerLocker out of scope + os::free(stalled_message); } // This function checks for cases where continuing with asynchronous logging may lead to stability issues, such as a deadlock. // If this returns false then we give up on logging asynchronously and do so synchronously instead. bool AsyncLogWriter::is_enqueue_allowed() { AsyncLogWriter* alw = AsyncLogWriter::instance(); - Thread* holding_thread = AsyncLogWriter::AsyncLogLocker::current_holder(); + Thread* holding_thread = AsyncLogWriter::ProducerLocker::current_holder(); Thread* this_thread = Thread::current_or_null(); if (this_thread == nullptr) { // The current thread is unattached. @@ -142,7 +183,7 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations& return false; } - AsyncLogLocker locker; + ProducerLocker plocker; #ifdef ASSERT if (TestingAsyncLoggingDeathTest || TestingAsyncLoggingDeathTestNoCrash) { @@ -162,7 +203,7 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iter } // If we get here we know the AsyncLogWriter is initialized. - AsyncLogLocker locker; + ProducerLocker plocker; for (; !msg_iterator.is_at_end(); msg_iterator++) { AsyncLogWriter::instance()->enqueue_locked(&output, msg_iterator.decorations(), msg_iterator.message()); } @@ -170,9 +211,13 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iter } AsyncLogWriter::AsyncLogWriter() - : _flush_sem(0), _lock(), _data_available(false), - _initialized(false), - _stats() { +: _flush_sem(0), + _producer_lock(), + _consumer_lock(), + _data_available(false), + _initialized(false), + _stats(), + _stalled_message(nullptr) { size_t size = AsyncLogBufferSize / 2; _buffer = new Buffer(size); @@ -185,7 +230,7 @@ AsyncLogWriter::AsyncLogWriter() } } -void AsyncLogWriter::write(AsyncLogMap& snapshot) { +bool AsyncLogWriter::write(AsyncLogMap& snapshot) { int req = 0; auto it = _buffer_staging->iterator(); while (it.hasNext()) { @@ -213,8 +258,9 @@ void AsyncLogWriter::write(AsyncLogMap& snapshot) { if (req > 0) { assert(req == 1, "Only one token is allowed in queue. AsyncLogWriter::flush() is NOT MT-safe!"); - _flush_sem.signal(req); + return true; } + return false; } void AsyncLogWriter::run() { @@ -222,11 +268,11 @@ void AsyncLogWriter::run() { ResourceMark rm; AsyncLogMap snapshot; { - AsyncLogLocker locker; - + ConsumerLocker clocker; while (!_data_available) { - locker.wait(); + clocker.wait(); } + // Only doing a swap and statistics under the lock to // guarantee that I/O jobs don't block logsites. _buffer_staging->reset(); @@ -243,7 +289,23 @@ void AsyncLogWriter::run() { }); _data_available = false; } - write(snapshot); + + bool saw_flush_token = write(snapshot); + + // Any stalled message must be written *after* the buffer has been written. + // This is because we try hard to output messages in program-order. + if (_stalled_message != nullptr) { + assert(LogConfiguration::async_mode() == LogConfiguration::AsyncMode::Stall, "must be"); + ConsumerLocker clocker; + Message* m = (Message*)_stalled_message; + m->output()->write_blocking(m->decorations(), m->message()); + _stalled_message = nullptr; + clocker.notify(); + } + + if (saw_flush_token) { + _flush_sem.signal(1); + } } } @@ -281,11 +343,12 @@ AsyncLogWriter* AsyncLogWriter::instance() { void AsyncLogWriter::flush() { if (_instance != nullptr) { { - AsyncLogLocker locker; + ProducerLocker plocker; + ConsumerLocker clocker; // Push directly in-case we are at logical max capacity, as this must not get dropped. _instance->_buffer->push_flush_token(); _instance->_data_available = true; - _instance->_lock.notify(); + clocker.notify(); } _instance->_flush_sem.wait(); @@ -293,7 +356,7 @@ void AsyncLogWriter::flush() { } AsyncLogWriter::BufferUpdater::BufferUpdater(size_t newsize) { - AsyncLogLocker locker; + ConsumerLocker clocker; auto p = AsyncLogWriter::_instance; _buf1 = p->_buffer; @@ -307,7 +370,7 @@ AsyncLogWriter::BufferUpdater::~BufferUpdater() { auto p = AsyncLogWriter::_instance; { - AsyncLogLocker locker; + ConsumerLocker clocker; delete p->_buffer; delete p->_buffer_staging; diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index 00818634bdd..355d15b904c 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -29,6 +29,7 @@ #include "logging/logMessageBuffer.hpp" #include "memory/allocation.hpp" #include "runtime/mutex.hpp" +#include "runtime/os.inline.hpp" #include "runtime/nonJavaThread.hpp" #include "runtime/semaphore.hpp" #include "utilities/resourceHash.hpp" @@ -59,7 +60,9 @@ class LogFileStreamOutput; class AsyncLogWriter : public NonJavaThread { friend class AsyncLogTest; friend class AsyncLogTest_logBuffer_vm_Test; - class AsyncLogLocker; + class Locker; + class ProducerLocker; + class ConsumerLocker; // account for dropped messages template @@ -125,7 +128,7 @@ class AsyncLogWriter : public NonJavaThread { } void push_flush_token(); - bool push_back(LogFileStreamOutput* output, const LogDecorations& decorations, const char* msg); + bool push_back(LogFileStreamOutput* output, const LogDecorations& decorations, const char* msg, const size_t msg_len); void reset() { // Ensure _pos is Message-aligned @@ -159,8 +162,13 @@ class AsyncLogWriter : public NonJavaThread { static AsyncLogWriter* _instance; Semaphore _flush_sem; // Can't use a Monitor here as we need a low-level API that can be used without Thread::current(). - PlatformMonitor _lock; + // Producers take both locks in the order producer lock and then consumer lock. + // The consumer protects the buffers and performs all communication between producer and consumer via wait/notify. + // This allows a producer to await progress from the consumer thread (by only releasing the producer lock)), whilst preventing all other producers from progressing. + PlatformMonitor _producer_lock; + PlatformMonitor _consumer_lock; bool _data_available; + // _initialized is set to true if the constructor succeeds volatile bool _initialized; AsyncLogMap _stats; @@ -168,11 +176,17 @@ class AsyncLogWriter : public NonJavaThread { Buffer* _buffer; Buffer* _buffer_staging; + // Stalled message + // Stalling is implemented by the producer writing to _stalled_message, notifying the consumer lock and releasing it. + // The consumer will then write all of the current buffers' content and then write the stalled message, at the end notifying the consumer lock and releasing it for the + // owning producer thread of the stalled message. This thread will finally release both locks in order, allowing for other producers to continue. + volatile Message* _stalled_message; + static const LogDecorations& None; AsyncLogWriter(); void enqueue_locked(LogFileStreamOutput* output, const LogDecorations& decorations, const char* msg); - void write(AsyncLogMap& snapshot); + bool write(AsyncLogMap& snapshot); void run() override; void pre_run() override { NonJavaThread::pre_run(); diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 5f8a045c356..194bd622b15 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -636,10 +636,15 @@ void LogConfiguration::print_command_line_help(outputStream* out) { out->cr(); out->print_cr("Asynchronous logging (off by default):"); - out->print_cr(" -Xlog:async"); + out->print_cr(" -Xlog:async[:[mode]]"); out->print_cr(" All log messages are written to an intermediate buffer first and will then be flushed" " to the corresponding log outputs by a standalone thread. Write operations at logsites are" " guaranteed non-blocking."); + out->print_cr(" A mode, either 'drop' or 'stall', may be provided. If 'drop' is provided then" + " messages will be dropped if there is no room in the intermediate buffer." + " If 'stall' is provided then the log operation will wait for room to be made by the output thread, without dropping any messages." + " The default mode is 'drop'."); + out->cr(); out->print_cr("Some examples:"); @@ -715,4 +720,20 @@ void LogConfiguration::notify_update_listeners() { } } -bool LogConfiguration::_async_mode = false; +LogConfiguration::AsyncMode LogConfiguration::_async_mode = AsyncMode::Off; + +bool LogConfiguration::parse_async_argument(const char* async_tail) { + bool ret = true; + if (*async_tail == '\0') { + // Default is to drop. + LogConfiguration::set_async_mode(LogConfiguration::AsyncMode::Drop); + } else if (strcmp(async_tail, ":stall") == 0) { + LogConfiguration::set_async_mode(LogConfiguration::AsyncMode::Stall); + } else if (strcmp(async_tail, ":drop") == 0) { + LogConfiguration::set_async_mode(LogConfiguration::AsyncMode::Drop); + } else { + // User provided unknown async option + ret = false; + } + return ret; +} diff --git a/src/hotspot/share/logging/logConfiguration.hpp b/src/hotspot/share/logging/logConfiguration.hpp index e9cf3e53c8b..840f6a9af57 100644 --- a/src/hotspot/share/logging/logConfiguration.hpp +++ b/src/hotspot/share/logging/logConfiguration.hpp @@ -62,7 +62,14 @@ class LogConfiguration : public AllStatic { static UpdateListenerFunction* _listener_callbacks; static size_t _n_listener_callbacks; - static bool _async_mode; + +public: + enum class AsyncMode { + Off, Stall, Drop + }; + +private: + static AsyncMode _async_mode; // Create a new output. Returns null if failed. static LogOutput* new_output(const char* name, const char* options, outputStream* errstream); @@ -120,6 +127,8 @@ class LogConfiguration : public AllStatic { const char* output_options, outputStream* errstream); + static bool parse_async_argument(const char* async_tail); + // Prints log configuration to outputStream, used by JCmd/MBean. static void describe(outputStream* out); @@ -129,9 +138,10 @@ class LogConfiguration : public AllStatic { // Rotates all LogOutput static void rotate_all_outputs(); - static bool is_async_mode() { return _async_mode; } - static void set_async_mode(bool value) { - _async_mode = value; + static AsyncMode async_mode() { return _async_mode; } + static bool is_async_mode() { return _async_mode != AsyncMode::Off; } + static void set_async_mode(AsyncMode mode) { + _async_mode = mode; } }; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index ab05cbeb891..c6651c46e02 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2605,9 +2605,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin } else if (strcmp(tail, ":disable") == 0) { LogConfiguration::disable_logging(); ret = true; - } else if (strcmp(tail, ":async") == 0) { - LogConfiguration::set_async_mode(true); - ret = true; + } else if (strncmp(tail, ":async", strlen(":async")) == 0) { + const char* async_tail = tail + strlen(":async"); + ret = LogConfiguration::parse_async_argument(async_tail); } else if (*tail == '\0') { ret = LogConfiguration::parse_command_line_arguments(); assert(ret, "-Xlog without arguments should never fail to parse"); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 61c4c0633c7..a1ebe226e85 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1871,7 +1871,7 @@ const int ObjectAlignmentInBytes = 8; product(size_t, AsyncLogBufferSize, 2*M, \ "Memory budget (in bytes) for the buffer of Asynchronous " \ "Logging (-Xlog:async).") \ - range(100*K, 50*M) \ + range(DEBUG_ONLY(192) NOT_DEBUG(100*K), 50*M) \ \ product(bool, CheckIntrinsics, true, DIAGNOSTIC, \ "When a class C is loaded, check that " \ diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index e1a247b20c3..32280f2c516 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -3357,16 +3357,18 @@ getting overwritten. ### -Xlog Output Mode By default logging messages are output synchronously - each log message is written to -the designated output when the logging call is made. But you can instead use asynchronous +the designated output when the logging call is made. You can instead use asynchronous logging mode by specifying: -`-Xlog:async` +`-Xlog:async[:[stall|drop]]` : Write all logging asynchronously. In asynchronous logging mode, log sites enqueue all logging messages to an intermediate buffer and a standalone thread is responsible for flushing them to the corresponding outputs. The -intermediate buffer is bounded and on buffer exhaustion the enqueuing message is discarded. -Log entry write operations are guaranteed non-blocking. +intermediate buffer is bounded. On buffer exhaustion the enqueuing message is either discarded (`async:drop`), +or logging threads are stalled until the flushing thread catches up (`async:stall`). +If no specific mode is chosen, then `async:drop` is chosen by default. +Log entry write operations are guaranteed to be non-blocking in the `async:drop` case. The option `-XX:AsyncLogBufferSize=N` specifies the memory budget in bytes for the intermediate buffer. The default value should be big enough to cater for most cases. Users can provide a custom value to diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index 401e31804ad..cb674603563 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -25,6 +25,7 @@ #include "jvm.h" #include "logging/log.hpp" #include "logging/logAsyncWriter.hpp" +#include "logging/logConfiguration.hpp" #include "logging/logFileOutput.hpp" #include "logging/logMessage.hpp" #include "logTestFixture.hpp" @@ -173,10 +174,10 @@ TEST_VM_F(AsyncLogTest, logBuffer) { const uintptr_t mask = (uintptr_t)(sizeof(void*) - 1); bool res; - res = buffer->push_back(output, Default, "a log line"); + res = buffer->push_back(output, Default, "a log line", strlen("a log line")); EXPECT_TRUE(res) << "first message should succeed."; line++; - res = buffer->push_back(output, Default, "yet another"); + res = buffer->push_back(output, Default, "yet another", strlen("yet another")); EXPECT_TRUE(res) << "second message should succeed."; line++; @@ -201,7 +202,7 @@ TEST_VM_F(AsyncLogTest, logBuffer) { written = e->output()->write_blocking(e->decorations(), e->message()); EXPECT_GT(written, 0); - while (buffer->push_back(output, Default, "0123456789abcdef")) { + while (buffer->push_back(output, Default, "0123456789abcdef", strlen("0123456789abcdef"))) { line++; } @@ -252,6 +253,18 @@ TEST_VM_F(AsyncLogTest, droppingMessage) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } +TEST_VM_F(AsyncLogTest, StallingModePreventsDroppedMessages) { + if (AsyncLogWriter::instance() == nullptr) { + return; + } + set_log_config(TestLogFileName, "logging=debug"); + LogConfiguration::AsyncMode prev_mode = LogConfiguration::async_mode(); + LogConfiguration::set_async_mode(LogConfiguration::AsyncMode::Off); + test_asynclog_drop_messages(); + EXPECT_FALSE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); + LogConfiguration::set_async_mode(prev_mode); +} + TEST_VM_F(AsyncLogTest, stdoutOutput) { testing::internal::CaptureStdout(); diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java new file mode 100644 index 00000000000..1fa6ab76ec2 --- /dev/null +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.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. + */ + +/* + * @test + * @summary Stress test async UL in dropping and stalling mode + * @requires vm.flagless + * @requires vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver StressAsyncUL + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class StressAsyncUL { + static void analyze_output(String... args) throws Exception { + ProcessBuilder pb = + ProcessTools.createLimitedTestJavaProcessBuilder(args); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + public static void main(String[] args) throws Exception { + analyze_output("-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output("-Xlog:async:stall", "-Xlog:all=trace", 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("-Xlog:async:drop", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output("-Xlog:async:stall", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + } + + public static class InnerClass { + public static void main(String[] args) { + } + } +} From 0f82268134df65bbc65ecda158d25f708f18d150 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Wed, 26 Feb 2025 14:14:33 +0000 Subject: [PATCH 137/587] 8345598: Upgrade NSS binaries for interop tests Reviewed-by: weijun, rhalade --- test/jdk/sun/security/pkcs11/PKCS11Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index b624afd69fb..a371effc72f 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -82,7 +82,7 @@ public abstract class PKCS11Test { // Version of the NSS artifact. This coincides with the version of // the NSS version - private static final String NSS_BUNDLE_VERSION = "3.101"; + private static final String NSS_BUNDLE_VERSION = "3.107"; private static final String NSSLIB = "jpg.tests.jdk.nsslib"; static double nss_version = -1; From 2731712383937ce7213c4c2b89f8c041708a3f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 26 Feb 2025 14:59:18 +0000 Subject: [PATCH 138/587] 8287749: Re-enable javadoc -serialwarn option Reviewed-by: erikj --- make/Docs.gmk | 4 ++-- make/scripts/genExceptions.sh | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index be9efbdc370..49c97946f75 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -98,14 +98,14 @@ JAVA_WARNINGS_ARE_ERRORS ?= -Werror # The initial set of options for javadoc JAVADOC_OPTIONS := -use -keywords -notimestamp \ - -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \ + -serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \ -splitIndex --system none -javafx --expand-requires transitive \ --override-methods=summary # The reference options must stay stable to allow for comparisons across the # development cycle. REFERENCE_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \ - -encoding ISO-8859-1 -breakiterator -splitIndex --system none \ + -serialwarn -encoding ISO-8859-1 -breakiterator -splitIndex --system none \ -html5 -javafx --expand-requires transitive # Should we add DRAFT stamps to the generated javadoc? diff --git a/make/scripts/genExceptions.sh b/make/scripts/genExceptions.sh index 4f6c0d9820b..7c191189827 100644 --- a/make/scripts/genExceptions.sh +++ b/make/scripts/genExceptions.sh @@ -1,6 +1,6 @@ #! /bin/sh # -# 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 @@ -70,6 +70,8 @@ __END__ /** * The $ARG_PHRASE. + * + * @serial */ private $ARG_TYPE $ARG_ID; From bd112c4fab8c6b6a8181d4629009b6cb408727a1 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 26 Feb 2025 15:00:47 +0000 Subject: [PATCH 139/587] 8350443: GHA: Split static-libs-bundles into a separate job Reviewed-by: ihse, yzheng --- .github/actions/upload-bundles/action.yml | 5 ++++- .github/workflows/build-linux.yml | 20 ++++++++------------ .github/workflows/main.yml | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml index 4e974ae58ba..30f4ac03c1e 100644 --- a/.github/actions/upload-bundles/action.yml +++ b/.github/actions/upload-bundles/action.yml @@ -32,6 +32,9 @@ inputs: debug-suffix: description: 'File name suffix denoting debug level, possibly empty' required: false + bundle-suffix: + description: 'Bundle name suffix, possibly empty' + required: false runs: using: composite @@ -75,7 +78,7 @@ runs: - name: 'Upload bundles artifact' uses: actions/upload-artifact@v4 with: - name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} + name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.bundle-suffix }} path: bundles retention-days: 1 if: steps.bundles.outputs.bundles-found == 'true' diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index b1d4278f8b4..101668b2bd5 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -61,6 +61,9 @@ on: make-arguments: required: false type: string + bundle-suffix: + required: false + type: string jobs: build-linux: @@ -71,10 +74,6 @@ jobs: fail-fast: false matrix: debug-level: ${{ fromJSON(inputs.debug-levels) }} - include: - - debug-level: debug - flags: --with-debug-level=fastdebug - suffix: -debug steps: - name: 'Checkout the JDK source' @@ -118,7 +117,7 @@ jobs: run: > bash configure --with-conf-name=${{ inputs.platform }} - ${{ matrix.flags }} + ${{ matrix.debug-level == 'debug' && '--with-debug-level=fastdebug' || '' }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} --with-boot-jdk=${{ steps.bootjdk.outputs.path }} --with-jtreg=${{ steps.jtreg.outputs.path }} @@ -133,17 +132,14 @@ jobs: - name: 'Build' id: build uses: ./.github/actions/do-build - env: - # Only build static-libs-bundles for release builds. - # For debug builds, building static-libs often exceeds disk space. - STATIC_LIBS: ${{ matrix.debug-level == 'release' && 'static-libs-bundles' }} with: - make-target: '${{ inputs.make-target }} ${STATIC_LIBS} ${{ inputs.make-arguments }}' + make-target: '${{ inputs.make-target }} ${{ inputs.make-arguments }}' platform: ${{ inputs.platform }} - debug-suffix: '${{ matrix.suffix }}' + debug-suffix: "${{ matrix.debug-level == 'debug' && '-debug' || '' }}" - name: 'Upload bundles' uses: ./.github/actions/upload-bundles with: platform: ${{ inputs.platform }} - debug-suffix: '${{ matrix.suffix }}' + debug-suffix: "${{ matrix.debug-level == 'debug' && '-debug' || '' }}" + bundle-suffix: ${{ inputs.bundle-suffix }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3ea07501477..2339bb390b9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -225,6 +225,25 @@ jobs: make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.prepare.outputs.linux-x64-variants == 'true' + build-linux-x64-static-libs: + name: linux-x64-static-libs + needs: prepare + uses: ./.github/workflows/build-linux.yml + with: + platform: linux-x64 + make-target: 'static-libs-bundles' + # Only build static-libs-bundles for release builds. + # For debug builds, building static-libs often exceeds disk space. + debug-levels: '[ "release" ]' + gcc-major-version: '10' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + # Upload static libs bundles separately to avoid interference with normal linux-x64 bundle. + # This bundle is not used by testing jobs, but downstreams use it to check that + # dependent projects, e.g. libgraal, builds fine. + bundle-suffix: "-static-libs" + if: needs.prepare.outputs.linux-x64-variants == 'true' + build-linux-cross-compile: name: linux-cross-compile needs: prepare From 3e46480dcfabf79b74cc371eaa84dce2e252f3da Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 26 Feb 2025 15:57:37 +0000 Subject: [PATCH 140/587] 8350770: [BACKOUT] Protection zone for easier detection of accidental zero-nKlass use Reviewed-by: mdoerr, rkennke --- src/hotspot/share/cds/archiveBuilder.cpp | 17 +- src/hotspot/share/cds/archiveBuilder.hpp | 13 +- src/hotspot/share/cds/archiveUtils.cpp | 55 +++-- src/hotspot/share/cds/dynamicArchive.cpp | 1 + src/hotspot/share/cds/filemap.hpp | 2 +- src/hotspot/share/cds/metaspaceShared.cpp | 92 +++----- src/hotspot/share/cds/metaspaceShared.hpp | 1 - src/hotspot/share/include/cds.h | 5 +- src/hotspot/share/memory/metaspace.cpp | 41 ++-- src/hotspot/share/oops/compressedKlass.cpp | 29 +-- src/hotspot/share/oops/compressedKlass.hpp | 11 +- .../share/oops/compressedKlass.inline.hpp | 6 +- src/hotspot/share/prims/whitebox.cpp | 12 -- src/hotspot/share/runtime/os.cpp | 6 - .../AccessZeroNKlassHitsProtectionZone.java | 203 ------------------ test/lib/jdk/test/whitebox/WhiteBox.java | 4 +- 16 files changed, 98 insertions(+), 400 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index f093b9d8070..21e97457a87 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -153,6 +153,7 @@ void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) { ArchiveBuilder::ArchiveBuilder() : _current_dump_region(nullptr), _buffer_bottom(nullptr), + _num_dump_regions_used(0), _requested_static_archive_bottom(nullptr), _requested_static_archive_top(nullptr), _requested_dynamic_archive_bottom(nullptr), @@ -160,7 +161,6 @@ ArchiveBuilder::ArchiveBuilder() : _mapped_static_archive_bottom(nullptr), _mapped_static_archive_top(nullptr), _buffer_to_requested_delta(0), - _pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive. _rw_region("rw", MAX_SHARED_DELTA), _ro_region("ro", MAX_SHARED_DELTA), _ptrmap(mtClassShared), @@ -323,14 +323,9 @@ address ArchiveBuilder::reserve_buffer() { _shared_rs = rs; _buffer_bottom = buffer_bottom; - - if (CDSConfig::is_dumping_static_archive()) { - _current_dump_region = &_pz_region; - _current_dump_region->init(&_shared_rs, &_shared_vs); - } else { - _current_dump_region = &_rw_region; - _current_dump_region->init(&_shared_rs, &_shared_vs); - } + _current_dump_region = &_rw_region; + _num_dump_regions_used = 1; + _current_dump_region->init(&_shared_rs, &_shared_vs); ArchivePtrMarker::initialize(&_ptrmap, &_shared_vs); @@ -371,8 +366,7 @@ address ArchiveBuilder::reserve_buffer() { 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()); - start_dump_region(&_rw_region); + rw_region()->allocate(16); } return buffer_bottom; @@ -550,6 +544,7 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref void ArchiveBuilder::start_dump_region(DumpRegion* next) { current_dump_region()->pack(next); _current_dump_region = next; + _num_dump_regions_used ++; } char* ArchiveBuilder::ro_strdup(const char* s) { diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 5913ae29c78..e3efedd46f1 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -96,6 +96,7 @@ class ArchiveBuilder : public StackObj { protected: DumpRegion* _current_dump_region; address _buffer_bottom; // for writing the contents of rw/ro regions + int _num_dump_regions_used; // These are the addresses where we will request the static and dynamic archives to be // mapped at run time. If the request fails (due to ASLR), we will map the archives at @@ -209,12 +210,6 @@ private: ReservedSpace _shared_rs; VirtualSpace _shared_vs; - // The "pz" region is used only during static dumps to reserve an unused space between SharedBaseAddress and - // the bottom of the rw region. During runtime, this space will be filled with a reserved area that disallows - // read/write/exec, so we can track for bad CompressedKlassPointers encoding. - // Note: this region does NOT exist in the cds archive. - DumpRegion _pz_region; - DumpRegion _rw_region; DumpRegion _ro_region; @@ -275,6 +270,9 @@ private: protected: virtual void iterate_roots(MetaspaceClosure* it) = 0; + + static const int _total_dump_regions = 2; + void start_dump_region(DumpRegion* next); public: @@ -369,7 +367,6 @@ public: void remember_embedded_pointer_in_enclosing_obj(MetaspaceClosure::Ref* ref); static void serialize_dynamic_archivable_items(SerializeClosure* soc); - DumpRegion* pz_region() { return &_pz_region; } DumpRegion* rw_region() { return &_rw_region; } DumpRegion* ro_region() { return &_ro_region; } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 7e04b6227f2..90eefd13d46 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -73,39 +73,34 @@ void ArchivePtrMarker::initialize(CHeapBitMap* ptrmap, VirtualSpace* vs) { } void ArchivePtrMarker::initialize_rw_ro_maps(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap) { - address* buff_bottom = (address*)ArchiveBuilder::current()->buffer_bottom(); - address* rw_bottom = (address*)ArchiveBuilder::current()->rw_region()->base(); - address* ro_bottom = (address*)ArchiveBuilder::current()->ro_region()->base(); - - // The bit in _ptrmap that cover the very first word in the rw/ro regions. - size_t rw_start = rw_bottom - buff_bottom; - size_t ro_start = ro_bottom - buff_bottom; - - // The number of bits used by the rw/ro ptrmaps. We might have lots of zero - // bits at the bottom and top of rrw/ro ptrmaps, but these zeros will be - // removed by FileMapInfo::write_bitmap_region(). - size_t rw_size = ArchiveBuilder::current()->rw_region()->used() / sizeof(address); - size_t ro_size = ArchiveBuilder::current()->ro_region()->used() / sizeof(address); - - // The last (exclusive) bit in _ptrmap that covers the rw/ro regions. - // Note: _ptrmap is dynamically expanded only when an actual pointer is written, so - // it may not be as large as we want. - size_t rw_end = MIN2(rw_start + rw_size, _ptrmap->size()); - size_t ro_end = MIN2(ro_start + ro_size, _ptrmap->size()); - - rw_ptrmap->initialize(rw_size); - ro_ptrmap->initialize(ro_size); - - for (size_t rw_bit = rw_start; rw_bit < rw_end; rw_bit++) { - rw_ptrmap->at_put(rw_bit - rw_start, _ptrmap->at(rw_bit)); - } - - for(size_t ro_bit = ro_start; ro_bit < ro_end; ro_bit++) { - ro_ptrmap->at_put(ro_bit - ro_start, _ptrmap->at(ro_bit)); - } + address* rw_bottom = (address*)ArchiveBuilder::current()->rw_region()->base(); + address* ro_bottom = (address*)ArchiveBuilder::current()->ro_region()->base(); _rw_ptrmap = rw_ptrmap; _ro_ptrmap = ro_ptrmap; + + size_t rw_size = ArchiveBuilder::current()->rw_region()->used() / sizeof(address); + size_t ro_size = ArchiveBuilder::current()->ro_region()->used() / sizeof(address); + // ro_start is the first bit in _ptrmap that covers the pointer that would sit at ro_bottom. + // E.g., if rw_bottom = (address*)100 + // ro_bottom = (address*)116 + // then for 64-bit platform: + // ro_start = ro_bottom - rw_bottom = (116 - 100) / sizeof(address) = 2; + size_t ro_start = ro_bottom - rw_bottom; + + // Note: ptrmap is big enough only to cover the last pointer in ro_region. + // See ArchivePtrMarker::compact() + _rw_ptrmap->initialize(rw_size); + _ro_ptrmap->initialize(_ptrmap->size() - ro_start); + + for (size_t rw_bit = 0; rw_bit < _rw_ptrmap->size(); rw_bit++) { + _rw_ptrmap->at_put(rw_bit, _ptrmap->at(rw_bit)); + } + + for(size_t ro_bit = ro_start; ro_bit < _ptrmap->size(); ro_bit++) { + _ro_ptrmap->at_put(ro_bit-ro_start, _ptrmap->at(ro_bit)); + } + assert(_ptrmap->size() - ro_start == _ro_ptrmap->size(), "must be"); } void ArchivePtrMarker::mark_pointer(address* ptr_loc) { diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index bcec4146aeb..095b443af66 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -170,6 +170,7 @@ public: post_dump(); + assert(_num_dump_regions_used == _total_dump_regions, "must be"); verify_universe("After CDS dynamic dump"); } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 52e8827a69a..25550d76d2a 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -400,7 +400,7 @@ public: // The offset of the (exclusive) end of the last core region in this archive, relative to SharedBaseAddress size_t mapping_end_offset() const { return last_core_region()->mapping_end_offset(); } - char* mapped_base() const { return header()->mapped_base_address(); } + char* mapped_base() const { return first_core_region()->mapped_base(); } char* mapped_end() const { return last_core_region()->mapped_end(); } // Non-zero if the archive needs to be mapped a non-default location due to ASLR. diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index e8866336b7a..2e5ebff456e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -147,10 +147,6 @@ size_t MetaspaceShared::core_region_alignment() { return os::cds_core_region_alignment(); } -size_t MetaspaceShared::protection_zone_size() { - return os::cds_core_region_alignment(); -} - static bool shared_base_valid(char* shared_base) { // We check user input for SharedBaseAddress at dump time. @@ -1284,7 +1280,6 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File ReservedSpace total_space_rs, archive_space_rs, class_space_rs; MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE; - size_t prot_zone_size = 0; char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo, use_requested_addr, @@ -1296,29 +1291,14 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File log_debug(cds)("Failed to reserve spaces (use_requested_addr=%u)", (unsigned)use_requested_addr); } else { - if (Metaspace::using_class_space()) { - prot_zone_size = protection_zone_size(); -#ifdef ASSERT - // Before mapping the core regions into the newly established address space, we mark - // start and the end of the future protection zone with canaries. That way we easily - // catch mapping errors (accidentally mapping data into the future protection zone). - os::commit_memory(mapped_base_address, prot_zone_size, false); - *(mapped_base_address) = 'P'; - *(mapped_base_address + prot_zone_size - 1) = 'P'; -#endif - } - #ifdef ASSERT // Some sanity checks after reserving address spaces for archives // and class space. assert(archive_space_rs.is_reserved(), "Sanity"); if (Metaspace::using_class_space()) { - assert(archive_space_rs.base() == mapped_base_address && - archive_space_rs.size() > protection_zone_size(), - "Archive space must lead and include the protection zone"); // Class space must closely follow the archive space. Both spaces // must be aligned correctly. - assert(class_space_rs.is_reserved() && class_space_rs.size() > 0, + assert(class_space_rs.is_reserved(), "A class space should have been reserved"); assert(class_space_rs.base() >= archive_space_rs.end(), "class space should follow the cds archive space"); @@ -1331,9 +1311,8 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File } #endif // ASSERT - log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes%s", - p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size(), - (prot_zone_size > 0 ? " (includes protection zone)" : "")); + log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", + p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size()); log_info(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size()); @@ -1405,40 +1384,38 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File if (result == MAP_ARCHIVE_SUCCESS) { SharedBaseAddress = (size_t)mapped_base_address; #ifdef _LP64 - if (Metaspace::using_class_space()) { - assert(*(mapped_base_address) == 'P' && - *(mapped_base_address + prot_zone_size - 1) == 'P', - "Protection zone was overwritten?"); + if (Metaspace::using_class_space()) { + // Set up ccs in metaspace. + Metaspace::initialize_class_space(class_space_rs); - // Set up ccs in metaspace. - Metaspace::initialize_class_space(class_space_rs); - - // Set up compressed Klass pointer encoding: the encoding range must - // cover both archive and class space. - const address encoding_base = (address)mapped_base_address; - const address klass_range_start = encoding_base + prot_zone_size; - const size_t klass_range_size = (address)class_space_rs.end() - klass_range_start; - if (INCLUDE_CDS_JAVA_HEAP || UseCompactObjectHeaders) { - // The CDS archive may contain narrow Klass IDs that were precomputed at archive generation time: - // - every archived java object header (only if INCLUDE_CDS_JAVA_HEAP) - // - every archived Klass' prototype (only if +UseCompactObjectHeaders) - // - // In order for those IDs to still be valid, we need to dictate base and shift: base should be the - // mapping start (including protection zone), shift should be the shift used at archive generation time. - CompressedKlassPointers::initialize_for_given_encoding( - klass_range_start, klass_range_size, - encoding_base, ArchiveBuilder::precomputed_narrow_klass_shift() // precomputed encoding, see ArchiveBuilder - ); - } else { - // Let JVM freely chose encoding base and shift - CompressedKlassPointers::initialize(klass_range_start, klass_range_size); - } - CompressedKlassPointers::establish_protection_zone(encoding_base, prot_zone_size); - - // map_or_load_heap_region() compares the current narrow oop and klass encodings - // with the archived ones, so it must be done after all encodings are determined. - static_mapinfo->map_or_load_heap_region(); - } + // Set up compressed Klass pointer encoding: the encoding range must + // cover both archive and class space. + address cds_base = (address)static_mapinfo->mapped_base(); + address ccs_end = (address)class_space_rs.end(); + assert(ccs_end > cds_base, "Sanity check"); + if (INCLUDE_CDS_JAVA_HEAP || UseCompactObjectHeaders) { + // The CDS archive may contain narrow Klass IDs that were precomputed at archive generation time: + // - every archived java object header (only if INCLUDE_CDS_JAVA_HEAP) + // - every archived Klass' prototype (only if +UseCompactObjectHeaders) + // + // In order for those IDs to still be valid, we need to dictate base and shift: base should be the + // mapping start, shift the shift used at archive generation time. + address precomputed_narrow_klass_base = cds_base; + const int precomputed_narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift(); + CompressedKlassPointers::initialize_for_given_encoding( + cds_base, ccs_end - cds_base, // Klass range + precomputed_narrow_klass_base, precomputed_narrow_klass_shift // precomputed encoding, see ArchiveBuilder + ); + } else { + // Let JVM freely chose encoding base and shift + CompressedKlassPointers::initialize ( + cds_base, ccs_end - cds_base // Klass range + ); + } + // map_or_load_heap_region() compares the current narrow oop and klass encodings + // with the archived ones, so it must be done after all encodings are determined. + static_mapinfo->map_or_load_heap_region(); + } #endif // _LP64 log_info(cds)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); log_info(cds)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); @@ -1520,6 +1497,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma const size_t archive_space_alignment = core_region_alignment(); // Size and requested location of the archive_space_rs (for both static and dynamic archives) + assert(static_mapinfo->mapping_base_offset() == 0, "Must be"); size_t archive_end_offset = (dynamic_mapinfo == nullptr) ? static_mapinfo->mapping_end_offset() : dynamic_mapinfo->mapping_end_offset(); size_t archive_space_size = align_up(archive_end_offset, archive_space_alignment); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index 27df816833c..6d5f273041a 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -139,7 +139,6 @@ public: // Alignment for the 2 core CDS regions (RW/RO) only. // (Heap region alignments are decided by GC). static size_t core_region_alignment(); - static size_t protection_zone_size(); static void rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik); // print loaded classes names to file. static void dump_loaded_classes(const char* file_name, TRAPS); diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index 8819e4c00be..2a80dd68abd 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -70,10 +70,7 @@ typedef struct CDSFileMapRegion { size_t _ptrmap_offset; // Bitmap for relocating native pointer fields in archived heap objects. // (The base address is the bottom of the BM region). 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 - // static archive) is is mapped. + char* _mapped_base; // Actually mapped address (null if this region is not mapped). bool _in_reserved_space; // Is this region in a ReservedSpace } CDSFileMapRegion; diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 2566c61188f..99d1d027db0 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. - * Copyright (c) 2023, 2025, Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, 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 @@ -37,7 +37,6 @@ #include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/commitLimiter.hpp" #include "memory/metaspace/internalStats.hpp" -#include "memory/metaspace/metachunk.hpp" #include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/metaspaceContext.hpp" #include "memory/metaspace/metaspaceReporter.hpp" @@ -805,37 +804,29 @@ void Metaspace::global_initialize() { // Set up compressed class pointer encoding. // In CDS=off mode, we give the JVM some leeway to choose a favorable base/shift combination. CompressedKlassPointers::initialize((address)rs.base(), rs.size()); - - // After narrowKlass encoding scheme is decided: if the encoding base points to class space start, - // establish a protection zone. Accidentally decoding a zero nKlass ID and then using it will result - // in an immediate segmentation fault instead of a delayed error much later. - if (CompressedKlassPointers::base() == (address)rs.base()) { - // Let the protection zone be a whole commit granule. Otherwise, buddy allocator may later place neighboring - // chunks in the same granule, see that the granule is not yet committed, and commit it, which would replace - // the protection mapping and make the zone readable. - // Alternatively, we could commit the chunk right now, but that is a tiny bit more fiddly, since we are not - // fully set up yet at this point. - const size_t protzone_size = metaspace::Settings::commit_granule_bytes(); // granule size >= page size - const size_t protzone_wordsize = protzone_size / BytesPerWord; - const metaspace::chunklevel_t lvl = metaspace::chunklevel::level_fitting_word_size(protzone_wordsize); - metaspace::Metachunk* const chunk = MetaspaceContext::context_class()->cm()->get_chunk(lvl); - const address protzone = (address) chunk->base(); - assert(protzone == (address)rs.base(), "The very first chunk should be located at the class space start?"); - assert(chunk->word_size() == protzone_wordsize, "Weird chunk size"); - CompressedKlassPointers::establish_protection_zone(protzone, protzone_size); - } else { - assert(CompressedKlassPointers::base() == nullptr, "Zero-based encoding expected"); - } - } -#endif // _LP64 +#endif // Initialize non-class virtual space list, and its chunk manager: MetaspaceContext::initialize_nonclass_space_context(); _tracer = new MetaspaceTracer(); + // We must prevent the very first address of the ccs from being used to store + // metadata, since that address would translate to a narrow pointer of 0, and the + // VM does not distinguish between "narrow 0 as in null" and "narrow 0 as in start + // of ccs". + // Before Elastic Metaspace that did not happen due to the fact that every Metachunk + // had a header and therefore could not allocate anything at offset 0. +#ifdef _LP64 + if (using_class_space()) { + // The simplest way to fix this is to allocate a tiny dummy chunk right at the + // start of ccs and do not use it for anything. + MetaspaceContext::context_class()->cm()->get_chunk(metaspace::chunklevel::HIGHEST_CHUNK_LEVEL); + } +#endif + #ifdef _LP64 if (UseCompressedClassPointers) { // Note: "cds" would be a better fit but keep this for backward compatibility. diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index 1e00571ef60..fc8c0513ca0 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -42,7 +42,6 @@ address CompressedKlassPointers::_klass_range_start = nullptr; address CompressedKlassPointers::_klass_range_end = nullptr; narrowKlass CompressedKlassPointers::_lowest_valid_narrow_klass_id = (narrowKlass)-1; narrowKlass CompressedKlassPointers::_highest_valid_narrow_klass_id = (narrowKlass)-1; -size_t CompressedKlassPointers::_protection_zone_size = 0; #ifdef _LP64 @@ -163,6 +162,11 @@ void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t vm_exit_during_initialization(ss.base()); } + // Note: While it would be technically valid for the encoding base to precede the start of the Klass range, + // we never do this here. This is used at CDS runtime to re-instate the scheme used to precompute the + // narrow Klass IDs in the archive, and the requested base should point to the start of the Klass range. + assert(requested_base == addr, "Invalid requested base"); + // Remember Klass range: _klass_range_start = addr; _klass_range_end = addr + len; @@ -300,32 +304,9 @@ void CompressedKlassPointers::print_mode(outputStream* st) { st->print_cr("Klass Range: " RANGE2FMT, RANGE2FMTARGS(_klass_range_start, _klass_range_end)); st->print_cr("Klass ID Range: [%u - %u) (%u)", _lowest_valid_narrow_klass_id, _highest_valid_narrow_klass_id + 1, _highest_valid_narrow_klass_id + 1 - _lowest_valid_narrow_klass_id); - if (_protection_zone_size > 0) { - st->print_cr("Protection zone: " RANGEFMT, RANGEFMTARGS(_base, _protection_zone_size)); - } else { - st->print_cr("No protection zone."); - } } else { st->print_cr("UseCompressedClassPointers off"); } } -// Protect a zone a the start of the encoding range -void CompressedKlassPointers::establish_protection_zone(address addr, size_t size) { - assert(_protection_zone_size == 0, "just once"); - assert(addr == base(), "Protection zone not at start of encoding range?"); - assert(size > 0 && is_aligned(size, os::vm_page_size()), "Protection zone not page sized"); - const bool rc = os::protect_memory((char*)addr, size, os::MEM_PROT_NONE, false); - assert(rc, "Failed to protect the Class space protection zone"); - log_info(metaspace)("%s Narrow Klass Protection zone " RANGEFMT, - (rc ? "Established" : "FAILED to establish "), - RANGEFMTARGS(addr, size)); - _protection_zone_size = size; -} - -bool CompressedKlassPointers::is_in_protection_zone(address addr) { - return _protection_zone_size > 0 ? - (addr >= base() && addr < base() + _protection_zone_size) : false; -} - #endif // _LP64 diff --git a/src/hotspot/share/oops/compressedKlass.hpp b/src/hotspot/share/oops/compressedKlass.hpp index 4ce644d9cef..dd54c8130eb 100644 --- a/src/hotspot/share/oops/compressedKlass.hpp +++ b/src/hotspot/share/oops/compressedKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -134,8 +134,6 @@ class CompressedKlassPointers : public AllStatic { static narrowKlass _lowest_valid_narrow_klass_id; static narrowKlass _highest_valid_narrow_klass_id; - // Protection zone size (0 if not set up) - static size_t _protection_zone_size; // Helper function for common cases. static char* reserve_address_space_X(uintptr_t from, uintptr_t to, size_t size, size_t alignment, bool aslr); @@ -233,7 +231,6 @@ public: static bool is_null(narrowKlass v) { return v == 0; } // Versions without asserts - static inline Klass* decode_not_null_without_asserts(narrowKlass v); static inline Klass* decode_without_asserts(narrowKlass v); static inline Klass* decode_not_null(narrowKlass v); static inline Klass* decode(narrowKlass v); @@ -261,12 +258,6 @@ public: is_aligned(addr, klass_alignment_in_bytes()); } - // Protect a zone a the start of the encoding range - static void establish_protection_zone(address addr, size_t size); - - // Returns true if address points into protection zone (for error reporting) - static bool is_in_protection_zone(address addr); - #if defined(AARCH64) && !defined(ZERO) // Check that with the given base, shift and range, aarch64 code can encode and decode the klass pointer. static bool check_klass_decode_mode(address base, int shift, const size_t range); diff --git a/src/hotspot/share/oops/compressedKlass.inline.hpp b/src/hotspot/share/oops/compressedKlass.inline.hpp index 94a78ed1894..7c5da48a494 100644 --- a/src/hotspot/share/oops/compressedKlass.inline.hpp +++ b/src/hotspot/share/oops/compressedKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -40,10 +40,6 @@ inline narrowKlass CompressedKlassPointers::encode_not_null_without_asserts(Klas return (narrowKlass)(pointer_delta(k, narrow_base, 1) >> shift); } -inline Klass* CompressedKlassPointers::decode_not_null_without_asserts(narrowKlass v) { - return decode_not_null_without_asserts(v, base(), shift()); -} - inline Klass* CompressedKlassPointers::decode_without_asserts(narrowKlass v) { return is_null(v) ? nullptr : decode_not_null_without_asserts(v, base(), shift()); } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 84fa9d06a1c..dd5a23f9209 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -325,17 +325,6 @@ WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o)) *(vs.low_boundary() - rhs.noaccess_prefix() / 2 )); WB_END -WB_ENTRY(void, WB_DecodeNKlassAndAccessKlass(JNIEnv* env, jobject o, jint nKlass)) - assert(UseCompressedClassPointers, "Should only call for UseCompressedClassPointers"); - const narrowKlass nk = (narrowKlass)nKlass; - const Klass* const k = CompressedKlassPointers::decode_not_null_without_asserts(nKlass); - printf("WB_DecodeNKlassAndAccessKlass: nk %u k " PTR_FORMAT "\n", nk, p2i(k)); - printf("Will attempt to crash now...\n"); - fflush(stdout); // flush now - we will crash below - // Access k by calling a virtual function - will result in loading the vtable from *k - k->print_on(tty); -WB_END - static jint wb_stress_virtual_space_resize(size_t reserved_space_size, size_t magnitude, size_t iterations) { size_t granularity = os::vm_allocation_granularity(); @@ -2744,7 +2733,6 @@ static JNINativeMethod methods[] = { (void*)&WB_GetCompressedOopsMaxHeapSize}, {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes }, {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea}, - {CC"decodeNKlassAndAccessKlass",CC"(I)V", (void*)&WB_DecodeNKlassAndAccessKlass}, {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, #if INCLUDE_CDS {CC"getCDSOffsetForName0", CC"(Ljava/lang/String;)I", (void*)&WB_GetCDSOffsetForName}, diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index efff891c72f..d266b632ed1 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1291,12 +1291,6 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { bool accessible = is_readable_pointer(addr); - // Check if addr points into the narrow Klass protection zone - if (UseCompressedClassPointers && CompressedKlassPointers::is_in_protection_zone(addr)) { - st->print_cr(PTR_FORMAT " points into nKlass protection zone", p2i(addr)); - return; - } - // Check if addr is a JNI handle. if (align_down((intptr_t)addr, sizeof(intptr_t)) != 0 && accessible) { if (JNIHandles::is_global_handle((jobject) addr)) { diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java b/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java deleted file mode 100644 index 2e70c1d8786..00000000000 --- a/test/hotspot/jtreg/runtime/ErrorHandling/AccessZeroNKlassHitsProtectionZone.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2025, Red Hat, Inc. - * 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=no_coh_no_cds - * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @library /test/lib - * @requires vm.bits == 64 & vm.debug == true - * @requires vm.flagless - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver AccessZeroNKlassHitsProtectionZone no_coh_no_cds - */ - -/* - * @test id=no_coh_cds - * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @requires vm.bits == 64 & vm.debug == true & vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver AccessZeroNKlassHitsProtectionZone no_coh_cds - */ - -/* - * @test id=coh_no_cds - * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @requires vm.bits == 64 & vm.debug == true & vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver AccessZeroNKlassHitsProtectionZone coh_no_cds - */ - -/* - * @test id=coh_cds - * @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone - * @requires vm.bits == 64 & vm.debug == true & vm.flagless - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver AccessZeroNKlassHitsProtectionZone coh_cds - */ - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import jdk.test.whitebox.WhiteBox; -import jtreg.SkippedException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.regex.Pattern; - -// Test that dereferencing a Klass that is the result of a narrowKlass=0 will give us immediate crashes -// that hit the protection zone at encoding base. -public class AccessZeroNKlassHitsProtectionZone { - - private static OutputAnalyzer run_test(boolean COH, boolean CDS, String forceBaseString) throws IOException, SkippedException { - ArrayList args = new ArrayList<>(); - args.add("-Xbootclasspath/a:."); - args.add("-XX:+UnlockDiagnosticVMOptions"); - args.add("-XX:+WhiteBoxAPI"); - args.add("-XX:CompressedClassSpaceSize=128m"); - args.add("-Xmx128m"); - args.add("-XX:-CreateCoredumpOnCrash"); - args.add("-Xlog:metaspace*"); - if (COH) { - args.add("-XX:+UnlockExperimentalVMOptions"); - args.add("-XX:+UseCompactObjectHeaders"); - } - if (CDS) { - args.add("-Xshare:on"); - } else { - args.add("-Xshare:off"); - args.add("-XX:CompressedClassSpaceBaseAddress=" + forceBaseString); - } - args.add(AccessZeroNKlassHitsProtectionZone.class.getName()); - args.add("runwb"); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args.toArray(new String[0])); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.reportDiagnosticSummary(); - return output; - } - - private static void run_test(boolean COH, boolean CDS) throws IOException, SkippedException { - // Notes: - // We want to enforce zero-based encoding, to test the protection page in that case. For zero-based encoding, - // protection page is at address zero, no need to test that. - // If CDS is on, we never use zero-based, forceBase is ignored. - // If CDS is off, we use forceBase to (somewhat) reliably force the encoding base to beyond 32G, - // in order to prevent zero-based encoding. Since that may fail, we try several times. - OutputAnalyzer output = null; - long forceBase = -1; - if (CDS) { - output = run_test(COH, CDS, ""); - } else { - long g4 = 0x1_0000_0000L; - long start = g4 * 8; // 32g - long step = g4; - long end = start + step * 16; - for (forceBase = start; forceBase < end; forceBase += step) { - String thisBaseString = String.format("0x%016X", forceBase).toLowerCase(); - output = run_test(COH, CDS, thisBaseString); - if (output.contains("CompressedClassSpaceBaseAddress=" + thisBaseString + " given, but reserving class space failed.")) { - // try next one - } else if (output.contains("Successfully forced class space address to " + thisBaseString)) { - break; - } else { - throw new RuntimeException("Unexpected"); - } - } - if (forceBase >= end) { - throw new SkippedException("Failed to force ccs to any of the given bases. Skipping test."); - } - } - - // Parse the encoding base from the output. In case of CDS, it depends on ASLR. Even in case of CDS=off, we want - // to double-check it is the force address. - String nKlassBaseString = output.firstMatch("Narrow klass base: 0x([0-9a-f]+)", 1); - if (nKlassBaseString == null) { - throw new RuntimeException("did not find Narrow klass base in log output"); - } - long nKlassBase = Long.valueOf(nKlassBaseString, 16); - - if (!CDS && nKlassBase != forceBase) { - throw new RuntimeException("Weird - we should have mapped at force base"); // .. otherwise we would have skipped out above - } - if (nKlassBase == 0) { - throw new RuntimeException("We should not be running zero-based at this point."); - } - - // Calculate the expected crash address pattern. The precise crash address is unknown, but should be located - // in the lower part of the guard page following the encoding base. We just accept any address matching the - // upper 52 digits (leaving 4K = 12 bits = 4 nibbles of wiggle room) - String expectedCrashAddressString = nKlassBaseString.substring(0, nKlassBaseString.length() - 3); - - // output from whitebox function: Klass* should point to encoding base - output.shouldMatch("WB_DecodeNKlassAndAccessKlass: nk 0 k 0x" + nKlassBaseString); - - // Then, we should have crashed - output.shouldNotHaveExitValue(0); - output.shouldContain("# A fatal error has been detected"); - - // The hs-err file should contain a reference to the nKlass protection zone, like this: - // "RDI=0x0000000800000000 points into nKlass protection zone" - File hsErrFile = HsErrFileUtils.openHsErrFileFromOutput(output); - - ArrayList hsErrPatternList = new ArrayList<>(); - hsErrPatternList.add(Pattern.compile(".*(SIGBUS|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*")); - - hsErrPatternList.add(Pattern.compile(".*siginfo:.*" + expectedCrashAddressString + ".*")); - hsErrPatternList.add(Pattern.compile(".*" + expectedCrashAddressString + ".*points into nKlass protection zone.*")); - Pattern[] hsErrPattern = hsErrPatternList.toArray(new Pattern[0]); - HsErrFileUtils.checkHsErrFileContent(hsErrFile, hsErrPattern, true); - } - - enum Argument { runwb, no_coh_no_cds, no_coh_cds, coh_no_cds, coh_cds }; - public static void main(String[] args) throws Exception { - if (args.length != 1) { - throw new RuntimeException("Expecting one argument"); - } - Argument arg = Argument.valueOf(args[0]); - System.out.println(arg); - switch (arg) { - case runwb -> WhiteBox.getWhiteBox().decodeNKlassAndAccessKlass(0); - case no_coh_no_cds -> run_test(false, false); - case no_coh_cds -> run_test(false, true); - case coh_no_cds -> run_test(true, false); - case coh_cds -> run_test(true, true); - } - } -} diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index c45aecbced5..be9bc646ce4 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -642,8 +642,6 @@ public class WhiteBox { // Tests on ReservedSpace/VirtualSpace classes public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); public native void readFromNoaccessArea(); - - public native void decodeNKlassAndAccessKlass(int nKlass); public native long getThreadStackSize(); public native long getThreadRemainingStackSize(); From 9477c705c0bd5ce2d445abb5ca44d46656fc315f Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 26 Feb 2025 16:24:25 +0000 Subject: [PATCH 141/587] 8024695: new File("").exists() returns false whereas it is the current working directory Reviewed-by: alanb, rriggs, lancea --- src/java.base/share/classes/java/io/File.java | 3 +- .../share/classes/java/io/FileSystem.java | 18 +- .../unix/classes/java/io/UnixFileSystem.java | 41 +-- .../classes/java/io/WinNTFileSystem.java | 26 +- test/jdk/java/io/File/EmptyPath.java | 267 ++++++++++++++++-- 5 files changed, 308 insertions(+), 47 deletions(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 7e31379002f..15e687ebf06 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -56,7 +56,8 @@ import jdk.internal.util.StaticProperty; * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name * in an abstract pathname denotes a directory; the last name may denote * either a directory or a file. The empty abstract pathname has no - * prefix and an empty name sequence. + * prefix and an empty name sequence. Accessing a file with the empty abstract + * pathname is equivalent to accessing the current user directory. * *

The conversion of a pathname string to or from an abstract pathname is * inherently system-dependent. When an abstract pathname is converted into a diff --git a/src/java.base/share/classes/java/io/FileSystem.java b/src/java.base/share/classes/java/io/FileSystem.java index db480d931de..3596e0e842a 100644 --- a/src/java.base/share/classes/java/io/FileSystem.java +++ b/src/java.base/share/classes/java/io/FileSystem.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 @@ -33,6 +33,22 @@ import java.lang.annotation.Native; abstract class FileSystem { + /* -- Current Working Directory --*/ + + /* lazy initialization of CWD object */ + private static class CurrentWorkingDirectoryHolder { + static final File CURRENT_WORKING_DIRECTORY = currentWorkingDirectory(); + + private static final File currentWorkingDirectory() { + return new File("."); + } + } + + /* CWD object accessor */ + static File getCWD() { + return CurrentWorkingDirectoryHolder.CURRENT_WORKING_DIRECTORY; + } + /* -- Normalization and construction -- */ /** diff --git a/src/java.base/unix/classes/java/io/UnixFileSystem.java b/src/java.base/unix/classes/java/io/UnixFileSystem.java index ea2ca28fe86..5f9edcd4356 100644 --- a/src/java.base/unix/classes/java/io/UnixFileSystem.java +++ b/src/java.base/unix/classes/java/io/UnixFileSystem.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 @@ -29,11 +29,18 @@ import java.util.Properties; import jdk.internal.util.StaticProperty; final class UnixFileSystem extends FileSystem { - private final char slash; private final char colon; private final String userDir; + private String getPathForSysCalls(String path) { + return path.isEmpty() ? getCWD().getPath() : path; + } + + private File getFileForSysCalls(File file) { + return file.getPath().isEmpty() ? getCWD() : file; + } + UnixFileSystem() { Properties props = System.getProperties(); slash = props.getProperty("file.separator").charAt(0); @@ -154,7 +161,7 @@ final class UnixFileSystem extends FileSystem { @Override public String canonicalize(String path) throws IOException { - return canonicalize0(path); + return canonicalize0(getPathForSysCalls(path)); } private native String canonicalize0(String path) throws IOException; @@ -164,13 +171,13 @@ final class UnixFileSystem extends FileSystem { @Override public int getBooleanAttributes(File f) { - int rv = getBooleanAttributes0(f); + int rv = getBooleanAttributes0(getFileForSysCalls(f)); return rv | isHidden(f); } @Override public boolean hasBooleanAttributes(File f, int attributes) { - int rv = getBooleanAttributes0(f); + int rv = getBooleanAttributes0(getFileForSysCalls(f)); if ((attributes & BA_HIDDEN) != 0) { rv |= isHidden(f); } @@ -183,25 +190,25 @@ final class UnixFileSystem extends FileSystem { @Override public boolean checkAccess(File f, int access) { - return checkAccess0(f, access); + return checkAccess0(getFileForSysCalls(f), access); } private native boolean checkAccess0(File f, int access); @Override public long getLastModifiedTime(File f) { - return getLastModifiedTime0(f); + return getLastModifiedTime0(getFileForSysCalls(f)); } private native long getLastModifiedTime0(File f); @Override public long getLength(File f) { - return getLength0(f); + return getLength0(getFileForSysCalls(f)); } private native long getLength0(File f); @Override public boolean setPermission(File f, int access, boolean enable, boolean owneronly) { - return setPermission0(f, access, enable, owneronly); + return setPermission0(getFileForSysCalls(f), access, enable, owneronly); } private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly); @@ -215,37 +222,37 @@ final class UnixFileSystem extends FileSystem { @Override public boolean delete(File f) { - return delete0(f); + return delete0(getFileForSysCalls(f)); } private native boolean delete0(File f); @Override public String[] list(File f) { - return list0(f); + return list0(getFileForSysCalls(f)); } private native String[] list0(File f); @Override public boolean createDirectory(File f) { - return createDirectory0(f); + return createDirectory0(getFileForSysCalls(f)); } private native boolean createDirectory0(File f); @Override public boolean rename(File f1, File f2) { - return rename0(f1, f2); + return rename0(getFileForSysCalls(f1), getFileForSysCalls(f2)); } private native boolean rename0(File f1, File f2); @Override public boolean setLastModifiedTime(File f, long time) { - return setLastModifiedTime0(f, time); + return setLastModifiedTime0(getFileForSysCalls(f), time); } private native boolean setLastModifiedTime0(File f, long time); @Override public boolean setReadOnly(File f) { - return setReadOnly0(f); + return setReadOnly0(getFileForSysCalls(f)); } private native boolean setReadOnly0(File f); @@ -260,7 +267,7 @@ final class UnixFileSystem extends FileSystem { @Override public long getSpace(File f, int t) { - return getSpace0(f, t); + return getSpace0(getFileForSysCalls(f), t); } private native long getSpace0(File f, int t); @@ -270,7 +277,7 @@ final class UnixFileSystem extends FileSystem { @Override public int getNameMax(String path) { - long nameMax = getNameMax0(path); + long nameMax = getNameMax0(getPathForSysCalls(path)); if (nameMax > Integer.MAX_VALUE) { nameMax = Integer.MAX_VALUE; } diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index dd567be1827..3f383187517 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -79,6 +79,14 @@ final class WinNTFileSystem extends FileSystem { return path; } + private String getPathForWin32Calls(String path) { + return (path != null && path.isEmpty()) ? getCWD().getPath() : path; + } + + private File getFileForWin32Calls(File file) { + return file.getPath().isEmpty() ? getCWD() : file; + } + WinNTFileSystem() { Properties props = System.getProperties(); slash = props.getProperty("file.separator").charAt(0); @@ -495,31 +503,31 @@ final class WinNTFileSystem extends FileSystem { @Override public int getBooleanAttributes(File f) { - return getBooleanAttributes0(f); + return getBooleanAttributes0(getFileForWin32Calls(f)); } private native int getBooleanAttributes0(File f); @Override public boolean checkAccess(File f, int access) { - return checkAccess0(f, access); + return checkAccess0(getFileForWin32Calls(f), access); } private native boolean checkAccess0(File f, int access); @Override public long getLastModifiedTime(File f) { - return getLastModifiedTime0(f); + return getLastModifiedTime0(getFileForWin32Calls(f)); } private native long getLastModifiedTime0(File f); @Override public long getLength(File f) { - return getLength0(f); + return getLength0(getFileForWin32Calls(f)); } private native long getLength0(File f); @Override public boolean setPermission(File f, int access, boolean enable, boolean owneronly) { - return setPermission0(f, access, enable, owneronly); + return setPermission0(getFileForWin32Calls(f), access, enable, owneronly); } private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly); @@ -533,7 +541,7 @@ final class WinNTFileSystem extends FileSystem { @Override public String[] list(File f) { - return list0(f); + return list0(getFileForWin32Calls(f)); } private native String[] list0(File f); @@ -545,7 +553,7 @@ final class WinNTFileSystem extends FileSystem { @Override public boolean setLastModifiedTime(File f, long time) { - return setLastModifiedTime0(f, time); + return setLastModifiedTime0(getFileForWin32Calls(f), time); } private native boolean setLastModifiedTime0(File f, long time); @@ -591,7 +599,7 @@ final class WinNTFileSystem extends FileSystem { // that free space <= total space if (t == SPACE_FREE) t = SPACE_USABLE; - return getSpace0(f, t); + return getSpace0(getFileForWin32Calls(f), t); } return 0; } @@ -618,7 +626,7 @@ final class WinNTFileSystem extends FileSystem { } } } - return getNameMax0(s); + return getNameMax0(getPathForWin32Calls(s)); } @Override diff --git a/test/jdk/java/io/File/EmptyPath.java b/test/jdk/java/io/File/EmptyPath.java index 57da428d760..d3211f917dd 100644 --- a/test/jdk/java/io/File/EmptyPath.java +++ b/test/jdk/java/io/File/EmptyPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 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 @@ -22,28 +22,257 @@ */ /* @test - @bug 4842706 - @summary Test some file operations with empty path + * @bug 4842706 8024695 + * @summary Test some file operations with empty path + * @run junit EmptyPath */ -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.FileStore; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import static org.junit.jupiter.api.Assertions.*; public class EmptyPath { - public static void main(String [] args) throws Exception { - File f = new File(""); - f.mkdir(); - try { - f.createNewFile(); - throw new RuntimeException("Expected exception not thrown"); - } catch (IOException ioe) { - // Correct result - } - try { - FileInputStream fis = new FileInputStream(f); - fis.close(); - throw new RuntimeException("Expected exception not thrown"); - } catch (FileNotFoundException fnfe) { - // Correct result + private static final String EMPTY_STRING = ""; + + static File f; + static Path p; + + @BeforeAll + public static void init() { + f = new File(EMPTY_STRING); + p = Path.of(EMPTY_STRING); + } + + @Test + public void canExecute() { + assertTrue(f.canExecute()); + } + + @Test + public void canRead() { + assertTrue(f.canRead()); + } + + @Test + public void canWrite() { + assertTrue(f.canWrite()); + } + + @Test + public void compareTo() { + assertEquals(0, f.compareTo(p.toFile())); + } + + @Test + public void createNewFile() { + assertThrows(IOException.class, () -> f.createNewFile()); + } + + @Test + public void open() throws FileNotFoundException { + assertThrows(FileNotFoundException.class, + () -> new FileInputStream(f)); + } + + @Test + public void delete() { + assertFalse(f.delete()); + } + + @Test + public void equals() { + assertTrue(f.equals(p.toFile())); + } + + @Test + public void exists() { + assertTrue(f.exists()); + } + + @Test + public void getAbsolutePath() { + System.out.println(p.toAbsolutePath().toString() + "\n" + + f.getAbsolutePath()); + assertEquals(p.toAbsolutePath().toString(), f.getAbsolutePath()); + } + + private void checkSpace(long expected, long actual) { + if (expected == 0) { + assertEquals(0L, actual); + } else { + assertTrue(actual > 0); } } + + @Test + public void getFreeSpace() throws IOException { + FileStore fs = Files.getFileStore(f.toPath()); + checkSpace(fs.getUnallocatedSpace(), f.getFreeSpace()); + } + + @Test + public void getName() { + assertEquals(p.getFileName().toString(), f.getName()); + } + + @Test + public void getParent() { + assertNull(f.getParent()); + } + + @Test + public void getPath() { + assertEquals(p.toString(), f.getPath()); + } + + @Test + public void getTotalSpace() throws IOException { + FileStore fs = Files.getFileStore(f.toPath()); + checkSpace(fs.getTotalSpace(), f.getTotalSpace()); + } + + @Test + public void getUsableSpace() throws IOException { + FileStore fs = Files.getFileStore(f.toPath()); + checkSpace(fs.getUsableSpace(), f.getUsableSpace()); + } + + @Test + public void isNotAbsolute() { + assertFalse(f.isAbsolute()); + } + + @Test + public void isAbsolute() { + assertTrue(f.getAbsoluteFile().isAbsolute()); + } + + @Test + public void isDirectory() { + assertTrue(f.isDirectory()); + } + + @Test + public void isFile() { + assertFalse(f.isFile()); + } + + @Test + public void isHidden() { + assertFalse(f.isHidden()); + } + + @Test + public void lastModified() { + assertTrue(f.lastModified() > 0); + } + + @Test + public void length() throws IOException { + assertEquals(Files.size(f.toPath()), f.length()); + } + + @Test + public void list() throws IOException { + String[] files = f.list(); + assertNotNull(files); + Set ioSet = new HashSet(Arrays.asList(files)); + Set nioSet = new HashSet(); + Files.list(p).forEach((x) -> nioSet.add(x.toString())); + assertEquals(nioSet, ioSet); + } + + @Test + public void mkdir() { + assertFalse(f.mkdir()); + } + + @Test + public void setLastModified() { + long t0 = f.lastModified(); + long t = System.currentTimeMillis(); + try { + assertTrue(f.setLastModified(t)); + assertEquals(t, f.lastModified()); + assertTrue(f.setLastModified(t0)); + assertEquals(t0, f.lastModified()); + } finally { + f.setLastModified(t0); + } + } + + // Note: Testing File.setExecutable is omitted because calling + // File.setExecutable(false) makes it impossible to set the CWD to + // executable again which makes subsequent tests fail + + @Test + @DisabledOnOs({OS.WINDOWS}) + public void setReadable() { + assertTrue(f.canRead()); + try { + assertTrue(f.setReadable(false)); + assertFalse(f.canRead()); + assertTrue(f.setReadable(true)); + assertTrue(f.canRead()); + } finally { + f.setReadable(true); + } + } + + @Test + @DisabledOnOs({OS.WINDOWS}) + public void setReadOnly() { + assertTrue(f.canExecute()); + assertTrue(f.canRead()); + assertTrue(f.canWrite()); + try { + assertTrue(f.setReadOnly()); + assertTrue(f.canRead()); + assertFalse(f.canWrite()); + assertTrue(f.setWritable(true, true)); + assertTrue(f.canWrite()); + } finally { + f.setWritable(true, true); + } + } + + @Test + @DisabledOnOs({OS.WINDOWS}) + public void setWritable() { + assertTrue(f.canWrite()); + try { + assertTrue(f.setWritable(false, true)); + assertFalse(f.canWrite()); + assertTrue(f.setWritable(true, true)); + assertTrue(f.canWrite()); + } finally { + f.setWritable(true, true); + } + } + + @Test + public void toPath() { + assertEquals(p, f.toPath()); + } + + @Test + public void toURI() { + assertEquals(f.toPath().toUri(), f.toURI()); + } } From ec6624b54eaf5c0f94bd760d2e9fa8b55717c350 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 26 Feb 2025 16:41:16 +0000 Subject: [PATCH 142/587] 8350649: Class unloading accesses/resurrects dead Java mirror after JDK-8346567 Reviewed-by: coleenp, egahlin --- .../share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp | 2 +- src/hotspot/share/oops/klass.hpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 8128674dc1e..b9dcd7a3694 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -347,7 +347,7 @@ static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr kla writer->write(cld != nullptr ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); - writer->write(klass->modifier_flags()); + writer->write(klass->compute_modifier_flags()); writer->write(klass->is_hidden()); if (leakp) { assert(IS_LEAKP(klass), "invariant"); diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index e7631f9dfe3..87f85dab956 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -749,9 +749,14 @@ public: virtual void release_C_heap_structures(bool release_constant_pool = true); public: - virtual u2 compute_modifier_flags() const = 0; + // Get modifier flags from Java mirror cache. int modifier_flags() const; + // Compute modifier flags from the original data. This also allows + // accessing flags when Java mirror is already dead, e.g. during class + // unloading. + virtual u2 compute_modifier_flags() const = 0; + // JVMTI support virtual jint jvmti_class_status() const; From 9ec46968fbfddf99a8349cb6903d24b1c2fdaf1d Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 26 Feb 2025 17:29:12 +0000 Subject: [PATCH 143/587] 8350313: Include timings for leaving safepoint in safepoint logging Reviewed-by: shade, dholmes --- src/hotspot/share/runtime/safepoint.cpp | 15 ++++++++++++--- src/hotspot/share/runtime/safepoint.hpp | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index e6f3b84945b..6f86aa09d95 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -468,6 +468,8 @@ void SafepointSynchronize::disarm_safepoint() { // operation has been carried out void SafepointSynchronize::end() { assert(Threads_lock->owned_by_self(), "must hold Threads_lock"); + SafepointTracing::leave(); + EventSafepointEnd event; assert(Thread::current()->is_VM_thread(), "Only VM thread can execute a safepoint"); @@ -862,6 +864,7 @@ void ThreadSafepointState::handle_polling_page_exception() { jlong SafepointTracing::_last_safepoint_begin_time_ns = 0; jlong SafepointTracing::_last_safepoint_sync_time_ns = 0; +jlong SafepointTracing::_last_safepoint_leave_time_ns = 0; jlong SafepointTracing::_last_safepoint_end_time_ns = 0; jlong SafepointTracing::_last_app_time_ns = 0; int SafepointTracing::_nof_threads = 0; @@ -963,6 +966,10 @@ void SafepointTracing::synchronized(int nof_threads, int nof_running, int traps) RuntimeService::record_safepoint_synchronized(_last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns); } +void SafepointTracing::leave() { + _last_safepoint_leave_time_ns = os::javaTimeNanos(); +} + void SafepointTracing::end() { _last_safepoint_end_time_ns = os::javaTimeNanos(); @@ -981,12 +988,14 @@ void SafepointTracing::end() { "Time since last: " JLONG_FORMAT " ns, " "Reaching safepoint: " JLONG_FORMAT " ns, " "At safepoint: " JLONG_FORMAT " ns, " + "Leaving safepoint: " JLONG_FORMAT " ns, " "Total: " JLONG_FORMAT " ns", VM_Operation::name(_current_type), _last_app_time_ns, - _last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns, - _last_safepoint_end_time_ns - _last_safepoint_sync_time_ns, - _last_safepoint_end_time_ns - _last_safepoint_begin_time_ns + _last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns, + _last_safepoint_leave_time_ns - _last_safepoint_sync_time_ns, + _last_safepoint_end_time_ns - _last_safepoint_leave_time_ns, + _last_safepoint_end_time_ns - _last_safepoint_begin_time_ns ); RuntimeService::record_safepoint_end(_last_safepoint_end_time_ns - _last_safepoint_sync_time_ns); diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index 93ede70c6ac..190095ec30b 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -230,6 +230,7 @@ private: // Absolute static jlong _last_safepoint_begin_time_ns; static jlong _last_safepoint_sync_time_ns; + static jlong _last_safepoint_leave_time_ns; static jlong _last_safepoint_end_time_ns; // Relative @@ -251,6 +252,7 @@ public: static void begin(VM_Operation::VMOp_Type type); static void synchronized(int nof_threads, int nof_running, int traps); + static void leave(); static void end(); static void statistics_exit_log(); From e43960a0170bf29b28ff4733e1c8c927947fb0bb Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 26 Feb 2025 20:14:11 +0000 Subject: [PATCH 144/587] 8350616: Skip ValidateHazardPtrsClosure in non-debug builds Reviewed-by: kbarrett, tschatzl, shade --- src/hotspot/share/runtime/threadSMR.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 0a420590fad..bcfd950ee39 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -366,6 +366,7 @@ class ScanHazardPtrPrintMatchingThreadsClosure : public ThreadClosure { } }; +#ifdef ASSERT // Closure to validate hazard ptrs. // class ValidateHazardPtrsClosure : public ThreadClosure { @@ -386,6 +387,7 @@ class ValidateHazardPtrsClosure : public ThreadClosure { p2i(thread)); } }; +#endif // Closure to determine if the specified JavaThread is found by // threads_do(). @@ -950,8 +952,10 @@ void ThreadsSMRSupport::free_list(ThreadsList* threads) { log_debug(thread, smr)("tid=%zu: ThreadsSMRSupport::free_list: threads=" INTPTR_FORMAT " is not freed.", os::current_thread_id(), p2i(threads)); } +#ifdef ASSERT ValidateHazardPtrsClosure validate_cl; threads_do(&validate_cl); +#endif delete scan_table; } From 78c18cfbcee92ba170810582e238b40b64805e5a Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Wed, 26 Feb 2025 23:23:42 +0000 Subject: [PATCH 145/587] 8349399: GHA: Add static-jdk build on linux-x64 Reviewed-by: shade, ihse --- .github/workflows/main.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2339bb390b9..8dce1d214dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -225,6 +225,24 @@ jobs: make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.prepare.outputs.linux-x64-variants == 'true' + build-linux-x64-static: + name: linux-x64-static + needs: prepare + uses: ./.github/workflows/build-linux.yml + with: + platform: linux-x64 + make-target: 'static-jdk-image' + # There are issues with fastdebug static build in GHA due to space limit. + # Only do release build for now. + debug-levels: '[ "release" ]' + gcc-major-version: '10' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + # It currently doesn't produce any bundles, but probably will do in + # the future. + bundle-suffix: "-static" + if: needs.prepare.outputs.linux-x64 == 'true' + build-linux-x64-static-libs: name: linux-x64-static-libs needs: prepare From b29f8b04780bffff2b25acb95f22b4fdf83f3724 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 27 Feb 2025 06:15:59 +0000 Subject: [PATCH 146/587] 8350665: SIZE_FORMAT_HEX macro undefined in gtest Reviewed-by: coleenp, stuefe --- test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index 83ecb39b7ef..2985dd7438d 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -58,9 +58,9 @@ namespace { static void diagnostic_print(ReservedMemoryRegion* rmr) { CommittedRegionIterator iter = rmr->iterate_committed_regions(); - LOG("In reserved region " PTR_FORMAT ", size " SIZE_FORMAT_HEX ":", p2i(rmr->base()), rmr->size()); + LOG("In reserved region " PTR_FORMAT ", size 0x%zx:", p2i(rmr->base()), rmr->size()); for (const CommittedMemoryRegion* region = iter.next(); region != nullptr; region = iter.next()) { - LOG(" committed region: " PTR_FORMAT ", size " SIZE_FORMAT_HEX, p2i(region->base()), region->size()); + LOG(" committed region: " PTR_FORMAT ", size 0x%zx", p2i(region->base()), region->size()); } } From bb48b7319c020f9bb135c0bdf3e8809d0314c837 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 27 Feb 2025 06:16:57 +0000 Subject: [PATCH 147/587] 8350723: RISC-V: debug.cpp help() is missing riscv line for pns Reviewed-by: fyang --- src/hotspot/share/utilities/debug.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 2d57df4ffe6..9413f1f72d7 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -625,6 +625,7 @@ void help() { tty->print_cr(" pns($sp, $fp, $pc) on Linux/AArch64 or"); tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); tty->print_cr(" pns($sp, $s8, $pc) on Linux/mips or"); + tty->print_cr(" pns($sp, $fp, $pc) on Linux/RISC-V"); tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); tty->print_cr(" - in dbx do 'frame 1' before calling pns()"); tty->print_cr("class metadata."); From 885338b5f38ed05d8b91efc0178b371f2f89310e Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 27 Feb 2025 06:58:43 +0000 Subject: [PATCH 148/587] 8323582: C2 SuperWord AlignVector: misaligned vector memory access with unaligned native memory Reviewed-by: roland, kvn --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/opto/c2_globals.hpp | 6 + src/hotspot/share/opto/cfgnode.hpp | 2 +- src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/graphKit.cpp | 1 + src/hotspot/share/opto/ifnode.cpp | 6 +- src/hotspot/share/opto/loopTransform.cpp | 33 +- src/hotspot/share/opto/loopUnswitch.cpp | 369 +++++++++++++++--- src/hotspot/share/opto/loopnode.cpp | 38 +- src/hotspot/share/opto/loopnode.hpp | 41 +- src/hotspot/share/opto/loopopts.cpp | 60 +++ src/hotspot/share/opto/mempointer.hpp | 5 +- src/hotspot/share/opto/node.hpp | 3 + src/hotspot/share/opto/opaquenode.hpp | 23 ++ src/hotspot/share/opto/phasetype.hpp | 11 +- src/hotspot/share/opto/predicates.cpp | 3 + src/hotspot/share/opto/predicates.hpp | 11 +- src/hotspot/share/opto/superword.cpp | 9 +- .../share/opto/traceAutoVectorizationTag.hpp | 39 +- src/hotspot/share/opto/vectorization.cpp | 81 +++- src/hotspot/share/opto/vectorization.hpp | 43 +- src/hotspot/share/opto/vtransform.cpp | 89 +++++ src/hotspot/share/opto/vtransform.hpp | 15 +- src/hotspot/share/runtime/deoptimization.cpp | 1 + src/hotspot/share/runtime/deoptimization.hpp | 1 + src/hotspot/share/runtime/vmStructs.cpp | 1 + .../TestMemorySegmentUnalignedAddress.java | 303 ++++++++++++++ 27 files changed, 1067 insertions(+), 129 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 8c964b56931..93c3449d0ff 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -708,6 +708,7 @@ declare_constant(Deoptimization::Reason_constraint) \ declare_constant(Deoptimization::Reason_div0_check) \ declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_auto_vectorization_check) \ declare_constant(Deoptimization::Reason_type_checked_inlining) \ declare_constant(Deoptimization::Reason_optimized_type_check) \ declare_constant(Deoptimization::Reason_aliasing) \ diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index caa0474c475..05b34bade43 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -346,6 +346,12 @@ develop(bool, TraceLoopUnswitching, false, \ "Trace loop unswitching") \ \ + product(bool, LoopMultiversioning, true, DIAGNOSTIC, \ + "Enable loop multiversioning (for speculative compilation)") \ + \ + develop(bool, TraceLoopMultiversioning, false, \ + "Trace loop multiversioning") \ + \ product(bool, AllowVectorizeOnDemand, true, \ "Globally suppress vectorization set in VectorizeMethod") \ \ diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 899e3c9bb85..c2cc0161df1 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -428,7 +428,7 @@ public: IfNode(Node* control, Node* bol, float p, float fcnt); IfNode(Node* control, Node* bol, float p, float fcnt, AssertionPredicateType assertion_predicate_type); - static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, BoolNode* bol); + static IfNode* make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node* bol); virtual int Opcode() const; virtual bool pinned() const { return true; } diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 918d8156b5f..41b621dfce9 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -277,6 +277,7 @@ macro(OnSpinWait) macro(Opaque1) macro(OpaqueLoopInit) macro(OpaqueLoopStride) +macro(OpaqueMultiversioning) macro(OpaqueZeroTripGuard) macro(OpaqueNotNull) macro(OpaqueInitializedAssertionPredicate) diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 2af70960f54..bb225eeabf5 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4086,6 +4086,7 @@ void GraphKit::add_parse_predicates(int nargs) { if (UseProfiledLoopPredicate) { add_parse_predicate(Deoptimization::Reason_profile_predicate, nargs); } + 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/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 56602135560..5da8993306f 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -469,7 +469,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { return new ConINode(TypeInt::ZERO); } -IfNode* IfNode::make_with_same_profile(IfNode* if_node_profile, Node* ctrl, BoolNode* bol) { +IfNode* IfNode::make_with_same_profile(IfNode* if_node_profile, Node* ctrl, Node* bol) { // Assert here that we only try to create a clone from an If node with the same profiling if that actually makes sense. // Some If node subtypes should not be cloned in this way. In theory, we should not clone BaseCountedLoopEndNodes. // But they can end up being used as normal If nodes when peeling a loop - they serve as zero-trip guard. @@ -2177,6 +2177,7 @@ ParsePredicateNode::ParsePredicateNode(Node* control, Deoptimization::DeoptReaso switch (deopt_reason) { case Deoptimization::Reason_predicate: case Deoptimization::Reason_profile_predicate: + case Deoptimization::Reason_auto_vectorization_check: case Deoptimization::Reason_loop_limit_check: break; default: @@ -2214,6 +2215,9 @@ void ParsePredicateNode::dump_spec(outputStream* st) const { case Deoptimization::DeoptReason::Reason_profile_predicate: st->print("Profiled Loop "); break; + case Deoptimization::DeoptReason::Reason_auto_vectorization_check: + st->print("Auto_Vectorization_Check "); + break; case Deoptimization::DeoptReason::Reason_loop_limit_check: st->print("Loop Limit Check "); break; diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 03a7bf50e70..436d8758df3 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -745,6 +745,11 @@ void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { cl->set_trip_count(cl->trip_count() - 1); if (cl->is_main_loop()) { cl->set_normal_loop(); + if (cl->is_multiversion()) { + // Peeling also destroys the connection of the main loop + // to the multiversion_if. + cl->set_no_multiversion(); + } #ifndef PRODUCT if (PrintOpto && VerifyLoopOptimizations) { tty->print("Peeling a 'main' loop; resetting to 'normal' "); @@ -1174,8 +1179,9 @@ bool IdealLoopTree::policy_range_check(PhaseIdealLoop* phase, bool provisional, if (!bol->is_Bool()) { assert(bol->is_OpaqueNotNull() || bol->is_OpaqueTemplateAssertionPredicate() || - bol->is_OpaqueInitializedAssertionPredicate(), - "Opaque node of a non-null-check or an Assertion Predicate"); + bol->is_OpaqueInitializedAssertionPredicate() || + bol->is_OpaqueMultiversioning(), + "Opaque node of a non-null-check or an Assertion Predicate or Multiversioning"); continue; } if (bol->as_Bool()->_test._test == BoolTest::ne) { @@ -3354,6 +3360,23 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n // Do nothing special to pre- and post- loops if (cl->is_pre_loop() || cl->is_post_loop()) return true; + // With multiversioning, we create a fast_loop and a slow_loop, and a multiversion_if that + // decides which loop is taken at runtime. At first, the multiversion_if always takes the + // fast_loop, and we only optimize the fast_loop. Since we are not sure if we will ever use + // the slow_loop, we delay optimizations for it, so we do not waste compile time and code + // size. If we never change the condition of the multiversion_if, the slow_loop is eventually + // folded away after loop-opts. While optimizing the fast_loop, we may want to perform some + // speculative optimization, for which we need a runtime-check. We add this runtime-check + // condition to the multiversion_if. Now, it becomes possible to execute the slow_loop at + // runtime, and we resume optimizations for slow_loop ("un-delay" it). + // TLDR: If the slow_loop is still in "delay" mode, check if the multiversion_if was changed + // and we should now resume optimizations for it. + if (cl->is_multiversion_delayed_slow_loop() && + !phase->try_resume_optimizations_for_delayed_slow_loop(this)) { + // We are still delayed, so wait with further loop-opts. + return true; + } + // Compute loop trip count from profile data compute_profile_trip_cnt(phase); @@ -3413,6 +3436,12 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n if (!phase->may_require_nodes(estimate)) { return false; } + + // We are going to add pre-loop and post-loop. + // But should we also multi-version for auto-vectorization speculative + // checks, i.e. fast and slow-paths? + phase->maybe_multiversion_for_auto_vectorization_runtime_checks(this, old_new); + phase->insert_pre_post_loops(this, old_new, peel_only); } // Adjust the pre- and main-loop limits to let the pre and post loops run diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 05e24e2271e..051aa59ca71 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -32,6 +32,23 @@ #include "opto/predicates.hpp" #include "opto/rootnode.hpp" +// Multiversioning: +// A loop is cloned, and a selector If decides which loop is taken at run-time: the true-path-loop (original) or the +// false-path-loop (cloned). +// +// Use-cases: +// - Speculative compilation: +// The selector If checks some assumptions which allow stronger optimization in the true-path-loop. If the assumptions +// do not hold, we can still execute in the false-path-loop, although with fewer optimizations. +// See: PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks +// PhaseIdealLoop::create_new_if_for_multiversion +// +// - Unswitching: +// The selector If has the same (loop invariant) condition as some unswitching candidate If inside the loop. This +// allows us to constant-fold the unswitching candidate If to true in the true-path-loop and to false in the +// false-path-loop, thus eliminating the unswitching candidate If from the loop. +// +// // Loop Unswitching is a loop optimization to move an invariant, non-loop-exiting test in the loop body before the loop. // Such a test is either always true or always false in all loop iterations and could therefore only be executed once. // To achieve that, we duplicate the loop and change the original and cloned loop as follows: @@ -145,14 +162,16 @@ IfNode* PhaseIdealLoop::find_unswitch_candidate(const IdealLoopTree* loop) const return unswitch_candidate; } -// This class creates an If node (i.e. loop selector) that selects if the true-path-loop or the false-path-loop should be -// executed at runtime. This is done by finding an invariant and non-loop-exiting unswitch candidate If node (guaranteed -// to exist at this point) to perform Loop Unswitching on. -class UnswitchedLoopSelector : public StackObj { +// LoopSelector is used for loop multiversioning and unswitching. This class creates an If node (i.e. loop selector) +// that selects if the true-path-loop or the false-path-loop should be executed at runtime. +class LoopSelector : public StackObj { + // Cached fields for construction. PhaseIdealLoop* const _phase; IdealLoopTree* const _outer_loop; Node* const _original_loop_entry; - IfNode* const _unswitch_candidate; + const uint _dom_depth; // of original_loop_entry + + // Constructed selector if with its projections. IfNode* const _selector; IfTrueNode* const _true_path_loop_proj; IfFalseNode* const _false_path_loop_proj; @@ -160,52 +179,59 @@ class UnswitchedLoopSelector : public StackObj { enum PathToLoop { TRUE_PATH, FALSE_PATH }; public: - UnswitchedLoopSelector(IdealLoopTree* loop) + // For multiversioning: create a new selector (multiversion_if) from a bol condition. + LoopSelector(IdealLoopTree* loop, Node* bol, float prob, float fcnt) : _phase(loop->_phase), _outer_loop(loop->skip_strip_mined()->_parent), _original_loop_entry(loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl)), - _unswitch_candidate(find_unswitch_candidate(loop)), - _selector(create_selector_if()), + _dom_depth(_phase->dom_depth(_original_loop_entry)), + _selector(create_multiversioning_if(bol, prob, fcnt)), // multiversioning _true_path_loop_proj(create_proj_to_loop(TRUE_PATH)->as_IfTrue()), _false_path_loop_proj(create_proj_to_loop(FALSE_PATH)->as_IfFalse()) { } - NONCOPYABLE(UnswitchedLoopSelector); - private: - IfNode* find_unswitch_candidate(IdealLoopTree* loop) { - IfNode* unswitch_candidate = _phase->find_unswitch_candidate(loop); - assert(unswitch_candidate != nullptr, "guaranteed to exist by policy_unswitching"); - assert(_phase->is_member(loop, unswitch_candidate), "must be inside original loop"); - return unswitch_candidate; + // For unswitching: create an unswitching if before the loop, from a pre-existing + // unswitching_candidate inside the loop. + LoopSelector(IdealLoopTree* loop, IfNode* unswitch_candidate) + : _phase(loop->_phase), + _outer_loop(loop->skip_strip_mined()->_parent), + _original_loop_entry(loop->_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl)), + _dom_depth(_phase->dom_depth(_original_loop_entry)), + _selector(create_unswitching_if(unswitch_candidate)), // unswitching + _true_path_loop_proj(create_proj_to_loop(TRUE_PATH)->as_IfTrue()), + _false_path_loop_proj(create_proj_to_loop(FALSE_PATH)->as_IfFalse()) { } + NONCOPYABLE(LoopSelector); - IfNode* create_selector_if() const { - const uint dom_depth = _phase->dom_depth(_original_loop_entry); + IfNode* create_multiversioning_if(Node* bol, float prob, float fcnt) { _phase->igvn().rehash_node_delayed(_original_loop_entry); - BoolNode* unswitch_candidate_bool = _unswitch_candidate->in(1)->as_Bool(); - IfNode* selector_if = IfNode::make_with_same_profile(_unswitch_candidate, _original_loop_entry, - unswitch_candidate_bool); - _phase->register_node(selector_if, _outer_loop, _original_loop_entry, dom_depth); + IfNode* selector_if = new IfNode(_original_loop_entry, bol, prob, fcnt); + _phase->register_node(selector_if, _outer_loop, _original_loop_entry, _dom_depth); return selector_if; } + IfNode* create_unswitching_if(IfNode* unswitch_candidate) { + _phase->igvn().rehash_node_delayed(_original_loop_entry); + BoolNode* unswitch_candidate_bool = unswitch_candidate->in(1)->as_Bool(); + IfNode* selector_if = IfNode::make_with_same_profile(unswitch_candidate, _original_loop_entry, + unswitch_candidate_bool); + _phase->register_node(selector_if, _outer_loop, _original_loop_entry, _dom_depth); + return selector_if; + } + + private: IfProjNode* create_proj_to_loop(const PathToLoop path_to_loop) { - const uint dom_depth = _phase->dom_depth(_original_loop_entry); IfProjNode* proj_to_loop; if (path_to_loop == TRUE_PATH) { proj_to_loop = new IfTrueNode(_selector); } else { proj_to_loop = new IfFalseNode(_selector); } - _phase->register_node(proj_to_loop, _outer_loop, _selector, dom_depth); + _phase->register_node(proj_to_loop, _outer_loop, _selector, _dom_depth); return proj_to_loop; } public: - IfNode* unswitch_candidate() const { - return _unswitch_candidate; - } - IfNode* selector() const { return _selector; } @@ -219,6 +245,37 @@ class UnswitchedLoopSelector : public StackObj { } }; +// This class creates an If node (i.e. loop selector) that selects if the true-path-loop or the false-path-loop should be +// executed at runtime. This is done by finding an invariant and non-loop-exiting unswitch candidate If node (guaranteed +// to exist at this point) to perform Loop Unswitching on. +class UnswitchedLoopSelector : public StackObj { + IfNode* const _unswitch_candidate; + const LoopSelector _loop_selector; + + public: + UnswitchedLoopSelector(IdealLoopTree* loop) + : _unswitch_candidate(find_unswitch_candidate(loop)), + _loop_selector(loop, _unswitch_candidate) {} + NONCOPYABLE(UnswitchedLoopSelector); + + private: + static IfNode* find_unswitch_candidate(IdealLoopTree* loop) { + IfNode* unswitch_candidate = loop->_phase->find_unswitch_candidate(loop); + assert(unswitch_candidate != nullptr, "guaranteed to exist by policy_unswitching"); + assert(loop->_phase->is_member(loop, unswitch_candidate), "must be inside original loop"); + return unswitch_candidate; + } + + public: + IfNode* unswitch_candidate() const { + return _unswitch_candidate; + } + + const LoopSelector& loop_selector() const { + return _loop_selector; + } +}; + // Class to unswitch the original loop and create Predicates at the new unswitched loop versions. The newly cloned loop // becomes the false-path-loop while original loop becomes the true-path-loop. class OriginalLoop : public StackObj { @@ -238,55 +295,62 @@ class OriginalLoop : public StackObj { // Unswitch the original loop on the invariant loop selector by creating a true-path-loop and a false-path-loop. // Remove the unswitch candidate If from both unswitched loop versions which are now covered by the loop selector If. void unswitch(const UnswitchedLoopSelector& unswitched_loop_selector) { - const uint first_false_path_loop_node_index = _phase->C->unique(); - clone_loop(unswitched_loop_selector); - - move_parse_and_template_assertion_predicates_to_unswitched_loops(unswitched_loop_selector, - first_false_path_loop_node_index); - DEBUG_ONLY(verify_unswitched_loop_versions(_loop->_head->as_Loop(), unswitched_loop_selector);) - - _phase->recompute_dom_depth(); + multiversion(unswitched_loop_selector.loop_selector()); remove_unswitch_candidate_from_loops(unswitched_loop_selector); } - private: - void clone_loop(const UnswitchedLoopSelector& unswitched_loop_selector) { - _phase->clone_loop(_loop, _old_new, _phase->dom_depth(_loop_head), - PhaseIdealLoop::CloneIncludesStripMined, unswitched_loop_selector.selector()); - fix_loop_entries(unswitched_loop_selector); + // Multiversion the original loop. The loop selector if selects between the original loop (true-path-loop), and + // a copy of it (false-path-loop). + void multiversion(const LoopSelector& loop_selector) { + const uint first_false_path_loop_node_index = _phase->C->unique(); + clone_loop(loop_selector); + + move_parse_and_template_assertion_predicates_to_unswitched_loops(loop_selector, + first_false_path_loop_node_index); + DEBUG_ONLY(verify_loop_versions(_loop->_head->as_Loop(), loop_selector);) + + _phase->recompute_dom_depth(); } - void fix_loop_entries(const UnswitchedLoopSelector& unswitched_loop_selector) { - _phase->replace_loop_entry(_loop_head, unswitched_loop_selector.true_path_loop_proj()); + private: + void clone_loop(const LoopSelector& loop_selector) { + _phase->clone_loop(_loop, _old_new, _phase->dom_depth(_loop_head), + PhaseIdealLoop::CloneIncludesStripMined, loop_selector.selector()); + fix_loop_entries(loop_selector); + } + + void fix_loop_entries(const LoopSelector& loop_selector) { + _phase->replace_loop_entry(_loop_head, loop_selector.true_path_loop_proj()); LoopNode* false_path_loop_strip_mined_head = old_to_new(_loop_head)->as_Loop(); _phase->replace_loop_entry(false_path_loop_strip_mined_head, - unswitched_loop_selector.false_path_loop_proj()); + loop_selector.false_path_loop_proj()); } // Moves the Parse And Template Assertion Predicates to the true and false path loop. They are inserted between the // loop heads and the loop selector If projections. The old Parse and Template Assertion Predicates before // the unswitched loop selector are killed. void move_parse_and_template_assertion_predicates_to_unswitched_loops( - const UnswitchedLoopSelector& unswitched_loop_selector, const uint first_false_path_loop_node_index) const { + const LoopSelector& loop_selector, const uint first_false_path_loop_node_index) const { const NodeInOriginalLoopBody node_in_true_path_loop_body(first_false_path_loop_node_index, _old_new); const NodeInClonedLoopBody node_in_false_path_loop_body(first_false_path_loop_node_index); CloneUnswitchedLoopPredicatesVisitor clone_unswitched_loop_predicates_visitor(_loop_head, old_to_new(_loop_head)->as_Loop(), node_in_true_path_loop_body, node_in_false_path_loop_body, _phase); - Node* source_loop_entry = unswitched_loop_selector.selector()->in(0); + Node* source_loop_entry = loop_selector.selector()->in(0); PredicateIterator predicate_iterator(source_loop_entry); predicate_iterator.for_each(clone_unswitched_loop_predicates_visitor); } #ifdef ASSERT - void verify_unswitched_loop_versions(LoopNode* true_path_loop_head, - const UnswitchedLoopSelector& unswitched_loop_selector) const { - verify_unswitched_loop_version(true_path_loop_head, unswitched_loop_selector.true_path_loop_proj()); - verify_unswitched_loop_version(old_to_new(true_path_loop_head)->as_Loop(), - unswitched_loop_selector.false_path_loop_proj()); + void verify_loop_versions(LoopNode* true_path_loop_head, + const LoopSelector& loop_selector) const { + verify_loop_version(true_path_loop_head, + loop_selector.true_path_loop_proj()); + verify_loop_version(old_to_new(true_path_loop_head)->as_Loop(), + loop_selector.false_path_loop_proj()); } - static void verify_unswitched_loop_version(LoopNode* loop_head, IfProjNode* loop_selector_if_proj) { + static void verify_loop_version(LoopNode* loop_head, IfProjNode* loop_selector_if_proj) { Node* entry = loop_head->skip_strip_mined()->in(LoopNode::EntryControl); const Predicates predicates(entry); // When skipping all predicates, we should end up at 'loop_selector_if_proj'. @@ -302,15 +366,15 @@ class OriginalLoop : public StackObj { // If node. Keep the true-path-path in the true-path-loop and the false-path-path in the false-path-loop by setting // the bool input accordingly. The unswitch candidate If nodes are folded in the next IGVN round. void remove_unswitch_candidate_from_loops(const UnswitchedLoopSelector& unswitched_loop_selector) { - IfNode* unswitching_candidate = unswitched_loop_selector.unswitch_candidate(); - _phase->igvn().rehash_node_delayed(unswitching_candidate); - _phase->dominated_by(unswitched_loop_selector.true_path_loop_proj(), unswitching_candidate); + const LoopSelector& loop_selector = unswitched_loop_selector.loop_selector();; + IfNode* unswitch_candidate = unswitched_loop_selector.unswitch_candidate(); + _phase->igvn().rehash_node_delayed(unswitch_candidate); + _phase->dominated_by(loop_selector.true_path_loop_proj(), unswitch_candidate); - IfNode* unswitching_candidate_clone = _old_new[unswitching_candidate->_idx]->as_If(); - _phase->igvn().rehash_node_delayed(unswitching_candidate_clone); - _phase->dominated_by(unswitched_loop_selector.false_path_loop_proj(), unswitching_candidate_clone); + IfNode* unswitch_candidate_clone = _old_new[unswitch_candidate->_idx]->as_If(); + _phase->igvn().rehash_node_delayed(unswitch_candidate_clone); + _phase->dominated_by(loop_selector.false_path_loop_proj(), unswitch_candidate_clone); } - }; // See comments below file header for more information about Loop Unswitching. @@ -343,6 +407,172 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree* loop, Node_List& old_new) { C->set_major_progress(); } +void PhaseIdealLoop::do_multiversioning(IdealLoopTree* lpt, Node_List& old_new) { +#ifndef PRODUCT + if (TraceLoopOpts || TraceLoopMultiversioning) { + tty->print("Multiversion "); + lpt->dump_head(); + } +#endif + assert(LoopMultiversioning, "LoopMultiversioning must be enabled"); + + CountedLoopNode* original_head = lpt->_head->as_CountedLoop(); + C->print_method(PHASE_BEFORE_LOOP_MULTIVERSIONING, 4, original_head); + + Node* one = _igvn.intcon(1); + set_ctrl(one, C->root()); + Node* opaque = new OpaqueMultiversioningNode(C, one); + set_ctrl(opaque, C->root()); + _igvn.register_new_node_with_optimizer(opaque); + _igvn.set_type(opaque, TypeInt::BOOL); + + const LoopSelector loop_selector(lpt, opaque, PROB_LIKELY_MAG(3), COUNT_UNKNOWN); + OriginalLoop original_loop(lpt, old_new); + original_loop.multiversion(loop_selector); + + add_unswitched_loop_version_bodies_to_igvn(lpt, old_new); + + CountedLoopNode* new_head = old_new[original_head->_idx]->as_CountedLoop(); + original_head->set_multiversion_fast_loop(); + new_head->set_multiversion_delayed_slow_loop(); + + NOT_PRODUCT(trace_loop_multiversioning_result(loop_selector, original_head, new_head);) + C->print_method(PHASE_AFTER_LOOP_MULTIVERSIONING, 4, new_head); + C->set_major_progress(); +} + +// Create a new if in the multiversioning pattern, adding an additional condition for the +// multiversioning fast-loop. +// +// Before: +// entry opaque +// | | +// multiversion_if +// | | +// +----------------+ +---------------+ +// | | +// multiversion_fast_proj multiversion_slow_proj +// | +// +--------+ +// | +// slow_path +// +// +// After: +// entry opaque <-- to be replaced by caller +// | | +// new_if +// | | +// | +-----------------------------+ +// | | +// new_if_true opaque new_if_false +// | | | +// multiversion_if | +// | | | +// +----------------+ +---------------+ | +// | | | +// multiversion_fast_proj new_multiversion_slow_proj | +// | | +// +------+ | +// | | +// region +// | +// slow_path +// +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(); + Node* entry = multiversion_if->in(0); + OpaqueMultiversioningNode* opaque = multiversion_if->in(1)->as_OpaqueMultiversioning(); + IfFalseNode* multiversion_slow_proj = multiversion_if->proj_out(0)->as_IfFalse(); + Node* slow_path = multiversion_slow_proj->unique_ctrl_out(); + + // The slow_loop may still be delayed, and waiting for runtime-checks to be added to the + // multiversion_if. Now that we have at least one condition for the multiversioning, + // we should resume optimizations for the slow loop. + opaque->notify_slow_loop_that_it_can_resume_optimizations(); + + // Create new_if with its projections. + IfNode* new_if = IfNode::make_with_same_profile(multiversion_if, entry, opaque); + IdealLoopTree* lp = get_loop(entry); + register_control(new_if, lp, entry); + + IfTrueNode* new_if_true = new IfTrueNode(new_if); + IfFalseNode* new_if_false = new IfFalseNode(new_if); + register_control(new_if_true, lp, new_if); + register_control(new_if_false, lp, new_if); + + // Hook new_if_true into multiversion_if. + _igvn.replace_input_of(multiversion_if, 0, new_if_true); + + // Clone multiversion_slow_path - this allows us to easily carry the dependencies to + // the new region below. + IfFalseNode* new_multiversion_slow_proj = multiversion_slow_proj->clone()->as_IfFalse(); + register_control(new_multiversion_slow_proj, lp, multiversion_if); + + // Create new Region. + RegionNode* region = new RegionNode(1); + region->add_req(new_multiversion_slow_proj); + region->add_req(new_if_false); + register_control(region, lp, new_multiversion_slow_proj); + + // Hook region into slow_path, in stead of the multiversion_slow_proj. + // This also moves all other dependencies of the multiversion_slow_proj to the region. + _igvn.replace_node(multiversion_slow_proj, region); + + return new_if_true; +} + +OpaqueMultiversioningNode* find_multiversion_opaque_from_multiversion_if_false(Node* maybe_multiversion_if_false) { + IfFalseNode* multiversion_if_false = maybe_multiversion_if_false->isa_IfFalse(); + if (multiversion_if_false == nullptr) { return nullptr; } + IfNode* multiversion_if = multiversion_if_false->in(0)->isa_If(); + if (multiversion_if == nullptr) { return nullptr; } + return multiversion_if->in(1)->isa_OpaqueMultiversioning(); +} + +bool PhaseIdealLoop::try_resume_optimizations_for_delayed_slow_loop(IdealLoopTree* lpt) { + CountedLoopNode* cl = lpt->_head->as_CountedLoop(); + assert(cl->is_multiversion_delayed_slow_loop(), "must currently be delayed"); + + // Find multiversion_if. + Node* entry = cl->skip_strip_mined()->in(LoopNode::EntryControl); + const Predicates predicates(entry); + + Node* slow_path = predicates.entry(); + + // Find opaque. + OpaqueMultiversioningNode* opaque = nullptr; + if (slow_path->is_Region()) { + for (uint i = 1; i < slow_path->req(); i++) { + Node* n = slow_path->in(i); + opaque = find_multiversion_opaque_from_multiversion_if_false(n); + if (opaque != nullptr) { break; } + } + } else { + opaque = find_multiversion_opaque_from_multiversion_if_false(slow_path); + } + assert(opaque != nullptr, "must have found multiversion opaque node"); + if (opaque == nullptr) { return false; } + + // We may still be delayed, if there were not yet any runtime-checks added + // for the multiversioning. We may never add any, and then this loop would + // fold away. So we wait until some runtime-checks are added, then we know + // that this loop will be reachable and it is worth optimizing further. + if (opaque->is_delayed_slow_loop()) { return false; } + + // Clear away the "delayed" status, i.e. resume optimizations. + cl->set_no_multiversion(); + cl->set_multiversion_slow_loop(); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Resume Optimizations "); + lpt->dump_head(); + } +#endif + return true; +} + bool PhaseIdealLoop::has_control_dependencies_from_predicates(LoopNode* head) { Node* entry = head->skip_strip_mined()->in(LoopNode::EntryControl); const Predicates predicates(entry); @@ -377,7 +607,7 @@ void PhaseIdealLoop::trace_loop_unswitching_result(const UnswitchedLoopSelector& const LoopNode* original_head, const LoopNode* new_head) { if (TraceLoopUnswitching) { IfNode* unswitch_candidate = unswitched_loop_selector.unswitch_candidate(); - IfNode* loop_selector = unswitched_loop_selector.selector(); + IfNode* loop_selector = unswitched_loop_selector.loop_selector().selector(); tty->print_cr("Loop Unswitching:"); tty->print_cr("- Unswitch-Candidate-If: %d %s", unswitch_candidate->_idx, unswitch_candidate->Name()); tty->print_cr("- Loop-Selector-If: %d %s", loop_selector->_idx, loop_selector->Name()); @@ -385,22 +615,33 @@ void PhaseIdealLoop::trace_loop_unswitching_result(const UnswitchedLoopSelector& tty->print_cr("- False-Path-Loop (=Clone): %d %s", new_head->_idx, new_head->Name()); } } + +void PhaseIdealLoop::trace_loop_multiversioning_result(const LoopSelector& loop_selector, + const LoopNode* original_head, const LoopNode* new_head) { + if (TraceLoopMultiversioning) { + IfNode* selector_if = loop_selector.selector(); + tty->print_cr("Loop Multiversioning:"); + tty->print_cr("- Loop-Selector-If: %d %s", selector_if->_idx, selector_if->Name()); + tty->print_cr("- True-Path-Loop (=Orig / Fast): %d %s", original_head->_idx, original_head->Name()); + tty->print_cr("- False-Path-Loop (=Clone / Slow): %d %s", new_head->_idx, new_head->Name()); + } +} #endif // When unswitching a counted loop, we need to convert it back to a normal loop since it's not a proper pre, main or, -// post loop anymore after loop unswitching. +// post loop anymore after loop unswitching. We also lose the multiversion structure, with access to the multiversion_if. void PhaseIdealLoop::revert_to_normal_loop(const LoopNode* loop_head) { CountedLoopNode* cl = loop_head->isa_CountedLoop(); - if (cl != nullptr && !cl->is_normal_loop()) { - cl->set_normal_loop(); - } + if (cl == nullptr) { return; } + if (!cl->is_normal_loop()) { cl->set_normal_loop(); } + if (cl->is_multiversion()) { cl->set_no_multiversion(); } } // Hoist invariant CheckCastPPNodes out of each unswitched loop version to the appropriate loop selector If projection. void PhaseIdealLoop::hoist_invariant_check_casts(const IdealLoopTree* loop, const Node_List& old_new, const UnswitchedLoopSelector& unswitched_loop_selector) { IfNode* unswitch_candidate = unswitched_loop_selector.unswitch_candidate(); - IfNode* loop_selector = unswitched_loop_selector.selector(); + IfNode* loop_selector = unswitched_loop_selector.loop_selector().selector(); ResourceMark rm; GrowableArray loop_invariant_check_casts; for (DUIterator_Fast imax, i = unswitch_candidate->fast_outs(imax); i < imax; i++) { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index ed2db13421f..a58fa44f9d6 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1090,6 +1090,14 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { if (UseProfiledLoopPredicate) { add_parse_predicate(Deoptimization::Reason_profile_predicate, inner_head, outer_ilt, cloned_sfpt); } + + // 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); } @@ -2511,6 +2519,9 @@ void CountedLoopNode::dump_spec(outputStream *st) const { if (is_main_loop()) st->print("main of N%d", _idx); if (is_post_loop()) st->print("post of N%d", _main_idx); if (is_strip_mined()) st->print(" strip mined"); + if (is_multiversion_fast_loop()) { st->print(" multiversion_fast"); } + if (is_multiversion_slow_loop()) { st->print(" multiversion_slow"); } + if (is_multiversion_delayed_slow_loop()) { st->print(" multiversion_delayed_slow"); } } #endif @@ -4303,6 +4314,9 @@ void IdealLoopTree::dump_head() { if (cl->is_post_loop()) tty->print(" post"); if (cl->is_vectorized_loop()) tty->print(" vector"); if (range_checks_present()) tty->print(" rc "); + if (cl->is_multiversion_fast_loop()) { tty->print(" multiversion_fast"); } + if (cl->is_multiversion_slow_loop()) { tty->print(" multiversion_slow"); } + if (cl->is_multiversion_delayed_slow_loop()) { tty->print(" multiversion_delayed_slow"); } } if (_has_call) tty->print(" has_call"); if (_has_sfpt) tty->print(" has_sfpt"); @@ -4948,18 +4962,6 @@ void PhaseIdealLoop::build_and_optimize() { C->set_major_progress(); } - // Keep loop predicates and perform optimizations with them - // until no more loop optimizations could be done. - // After that switch predicates off and do more loop optimizations. - if (!C->major_progress() && (C->parse_predicate_count() > 0)) { - C->mark_parse_predicate_nodes_useless(_igvn); - assert(C->parse_predicate_count() == 0, "should be zero now"); - if (TraceLoopOpts) { - tty->print_cr("PredicatesOff"); - } - C->set_major_progress(); - } - // Auto-vectorize main-loop if (C->do_superword() && C->has_loops() && !C->major_progress()) { Compile::TracePhase tp(_t_autoVectorize); @@ -4992,6 +4994,18 @@ void PhaseIdealLoop::build_and_optimize() { } } } + + // Keep loop predicates and perform optimizations with them + // until no more loop optimizations could be done. + // After that switch predicates off and do more loop optimizations. + if (!C->major_progress() && (C->parse_predicate_count() > 0)) { + C->mark_parse_predicate_nodes_useless(_igvn); + assert(C->parse_predicate_count() == 0, "should be zero now"); + if (TraceLoopOpts) { + tty->print_cr("PredicatesOff"); + } + C->set_major_progress(); + } } #ifndef PRODUCT diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 4e5a60ee3cd..a9c5d697c6b 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -43,6 +43,7 @@ class OuterStripMinedLoopEndNode; class PredicateBlock; class PathFrequency; class PhaseIdealLoop; +class LoopSelector; class UnswitchedLoopSelector; class VectorSet; class VSharedData; @@ -79,7 +80,12 @@ protected: SubwordLoop = 1<<13, ProfileTripFailed = 1<<14, LoopNestInnerLoop = 1<<15, - LoopNestLongOuterLoop = 1<<16 }; + LoopNestLongOuterLoop = 1<<16, + MultiversionFastLoop = 1<<17, + MultiversionSlowLoop = 2<<17, + MultiversionDelayedSlowLoop = 3<<17, + MultiversionFlagsMask = 3<<17, + }; char _unswitch_count; enum { _unswitch_max=3 }; @@ -315,6 +321,32 @@ public: void set_slp_max_unroll(int unroll_factor) { _slp_maximum_unroll_factor = unroll_factor; } int slp_max_unroll() const { return _slp_maximum_unroll_factor; } + // Multiversioning allows us to duplicate a CountedLoop, and have two versions, and the multiversion_if + // decides which one is taken: + // (1) fast_loop: We enter this loop by default, by default the multiversion_if has its condition set to + // "true", guarded by a OpaqueMultiversioning. If we want to make a speculative assumption + // for an optimization, we can add the runtime-check to the multiversion_if, and if the + // assumption fails we take the slow_loop instead, where we do not make the same speculative + // assumption. + // We call it the "fast_loop" because it has more optimizations, enabled by the speculative + // runtime-checks at the multiversion_if, and we expect the fast_loop to execute faster. + // (2) slow_loop: By default, it is not taken, until a runtime-check is added to the multiversion_if while + // optimizing the fast_looop. If such a runtime-check is never added, then after loop-opts + // the multiversion_if constant folds to true, and the slow_loop is folded away. To save + // compile time, we delay the optimization of the slow_loop until a runtime-check is added + // to the multiversion_if, at which point we resume optimizations for the slow_loop. + // We call it the "slow_loop" because it has fewer optimizations, since this is the fall-back + // loop where we do not make any of the speculative assumptions we make for the fast_loop. + // Hence, we expect the slow_loop to execute slower. + bool is_multiversion() const { return (_loop_flags & MultiversionFlagsMask) != Normal; } + bool is_multiversion_fast_loop() const { return (_loop_flags & MultiversionFlagsMask) == MultiversionFastLoop; } + bool is_multiversion_slow_loop() const { return (_loop_flags & MultiversionFlagsMask) == MultiversionSlowLoop; } + bool is_multiversion_delayed_slow_loop() const { return (_loop_flags & MultiversionFlagsMask) == MultiversionDelayedSlowLoop; } + void set_multiversion_fast_loop() { assert(!is_multiversion(), ""); _loop_flags |= MultiversionFastLoop; } + void set_multiversion_slow_loop() { assert(!is_multiversion(), ""); _loop_flags |= MultiversionSlowLoop; } + void set_multiversion_delayed_slow_loop() { assert(!is_multiversion(), ""); _loop_flags |= MultiversionDelayedSlowLoop; } + void set_no_multiversion() { assert( is_multiversion(), ""); _loop_flags &= ~MultiversionFlagsMask; } + virtual LoopNode* skip_strip_mined(int expect_skeleton = 1); OuterStripMinedLoopNode* outer_loop() const; virtual IfTrueNode* outer_loop_tail() const; @@ -1457,6 +1489,8 @@ public: static void trace_loop_unswitching_impossible(const LoopNode* original_head); static void trace_loop_unswitching_result(const UnswitchedLoopSelector& unswitched_loop_selector, const LoopNode* original_head, const LoopNode* new_head); + static void trace_loop_multiversioning_result(const LoopSelector& loop_selector, + const LoopNode* original_head, const LoopNode* new_head); #endif public: @@ -1483,6 +1517,11 @@ public: }; AutoVectorizeStatus auto_vectorize(IdealLoopTree* lpt, VSharedData &vshared); + void maybe_multiversion_for_auto_vectorization_runtime_checks(IdealLoopTree* lpt, Node_List& old_new); + void do_multiversioning(IdealLoopTree* lpt, Node_List& old_new); + IfTrueNode* create_new_if_for_multiversion(IfTrueNode* multiversioning_fast_proj); + bool try_resume_optimizations_for_delayed_slow_loop(IdealLoopTree* lpt); + // Move an unordered Reduction out of loop if possible void move_unordered_reduction_out_of_loop(IdealLoopTree* loop); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 8afce3e86ae..2d564c3c8cf 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -4482,6 +4482,66 @@ PhaseIdealLoop::auto_vectorize(IdealLoopTree* lpt, VSharedData &vshared) { return AutoVectorizeStatus::Success; } +// Just before insert_pre_post_loops, we can multi-version the loop: +// +// multiversion_if +// | | +// fast_loop slow_loop +// +// In the fast_loop we can make speculative assumptions, and put the +// conditions into the multiversion_if. If the conditions hold at runtime, +// we enter the fast_loop, if the conditions fail, we take the slow_loop +// instead which does not make any of the speculative assumptions. +// +// Note: we only multiversion the loop if the loop does not have any +// auto vectorization check Predicate. If we have that predicate, +// then we can simply add the speculative assumption checks to +// that Predicate. This means we do not need to duplicate the +// loop - we have a smaller graph and save compile time. Should +// the conditions ever fail, then we deopt / trap at the Predicate +// and recompile without that Predicate. At that point we will +// multiversion the loop, so that we can still have speculative +// runtime checks. +// +// We perform the multiversioning when the loop is still in its single +// iteration form, even before we insert pre and post loops. This makes +// the cloning much simpler. However, this means that both the fast +// and the slow loop have to be optimized independently (adding pre +// and post loops, unrolling the main loop, auto-vectorize etc.). And +// we may end up not needing any speculative assumptions in the fast_loop +// and then rejecting the slow_loop by constant folding the multiversion_if. +// +// Therefore, we "delay" the optimization of the slow_loop until we add +// at least one speculative assumption for the fast_loop. If we never +// add such a speculative runtime check, the OpaqueMultiversioningNode +// of the multiversion_if constant folds to true after loop opts, and the +// multiversion_if folds away the "delayed" slow_loop. If we add any +// speculative assumption, then we notify the OpaqueMultiversioningNode +// with "notify_slow_loop_that_it_can_resume_optimizations". +// +// Note: new runtime checks can be added to the multiversion_if with +// PhaseIdealLoop::create_new_if_for_multiversion +void PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks(IdealLoopTree* lpt, Node_List& old_new) { + CountedLoopNode* cl = lpt->_head->as_CountedLoop(); + LoopNode* outer_loop = cl->skip_strip_mined(); + Node* entry = outer_loop->in(LoopNode::EntryControl); + + // Check we have multiversioning enabled, and are not already multiversioned. + if (!LoopMultiversioning || cl->is_multiversion()) { return; } + + // Check that we do not have a parse-predicate where we can add the runtime checks + // during auto-vectorization. + const Predicates predicates(entry); + const PredicateBlock* predicate_block = predicates.auto_vectorization_check_block(); + if (predicate_block->has_parse_predicate()) { return; } + + // Check node budget. + uint estimate = lpt->est_loop_clone_sz(2); + if (!may_require_nodes(estimate)) { return; } + + do_multiversioning(lpt, old_new); +} + // Returns true if the Reduction node is unordered. static bool is_unordered_reduction(Node* n) { return n->is_Reduction() && !n->as_Reduction()->requires_strict_order(); diff --git a/src/hotspot/share/opto/mempointer.hpp b/src/hotspot/share/opto/mempointer.hpp index f1d29f2453f..90216a5e2d3 100644 --- a/src/hotspot/share/opto/mempointer.hpp +++ b/src/hotspot/share/opto/mempointer.hpp @@ -229,9 +229,12 @@ // Even if we could know that there is some base address to which we add index offsets, we cannot know // if this reference address points to the beginning of a native memory allocation or into the middle, // or outside it. We also have no guarantee for alignment with such a base address. +// // Still: we would like to find such a base if possible, and if two pointers are similar (i.e. have the // same summands), we would like to find the same base. Further, it is reasonable to speculatively -// assume that such base addresses are aligned (TODO: need to add this speculative check in JDK-8323582). +// assume that such base addresses are aligned. We performs such a speculative alignment runtime check +// in VTransform::add_speculative_alignment_check. +// // A base pointer must have scale = 1, and be accepted byMemPointer::is_native_memory_base_candidate. // It can thus be one of these: // (1) CastX2P diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 2e52c12e4e8..941b816d8e0 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -139,6 +139,7 @@ class NeverBranchNode; class Opaque1Node; class OpaqueLoopInitNode; class OpaqueLoopStrideNode; +class OpaqueMultiversioningNode; class OpaqueNotNullNode; class OpaqueInitializedAssertionPredicateNode; class OpaqueTemplateAssertionPredicateNode; @@ -800,6 +801,7 @@ public: DEFINE_CLASS_ID(Opaque1, Node, 16) DEFINE_CLASS_ID(OpaqueLoopInit, Opaque1, 0) DEFINE_CLASS_ID(OpaqueLoopStride, Opaque1, 1) + DEFINE_CLASS_ID(OpaqueMultiversioning, Opaque1, 2) DEFINE_CLASS_ID(OpaqueNotNull, Node, 17) DEFINE_CLASS_ID(OpaqueInitializedAssertionPredicate, Node, 18) DEFINE_CLASS_ID(OpaqueTemplateAssertionPredicate, Node, 19) @@ -982,6 +984,7 @@ public: DEFINE_CLASS_QUERY(OpaqueTemplateAssertionPredicate) DEFINE_CLASS_QUERY(OpaqueLoopInit) DEFINE_CLASS_QUERY(OpaqueLoopStride) + DEFINE_CLASS_QUERY(OpaqueMultiversioning) DEFINE_CLASS_QUERY(OuterStripMinedLoop) DEFINE_CLASS_QUERY(OuterStripMinedLoopEnd) DEFINE_CLASS_QUERY(Parm) diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index c1686d846f9..0e8a53efd34 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -91,6 +91,29 @@ public: IfNode* if_node() const; }; +// This node is used to mark the auto vectorization Predicate. +// At first, the multiversion_if has its condition set to "true" and we always +// take the fast_loop. Since we do not know if the slow_loop is ever going to +// be used, we delay optimizations for it. Once the fast_loop decides to use +// speculative runtime-checks and adds them to the multiversion_if, the slow_loop +// can now resume optimizations, as it is reachable at runtime. +// See PhaseIdealLoop::maybe_multiversion_for_auto_vectorization_runtime_checks +class OpaqueMultiversioningNode : public Opaque1Node { +private: + bool _is_delayed_slow_loop; + +public: + OpaqueMultiversioningNode(Compile* C, Node* n) : + Opaque1Node(C, n), _is_delayed_slow_loop(true) + { + init_class_id(Class_OpaqueMultiversioning); + } + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } + bool is_delayed_slow_loop() const { return _is_delayed_slow_loop; } + void notify_slow_loop_that_it_can_resume_optimizations() { _is_delayed_slow_loop = false; } +}; + // This node is used in the context of intrinsics. We sometimes implicitly know that an object is non-null even though // the compiler cannot prove it. We therefore add a corresponding cast to propagate this implicit knowledge. However, // this cast could become top during optimizations (input to cast becomes null) and the data path is folded. To ensure diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index dcdf3aa3f86..8015255c03b 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -64,14 +64,17 @@ flags(AFTER_LOOP_PEELING, "After Loop Peeling") \ flags(BEFORE_LOOP_UNSWITCHING, "Before Loop Unswitching") \ flags(AFTER_LOOP_UNSWITCHING, "After Loop Unswitching") \ + flags(BEFORE_LOOP_MULTIVERSIONING, "Before Loop Multiversioning") \ + flags(AFTER_LOOP_MULTIVERSIONING, "After Loop Multiversioning") \ flags(BEFORE_RANGE_CHECK_ELIMINATION, "Before Range Check Elimination") \ flags(AFTER_RANGE_CHECK_ELIMINATION, "After Range Check Elimination") \ flags(BEFORE_PRE_MAIN_POST, "Before Pre/Main/Post Loops") \ flags(AFTER_PRE_MAIN_POST, "After Pre/Main/Post Loops") \ - flags(AUTO_VECTORIZATION1_BEFORE_APPLY, "AutoVectorization 1, Before Apply") \ - flags(AUTO_VECTORIZATION2_AFTER_REORDER, "AutoVectorization 2, After Apply Memop Reordering") \ - flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 3, After Adjusting Pre-Loop Limit") \ - flags(AUTO_VECTORIZATION4_AFTER_APPLY, "AutoVectorization 4, After Apply") \ + flags(AUTO_VECTORIZATION1_BEFORE_APPLY, "AutoVectorization 1, Before Apply") \ + flags(AUTO_VECTORIZATION2_AFTER_REORDER, "AutoVectorization 2, After Apply Memop Reordering") \ + flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 3, After Adjusting Pre-Loop Limit") \ + flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 4, After Adding Speculative Runtime Checks") \ + flags(AUTO_VECTORIZATION5_AFTER_APPLY, "AutoVectorization 5, After Apply") \ flags(BEFORE_CLOOPS, "Before CountedLoop") \ flags(AFTER_CLOOPS, "After CountedLoop") \ flags(PHASEIDEAL_BEFORE_EA, "PhaseIdealLoop before EA") \ diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 6badaa65487..be4e0067c10 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -120,6 +120,7 @@ bool RuntimePredicate::has_valid_uncommon_trap(const Node* success_proj) { assert(RegularPredicate::may_be_predicate_if(success_proj), "must have been checked before"); const Deoptimization::DeoptReason deopt_reason = uncommon_trap_reason(success_proj->as_IfProj()); return (deopt_reason == Deoptimization::Reason_loop_limit_check || + deopt_reason == Deoptimization::Reason_auto_vectorization_check || deopt_reason == Deoptimization::Reason_predicate || deopt_reason == Deoptimization::Reason_profile_predicate); } @@ -893,6 +894,8 @@ void Predicates::dump() const { tty->print_cr("%d %s:", loop_head->_idx, loop_head->Name()); tty->print_cr("- Loop Limit Check Predicate Block:"); _loop_limit_check_predicate_block.dump(" "); + tty->print_cr("- Auto Vectorization Check Block:"); + _auto_vectorization_check_block.dump(" "); tty->print_cr("- Profiled Loop Predicate Block:"); _profiled_loop_predicate_block.dump(" "); tty->print_cr("- Loop Predicate Block:"); diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index bfc1b23115e..ceb8fe7e317 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -734,6 +734,8 @@ class PredicateIterator : public StackObj { Node* current = _start_node; PredicateBlockIterator loop_limit_check_predicate_iterator(current, Deoptimization::Reason_loop_limit_check); current = loop_limit_check_predicate_iterator.for_each(predicate_visitor); + PredicateBlockIterator auto_vectorization_check_iterator(current, Deoptimization::Reason_auto_vectorization_check); + current = auto_vectorization_check_iterator.for_each(predicate_visitor); if (UseLoopPredicate) { if (UseProfiledLoopPredicate) { PredicateBlockIterator profiled_loop_predicate_iterator(current, Deoptimization::Reason_profile_predicate); @@ -906,6 +908,7 @@ class PredicateBlock : public StackObj { class Predicates : public StackObj { Node* const _tail; const PredicateBlock _loop_limit_check_predicate_block; + const PredicateBlock _auto_vectorization_check_block; const PredicateBlock _profiled_loop_predicate_block; const PredicateBlock _loop_predicate_block; Node* const _entry; @@ -914,7 +917,9 @@ class Predicates : public StackObj { explicit Predicates(Node* loop_entry) : _tail(loop_entry), _loop_limit_check_predicate_block(loop_entry, Deoptimization::Reason_loop_limit_check), - _profiled_loop_predicate_block(_loop_limit_check_predicate_block.entry(), + _auto_vectorization_check_block(_loop_limit_check_predicate_block.entry(), + Deoptimization::Reason_auto_vectorization_check), + _profiled_loop_predicate_block(_auto_vectorization_check_block.entry(), Deoptimization::Reason_profile_predicate), _loop_predicate_block(_profiled_loop_predicate_block.entry(), Deoptimization::Reason_predicate), @@ -935,6 +940,10 @@ class Predicates : public StackObj { return &_profiled_loop_predicate_block; } + const PredicateBlock* auto_vectorization_check_block() const { + return &_auto_vectorization_check_block; + } + const PredicateBlock* loop_limit_check_predicate_block() const { return &_loop_limit_check_predicate_block; } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 31aa1507d23..697e4d842d5 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1484,7 +1484,8 @@ const AlignmentSolution* SuperWord::pack_alignment_solution(const Node_List* pac pack->size(), pre_end->init_trip(), pre_end->stride_con(), - iv_stride() + iv_stride(), + _vloop.are_speculative_checks_possible() DEBUG_ONLY(COMMA is_trace_align_vector())); return solver.solve(); } @@ -1896,6 +1897,7 @@ bool SuperWord::schedule_and_apply() const { VTransformTrace trace(_vloop.vtrace(), is_trace_superword_rejections(), is_trace_align_vector(), + _vloop.is_trace_speculative_runtime_checks(), is_trace_superword_info()); #endif VTransform vtransform(_vloop_analyzer, @@ -1938,8 +1940,11 @@ 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(); + C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, 4, cl()); + apply_vectorization(); - C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_APPLY, 4, cl()); + C->print_method(PHASE_AUTO_VECTORIZATION5_AFTER_APPLY, 4, cl()); } // We prepare the memory graph for the replacement of scalar memops with vector memops. diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 0c08777c90c..0e14964263d 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -29,25 +29,26 @@ #include "utilities/stringUtils.hpp" #define COMPILER_TRACE_AUTO_VECTORIZATION_TAG(flags) \ - flags(POINTER_PARSING, "Trace VPointer/MemPointer parsing") \ - flags(POINTER_ALIASING, "Trace VPointer/MemPointer aliasing") \ - flags(POINTER_ADJACENCY, "Trace VPointer/MemPointer adjacency") \ - flags(POINTER_OVERLAP, "Trace VPointer/MemPointer overlap") \ - flags(PRECONDITIONS, "Trace VLoop::check_preconditions") \ - flags(LOOP_ANALYZER, "Trace VLoopAnalyzer::setup_submodules") \ - flags(MEMORY_SLICES, "Trace VLoopMemorySlices") \ - flags(BODY, "Trace VLoopBody") \ - flags(TYPES, "Trace VLoopTypes") \ - flags(POINTERS, "Trace VLoopPointers") \ - flags(DEPENDENCY_GRAPH, "Trace VLoopDependencyGraph") \ - flags(SW_ADJACENT_MEMOPS, "Trace SuperWord::find_adjacent_memop_pairs") \ - flags(SW_REJECTIONS, "Trace SuperWord rejections (non vectorizations)") \ - flags(SW_PACKSET, "Trace SuperWord packset at different stages") \ - 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(VTRANSFORM, "Trace VTransform Graph") \ - flags(ALL, "Trace everything (very verbose)") + flags(POINTER_PARSING, "Trace VPointer/MemPointer parsing") \ + flags(POINTER_ALIASING, "Trace VPointer/MemPointer aliasing") \ + flags(POINTER_ADJACENCY, "Trace VPointer/MemPointer adjacency") \ + flags(POINTER_OVERLAP, "Trace VPointer/MemPointer overlap") \ + flags(PRECONDITIONS, "Trace VLoop::check_preconditions") \ + flags(LOOP_ANALYZER, "Trace VLoopAnalyzer::setup_submodules") \ + flags(MEMORY_SLICES, "Trace VLoopMemorySlices") \ + flags(BODY, "Trace VLoopBody") \ + flags(TYPES, "Trace VLoopTypes") \ + flags(POINTERS, "Trace VLoopPointers") \ + flags(DEPENDENCY_GRAPH, "Trace VLoopDependencyGraph") \ + flags(SW_ADJACENT_MEMOPS, "Trace SuperWord::find_adjacent_memop_pairs") \ + flags(SW_REJECTIONS, "Trace SuperWord rejections (non vectorizations)") \ + flags(SW_PACKSET, "Trace SuperWord packset at different stages") \ + 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_RUNTIME_CHECKS, "Trace VTransform::apply_speculative_runtime_checks") \ + flags(VTRANSFORM, "Trace VTransform Graph") \ + flags(ALL, "Trace everything (very verbose)") #define table_entry(name, description) name, enum TraceAutoVectorizationTag { diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index ffc2314a59b..e607a1065dd 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -93,9 +93,9 @@ VStatus VLoop::check_preconditions_helper() { return VStatus::make_failure(VLoop::FAILURE_BACKEDGE); } - // To align vector memory accesses in the main-loop, we will have to adjust - // the pre-loop limit. if (_cl->is_main_loop()) { + // To align vector memory accesses in the main-loop, we will have to adjust + // the pre-loop limit. CountedLoopEndNode* pre_end = _cl->find_pre_loop_end(); if (pre_end == nullptr) { return VStatus::make_failure(VLoop::FAILURE_PRE_LOOP_LIMIT); @@ -105,6 +105,41 @@ VStatus VLoop::check_preconditions_helper() { return VStatus::make_failure(VLoop::FAILURE_PRE_LOOP_LIMIT); } _pre_loop_end = pre_end; + + // See if we find the infrastructure for speculative runtime-checks. + // (1) Auto Vectorization Parse Predicate + Node* pre_ctrl = pre_loop_head()->in(LoopNode::EntryControl); + const Predicates predicates(pre_ctrl); + const PredicateBlock* predicate_block = predicates.auto_vectorization_check_block(); + if (predicate_block->has_parse_predicate()) { + _auto_vectorization_parse_predicate_proj = predicate_block->parse_predicate_success_proj(); + } + + // (2) Multiversioning fast-loop projection + IfTrueNode* before_predicates = predicates.entry()->isa_IfTrue(); + if (before_predicates != nullptr && + before_predicates->in(0)->is_If() && + before_predicates->in(0)->in(1)->is_OpaqueMultiversioning()) { + _multiversioning_fast_proj = before_predicates; + } +#ifndef PRODUCT + if (is_trace_preconditions() || is_trace_speculative_runtime_checks()) { + tty->print_cr(" Infrastructure for speculative runtime-checks:"); + if (_auto_vectorization_parse_predicate_proj != nullptr) { + tty->print_cr(" auto_vectorization_parse_predicate_proj: speculate and trap"); + _auto_vectorization_parse_predicate_proj->dump_bfs(5,0,""); + } else if (_multiversioning_fast_proj != nullptr) { + tty->print_cr(" multiversioning_fast_proj: speculate and multiversion"); + _multiversioning_fast_proj->dump_bfs(5,0,""); + } else { + tty->print_cr(" Not found."); + } + } +#endif + assert(_auto_vectorization_parse_predicate_proj == nullptr || + _multiversioning_fast_proj == nullptr, "we should only have at most one of these"); + assert(_cl->is_multiversion_fast_loop() == (_multiversioning_fast_proj != nullptr), + "must find the multiversion selector IFF loop is a multiversion fast loop"); } return VStatus::make_success(); @@ -472,15 +507,28 @@ AlignmentSolution* AlignmentSolver::solve() const { // + con + con + C_const (sum of constant terms) // // We describe the 6 terms: - // 1) The "base" of the address is the address of a Java object (e.g. array), - // and as such ObjectAlignmentInBytes (a power of 2) aligned. We have - // defined aw = MIN(vector_width, ObjectAlignmentInBytes), which is also + // 1) The "base" of the address: + // - For heap objects, this is the base of the object, and as such + // ObjectAlignmentInBytes (a power of 2) aligned. + // - For off-heap / native memory, the "base" has no alignment + // gurantees. To ensure alignment we can do either of these: + // - Add a runtime check to verify ObjectAlignmentInBytes alignment, + // i.e. we can speculatively compile with an alignment assumption. + // If we pass the check, we can go into the loop with the alignment + // assumption, if we fail we have to trap/deopt or take the other + // loop version without alignment assumptions. + // - If runtime checks are not possible, then we return an empty + // solution, i.e. we do not vectorize the corresponding pack. + // + // Let us assume we have an object "base", or passed the alignment + // runtime check for native "bases", hence we know: + // + // base % ObjectAlignmentInBytes = 0 + // + // We defined aw = MIN(vector_width, ObjectAlignmentInBytes), which is // a power of 2. And hence we know that "base" is thus also aw-aligned: // - // base % ObjectAlignmentInBytes = 0 ==> base % aw = 0 - // - // TODO: Note: we have been assuming that this also holds for native memory base - // addresses. This is incorrect, see JDK-8323582. + // base % ObjectAlignmentInBytes = 0 ==> base % aw = 0 (BASE_ALIGNED) // // 2) The "C_const" term is the sum of all constant terms. This is "con", // plus "iv_scale * init" if it is constant. @@ -505,6 +553,13 @@ AlignmentSolution* AlignmentSolver::solve() const { // 6) The "C_main * main_iter" term represents how much the iv is increased // during "main_iter" main-loop iterations. + // For native memory, we must add a runtime-check that "base % ObjectAlignmentInBytes = ", + // to ensure (BASE_ALIGNED). If we cannot add this runtime-check, we have no guarantee on + // its alignment. + if (!_vpointer.mem_pointer().base().is_object() && !_are_speculative_checks_possible) { + return new EmptyAlignmentSolution("Cannot add speculative check for native memory alignment."); + } + // Attribute init (i.e. _init_node) either to C_const or to C_init term. const int C_const_init = _init_node->is_ConI() ? _init_node->as_ConI()->get_int() : 0; const int C_const = _vpointer.con() + C_const_init * iv_scale(); @@ -521,8 +576,7 @@ AlignmentSolution* AlignmentSolver::solve() const { // We must find a pre_iter, such that adr is aw aligned: adr % aw = 0. Note, that we are defining the // modulo operator "%" such that the remainder is always positive, see AlignmentSolution::mod(i, q). // - // TODO: Note: the following assumption is incorrect for native memory bases, see JDK-8323582. - // Since "base % aw = 0", we only need to ensure alignment of the other 5 terms: + // Since "base % aw = 0" (BASE_ALIGNED), we only need to ensure alignment of the other 5 terms: // // (C_const + C_invar * var_invar + C_init * var_init + C_pre * pre_iter + C_main * main_iter) % aw = 0 (1) // @@ -878,8 +932,7 @@ AlignmentSolution* AlignmentSolver::solve() const { // + iv_scale * pre_stride * pre_iter // + iv_scale * main_stride * main_iter)) % aw = // - // -> base aligned: base % aw = 0 - // TODO: Note: this assumption is incorrect for native memory bases, see JDK-8323582. + // -> apply (BASE_ALIGNED): base % aw = 0 // -> main-loop iterations aligned (2): C_main % aw = (iv_scale * main_stride) % aw = 0 // (con + invar + iv_scale * init + iv_scale * pre_stride * pre_iter) % aw = // @@ -958,7 +1011,7 @@ void AlignmentSolver::trace_start_solve() const { _pre_stride, _main_stride); // adr = base + con + invar + iv_scale * iv tty->print(" adr = base[%d]", base().object_or_native()->_idx); - tty->print(" + invar + iv_scale(%d) * iv + con(%d)", iv_scale(), _vpointer.con()); + tty->print_cr(" + invar + iv_scale(%d) * iv + con(%d)", iv_scale(), _vpointer.con()); } } diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index cb1e8c45856..620eac25c9b 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -85,6 +85,14 @@ private: PhiNode* _iv; CountedLoopEndNode* _pre_loop_end; // cache access to pre-loop for main loops only + // We can add speculative runtime-checks if we have one of these: + // - Auto Vectorization Parse Predicate: + // pass all checks or trap -> recompile without this predicate. + // - Multiversioning fast-loop projection: + // pass all checks or go to slow-path-loop, where we have no speculative assumptions. + ParsePredicateSuccessProj* _auto_vectorization_parse_predicate_proj; + IfTrueNode* _multiversioning_fast_proj; + NOT_PRODUCT(VTrace _vtrace;) NOT_PRODUCT(TraceMemPointer _mptrace;) @@ -104,7 +112,9 @@ public: _cl (nullptr), _cl_exit (nullptr), _iv (nullptr), - _pre_loop_end (nullptr) + _pre_loop_end (nullptr), + _auto_vectorization_parse_predicate_proj(nullptr), + _multiversioning_fast_proj(nullptr) #ifndef PRODUCT COMMA _mptrace(TraceMemPointer( @@ -138,6 +148,19 @@ public: return head; }; + ParsePredicateSuccessProj* auto_vectorization_parse_predicate_proj() const { + return _auto_vectorization_parse_predicate_proj; + } + + IfTrueNode* multiversioning_fast_proj() const { + return _multiversioning_fast_proj; + } + + bool are_speculative_checks_possible() const { + return _auto_vectorization_parse_predicate_proj != nullptr || + _multiversioning_fast_proj != nullptr; + } + // 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()); }; @@ -176,6 +199,10 @@ public: bool is_trace_vpointers() const { return _vtrace.is_trace(TraceAutoVectorizationTag::POINTERS); } + + bool is_trace_speculative_runtime_checks() const { + return _vtrace.is_trace(TraceAutoVectorizationTag::SPECULATIVE_RUNTIME_CHECKS); + } #endif // Is the node in the basic block of the loop? @@ -1296,6 +1323,14 @@ private: const int _pre_stride; // address increment per pre-loop iteration const int _main_stride; // address increment per main-loop iteration + // For native bases, we have no alignment guarantee. This means we cannot in + // general guarantee alignment statically. But we can check alignment with a + // speculative runtime check, see VTransform::apply_speculative_runtime_checks. + // For this, we need find the Predicate for auto vectorization checks, or else + // we need to find the multiversion_if. If we cannot find either, then we + // cannot make any speculative runtime checks. + const bool _are_speculative_checks_possible; + DEBUG_ONLY( const bool _is_trace; ); static const MemNode* mem_ref_not_null(const MemNode* mem_ref) { @@ -1309,7 +1344,8 @@ public: const uint vector_length, const Node* init_node, const int pre_stride, - const int main_stride + const int main_stride, + const bool are_speculative_checks_possible DEBUG_ONLY( COMMA const bool is_trace) ) : _vpointer( vpointer), @@ -1318,7 +1354,8 @@ public: _aw( MIN2(_vector_width, ObjectAlignmentInBytes)), _init_node( init_node), _pre_stride( pre_stride), - _main_stride( main_stride) + _main_stride( main_stride), + _are_speculative_checks_possible(are_speculative_checks_possible) DEBUG_ONLY( COMMA _is_trace(is_trace) ) { assert(_mem_ref != nullptr && diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 4730f3ac134..18b5c09acb8 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -23,6 +23,7 @@ #include "opto/vtransform.hpp" #include "opto/vectornode.hpp" +#include "opto/castnode.hpp" #include "opto/convertnode.hpp" void VTransformGraph::add_vtnode(VTransformNode* vtnode) { @@ -143,6 +144,94 @@ void VTransformApplyResult::trace(VTransformNode* vtnode) const { } #endif +void VTransform::apply_speculative_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"); + } +#endif + + const GrowableArray& vtnodes = _graph.vtnodes(); + for (int i = 0; i < vtnodes.length(); i++) { + VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + if (vtn == nullptr) { continue; } + MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); + if (p0 == nullptr) { continue; } + const VPointer& vp = vpointer(p0); + if (vp.mem_pointer().base().is_object()) { continue; } + assert(vp.mem_pointer().base().is_native(), "VPointer base must be object or native"); + + // We have a native memory reference. Build a runtime check for it. + // See: AlignmentSolver::solve + // In a future RFE we may be able to speculate on invar alignment as + // well, and allow vectorization of more cases. + add_speculative_alignment_check(vp.mem_pointer().base().native(), ObjectAlignmentInBytes); + } + } +} + +#define TRACE_SPECULATIVE_ALIGNMENT_CHECK(node) { \ + DEBUG_ONLY( \ + if (_trace._align_vector || _trace._speculative_runtime_checks) { \ + tty->print(" " #node ": "); \ + node->dump(); \ + } \ + ) \ +} \ + +// Check: (node % alignment) == 0. +void VTransform::add_speculative_alignment_check(Node* node, juint alignment) { + TRACE_SPECULATIVE_ALIGNMENT_CHECK(node); + Node* ctrl = phase()->get_ctrl(node); + + // Cast adr/long -> int + if (node->bottom_type()->basic_type() == T_ADDRESS) { + // adr -> int/long + node = new CastP2XNode(nullptr, node); + phase()->register_new_node(node, ctrl); + TRACE_SPECULATIVE_ALIGNMENT_CHECK(node); + } + if (node->bottom_type()->basic_type() == T_LONG) { + // long -> int + node = new ConvL2INode(node); + phase()->register_new_node(node, ctrl); + TRACE_SPECULATIVE_ALIGNMENT_CHECK(node); + } + + Node* mask_alignment = igvn().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* 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); + phase()->register_new_node(bol_alignment, ctrl); + TRACE_SPECULATIVE_ALIGNMENT_CHECK(cmp_alignment); + TRACE_SPECULATIVE_ALIGNMENT_CHECK(bol_alignment); + + add_speculative_check(bol_alignment); +} + +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(); + IfTrueNode* new_check_proj = nullptr; + if (parse_predicate_proj != nullptr) { + new_check_proj = phase()->create_new_if_for_predicate(parse_predicate_proj, nullptr, + Deoptimization::Reason_auto_vectorization_check, + Op_If); + } else { + new_check_proj = phase()->create_new_if_for_multiversion(_vloop.multiversioning_fast_proj()); + } + Node* iff_speculate = new_check_proj->in(0); + igvn().replace_input_of(iff_speculate, 1, bol); + TRACE_SPECULATIVE_ALIGNMENT_CHECK(iff_speculate); +} + // Helper-class for VTransformGraph::has_store_to_load_forwarding_failure. // It wraps a VPointer. The VPointer has an iv_offset applied, which // simulates a virtual unrolling. They represent the memory region: diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 4fc68c7b4df..308578ecb57 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -109,16 +109,19 @@ public: const bool _verbose; const bool _rejections; const bool _align_vector; + 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_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), - _info (_verbose | is_trace_vtransform(vtrace) | 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) {} static bool is_trace_vtransform(const VTrace& vtrace) { return vtrace.is_trace(TraceAutoVectorizationTag::VTRANSFORM); @@ -245,6 +248,10 @@ 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 add_speculative_alignment_check(Node* node, juint alignment); + void add_speculative_check(BoolNode* bol); + void apply_vectorization() const; }; diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 2945e98bd2b..4a51e2cbd92 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -2717,6 +2717,7 @@ const char* Deoptimization::_trap_reason_name[] = { "intrinsic" JVMCI_ONLY("_or_type_checked_inlining"), "bimorphic" JVMCI_ONLY("_or_optimized_type_check"), "profile_predicate", + "auto_vectorization_check", "unloaded", "uninitialized", "initialized", diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index 0a2bafb3830..42cf25e5162 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.hpp @@ -98,6 +98,7 @@ class Deoptimization : AllStatic { #endif Reason_profile_predicate, // compiler generated predicate moved from frequent branch in a loop failed + Reason_auto_vectorization_check, // compiler generated (speculative) auto vectorization checks failed // recorded per method Reason_unloaded, // unloaded class or constant pool entry diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 1c776f7b8e2..c9d93930d63 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -2269,6 +2269,7 @@ declare_constant(Deoptimization::Reason_age) \ declare_constant(Deoptimization::Reason_predicate) \ declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_auto_vectorization_check) \ declare_constant(Deoptimization::Reason_speculate_class_check) \ declare_constant(Deoptimization::Reason_speculate_null_check) \ declare_constant(Deoptimization::Reason_speculate_null_assert) \ diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java new file mode 100644 index 00000000000..13fd9ff9b17 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java @@ -0,0 +1,303 @@ +/* + * 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-buffer-direct + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress ByteBufferDirect + */ + +/* + * @test id=byte-buffer-direct-AlignVector + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress ByteBufferDirect AlignVector + */ + +/* + * @test id=byte-buffer-direct-VerifyAlignVector + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress ByteBufferDirect VerifyAlignVector + */ + +/* + * @test id=native + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress Native + */ + +/* + * @test id=native-AlignVector + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress Native AlignVector + */ + +/* + * @test id=native-VerifyAlignVector + * @bug 8323582 + * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress Native VerifyAlignVector + */ + +public class TestMemorySegmentUnalignedAddress { + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestMemorySegmentUnalignedAddressImpl.class); + framework.addFlags("-DmemorySegmentProviderNameForTestVM=" + args[0]); + if (args.length > 1) { + switch (args[1]) { + case "AlignVector" -> { framework.addFlags("-XX:+AlignVector"); } + case "VerifyAlignVector" -> { framework.addFlags("-XX:+AlignVector", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+VerifyAlignVector"); } + default -> { throw new RuntimeException("unexpected: " + args[1]); } + } + } + framework.setDefaultWarmup(100); + framework.start(); + } +} + +class TestMemorySegmentUnalignedAddressImpl { + static final int SIZE = 10_000; + static final int BACKING_SIZE = 10_000 + 1; + static final Random RANDOM = Utils.getRandomInstance(); + + interface TestFunction { + Object run(int i); + } + + interface MemorySegmentProvider { + MemorySegment newMemorySegment(); + } + + static MemorySegmentProvider provider; + + static { + String providerName = System.getProperty("memorySegmentProviderNameForTestVM"); + provider = switch (providerName) { + case "ByteBufferDirect" -> TestMemorySegmentUnalignedAddressImpl::newMemorySegmentOfByteBufferDirect; + case "Native" -> TestMemorySegmentUnalignedAddressImpl::newMemorySegmentOfNative; + default -> throw new RuntimeException("Test argument not recognized: " + providerName); + }; + } + + // List of tests + Map tests = new HashMap<>(); + + // List of gold, the results from the first run before compilation + Map golds = new HashMap<>(); + + public TestMemorySegmentUnalignedAddressImpl () { + // Generate two MemorySegments as inputs + MemorySegment a = sliceAligned(newMemorySegment()); + MemorySegment b = sliceAligned(newMemorySegment()); + fillRandom(a); + fillRandom(b); + + // Add all tests to list + tests.put("testAlwaysAligned", (int i) -> { + MemorySegment ms = newMemorySegment(); + MemorySegment slice = sliceAligned(ms); + copy(a, slice); + return testAlwaysAligned(slice); + }); + tests.put("testAlwaysUnaligned", (int i) -> { + MemorySegment ms = newMemorySegment(); + MemorySegment slice = sliceUnaligned(ms); + copy(a, slice); + return testAlwaysUnaligned(slice); + }); + tests.put("testMixedAlignedAndUnaligned", (int i) -> { + MemorySegment ms = newMemorySegment(); + MemorySegment slice = (i % 2 == 0) ? sliceUnaligned(ms) : sliceAligned(ms); + copy(a, slice); + return testMixedAlignedAndUnaligned(slice); + }); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + Object gold = test.run(0); + golds.put(name, gold); + } + } + + MemorySegment sliceAligned(MemorySegment src) { + return src.asSlice(0, SIZE); + } + + MemorySegment sliceUnaligned(MemorySegment src) { + return src.asSlice(1, SIZE); + } + + MemorySegment newMemorySegment() { + return provider.newMemorySegment(); + } + + static void copy(MemorySegment src, MemorySegment dst) { + MemorySegment.copy(src, 0, dst, 0, src.byteSize()); + } + + 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 void fillRandom(MemorySegment data) { + for (int i = 0; i < (int)data.byteSize(); i++) { + data.set(ValueLayout.JAVA_BYTE, i, (byte)RANDOM.nextInt()); + } + } + + static void verify(String name, Object gold, Object result) { + try { + Verify.checkEQ(gold, result); + } catch (VerifyException e) { + throw new RuntimeException("Verify: wrong result in " + name, e); + } + } + + static int runInvocationCounter = 0; + + @Run(test = {"testAlwaysAligned", + "testAlwaysUnaligned", + "testMixedAlignedAndUnaligned"}) + void runTests() { + runInvocationCounter++; + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object gold = golds.get(name); + // Compute new result + Object result = test.run(runInvocationCounter); + // Compare gold and new result + verify(name, gold, result); + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0", + "multiversion", "= 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + // We never fail the alignment check in the auto vectorization Predicate, + // hence we never even create the multiversioned loops. + static Object testAlwaysAligned(MemorySegment ms) { + for (long i = 0; i < ms.byteSize(); i += 4) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, i); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, i, (int)(v + 1)); + } + return new Object[]{ ms }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0", + "multiversion_fast", "= 4", // pre, main, drain, post + "multiversion_slow", "= 2"}, // main, post + applyIf = {"AlignVector", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + // We add alignment checks to the auto vectorization Predicate. It fails + // at runtime, deopts, and recompiles with multiversioning. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0", + "multiversion_fast", "= 0", + "multiversion_slow", "= 0"}, + applyIf = {"AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + // We never add any conditions to the auto vectorization Predicate, so + // we also never deopt and never end up multiversioning. + static Object testAlwaysUnaligned(MemorySegment ms) { + for (long i = 0; i < ms.byteSize(); i += 4) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, i); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, i, (int)(v + 1)); + } + return new Object[]{ ms }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0", + "multiversion_fast", "= 4", // pre, main, drain, post + "multiversion_slow", "= 2"}, // main, post + applyIf = {"AlignVector", "true"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + // We add alignment checks to the auto vectorization Predicate. It fails + // at runtime, deopts, and recompiles with multiversioning. + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.ADD_VI, "> 0", + IRNode.STORE_VECTOR, "> 0", + "multiversion_fast", "= 0", + "multiversion_slow", "= 0"}, + applyIf = {"AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + // We never add any conditions to the auto vectorization Predicate, so + // we also never deopt and never end up multiversioning. + static Object testMixedAlignedAndUnaligned(MemorySegment ms) { + for (long i = 0; i < ms.byteSize(); i += 4) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, i); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, i, (int)(v + 1)); + } + return new Object[]{ ms }; + } +} From e4d3c97c0f388fc4b1684b78844f2166277ffd91 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Thu, 27 Feb 2025 09:24:15 +0000 Subject: [PATCH 149/587] 8350111: [PPC] AsyncGetCallTrace crashes when called while handling SIGTRAP Reviewed-by: mdoerr, stuefe --- src/hotspot/cpu/ppc/frame_ppc.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 38c26e5e497..6b6a792117d 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 2012, 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 @@ -195,6 +195,15 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } + if (sender_pc() == nullptr) { + // Likely the return pc was not yet stored to stack. We rather discard this + // sample also because we would hit an assertion in frame::setup(). We can + // find any other random value if the return pc was not yet stored to + // stack. We rely on consistency checks to handle this (see + // e.g. find_initial_Java_frame()) + return false; + } + return true; } From 4522f128a3953e3ae885f96c463cb581eaa1e1e7 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 27 Feb 2025 09:31:14 +0000 Subject: [PATCH 150/587] 8349921: Crash in codeBuffer.cpp:1004: guarantee(sect->end() <= tend) failed: sanity Reviewed-by: kvn, dlong --- src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index 1830bdf4a88..3b5d0640ea4 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -44,7 +44,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 30000 ZGC_ONLY(+10000)) \ + do_arch_blob(compiler, 35000 ZGC_ONLY(+5000)) \ do_stub(compiler, vector_iota_indices) \ do_arch_entry(aarch64, compiler, vector_iota_indices, \ vector_iota_indices, vector_iota_indices) \ @@ -109,7 +109,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(final, 20000 ZGC_ONLY(+100000)) \ + do_arch_blob(final, 20000 ZGC_ONLY(+60000)) \ do_stub(final, copy_byte_f) \ do_arch_entry(aarch64, final, copy_byte_f, copy_byte_f, \ copy_byte_f) \ From 01bd7e417ee3d39067370e616660b7f5c723dc26 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Thu, 27 Feb 2025 09:49:29 +0000 Subject: [PATCH 151/587] 8350314: Shenandoah: Capture thread state sync times in GC timings Reviewed-by: ysr, shade, wkemper --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 20 +++++++++++++++++++ .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 4 ++++ .../share/gc/shenandoah/shenandoahFullGC.cpp | 5 +++++ .../share/gc/shenandoah/shenandoahOldGC.cpp | 5 +++++ .../gc/shenandoah/shenandoahPhaseTimings.hpp | 6 ++++++ .../gc/shenandoah/shenandoahVMOperations.cpp | 7 ------- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index beff760cdfe..5327c9d230e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -688,6 +688,11 @@ void ShenandoahConcurrentGC::op_init_mark() { if (ShenandoahPacing) { heap->pacer()->setup_for_mark(); } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::init_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } void ShenandoahConcurrentGC::op_mark_roots() { @@ -755,6 +760,11 @@ void ShenandoahConcurrentGC::op_final_mark() { } } } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } bool ShenandoahConcurrentGC::has_in_place_promotions(ShenandoahHeap* heap) { @@ -1158,6 +1168,11 @@ void ShenandoahConcurrentGC::op_final_update_refs() { } heap->rebuild_free_set(true /*concurrent*/); + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_update_refs_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } void ShenandoahConcurrentGC::op_final_roots() { @@ -1182,6 +1197,11 @@ void ShenandoahConcurrentGC::op_final_roots() { if (VerifyAfterGC) { Universe::verify(); } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } void ShenandoahConcurrentGC::op_cleanup_complete() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 17af519392e..95981969d06 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -83,6 +83,10 @@ void ShenandoahDegenGC::entry_degenerated() { heap->set_degenerated_gc_in_progress(true); op_degenerated(); heap->set_degenerated_gc_in_progress(false); + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::degen_gc_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } void ShenandoahDegenGC::op_degenerated() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 5f8543ca751..474838c3bb3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -130,6 +130,11 @@ void ShenandoahFullGC::op_full(GCCause::Cause cause) { // Regardless if progress was made, we record that we completed a "successful" full GC. heap->global_generation()->heuristics()->record_success_full(); heap->shenandoah_policy()->record_success_full(); + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::full_gc_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp index 708d27db165..2f5abf99200 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGC.cpp @@ -78,6 +78,11 @@ void ShenandoahOldGC::op_final_mark() { if (VerifyAfterGC) { Universe::verify(); } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index 7a8fed9f548..eab1e279b0f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -57,6 +57,7 @@ class outputStream; f(init_swap_rset, " Swap Remembered Set") \ f(init_transfer_satb, " Transfer Old From SATB") \ f(init_update_region_states, " Update Region States") \ + f(init_propagate_gc_state, " Propagate GC State") \ \ f(init_scan_rset, "Concurrent Scan Remembered Set") \ SHENANDOAH_PAR_PHASE_DO(init_scan_rset_, " RS: ", f) \ @@ -70,6 +71,7 @@ class outputStream; f(final_mark_gross, "Pause Final Mark (G)") \ f(final_mark, "Pause Final Mark (N)") \ f(finish_mark, " Finish Mark") \ + f(final_mark_propagate_gc_state, " Propagate GC State") \ SHENANDOAH_PAR_PHASE_DO(finish_mark_, " FM: ", f) \ f(purge, " System Purge") \ SHENANDOAH_PAR_PHASE_DO(purge_cu_par_, " CU: ", f) \ @@ -107,6 +109,7 @@ class outputStream; f(promote_in_place, "Concurrent Promote Regions") \ f(final_roots_gross, "Pause Final Roots (G)") \ f(final_roots, "Pause Final Roots (N)") \ + f(final_roots_propagate_gc_state, " Propagate GC State") \ \ f(init_update_refs_gross, "Pause Init Update Refs (G)") \ f(init_update_refs, "Pause Init Update Refs (N)") \ @@ -121,6 +124,7 @@ class outputStream; f(final_update_refs_update_region_states, " Update Region States") \ f(final_update_refs_trash_cset, " Trash Collection Set") \ f(final_update_refs_rebuild_freeset, " Rebuild Free Set") \ + f(final_update_refs_propagate_gc_state, " Propagate GC State") \ \ f(conc_cleanup_complete, "Concurrent Cleanup") \ f(conc_coalesce_and_fill, "Concurrent Coalesce and Fill") \ @@ -157,6 +161,7 @@ class outputStream; f(degen_gc_promote_regions, " Degen Promote Regions") \ f(degen_gc_coalesce_and_fill, " Degen Coalesce and Fill") \ SHENANDOAH_PAR_PHASE_DO(degen_coalesce_, " DC&F", f) \ + f(degen_gc_propagate_gc_state, " Propagate GC State") \ \ f(full_gc_gross, "Pause Full GC (G)") \ f(full_gc, "Pause Full GC (N)") \ @@ -188,6 +193,7 @@ class outputStream; f(full_gc_copy_objects_rebuild, " Rebuild Region Sets") \ f(full_gc_reconstruct_remembered_set, " Reconstruct Remembered Set") \ f(full_gc_heapdump_post, " Post Heap Dump") \ + f(full_gc_propagate_gc_state, " Propagate GC State") \ \ f(pacing, "Pacing") \ \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 30a677fc126..bb9c3498a06 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -81,47 +81,40 @@ void VM_ShenandoahInitMark::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Mark", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_init_mark(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahFinalMarkStartEvac::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Mark", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_final_mark(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahFullGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Full GC", SvcGCMarker::FULL); set_active_generation(); _full_gc->entry_full(_gc_cause); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahDegeneratedGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Degenerated GC", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_degenerated(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahInitUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Update Refs", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_init_update_refs(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahFinalUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Update Refs", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_final_update_refs(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } void VM_ShenandoahFinalRoots::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT); set_active_generation(); _gc->entry_final_roots(); - ShenandoahHeap::heap()->propagate_gc_state_to_all_threads(); } From acc6f19cecd1c55afab3f4d6789cfa90b472d621 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 27 Feb 2025 11:06:50 +0000 Subject: [PATCH 152/587] 8350614: [JMH] jdk.incubator.vector.VectorCommutativeOperSharingBenchmark fails Reviewed-by: redestad --- .../incubator/vector/VectorCommutativeOperSharingBenchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java index 91851efa4f3..cbb32ceb213 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorCommutativeOperSharingBenchmark.java @@ -32,7 +32,7 @@ import org.openjdk.jmh.annotations.*; @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) -@Fork(jvmArgsPrepend = {"--add-modules=jdk.incubator.vector"}) +@Fork(jvmArgs = {"--add-modules=jdk.incubator.vector"}) public class VectorCommutativeOperSharingBenchmark { @Param({"1024","2048"}) int size; From 63e0fc4331df5443f21a402153ceda87d99dbd46 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 27 Feb 2025 11:29:02 +0000 Subject: [PATCH 153/587] 8350841: ProblemList jdk/incubator/vector/Long256VectorTests.java Reviewed-by: thartmann --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 7472e4adad2..6f111ddcbfd 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -749,6 +749,7 @@ sun/tools/jstat/jstatLineCounts4.sh 8248691,8268211 jdk/incubator/vector/ShortMaxVectorTests.java 8306592 generic-i586 jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows-x64 +jdk/incubator/vector/Long256VectorTests.java 8350840 generic-x64 ############################################################################ From 799ac5288efbbb89e21319cd45657c8f817ad680 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Thu, 27 Feb 2025 12:58:35 +0000 Subject: [PATCH 154/587] 8314840: 3 gc/epsilon tests ignore external vm options Reviewed-by: tschatzl --- test/hotspot/jtreg/gc/epsilon/TestDieDefault.java | 6 +++--- test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java | 6 +++--- test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java index 016bb517c3c..8c393ceb178 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 2025, Red Hat, 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 @@ -37,13 +37,13 @@ import jdk.test.lib.process.ProcessTools; public class TestDieDefault { public static void passWith(String... args) throws Exception { - OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); + OutputAnalyzer out = ProcessTools.executeTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.shouldHaveExitValue(0); } public static void failWith(String... args) throws Exception { - OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); + OutputAnalyzer out = ProcessTools.executeTestJava(args); out.shouldContain("OutOfMemoryError"); if (out.getExitValue() == 0) { throw new IllegalStateException("Should have failed with non-zero exit code"); diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java index 8f6e9a36d77..e9f94f47f0c 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithHeapDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 2025, Red Hat, 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 @@ -38,13 +38,13 @@ import jdk.test.lib.process.ProcessTools; public class TestDieWithHeapDump { public static void passWith(String... args) throws Exception { - OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); + OutputAnalyzer out = ProcessTools.executeTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.shouldHaveExitValue(0); } public static void failWith(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(args); Process p = pb.start(); OutputAnalyzer out = new OutputAnalyzer(p); out.shouldContain("OutOfMemoryError"); diff --git a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java index 7be60c59595..9212cac807f 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java +++ b/test/hotspot/jtreg/gc/epsilon/TestDieWithOnError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2017, 2025, Red Hat, 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 @@ -39,14 +39,14 @@ public class TestDieWithOnError { static String ON_ERR_MSG = "Epsilon error handler message"; public static void passWith(String... args) throws Exception { - OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); + OutputAnalyzer out = ProcessTools.executeTestJava(args); out.shouldNotContain("OutOfMemoryError"); out.stdoutShouldNotMatch("^" + ON_ERR_MSG); out.shouldHaveExitValue(0); } public static void failWith(String... args) throws Exception { - OutputAnalyzer out = ProcessTools.executeLimitedTestJava(args); + OutputAnalyzer out = ProcessTools.executeTestJava(args); out.shouldContain("OutOfMemoryError"); if (out.getExitValue() == 0) { throw new IllegalStateException("Should have failed with non-zero exit code"); From e80b76b663c6b82a353665fd68819cc9295ec429 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 27 Feb 2025 12:59:47 +0000 Subject: [PATCH 155/587] 8276995: Bug in jdk.jfr.event.gc.collection.TestSystemGC Reviewed-by: egahlin, dholmes --- test/jdk/jdk/jfr/event/gc/collection/TestSystemGC.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestSystemGC.java b/test/jdk/jdk/jfr/event/gc/collection/TestSystemGC.java index c22670e4528..f36a48686ee 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestSystemGC.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestSystemGC.java @@ -66,12 +66,12 @@ public class TestSystemGC { RecordedEvent event2 = events.get(1); Events.assertFrame(event2, Runtime.class, "gc"); Events.assertEventThread(event2, Thread.currentThread()); - Events.assertField(event1, "invokedConcurrent").isEqual(concurrent); + Events.assertField(event2, "invokedConcurrent").isEqual(concurrent); RecordedEvent event3 = events.get(2); // MemoryMXBean.class is an interface so can't assertFrame on it Events.assertEventThread(event3, Thread.currentThread()); - Events.assertField(event1, "invokedConcurrent").isEqual(concurrent); + Events.assertField(event3, "invokedConcurrent").isEqual(concurrent); } } } From d6d94472c21b1fa4839f548b85908967057c3f07 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 27 Feb 2025 13:34:38 +0000 Subject: [PATCH 156/587] 8350786: Some java/lang jtreg tests miss requires vm.hasJFR Reviewed-by: alanb --- test/jdk/java/lang/Thread/ThreadSleepEvent.java | 3 ++- test/jdk/java/lang/Thread/virtual/JfrEvents.java | 2 +- test/jdk/java/lang/Thread/virtual/MonitorPinnedEvents.java | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/lang/Thread/ThreadSleepEvent.java b/test/jdk/java/lang/Thread/ThreadSleepEvent.java index 7aa2f507ff0..441e79f3a94 100644 --- a/test/jdk/java/lang/Thread/ThreadSleepEvent.java +++ b/test/jdk/java/lang/Thread/ThreadSleepEvent.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,6 +24,7 @@ /** * @test * @summary Test that Thread.sleep emits a JFR jdk.ThreadSleep event + * @requires vm.hasJFR * @modules jdk.jfr * @run junit ThreadSleepEvent */ diff --git a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java index badecba7a54..0b0c2ccc7a0 100644 --- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java +++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java @@ -24,7 +24,7 @@ /** * @test * @summary Basic test for JFR jdk.VirtualThreadXXX events - * @requires vm.continuations + * @requires vm.continuations & vm.hasJFR * @modules jdk.jfr java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm/native --enable-native-access=ALL-UNNAMED JfrEvents diff --git a/test/jdk/java/lang/Thread/virtual/MonitorPinnedEvents.java b/test/jdk/java/lang/Thread/virtual/MonitorPinnedEvents.java index bf63404d79e..23078c4b892 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorPinnedEvents.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorPinnedEvents.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 * @summary Test JFR jdk.VirtualThreadPinned event recorded for contended monitor enter * and Object.wait when pinned - * @requires vm.continuations + * @requires vm.continuations & vm.hasJFR * @modules jdk.jfr jdk.management * @library /test/lib * @run junit/othervm --enable-native-access=ALL-UNNAMED MonitorPinnedEvents From 3c9d64eb07c5bc9006ef05b0ab81bdc318cccc20 Mon Sep 17 00:00:00 2001 From: Kuai Wei Date: Thu, 27 Feb 2025 13:55:59 +0000 Subject: [PATCH 157/587] 8350858: [IR Framework] Some tests failed on Cascade Lake Reviewed-by: chagedorn, epeter --- .../lib/ir_framework/driver/irmatching/parser/VMInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java index d76dea902c2..932bacdc795 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfo.java @@ -42,7 +42,7 @@ public class VMInfo { private final Map keyValueMap; private static final Pattern CPU_SKYLAKE_PATTERN = - Pattern.compile("family 6 model 85 stepping (\\d) "); + Pattern.compile("family 6 model 85 stepping (\\d+) "); public VMInfo(Map map) { this.keyValueMap = map; From 8323ddfe189e8a189176a37746985c2473ebab3b Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 27 Feb 2025 14:52:18 +0000 Subject: [PATCH 158/587] 8346659: SnippetTaglet should report an error if provided ambiguous links Reviewed-by: hannesw, liach --- .../formats/html/taglets/SnippetTaglet.java | 46 +++++------ .../toolkit/resources/doclets.properties | 6 +- .../ReproducibleSnippetTest.java | 78 +++++++++++++++++++ .../doclet/TestGlobalHtml/TestGlobalHtml.java | 4 +- 4 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index 93f83c5ba90..37333552e10 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.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 @@ -26,8 +26,6 @@ package jdk.javadoc.internal.doclets.formats.html.taglets; import java.io.IOException; -import java.net.URI; -import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -133,43 +131,39 @@ public class SnippetTaglet extends BaseTaglet { if (lang != null && !lang.isBlank()) { code.addStyle("language-" + lang); } - content.consumeBy((styles, sequence) -> { CharSequence text = Text.normalizeNewlines(sequence); if (styles.isEmpty()) { code.add(text); } else { Element e = null; - String t = null; - boolean linkEncountered = false; + String linkTarget = null; boolean markupEncountered = false; Set classes = new HashSet<>(); for (Style s : styles) { - if (s instanceof Style.Name n) { - classes.add(n.name()); - } else if (s instanceof Style.Link l) { - assert !linkEncountered; // TODO: do not assert; pick the first link report on subsequent - linkEncountered = true; - t = l.target(); - e = getLinkedElement(element, t); - if (e == null) { - // TODO: diagnostic output + switch (s) { + case Style.Name n -> classes.add(n.name()); + case Style.Link l -> { + if (linkTarget != null) { + messages.error(utils.getCommentHelper(element).getDocTreePath(tag), + "doclet.error.snippet.ambiguous.link", + linkTarget, + l.target(), + content.asCharSequence().toString().trim()); + } + linkTarget = l.target(); + e = getLinkedElement(element, linkTarget); + if (e == null) { + // TODO: diagnostic output + } } - } else if (s instanceof Style.Markup) { - markupEncountered = true; - break; - } else { - // TODO: transform this if...else into an exhaustive - // switch over the sealed Style hierarchy when "Pattern - // Matching for switch" has been implemented (JEP 406 - // and friends) - throw new AssertionError(styles); + case Style.Markup m -> markupEncountered = true; } } Content c; if (markupEncountered) { return; - } else if (linkEncountered) { + } else if (linkTarget != null) { assert e != null; //disable preview tagging inside the snippets: Utils.PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false); @@ -177,7 +171,7 @@ public class SnippetTaglet extends BaseTaglet { var lt = (LinkTaglet) config.tagletManager.getTaglet(DocTree.Kind.LINK); c = lt.linkSeeReferenceOutput(element, null, - t, + linkTarget, e, false, // TODO: for now Text.of(sequence.toString()), 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 0ee9429ec0c..6b1cd9b0fc8 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 @@ -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 @@ -432,3 +432,7 @@ doclet.cannot_use_snippet_path=\ # 0: path; 1: exception doclet.error_setting_snippet_path=\ Error setting snippet path {0}: {1} + +# 0: location +doclet.error.snippet.ambiguous.link=\ + snippet link tags: {0} and {1} overlap in {2} diff --git a/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java b/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java new file mode 100644 index 00000000000..5870d1be282 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java @@ -0,0 +1,78 @@ +/* + * 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 8346128 8346659 + * @summary Check that snippet generation is reproducible + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main ReproducibleSnippetTest + */ + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +import java.nio.file.Path; + +public class ReproducibleSnippetTest extends JavadocTester { + ToolBox tb = new ToolBox(); + + public static void main(String... args) throws Exception { + var tester = new ReproducibleSnippetTest(); + tester.runTests(); + } + + @Test + public void test(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package p; + public interface One { + /** + * {@code One obj1} + * {@snippet lang = java: + * // @link substring="ab" target="One#ab" : + * obj1.ab(a()); // @link substring="a" target="#a" + *} class comment + */ + int a(); + void ab(int i); + } + """); + javadoc("-d", + "out", + "-sourcepath", + src.toString(), + "p"); + checkExit(Exit.ERROR); + + checkOutput(Output.OUT, true, + "One.java:5: error: snippet link tags:", + "#a", + "One#ab", + "overlap in obj1.ab(a());\n * {@snippet lang = java:\n ^"); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/TestGlobalHtml/TestGlobalHtml.java b/test/langtools/jdk/javadoc/doclet/TestGlobalHtml/TestGlobalHtml.java index 8d2d8e7dd78..a0dd06a2e4a 100644 --- a/test/langtools/jdk/javadoc/doclet/TestGlobalHtml/TestGlobalHtml.java +++ b/test/langtools/jdk/javadoc/doclet/TestGlobalHtml/TestGlobalHtml.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 @@ -26,7 +26,7 @@ * @bug 8322708 * @summary Test to make sure global tags work properly * @library /tools/lib ../../lib - * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build toolbox.ToolBox javadoc.tester.* * @run main TestGlobalHtml */ From 939815fdcfd046b00b331e085c7b6c5ced0f5dbe Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 27 Feb 2025 16:47:31 +0000 Subject: [PATCH 159/587] 8347040: C2: assert(!loop->_body.contains(in)) failed Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/loopnode.cpp | 4 +- ...tAssertWhenOuterStripMinedLoopRemoved.java | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/longcountedloops/TestAssertWhenOuterStripMinedLoopRemoved.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index a58fa44f9d6..8be412412ea 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -3194,10 +3194,10 @@ void OuterStripMinedLoopNode::transform_to_counted_loop(PhaseIterGVN* igvn, Phas if (iloop->get_loop(iloop->get_ctrl(in)) != outer_loop_ilt) { continue; } - assert(!loop->_body.contains(in), ""); - loop->_body.push(in); wq.push(in); } + assert(!loop->_body.contains(n), "Shouldn't append node to body twice"); + loop->_body.push(n); } iloop->set_loop(safepoint, loop); loop->_body.push(safepoint); diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestAssertWhenOuterStripMinedLoopRemoved.java b/test/hotspot/jtreg/compiler/longcountedloops/TestAssertWhenOuterStripMinedLoopRemoved.java new file mode 100644 index 00000000000..7452a5be616 --- /dev/null +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestAssertWhenOuterStripMinedLoopRemoved.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Red Hat, 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 8347040 + * @summary C2: assert(!loop->_body.contains(in)) failed + * @run main/othervm -XX:-BackgroundCompilation TestAssertWhenOuterStripMinedLoopRemoved + */ + + +import static java.lang.foreign.ValueLayout.JAVA_LONG; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +public class TestAssertWhenOuterStripMinedLoopRemoved { + static final int COUNT = 100000; + static final MemorySegment segment = Arena.global().allocate(JAVA_LONG, COUNT); + + public static void main(String[] args) { + for (int i = 0; i < 10000; i++) { + test(); + } + } + + static void test() { + var i = 0; + var j = 0; + while (i < 100000) { + segment.setAtIndex(JAVA_LONG, i++, 0); + segment.setAtIndex(JAVA_LONG, j++, 0); + } + } +} From 2fd71561107a5226f44e1732b646e43a82566eb3 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 27 Feb 2025 18:06:50 +0000 Subject: [PATCH 160/587] 8347426: Invalid value used for enum Cell in iTypeFlow::StateVector::meet_exception Reviewed-by: dlong, kvn --- src/hotspot/share/ci/ciTypeFlow.cpp | 4 ++-- src/hotspot/share/ci/ciTypeFlow.hpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 3caca6424bc..234b4611ea1 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -500,8 +500,8 @@ bool ciTypeFlow::StateVector::meet_exception(ciInstanceKlass* exc, bool different = false; // Meet locals from incoming array. - Cell limit = local(_outer->max_locals()-1); - for (Cell c = start_cell(); c <= limit; c = next_cell(c)) { + Cell limit = local_limit_cell(); + for (Cell c = start_cell(); c < limit; c = next_cell(c)) { ciType* t1 = type_at(c); ciType* t2 = incoming->type_at(c); if (!t1->equals(t2)) { diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 2e727985307..92db6253aa0 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -213,9 +213,12 @@ public: return (Cell)(outer()->max_locals() + stack_size()); } + Cell local_limit_cell() const { return (Cell) outer()->max_locals(); } + // Cell creation Cell local(int lnum) const { assert(lnum < outer()->max_locals(), "index check"); + assert(Cell_0 <= lnum && lnum <= Cell_max, "out of Cell's range"); return (Cell)(lnum); } From 3ae80bfb6085e1a6bcb551c7b0be8f27b6f9fde9 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Thu, 27 Feb 2025 18:40:20 +0000 Subject: [PATCH 161/587] 8349766: GenShen: Bad progress after degen does not always need full gc Reviewed-by: wkemper --- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 22 ++++++++++++++++--- .../gc/shenandoah/shenandoahDegeneratedGC.hpp | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 95981969d06..4d250a98fe6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -49,7 +49,8 @@ ShenandoahDegenGC::ShenandoahDegenGC(ShenandoahDegenPoint degen_point, Shenandoa ShenandoahGC(), _degen_point(degen_point), _generation(generation), - _abbreviated(false) { + _abbreviated(false), + _consecutive_degen_with_bad_progress(0) { } bool ShenandoahDegenGC::collect(GCCause::Cause cause) { @@ -305,9 +306,24 @@ void ShenandoahDegenGC::op_degenerated() { metrics.snap_after(); - // Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles, - // because that probably means the heap is overloaded and/or fragmented. + // The most common scenario for lack of good progress following a degenerated GC is an accumulation of floating + // garbage during the most recently aborted concurrent GC effort. With generational GC, it is far more effective to + // reclaim this floating garbage with another degenerated cycle (which focuses on young generation and might require + // a pause of 200 ms) rather than a full GC cycle (which may require over 2 seconds with a 10 GB old generation). + // + // In generational mode, we'll only upgrade to full GC if we've done two degen cycles in a row and both indicated + // bad progress. In non-generational mode, we'll preserve the original behavior, which is to upgrade to full + // immediately following a degenerated cycle with bad progress. This preserves original behavior of non-generational + // Shenandoah so as to avoid introducing "surprising new behavior." It also makes less sense with non-generational + // Shenandoah to replace a full GC with a degenerated GC, because both have similar pause times in non-generational + // mode. if (!metrics.is_good_progress(_generation)) { + _consecutive_degen_with_bad_progress++; + } else { + _consecutive_degen_with_bad_progress = 0; + } + if (!heap->mode()->is_generational() || + ((heap->shenandoah_policy()->consecutive_degenerated_gc_count() > 1) && (_consecutive_degen_with_bad_progress >= 2))) { heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc); op_degenerated_futile(); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp index 971bd67eb0d..a2598fe4e8e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.hpp @@ -36,6 +36,7 @@ private: const ShenandoahDegenPoint _degen_point; ShenandoahGeneration* _generation; bool _abbreviated; + size_t _consecutive_degen_with_bad_progress; public: ShenandoahDegenGC(ShenandoahDegenPoint degen_point, ShenandoahGeneration* generation); From f1398ecbe4a650d8d8c21fabb1b8e2e9600fdfec Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 27 Feb 2025 20:35:58 +0000 Subject: [PATCH 162/587] 8350701: [JMH] test foreign.AllocFromSliceTest failed with Exception for size>1024 Reviewed-by: pminborg --- .../openjdk/bench/java/lang/foreign/AllocFromSliceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java index c54aa2e0724..58c17f09997 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java @@ -55,10 +55,10 @@ public class AllocFromSliceTest extends CLayouts { @Setup public void setup() { - arr = new byte[1024]; + arr = new byte[size * 2]; Random random = new Random(0); random.nextBytes(arr); - start = random.nextInt(1024 - size); + start = random.nextInt(size); } @Benchmark From 0a4c5a8a483b23ec8c534054187c44f986d137bb Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Thu, 27 Feb 2025 23:10:16 +0000 Subject: [PATCH 163/587] 8347804: GenShen: Crash with small GCCardSizeInBytes and small Java heap Reviewed-by: wkemper --- .../gc/shenandoah/shenandoahArguments.cpp | 6 +++ .../gc/shenandoah/shenandoahCardTable.hpp | 2 + .../shenandoah/shenandoahScanRemembered.cpp | 33 ++++++++++------ .../shenandoah/shenandoahScanRemembered.hpp | 38 +++++++++++++------ .../gc/shenandoah/compiler/TestClone.java | 26 +++++++++++++ 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index cd1949b19ad..d635781f90f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -29,6 +29,7 @@ #include "gc/shared/tlab_globals.hpp" #include "gc/shared/workerPolicy.hpp" #include "gc/shenandoah/shenandoahArguments.hpp" +#include "gc/shenandoah/shenandoahCardTable.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" @@ -187,6 +188,11 @@ void ShenandoahArguments::initialize() { FLAG_SET_DEFAULT(TLABAllocationWeight, 90); } + if (GCCardSizeInBytes < ShenandoahMinCardSizeInBytes) { + vm_exit_during_initialization( + err_msg("GCCardSizeInBytes ( %u ) must be >= %u\n", GCCardSizeInBytes, (unsigned int) ShenandoahMinCardSizeInBytes)); + } + FullGCForwarding::initialize_flags(MaxHeapSize); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp index f30ce09668a..b012da09c7a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp @@ -30,6 +30,8 @@ #include "oops/oopsHierarchy.hpp" #include "utilities/macros.hpp" +#define ShenandoahMinCardSizeInBytes 128 + class ShenandoahCardTable: public CardTable { friend class VMStructs; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index b9f52909cbe..9bbb76b3e48 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -727,7 +727,6 @@ size_t ShenandoahRegionChunkIterator::calc_regular_group_size() { // half of the remaining heap, the third processes half of what remains and so on. The smallest chunk size // is represented by _smallest_chunk_size_words. We do not divide work any smaller than this. // - size_t group_size = _heap->num_regions() / 2; return group_size; } @@ -773,6 +772,7 @@ size_t ShenandoahRegionChunkIterator::calc_num_groups() { // Any remaining regions will be treated as if they are part of the most recently created group. This group will // have more than _regular_group_size chunks within it. } + assert (num_groups <= _maximum_groups, "Cannot have more than %zu groups", _maximum_groups); return num_groups; } @@ -784,21 +784,31 @@ size_t ShenandoahRegionChunkIterator::calc_total_chunks() { size_t current_group_span = _first_group_chunk_size_b4_rebalance * _regular_group_size; size_t smallest_group_span = smallest_chunk_size_words() * _regular_group_size; - // The first group gets special handling because the first chunk size can be no larger than _largest_chunk_size_words + // The first group gets special handling because the first chunk size can be no larger than _maximum_chunk_size_words if (region_size_words > _maximum_chunk_size_words) { // In the case that we shrink the first group's chunk size, certain other groups will also be subsumed within the first group size_t effective_chunk_size = _first_group_chunk_size_b4_rebalance; + uint coalesced_groups = 0; while (effective_chunk_size >= _maximum_chunk_size_words) { + // Each iteration of this loop subsumes one original group into a new rebalanced initial group. num_chunks += current_group_span / _maximum_chunk_size_words; unspanned_heap_size -= current_group_span; effective_chunk_size /= 2; current_group_span /= 2; + coalesced_groups++; } + assert(effective_chunk_size * 2 == _maximum_chunk_size_words, + "We assume _first_group_chunk_size_b4_rebalance is _maximum_chunk_size_words * a power of two"); + _largest_chunk_size_words = _maximum_chunk_size_words; + _adjusted_num_groups = _num_groups - (coalesced_groups - 1); } else { num_chunks = _regular_group_size; unspanned_heap_size -= current_group_span; + _largest_chunk_size_words = current_group_span / num_chunks; + _adjusted_num_groups = _num_groups; current_group_span /= 2; } + size_t spanned_groups = 1; while (unspanned_heap_size > 0) { if (current_group_span <= unspanned_heap_size) { @@ -856,11 +866,12 @@ ShenandoahRegionChunkIterator::ShenandoahRegionChunkIterator(ShenandoahHeap* hea size_t expected_chunk_size_words = _clusters_in_smallest_chunk * CardTable::card_size_in_words() * ShenandoahCardCluster::CardsPerCluster; assert(smallest_chunk_size_words() == expected_chunk_size_words, "_smallest_chunk_size (%zu) is not valid because it does not equal (%zu)", smallest_chunk_size_words(), expected_chunk_size_words); -#endif assert(_num_groups <= _maximum_groups, "The number of remembered set scanning groups must be less than or equal to maximum groups"); - assert(smallest_chunk_size_words() << (_maximum_groups - 1) == _maximum_chunk_size_words, - "Maximum number of groups needs to span maximum chunk size to smallest chunk size"); + assert(smallest_chunk_size_words() << (_adjusted_num_groups - 1) == _largest_chunk_size_words, + "The number of groups (%zu) needs to span smallest chunk size (%zu) to largest chunk size (%zu)", + _adjusted_num_groups, smallest_chunk_size_words(), _largest_chunk_size_words); +#endif size_t words_in_region = ShenandoahHeapRegion::region_size_words(); _region_index[0] = 0; @@ -883,7 +894,7 @@ ShenandoahRegionChunkIterator::ShenandoahRegionChunkIterator(ShenandoahHeap* hea } size_t previous_group_span = _group_entries[0] * _group_chunk_size[0]; - for (size_t i = 1; i < _num_groups; i++) { + for (size_t i = 1; i < _adjusted_num_groups; i++) { _group_chunk_size[i] = _group_chunk_size[i-1] / 2; size_t chunks_in_group = _regular_group_size; size_t this_group_span = _group_chunk_size[i] * chunks_in_group; @@ -893,19 +904,19 @@ ShenandoahRegionChunkIterator::ShenandoahRegionChunkIterator(ShenandoahHeap* hea _group_entries[i] = _group_entries[i-1] + _regular_group_size; previous_group_span = total_span_of_groups; } - if (_group_entries[_num_groups-1] < _total_chunks) { - assert((_total_chunks - _group_entries[_num_groups-1]) * _group_chunk_size[_num_groups-1] + previous_group_span == + if (_group_entries[_adjusted_num_groups-1] < _total_chunks) { + assert((_total_chunks - _group_entries[_adjusted_num_groups-1]) * _group_chunk_size[_adjusted_num_groups-1] + previous_group_span == heap->num_regions() * words_in_region, "Total region chunks (%zu" ") do not span total heap regions (%zu)", _total_chunks, _heap->num_regions()); - previous_group_span += (_total_chunks - _group_entries[_num_groups-1]) * _group_chunk_size[_num_groups-1]; - _group_entries[_num_groups-1] = _total_chunks; + previous_group_span += (_total_chunks - _group_entries[_adjusted_num_groups-1]) * _group_chunk_size[_adjusted_num_groups-1]; + _group_entries[_adjusted_num_groups-1] = _total_chunks; } assert(previous_group_span == heap->num_regions() * words_in_region, "Total region chunks (%zu" ") do not span total heap regions (%zu): %zu does not equal %zu", _total_chunks, _heap->num_regions(), previous_group_span, heap->num_regions() * words_in_region); // Not necessary, but keeps things tidy - for (size_t i = _num_groups; i < _maximum_groups; i++) { + for (size_t i = _adjusted_num_groups; i < _maximum_groups; i++) { _region_index[i] = 0; _group_offset[i] = 0; _group_entries[i] = _group_entries[i-1]; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 2a0713bf4ed..f5acb4f10ed 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -196,11 +196,14 @@ private: // Use symbolic constants defined in cardTable.hpp // CardTable::card_shift = 9; - // CardTable::card_size = 512; - // CardTable::card_size_in_words = 64; + // CardTable::card_size = 512; (default value 512, a power of 2 >= 128) + // CardTable::card_size_in_words = 64; (default value 64, a power of 2 >= 16) // CardTable::clean_card_val() // CardTable::dirty_card_val() + // See shenandoahCardTable.hpp + // ShenandoahMinCardSizeInBytes 128 + const size_t LogCardValsPerIntPtr; // the number of card values (entries) in an intptr_t const size_t LogCardSizeInWords; // the size of a card in heap word units @@ -888,14 +891,14 @@ private: // The largest chunk size is 4 MiB, measured in words. Otherwise, remembered set scanning may become too unbalanced. // If the largest chunk size is too small, there is too much overhead sifting out assignments to individual worker threads. static const size_t _maximum_chunk_size_words = (4 * 1024 * 1024) / HeapWordSize; - static const size_t _clusters_in_smallest_chunk = 4; + size_t _largest_chunk_size_words; + // smallest_chunk_size is 4 clusters. Each cluster spans 128 KiB. // This is computed from CardTable::card_size_in_words() * ShenandoahCardCluster::CardsPerCluster; static size_t smallest_chunk_size_words() { - return _clusters_in_smallest_chunk * CardTable::card_size_in_words() * - ShenandoahCardCluster::CardsPerCluster; + return _clusters_in_smallest_chunk * CardTable::card_size_in_words() * ShenandoahCardCluster::CardsPerCluster; } // The total remembered set scanning effort is divided into chunks of work that are assigned to individual worker tasks. @@ -910,19 +913,30 @@ private: // The first group "effectively" processes chunks of size 1 MiB (or smaller for smaller region sizes). // The last group processes chunks of size 128 KiB. There are four groups total. - // group[0] is 4 MiB chunk size (_maximum_chunk_size_words) - // group[1] is 2 MiB chunk size - // group[2] is 1 MiB chunk size - // group[3] is 512 KiB chunk size - // group[4] is 256 KiB chunk size - // group[5] is 128 Kib shunk size (_smallest_chunk_size_words = 4 * 64 * 64 - static const size_t _maximum_groups = 6; + // group[ 0] is 4 MiB chunk size (_maximum_chunk_size_words) + // group[ 1] is 2 MiB chunk size + // group[ 2] is 1 MiB chunk size + // group[ 3] is 512 KiB chunk size + // group[ 4] is 256 KiB chunk size + // group[ 5] is 128 KiB chunk size + // group[ 6] is 64 KiB chunk size + // group[ 7] is 32 KiB chunk size + // group[ 8] is 16 KiB chunk size + // group[ 9] is 8 KiB chunk size + // group[10] is 4 KiB chunk size + // Note: 4 KiB is smallest possible chunk_size, computed from: + // _clusters_in_smallest_chunk * MinimumCardSizeInWords * ShenandoahCardCluster::CardsPerCluster, which is + // 4 * 16 * 64 = 4096 + + // We set aside arrays to represent the maximum number of groups that may be required for any heap configuration + static const size_t _maximum_groups = 11; const ShenandoahHeap* _heap; const size_t _regular_group_size; // Number of chunks in each group const size_t _first_group_chunk_size_b4_rebalance; const size_t _num_groups; // Number of groups in this configuration + size_t _adjusted_num_groups; // Rebalancing may coalesce groups const size_t _total_chunks; shenandoah_padding(0); diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java index 2b1340890e1..2e98c72ee17 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestClone.java @@ -232,6 +232,32 @@ * TestClone */ +/* + * @test id=generational-small-card-size + * @summary Test clone barriers work correctly + * @requires vm.gc.Shenandoah + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:GCCardSizeInBytes=128 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:GCCardSizeInBytes=128 + * -Xint + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:GCCardSizeInBytes=128 + * -XX:-TieredCompilation + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:GCCardSizeInBytes=128 + * -XX:TieredStopAtLevel=1 + * TestClone + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xms1g -Xmx1g + * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:GCCardSizeInBytes=128 + * -XX:TieredStopAtLevel=4 + * TestClone + */ + /* * @test id=generational-verify * @summary Test clone barriers work correctly From ab4b0ef9242a4cd964fbcf2d1f3d370234c09408 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Thu, 27 Feb 2025 23:23:40 +0000 Subject: [PATCH 164/587] 8350889: GenShen: Break out of infinite loop of old GC cycles Reviewed-by: wkemper, ysr --- .../gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp | 1 + src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 7a624d4d4a4..5280e9b2ac4 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -241,6 +241,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { ", allocated: %zu", available, capacity, allocated); if (_start_gc_is_pending) { + log_trigger("GC start is already pending"); return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index a684e8ff228..752ad743520 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -74,6 +74,7 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { if (start_old_cycle()) { log_debug(gc)("Heuristics request for old collection accepted"); _young_heuristics->cancel_trigger_request(); + _old_heuristics->cancel_trigger_request(); } else if (request_concurrent_gc(YOUNG)) { log_debug(gc)("Heuristics request for young collection accepted"); _young_heuristics->cancel_trigger_request(); From 2af76de05a50dee052307b8b82055a4787e96df9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 28 Feb 2025 07:36:35 +0000 Subject: [PATCH 165/587] 8350683: Non-C2 / minimal JVM crashes in the build on ppc64 platforms Co-authored-by: Martin Doerr Reviewed-by: mdoerr, amitkumar --- src/hotspot/cpu/ppc/compiledIC_ppc.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp index c8cb68e3eb4..8a29da66436 100644 --- a/src/hotspot/cpu/ppc/compiledIC_ppc.cpp +++ b/src/hotspot/cpu/ppc/compiledIC_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2012, 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 @@ -29,9 +29,6 @@ #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" -#ifdef COMPILER2 -#include "opto/matcher.hpp" -#endif // ---------------------------------------------------------------------------- @@ -78,7 +75,6 @@ const int IC_pos_in_java_to_interp_stub = 8; #define __ masm-> address CompiledDirectCall::emit_to_interp_stub(MacroAssembler *masm, address mark/* = nullptr*/) { -#ifdef COMPILER2 if (mark == nullptr) { // Get the mark within main instrs section which is set to the address of the call. mark = __ inst_mark(); @@ -108,7 +104,7 @@ address CompiledDirectCall::emit_to_interp_stub(MacroAssembler *masm, address ma // - call __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); AddressLiteral ic = __ allocate_metadata_address((Metadata *)nullptr); - bool success = __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), + bool success = __ load_const_from_method_toc(R19_inline_cache_reg, ic, reg_scratch, /*fixed_size*/ true); if (!success) { return nullptr; // CodeCache is full @@ -134,13 +130,9 @@ address CompiledDirectCall::emit_to_interp_stub(MacroAssembler *masm, address ma assert(!is_NativeCallTrampolineStub_at(__ addr_at(stub_start_offset)), "must not confuse java_to_interp with trampoline stubs"); - // End the stub. + // End the stub. __ end_a_stub(); return stub; -#else - ShouldNotReachHere(); - return nullptr; -#endif } #undef __ From eada1ea8d21c4811834e20ca467e136580d6cd0a Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 28 Feb 2025 09:05:42 +0000 Subject: [PATCH 166/587] 8350855: RISC-V: print offset by assert of patch_offset_in_conditional_branch Reviewed-by: fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 4276595ffcc..f2bdd20890b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2300,7 +2300,7 @@ static int patch_offset_in_jal(address branch, int64_t offset) { static int patch_offset_in_conditional_branch(address branch, int64_t offset) { assert(Assembler::is_simm13(offset) && ((offset % 2) == 0), - "offset is too large to be patched in one beq/bge/bgeu/blt/bltu/bne instruction!\n"); + "offset (%ld) is too large to be patched in one beq/bge/bgeu/blt/bltu/bne instruction!\n", offset); Assembler::patch(branch, 31, 31, (offset >> 12) & 0x1); // offset[12] ==> branch[31] Assembler::patch(branch, 30, 25, (offset >> 5) & 0x3f); // offset[10:5] ==> branch[30:25] Assembler::patch(branch, 7, 7, (offset >> 11) & 0x1); // offset[11] ==> branch[7] From ac76d8d63ff7b06a3c116559712a8b48f8acfa20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Fri, 28 Feb 2025 09:48:17 +0000 Subject: [PATCH 167/587] 8350824: New async logging gtest StallingModePreventsDroppedMessages fails Reviewed-by: mbaesken, dholmes --- test/hotspot/gtest/logging/test_asynclog.cpp | 18 ++++-------------- .../jtreg/runtime/logging/StressAsyncUL.java | 13 ++++++++----- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index cb674603563..ebc3e35a4b9 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -253,18 +253,6 @@ TEST_VM_F(AsyncLogTest, droppingMessage) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } -TEST_VM_F(AsyncLogTest, StallingModePreventsDroppedMessages) { - if (AsyncLogWriter::instance() == nullptr) { - return; - } - set_log_config(TestLogFileName, "logging=debug"); - LogConfiguration::AsyncMode prev_mode = LogConfiguration::async_mode(); - LogConfiguration::set_async_mode(LogConfiguration::AsyncMode::Off); - test_asynclog_drop_messages(); - EXPECT_FALSE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); - LogConfiguration::set_async_mode(prev_mode); -} - TEST_VM_F(AsyncLogTest, stdoutOutput) { testing::internal::CaptureStdout(); @@ -272,7 +260,8 @@ TEST_VM_F(AsyncLogTest, stdoutOutput) { return; } - bool async = AsyncLogWriter::instance() != nullptr; + bool async = AsyncLogWriter::instance() != nullptr + && LogConfiguration::async_mode() == LogConfiguration::AsyncMode::Drop; if (async) { test_asynclog_drop_messages(); AsyncLogWriter::flush(); @@ -301,7 +290,8 @@ TEST_VM_F(AsyncLogTest, stderrOutput) { return; } - bool async = AsyncLogWriter::instance() != nullptr; + bool async = AsyncLogWriter::instance() != nullptr + && LogConfiguration::async_mode() == LogConfiguration::AsyncMode::Drop; if (async) { test_asynclog_drop_messages(); AsyncLogWriter::flush(); diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index 1fa6ab76ec2..e14cad6cc65 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -35,19 +35,22 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; public class StressAsyncUL { - static void analyze_output(String... args) throws Exception { + static void analyze_output(boolean stalling_mode, String... args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); + if (stalling_mode) { + output.shouldNotContain("messages dropped due to async logging"); + } } public static void main(String[] args) throws Exception { - analyze_output("-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); - analyze_output("-Xlog:async:stall", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", 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("-Xlog:async:drop", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); - analyze_output("-Xlog:async:stall", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + 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()); } public static class InnerClass { From 2019f44539db0e19d92eeb1b4e80b74a6de3276c Mon Sep 17 00:00:00 2001 From: Ivan Bereziuk Date: Fri, 28 Feb 2025 13:46:17 +0000 Subject: [PATCH 168/587] 8343832: Enhance test summary with number of skipped tests Co-authored-by: Magnus Ihse Bursie Reviewed-by: ihse, erikj --- make/RunTests.gmk | 92 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 616341a8901..44d387080df 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -530,21 +530,34 @@ define SetupRunGtestTestBody $$(call LogWarn, Test report is stored in $$(strip \ $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR)))) $$(if $$(wildcard $$($1_RESULT_FILE)), \ - $$(eval $1_TOTAL := $$(shell $$(AWK) '/==========.* tests? from .* \ - test (cases?|suites?) ran/ { print $$$$2 }' $$($1_RESULT_FILE))) \ - $$(if $$($1_TOTAL), , $$(eval $1_TOTAL := 0)) \ + $$(eval $1_RUN := $$(shell $$(AWK) \ + '/==========.* tests? from .* test (cases?|suites?) ran/ { print $$$$2 }' \ + $$($1_RESULT_FILE))) \ + $$(if $$($1_RUN), , $$(eval $1_RUN := 0)) \ $$(eval $1_PASSED := $$(shell $$(AWK) '/\[ PASSED \] .* tests?./ \ { print $$$$4 }' $$($1_RESULT_FILE))) \ $$(if $$($1_PASSED), , $$(eval $1_PASSED := 0)) \ + $$(eval $1_SKIPPED := $$(shell $$(AWK) \ + '/YOU HAVE [0-9]+ DISABLED TEST/ { \ + if (match($$$$0, /[0-9]+/, arr)) { \ + print arr[0]; \ + found=1; \ + } \ + if (!found) { print 0; } \ + }' \ + $$($1_RESULT_FILE))) \ $$(eval $1_FAILED := $$(shell $$(AWK) '/\[ FAILED \] .* tests?, \ listed below/ { print $$$$4 }' $$($1_RESULT_FILE))) \ $$(if $$($1_FAILED), , $$(eval $1_FAILED := 0)) \ $$(eval $1_ERROR := $$(shell \ - $$(EXPR) $$($1_TOTAL) - $$($1_PASSED) - $$($1_FAILED))) \ + $$(EXPR) $$($1_RUN) - $$($1_PASSED) - $$($1_FAILED))) \ + $$(eval $1_TOTAL := $$(shell \ + $$(EXPR) $$($1_RUN) + $$($1_SKIPPED))) \ , \ $$(eval $1_PASSED := 0) \ $$(eval $1_FAILED := 0) \ $$(eval $1_ERROR := 1) \ + $$(eval $1_SKIPPED := 0) \ $$(eval $1_TOTAL := 1) \ ) @@ -668,6 +681,7 @@ define SetupRunMicroTestBody $$(eval $1_ERROR := 1) \ $$(eval $1_TOTAL := 1) \ ) + $$(eval $1_SKIPPED := 0) $1: run-test-$1 parse-test-$1 @@ -1036,23 +1050,64 @@ define SetupRunJtregTestBody $$(call LogWarn, Finished running test '$$($1_TEST)') $$(call LogWarn, Test report is stored in $$(strip \ $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR)))) + + # Read jtreg documentation to learn on the test stats categories: + # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean + # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. + # At the same time these tests contribute to "passed:" tests. + # In here we don't want that and so we substract number of "skipped:" from "passed:". + $$(if $$(wildcard $$($1_RESULT_FILE)), \ - $$(eval $1_PASSED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \ + $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \ for (i=1; i<=NF; i++) { if ($$$$i == "passed:") \ print $$$$(i+1) } }' $$($1_RESULT_FILE))) \ - $$(if $$($1_PASSED), , $$(eval $1_PASSED := 0)) \ + $$(if $$($1_PASSED_AND_RUNTIME_SKIPPED), , $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := 0)) \ $$(eval $1_FAILED := $$(shell $$(AWK) '{gsub(/[,;]/, ""); \ for (i=1; i<=NF; i++) { if ($$$$i == "failed:") \ print $$$$(i+1) } }' $$($1_RESULT_FILE))) \ $$(if $$($1_FAILED), , $$(eval $1_FAILED := 0)) \ + $$(eval $1_RUNTIME_SKIPPED := $$(shell $$(AWK) '{gsub(/[,;]/, ""); \ + for (i=1; i<=NF; i++) { if ($$$$i == "skipped:") \ + print $$$$(i+1) } }' $$($1_RESULT_FILE))) \ + $$(if $$($1_RUNTIME_SKIPPED), , $$(eval $1_RUNTIME_SKIPPED := 0)) \ + $$(eval $1_SKIPPED := $$(shell \ + $$(AWK) \ + 'BEGIN { \ + overall_skipped = 0; \ + patterns[1] = "skipped"; \ + patterns[2] = "excluded"; \ + patterns[3] = "not in match-list"; \ + patterns[4] = "did not match keywords"; \ + patterns[5] = "did not meet module requirements"; \ + patterns[6] = "did not meet platform requirements"; \ + patterns[7] = "did not match prior status"; \ + patterns[8] = "did not meet time-limit requirements"; \ + } { \ + split($$$$0, arr, ";"); \ + for (item in arr) { \ + for (p in patterns) { \ + if (match(arr[item], patterns[p] ": [0-9]+")) { \ + overall_skipped += substr(arr[item], RSTART + length(patterns[p]) + 2, RLENGTH); \ + } \ + } \ + } \ + print overall_skipped; \ + }' \ + $$($1_RESULT_FILE) \ + )) \ $$(eval $1_ERROR := $$(shell $$(AWK) '{gsub(/[,;]/, ""); \ for (i=1; i<=NF; i++) { if ($$$$i == "error:") \ print $$$$(i+1) } }' $$($1_RESULT_FILE))) \ $$(if $$($1_ERROR), , $$(eval $1_ERROR := 0)) \ + \ + $$(eval $1_PASSED := $$(shell \ + $$(EXPR) $$($1_PASSED_AND_RUNTIME_SKIPPED) - $$($1_RUNTIME_SKIPPED))) \ $$(eval $1_TOTAL := $$(shell \ - $$(EXPR) $$($1_PASSED) + $$($1_FAILED) + $$($1_ERROR))) \ + $$(EXPR) $$($1_PASSED) + $$($1_FAILED) + $$($1_ERROR) + $$($1_SKIPPED))) \ , \ - $$(eval $1_PASSED := 0) \ + $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := 0) \ + $$(eval $1_RUNTIME_SKIPPED := 0) \ + $$(eval $1_SKIPPED := 0) \ $$(eval $1_FAILED := 0) \ $$(eval $1_ERROR := 1) \ $$(eval $1_TOTAL := 1) \ @@ -1111,8 +1166,6 @@ define SetupRunSpecialTestBody || $$(ECHO) $$$$? > $$($1_EXITCODE) \ )) - $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt - # We can not parse the various "special" tests. parse-test-$1: run-test-$1 $$(call LogWarn, Finished running test '$$($1_TEST)') @@ -1122,6 +1175,7 @@ define SetupRunSpecialTestBody $$(eval $1_PASSED := $$(shell \ if [ `$(CAT) $$($1_EXITCODE)` = "0" ]; then $(ECHO) 1; else $(ECHO) 0; fi \ )) + $$(eval $1_SKIPPED := 0) $$(eval $1_FAILED := $$(shell \ if [ `$(CAT) $$($1_EXITCODE)` = "0" ]; then $(ECHO) 0; else $(ECHO) 1; fi \ )) @@ -1231,8 +1285,8 @@ run-test-report: post-run-test $(ECHO) >> $(TEST_SUMMARY) ============================== $(ECHO) >> $(TEST_SUMMARY) Test summary $(ECHO) >> $(TEST_SUMMARY) ============================== - $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5s %5s %5s %5s %2s\n" " " \ - TEST TOTAL PASS FAIL ERROR " " + $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5s %5s %5s %5s %5s %2s\n" " " \ + 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]')) \ @@ -1244,15 +1298,15 @@ run-test-report: post-run-test , \ $(eval TEST_NAME := $(test)) \ ) \ - $(if $(filter $($(TEST_ID)_PASSED), $($(TEST_ID)_TOTAL)), \ - $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %2s\n" \ - " " "$(TEST_NAME)" $($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) \ - $($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) " " $(NEWLINE) \ - , \ - $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %2s\n" \ + $(if $(filter-out 0, $($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR)), \ + $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %5d %2s\n" \ ">>" "$(TEST_NAME)" $($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) \ - $($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) "<<" $(NEWLINE) \ + $($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) $($(TEST_ID)_SKIPPED) "<<" $(NEWLINE) \ $(eval TEST_FAILURE := true) \ + , \ + $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s %5d %5d %5d %5d %5d %2s\n" \ + " " "$(TEST_NAME)" $($(TEST_ID)_TOTAL) $($(TEST_ID)_PASSED) \ + $($(TEST_ID)_FAILED) $($(TEST_ID)_ERROR) $($(TEST_ID)_SKIPPED) " " $(NEWLINE) \ ) \ ) $(ECHO) >> $(TEST_SUMMARY) ============================== From d6c4be672f6348f8ed985416ed90d0447f5d5bb3 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 28 Feb 2025 14:16:52 +0000 Subject: [PATCH 169/587] 8350758: G1: Use actual last prediction in accumulated survivor rate prediction too Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index d5fd50c4523..f858b93b13d 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -68,26 +68,23 @@ void G1SurvRateGroup::stop_adding_regions() { _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(double, _accum_surv_rate_pred, _num_added_regions, mtGC); _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_predictors, _num_added_regions, mtGC); - // Assume that the prediction for the newly added regions is the same as the - // ones at the (current) end of the array. Particularly predictions at the end - // of this array fairly seldom get updated, so having a better initial value - // that is at least somewhat related to the actual application is preferable. - double new_pred = _stats_arrays_length > 1 - ? _accum_surv_rate_pred[_stats_arrays_length - 1] - _accum_surv_rate_pred[_stats_arrays_length - 2] - : InitialSurvivorRate; - for (uint i = _stats_arrays_length; i < _num_added_regions; ++i) { // Initialize predictors and accumulated survivor rate predictions. _surv_rate_predictors[i] = new TruncatedSeq(10); if (i == 0) { _surv_rate_predictors[i]->add(InitialSurvivorRate); - _accum_surv_rate_pred[i] = 0.0; + _accum_surv_rate_pred[i] = InitialSurvivorRate; } else { - _surv_rate_predictors[i]->add(_surv_rate_predictors[i-1]->last()); - _accum_surv_rate_pred[i] = _accum_surv_rate_pred[i-1] + new_pred; + // Assume that the prediction for the newly added regions is the same as the + // ones at the (current) end of the array. Particularly predictions at the end + // of this array fairly seldom get updated, so having a better initial value + // that is at least somewhat related to the actual application is preferable. + double next_pred = _surv_rate_predictors[i-1]->last(); + _surv_rate_predictors[i]->add(next_pred); + _accum_surv_rate_pred[i] = _accum_surv_rate_pred[i-1] + next_pred; } } - _last_pred = new_pred; + _last_pred = _surv_rate_predictors[_num_added_regions-1]->last(); _stats_arrays_length = _num_added_regions; } From e98df71d9c5120fbb73a4c2f49863775fe5db781 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 28 Feb 2025 17:08:25 +0000 Subject: [PATCH 170/587] 8348028: Unable to run gtests with CDS enabled Reviewed-by: dholmes, iklam, ihse --- make/hotspot/lib/CompileJvm.gmk | 1 + src/hotspot/os/bsd/os_bsd.cpp | 12 +----------- src/hotspot/share/cds/cdsConfig.cpp | 8 +++----- src/hotspot/share/runtime/abstract_vm_version.cpp | 8 ++++++++ src/hotspot/share/runtime/abstract_vm_version.hpp | 3 ++- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index b2c59505f9a..6b5edc85b23 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -89,6 +89,7 @@ CFLAGS_VM_VERSION := \ -DHOTSPOT_VM_DISTRO='"$(HOTSPOT_VM_DISTRO)"' \ -DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \ -DHOTSPOT_BUILD_TIME='"$(HOTSPOT_BUILD_TIME)"' \ + -DJVM_VARIANT='"$(JVM_VARIANT)"' \ # ################################################################################ diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index c538c54e86f..faa3efa2384 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -242,16 +242,6 @@ static char cpu_arch[] = "ppc"; #error Add appropriate cpu_arch setting #endif -// JVM variant -#if defined(ZERO) - #define JVM_VARIANT "zero" -#elif defined(COMPILER2) - #define JVM_VARIANT "server" -#else - #define JVM_VARIANT "client" -#endif - - void os::Bsd::initialize_system_info() { int mib[2]; size_t len; @@ -1558,7 +1548,7 @@ void os::jvm_path(char *buf, jint buflen) { // Add the appropriate JVM variant subdir len = strlen(buf); jrelib_p = buf + len; - snprintf(jrelib_p, buflen-len, "/%s", JVM_VARIANT); + snprintf(jrelib_p, buflen-len, "/%s", Abstract_VM_Version::vm_variant()); if (0 != access(buf, F_OK)) { snprintf(jrelib_p, buflen-len, "%s", ""); } diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 1bb842af953..a5c5742eaf2 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -89,12 +89,10 @@ void CDSConfig::initialize() { char* CDSConfig::default_archive_path() { if (_default_archive_path == nullptr) { - char jvm_path[JVM_MAXPATHLEN]; - os::jvm_path(jvm_path, sizeof(jvm_path)); - char *end = strrchr(jvm_path, *os::file_separator()); - if (end != nullptr) *end = '\0'; stringStream tmp; - tmp.print("%s%sclasses", jvm_path, os::file_separator()); + const char* subdir = WINDOWS_ONLY("bin") NOT_WINDOWS("lib"); + tmp.print("%s%s%s%s%s%sclasses", Arguments::get_java_home(), os::file_separator(), subdir, + os::file_separator(), Abstract_VM_Version::vm_variant(), os::file_separator()); #ifdef _LP64 if (!UseCompressedOops) { tmp.print_raw("_nocoops"); diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 0776d501339..05cccd4fe45 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -81,6 +81,10 @@ VirtualizationType Abstract_VM_Version::_detected_virtualization = NoDetectedVir #error HOTSPOT_BUILD_TIME must be defined #endif +#ifndef JVM_VARIANT + #error JVM_VARIANT must be defined +#endif + #define VM_RELEASE HOTSPOT_VERSION_STRING // HOTSPOT_VERSION_STRING equals the JDK VERSION_STRING (unless overridden @@ -195,6 +199,10 @@ const char *Abstract_VM_Version::vm_platform_string() { return OS "-" CPU; } +const char* Abstract_VM_Version::vm_variant() { + return JVM_VARIANT; +} + const char* Abstract_VM_Version::internal_vm_info_string() { #ifndef HOTSPOT_BUILD_COMPILER #ifdef _MSC_VER diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 491d8a49dae..8cfc7031f97 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.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 @@ -110,6 +110,7 @@ class Abstract_VM_Version: AllStatic { static const char* vm_info_string(); static const char* vm_release(); static const char* vm_platform_string(); + static const char* vm_variant(); static int vm_major_version() { return _vm_major_version; } static int vm_minor_version() { return _vm_minor_version; } From 197004f4c621d7ab4c8b9e48362973eaa18156a4 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 28 Feb 2025 18:13:53 +0000 Subject: [PATCH 171/587] 8350820: OperatingSystemMXBean CpuLoad() methods return -1.0 on Windows Reviewed-by: kevinw, jwaters --- .../libmanagement_ext/OperatingSystemImpl.c | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c b/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c index 3cfd4679134..37c30bbc898 100644 --- a/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c +++ b/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c @@ -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 @@ -436,13 +436,13 @@ makeFullCounterPath(const char* const objectName, return NULL; } - snprintf(fullCounterPath, - fullCounterPathLen, - PROCESS_OBJECT_INSTANCE_COUNTER_FMT, - objectName, - imageName, - instance, - counterName); + _snprintf(fullCounterPath, + fullCounterPathLen, + PROCESS_OBJECT_INSTANCE_COUNTER_FMT, + objectName, + imageName, + instance, + counterName); } else { if (instance) { /* @@ -472,18 +472,18 @@ makeFullCounterPath(const char* const objectName, } if (instance) { - snprintf(fullCounterPath, - fullCounterPathLen, - OBJECT_WITH_INSTANCES_COUNTER_FMT, - objectName, - instance, - counterName); + _snprintf(fullCounterPath, + fullCounterPathLen, + OBJECT_WITH_INSTANCES_COUNTER_FMT, + objectName, + instance, + counterName); } else { - snprintf(fullCounterPath, - fullCounterPathLen, - OBJECT_COUNTER_FMT, - objectName, - counterName); + _snprintf(fullCounterPath, + fullCounterPathLen, + OBJECT_COUNTER_FMT, + objectName, + counterName); } } @@ -719,10 +719,10 @@ currentQueryIndexForProcess(void) { PDH_FMT_COUNTERVALUE counterValue; PDH_STATUS res; - snprintf(fullIDProcessCounterPath, - MAX_PATH, - pdhIDProcessCounterFmt, - index); + _snprintf(fullIDProcessCounterPath, + MAX_PATH, + pdhIDProcessCounterFmt, + index); if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) { break; @@ -1059,13 +1059,13 @@ allocateAndInitializePdhConstants() { } /* "\Process(java#%d)\ID Process" */ - snprintf(pdhIDProcessCounterFmt, - pdhIDProcessCounterFmtLen, - PROCESS_OBJECT_INSTANCE_COUNTER_FMT, - pdhLocalizedProcessObject, - pdhProcessImageName, - "%d", - pdhLocalizedIDProcessCounter); + _snprintf(pdhIDProcessCounterFmt, + pdhIDProcessCounterFmtLen, + PROCESS_OBJECT_INSTANCE_COUNTER_FMT, + pdhLocalizedProcessObject, + pdhProcessImageName, + "%d", + pdhLocalizedIDProcessCounter); pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0'; From 3a7d98687849ba0625fed2b516f4103ee8d27e41 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 28 Feb 2025 19:37:36 +0000 Subject: [PATCH 172/587] 8350646: Calendar.Builder.build() Throws ArrayIndexOutOfBoundsException Reviewed-by: naoto --- .../java/util/JapaneseImperialCalendar.java | 10 +++++++++- .../util/Calendar/Builder/BuilderTest.java | 10 ++++++++-- .../Calendar/SupplementalJapaneseEraTest.java | 18 +++++++++++++++++- .../SupplementalJapaneseEraTestRun.java | 4 ++-- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java b/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java index d275b09834a..755fe1133f5 100644 --- a/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java +++ b/src/java.base/share/classes/java/util/JapaneseImperialCalendar.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 @@ -1856,6 +1856,14 @@ class JapaneseImperialCalendar extends Calendar { if (isSet(ERA)) { era = internalGet(ERA); + // Don't check under, historically we have allowed values under + // BEFORE_MEIJI to be ignored during normalization + // We check against eras.length (not the highest constant ERA value) + // due to future added eras, or additional eras via + // "jdk.calendar.japanese.supplemental.era" + if (era >= eras.length) { + throw new IllegalArgumentException("Invalid era"); + } year = isSet(YEAR) ? internalGet(YEAR) : 1; } else { if (isSet(YEAR)) { diff --git a/test/jdk/java/util/Calendar/Builder/BuilderTest.java b/test/jdk/java/util/Calendar/Builder/BuilderTest.java index d74c38c067a..34fab9204ed 100644 --- a/test/jdk/java/util/Calendar/Builder/BuilderTest.java +++ b/test/jdk/java/util/Calendar/Builder/BuilderTest.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 @@ -23,8 +23,9 @@ /* * @test - * @bug 4745761 + * @bug 4745761 8350646 * @summary Unit test for Calendar.Builder. + * @run main BuilderTest */ import java.time.LocalDateTime; @@ -245,6 +246,11 @@ public class BuilderTest { checkException(calb, IllegalArgumentException.class); calb = builder().setCalendarType("japanese").setWeekDate(2013, 1, MONDAY); checkException(calb, IllegalArgumentException.class); + // JDK-8350646 : Ensure IAE (instead of AIOOBE) for ERA over largest supported + calb = builder().setCalendarType("japanese").setFields(ERA, 6); + checkException(calb, IllegalArgumentException.class); + // Note that we don't check ERAs under BEFORE_MEIJI, i.e. -1, -2, ... as + // historically JapaneseImperialCalendar ignores such values when normalizing } private static Calendar.Builder builder() { diff --git a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTest.java b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTest.java index 010519dc89e..411fc528dce 100644 --- a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTest.java +++ b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, 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 @@ -67,6 +67,22 @@ public class SupplementalJapaneseEraTest { } private static void testProperty() { + // JDK-8350646: Ensure that IAE is thrown for out of range era, when + // additional era is defined + try { + new Calendar.Builder() + .setCalendarType("japanese") + .setFields(ERA, JapaneseEra.values().length + 2) + .build(); + System.err.println("Out of range era should have thrown IAE"); + errors++; + } catch (Exception e) { + if (!(e instanceof IllegalArgumentException)) { + System.err.printf("Out of range era threw \"%s\" instead of IAE\n", e); + errors++; + } + } + Calendar jcal = new Calendar.Builder() .setCalendarType("japanese") .setFields(ERA, 6, YEAR, 1, DAY_OF_YEAR, 1) diff --git a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java index 5383d0d1240..8eac4a97ef7 100644 --- a/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.java +++ b/test/jdk/java/util/Calendar/SupplementalJapaneseEraTestRun.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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8048123 8054214 8173423 + * @bug 8048123 8054214 8173423 8350646 * @summary Test for jdk.calendar.japanese.supplemental.era support * @library /test/lib * @build SupplementalJapaneseEraTest From fb659eba028f793f7efb844d42024e903c1d0c5f Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 28 Feb 2025 19:38:25 +0000 Subject: [PATCH 173/587] 8350915: [JMH] test SocketChannelConnectionSetup failed for 2 threads config Reviewed-by: michaelm --- .../bench/java/net/SocketChannelConnectionSetup.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java index dedaaa59229..505e124e43e 100644 --- a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java +++ b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.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 @@ -23,11 +23,8 @@ package org.openjdk.bench.java.net; import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.StandardProtocolFamily; import java.net.UnixDomainSocketAddress; -import java.nio.channels.ClosedChannelException; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.file.*; @@ -80,7 +77,6 @@ public class SocketChannelConnectionSetup { private ServerSocketChannel getInetServerSocketChannel() throws IOException { - InetAddress iaddr = InetAddress.getLoopbackAddress(); return ServerSocketChannel.open().bind(null); } @@ -97,11 +93,11 @@ public class SocketChannelConnectionSetup { } @TearDown(Level.Trial) - public void afterRun() throws IOException, InterruptedException { + public void afterRun() throws IOException { ssc.close(); if (family.equals("unix")) { - Files.delete(socket); - Files.delete(Path.of(tempDir)); + Files.deleteIfExists(socket); + Files.deleteIfExists(Path.of(tempDir)); } } From c7fa499bf5023a3f16bb3742d2ba3cd74f2b41bd Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 28 Feb 2025 20:01:17 +0000 Subject: [PATCH 174/587] 8350118: Simplify the layout access VarHandle Reviewed-by: mcimadamore, jvernee, erikj --- .../gensrc/GensrcScopedMemoryAccess.gmk | 24 +- .../java.base/gensrc/GensrcVarHandles.gmk | 19 +- .../java/lang/invoke/MethodHandleImpl.java | 7 +- .../java/lang/invoke/SegmentVarHandle.java | 95 + .../classes/java/lang/invoke/VarForm.java | 23 +- .../classes/java/lang/invoke/VarHandle.java | 3 +- .../java/lang/invoke/VarHandleGuards.java | 1912 +++++++++++------ .../lang/invoke/VarHandleSegmentViewBase.java | 55 - .../classes/java/lang/invoke/VarHandles.java | 109 +- .../X-VarHandleSegmentView.java.template | 651 ++++-- .../internal/access/JavaLangInvokeAccess.java | 6 +- .../jdk/internal/foreign/LayoutPath.java | 13 +- .../classes/jdk/internal/foreign/Utils.java | 138 +- .../jdk/internal/foreign/abi/SharedUtils.java | 9 + .../internal/foreign/layout/ValueLayouts.java | 23 +- .../classes/jdk/internal/invoke/MhUtil.java | 27 +- .../misc/X-ScopedMemoryAccess.java.template | 2 +- test/jdk/java/foreign/TestAccessModes.java | 1 + 18 files changed, 1977 insertions(+), 1140 deletions(-) create mode 100644 src/java.base/share/classes/java/lang/invoke/SegmentVarHandle.java delete mode 100644 src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index 1ed3fb3db79..00fba64394b 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -42,6 +42,17 @@ define GenerateScopedOp $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 + endif + ifeq ($$($1_Type), Byte) $1_type := byte $1_BoxType := $$($1_Type) @@ -50,6 +61,7 @@ define GenerateScopedOp $1_RawType := $$($1_Type) $1_RawBoxType := $$($1_BoxType) + $1_ARGS += -KCAS $1_ARGS += -Kbyte endif @@ -60,6 +72,8 @@ define GenerateScopedOp $1_rawType := $$($1_type) $1_RawType := $$($1_Type) $1_RawBoxType := $$($1_BoxType) + + $1_ARGS += -KCAS $1_ARGS += -KUnaligned endif @@ -70,6 +84,8 @@ define GenerateScopedOp $1_rawType := $$($1_type) $1_RawType := $$($1_Type) $1_RawBoxType := $$($1_BoxType) + + $1_ARGS += -KCAS $1_ARGS += -KUnaligned endif @@ -82,8 +98,6 @@ define GenerateScopedOp $1_RawBoxType := $$($1_BoxType) $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise $1_ARGS += -KUnaligned endif @@ -96,8 +110,6 @@ define GenerateScopedOp $1_RawBoxType := $$($1_BoxType) $1_ARGS += -KCAS - $1_ARGS += -KAtomicAdd - $1_ARGS += -KBitwise $1_ARGS += -KUnaligned endif @@ -133,7 +145,7 @@ define GenerateScopedOp $1_ARGS += -KBitwise endif - ifneq ($$(findstring $$($1_Type), Byte Short Char), ) + ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char), ) $1_ARGS += -KShorterThanInt endif endef @@ -141,7 +153,7 @@ endef ################################################################################ # Setup a rule for generating the ScopedMemoryAccess java class -SCOPE_MEMORY_ACCESS_TYPES := Byte Short Char Int Long Float Double +SCOPE_MEMORY_ACCESS_TYPES := Boolean Byte Short Char Int Long Float Double $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ $(eval $(call GenerateScopedOp,BIN_$t,$t))) diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index e2f5664dec6..899f827462c 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -174,6 +174,18 @@ define GenerateVarHandleMemorySegment $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 + endif + ifeq ($$($1_Type), Byte) $1_type := byte $1_BoxType := $$($1_Type) @@ -183,6 +195,7 @@ define GenerateVarHandleMemorySegment $1_RawBoxType := $$($1_BoxType) $1_ARGS += -Kbyte + $1_ARGS += -KShorterThanInt endif ifeq ($$($1_Type), Short) @@ -192,6 +205,8 @@ define GenerateVarHandleMemorySegment $1_rawType := $$($1_type) $1_RawType := $$($1_Type) $1_RawBoxType := $$($1_BoxType) + + $1_ARGS += -KShorterThanInt endif ifeq ($$($1_Type), Char) @@ -201,6 +216,8 @@ define GenerateVarHandleMemorySegment $1_rawType := $$($1_type) $1_RawType := $$($1_Type) $1_RawBoxType := $$($1_BoxType) + + $1_ARGS += -KShorterThanInt endif ifeq ($$($1_Type), Int) @@ -277,7 +294,7 @@ $(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \ $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t))) # List the types to generate source for, with capitalized first letter -VARHANDLES_MEMORY_SEGMENT_TYPES := Byte Short Char Int Long Float Double +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))) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index e11ec88e2e6..d57a932c4dd 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.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 sun.invoke.util.Wrapper; import java.lang.classfile.ClassFile; import java.lang.constant.ClassDesc; +import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Array; import java.lang.reflect.Constructor; @@ -1552,8 +1553,8 @@ abstract class MethodHandleImpl { } @Override - public VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, ByteOrder order) { - return VarHandles.memorySegmentViewHandle(carrier, alignmentMask, order); + public VarHandle memorySegmentViewHandle(Class carrier, MemoryLayout enclosing, long alignmentMask, ByteOrder order, boolean constantOffset, long offset) { + return VarHandles.memorySegmentViewHandle(carrier, enclosing, alignmentMask, constantOffset, offset, order); } @Override diff --git a/src/java.base/share/classes/java/lang/invoke/SegmentVarHandle.java b/src/java.base/share/classes/java/lang/invoke/SegmentVarHandle.java new file mode 100644 index 00000000000..99fb35379e0 --- /dev/null +++ b/src/java.base/share/classes/java/lang/invoke/SegmentVarHandle.java @@ -0,0 +1,95 @@ +/* + * 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. 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 java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.util.Objects; + +import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.vm.annotation.ForceInline; + +/** + * A var handle that accesses primitive values in a memory segment. + */ +final class SegmentVarHandle extends VarHandle { + + // Common implementation fields for the VarForms + static final boolean BE = MethodHandleStatics.UNSAFE.isBigEndian(); + static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess(); + + /** endianness **/ + final boolean be; + /** The layout the accessed segment must be compatible with. */ + final MemoryLayout enclosing; + /** The offset value, if is constant. vform decides if offset is constant or variable. */ + final long offset; + + SegmentVarHandle(VarForm form, boolean be, MemoryLayout enclosing, long offset, boolean exact) { + super(form, exact); + this.be = be; + this.enclosing = enclosing; + this.offset = offset; + } + + @Override + final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) { + var getType = vform.methodType_table[0]; // erased, but our value type is erase-compatible + return getType.parameterCount() == 2 + ? accessType.accessModeType(MemorySegment.class, getType.returnType(), long.class) + : accessType.accessModeType(MemorySegment.class, getType.returnType(), long.class, long.class); + } + + @Override + public SegmentVarHandle withInvokeExactBehavior() { + return hasInvokeExactBehavior() ? + this : + new SegmentVarHandle(vform, be, enclosing, offset, true); + } + + @Override + public SegmentVarHandle withInvokeBehavior() { + return !hasInvokeExactBehavior() ? + this : + new SegmentVarHandle(vform, be, enclosing, offset, false); + } + + // Common implementation methods for the VarForms + + @ForceInline + static long offset(AbstractMemorySegmentImpl bb, long base, long offset) { + long segment_base = bb.unsafeGetOffset(); + return segment_base + base + offset; + } + + @ForceInline + AbstractMemorySegmentImpl checkSegment(Object obb, long base, boolean ro) { + AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl) Objects.requireNonNull(obb); + oo.checkEnclosingLayout(base, this.enclosing, ro); + return oo; + } +} diff --git a/src/java.base/share/classes/java/lang/invoke/VarForm.java b/src/java.base/share/classes/java/lang/invoke/VarForm.java index 0856bf126f9..f1f94a1c26b 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarForm.java +++ b/src/java.base/share/classes/java/lang/invoke/VarForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, 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 @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.List; import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic; +import static java.lang.invoke.MethodHandleStatics.UNSAFE; /** * A var handle form containing a set of member name, one for each operation. @@ -43,6 +44,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic; */ final class VarForm { + // implClass must be initialized when the member names are accessed! final Class implClass; final @Stable MethodType[] methodType_table; @@ -63,6 +65,15 @@ final class VarForm { } } + VarForm(Class implClass, VarForm methodTypeSource) { + this.implClass = implClass; + // reuse initMethodTypes result from methodTypeSource + this.methodType_table = methodTypeSource.methodType_table; + this.methodType_V_table = methodTypeSource.methodType_V_table; + this.memberName_table = new MemberName[VarHandle.AccessMode.COUNT]; + assert assertMethodTypeTableInitialized() : implClass; + } + // Used by IndirectVarHandle VarForm(Class value, Class[] coordinates) { this.methodType_table = new MethodType[VarHandle.AccessType.COUNT]; @@ -103,6 +114,15 @@ final class VarForm { type.changeReturnType(boolean.class); } + private boolean assertMethodTypeTableInitialized() { + if (methodType_table == null) + return false; + for (int i = 0; i < VarHandle.AccessType.COUNT; i++) { + assert methodType_table[i] != null : implClass + " " + VarHandle.AccessType.values()[i]; + } + return true; + } + @ForceInline final MethodType getMethodType(int type) { return methodType_table[type]; @@ -137,6 +157,7 @@ final class VarForm { AccessMode value = AccessMode.valueFromOrdinal(mode); String methodName = value.methodName(); MethodType type = methodType_table[value.at.ordinal()].insertParameterTypes(0, VarHandle.class); + assert !UNSAFE.shouldBeInitialized(implClass) : implClass; return memberName_table[mode] = MethodHandles.Lookup.IMPL_LOOKUP .resolveOrNull(REF_invokeStatic, implClass, methodName, type); } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index dda5f999715..9246fdc0395 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -472,8 +472,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE; * @since 9 */ public abstract sealed class VarHandle implements Constable - permits IndirectVarHandle, LazyInitializingVarHandle, - VarHandleSegmentViewBase, + permits IndirectVarHandle, LazyInitializingVarHandle, SegmentVarHandle, VarHandleByteArrayAsChars.ByteArrayViewVarHandle, VarHandleByteArrayAsDoubles.ByteArrayViewVarHandle, VarHandleByteArrayAsFloats.ByteArrayViewVarHandle, diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java index 8b73587eca5..1590053a6d0 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.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 @@ -47,49 +47,125 @@ final class VarHandleGuards { @ForceInline @LambdaForm.Compiled @Hidden - static final void guard_LL_V(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { + 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) { - 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)); + return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled @Hidden - static final boolean guard_LLL_Z(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + 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 (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled @Hidden - static final Object guard_LLL_L(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + 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) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + 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(), arg0, arg1, arg2); + return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } } @ForceInline @LambdaForm.Compiled @Hidden - static final Object guard_LL_L(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { + 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)); @@ -103,13 +179,199 @@ final class VarHandleGuards { @ForceInline @LambdaForm.Compiled @Hidden - static final int guard_L_I(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + 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, handle.vform.getMemberName(ad.mode)); + 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); + 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); } } @@ -128,58 +390,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -195,58 +405,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -262,58 +420,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -329,59 +435,6 @@ final class VarHandleGuards { } } - @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 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 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 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 @@ -397,32 +450,6 @@ final class VarHandleGuards { } } - @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 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 @@ -438,58 +465,6 @@ final class VarHandleGuards { } } - @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 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 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(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 @@ -505,58 +480,6 @@ final class VarHandleGuards { } } - @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 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 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(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 @@ -572,58 +495,6 @@ final class VarHandleGuards { } } - @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 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 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(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 @@ -639,59 +510,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -707,47 +525,6 @@ final class VarHandleGuards { } } - @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 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 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 @@ -763,45 +540,6 @@ final class VarHandleGuards { } } - @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 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_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 @@ -817,58 +555,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -884,58 +570,6 @@ final class VarHandleGuards { } } - @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 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 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_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 @@ -954,52 +588,15 @@ final class VarHandleGuards { @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 { + 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) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + 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); - return (boolean) 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 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 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); + mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @@ -1021,7 +618,257 @@ final class VarHandleGuards { @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 { + 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)); @@ -1034,41 +881,78 @@ final class VarHandleGuards { @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 { + 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 (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + return (boolean) 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); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled @Hidden - static final int guard_LJI_I(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + 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 (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + return (boolean) 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); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled @Hidden - static final void guard_LJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + 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) { - 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)); + return (boolean) 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); + 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); } } @@ -1085,6 +969,309 @@ final class VarHandleGuards { } } + @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 @@ -1098,4 +1285,333 @@ final class VarHandleGuards { } } + @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/VarHandleSegmentViewBase.java b/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java deleted file mode 100644 index 31ec02c3d7c..00000000000 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2019, 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. 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; - -/** - * Base class for memory segment var handle view implementations. - */ -abstract sealed class VarHandleSegmentViewBase extends VarHandle permits - VarHandleSegmentAsBytes, - VarHandleSegmentAsChars, - VarHandleSegmentAsDoubles, - VarHandleSegmentAsFloats, - VarHandleSegmentAsInts, - VarHandleSegmentAsLongs, - VarHandleSegmentAsShorts { - - /** endianness **/ - final boolean be; - - /** alignment constraint (in bytes, expressed as a bit mask) **/ - final long alignmentMask; - - VarHandleSegmentViewBase(VarForm form, boolean be, long alignmentMask, boolean exact) { - super(form, exact); - this.be = be; - this.alignmentMask = alignmentMask; - } - - static UnsupportedOperationException newUnsupportedAccessModeForAlignment(long alignment) { - return new UnsupportedOperationException("Unsupported access mode for alignment: " + alignment); - } -} 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 a21092c6cf7..298b2e7baa1 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -27,6 +27,7 @@ package java.lang.invoke; import sun.invoke.util.Wrapper; +import java.lang.foreign.MemoryLayout; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -291,44 +292,55 @@ final class VarHandles { } /** - * Creates a memory segment view var handle. - * + * Creates a memory segment view var handle accessing a {@code carrier} element. It has access coordinates + * {@code (MS, long)} if {@code constantOffset}, {@code (MS, long, (validated) long)} otherwise. + *

* The resulting var handle will take a memory segment as first argument (the segment to be dereferenced), - * and a {@code long} as second argument (the offset into the segment). + * and a {@code long} as second argument (the offset into the segment). Both arguments are checked. + *

+ * If {@code constantOffset == false}, the resulting var handle will take a third pre-validated additional + * offset instead of the given fixed {@code offset}, and caller must ensure that passed additional offset, + * either to the handle (such as computing through method handles) or as fixed {@code offset} here, is valid. * - * Note: the returned var handle does not perform any size or alignment check. It is up to clients - * to adapt the returned var handle and insert the appropriate checks. - * - * @param carrier the Java carrier type. - * @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask. - * @param byteOrder the byte order. - * @return the created VarHandle. + * @param carrier the Java carrier type of the element + * @param enclosing the enclosing layout to perform bound and alignment checks against + * @param alignmentMask alignment of this accessed element in the enclosing layout + * @param constantOffset if access path has a constant offset value, i.e. it has no strides + * @param offset the offset value, if the offset is constant + * @param byteOrder the byte order + * @return the created var handle */ - static VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, - ByteOrder byteOrder) { - if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { + static VarHandle memorySegmentViewHandle(Class carrier, MemoryLayout enclosing, long alignmentMask, + boolean constantOffset, long offset, ByteOrder byteOrder) { + if (!carrier.isPrimitive() || carrier == void.class) { throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); } boolean be = byteOrder == ByteOrder.BIG_ENDIAN; boolean exact = VAR_HANDLE_SEGMENT_FORCE_EXACT; + // All carrier types must persist across MethodType erasure + VarForm form; if (carrier == byte.class) { - return maybeAdapt(new VarHandleSegmentAsBytes(be, alignmentMask, exact)); + form = VarHandleSegmentAsBytes.selectForm(alignmentMask, constantOffset); } else if (carrier == char.class) { - return maybeAdapt(new VarHandleSegmentAsChars(be, alignmentMask, exact)); + form = VarHandleSegmentAsChars.selectForm(alignmentMask, constantOffset); } else if (carrier == short.class) { - return maybeAdapt(new VarHandleSegmentAsShorts(be, alignmentMask, exact)); + form = VarHandleSegmentAsShorts.selectForm(alignmentMask, constantOffset); } else if (carrier == int.class) { - return maybeAdapt(new VarHandleSegmentAsInts(be, alignmentMask, exact)); + form = VarHandleSegmentAsInts.selectForm(alignmentMask, constantOffset); } else if (carrier == float.class) { - return maybeAdapt(new VarHandleSegmentAsFloats(be, alignmentMask, exact)); + form = VarHandleSegmentAsFloats.selectForm(alignmentMask, constantOffset); } else if (carrier == long.class) { - return maybeAdapt(new VarHandleSegmentAsLongs(be, alignmentMask, exact)); + form = VarHandleSegmentAsLongs.selectForm(alignmentMask, constantOffset); } else if (carrier == double.class) { - return maybeAdapt(new VarHandleSegmentAsDoubles(be, alignmentMask, exact)); + form = VarHandleSegmentAsDoubles.selectForm(alignmentMask, constantOffset); + } else if (carrier == boolean.class) { + form = VarHandleSegmentAsBooleans.selectForm(alignmentMask, constantOffset); } else { throw new IllegalStateException("Cannot get here"); } + + return maybeAdapt(new SegmentVarHandle(form, be, enclosing, offset, exact)); } private static VarHandle maybeAdapt(VarHandle target) { @@ -724,7 +736,7 @@ final class VarHandles { // Object getAndUpdate(Object value); // } // -// record HandleType(Class receiver, Class value, Class... intermediates) { +// record HandleType(Class receiver, Class... intermediates) { // } // // /** @@ -744,48 +756,31 @@ final class VarHandles { // System.out.println(); // // // Declare the stream of shapes -// Stream hts = Stream.of( -// // Object->Object -// new HandleType(Object.class, Object.class), -// // Object->int +// List hts = List.of( +// // Object->T +// new HandleType(Object.class), +// +// // ->T +// new HandleType(null), +// +// // Array[index]->T // new HandleType(Object.class, int.class), -// // Object->long +// +// // MS[base]->T // new HandleType(Object.class, long.class), -// // Object->float -// new HandleType(Object.class, float.class), -// // Object->double -// new HandleType(Object.class, double.class), // -// // ->Object -// new HandleType(null, Object.class), -// // ->int -// new HandleType(null, int.class), -// // ->long -// new HandleType(null, long.class), -// // ->float -// new HandleType(null, float.class), -// // ->double -// new HandleType(null, double.class), -// -// // Array[int]->Object -// new HandleType(Object.class, Object.class, int.class), -// // Array[int]->int -// new HandleType(Object.class, int.class, int.class), -// // Array[int]->long -// new HandleType(Object.class, long.class, int.class), -// // Array[int]->float -// new HandleType(Object.class, float.class, int.class), -// // Array[int]->double -// new HandleType(Object.class, double.class, int.class), -// -// // Array[long]->int -// new HandleType(Object.class, int.class, long.class), -// // Array[long]->long +// // MS[base][offset]->T // new HandleType(Object.class, long.class, long.class) // ); // -// hts.flatMap(ht -> Stream.of(VarHandleTemplate.class.getMethods()). -// map(m -> generateMethodType(m, ht.receiver, ht.value, ht.intermediates))). +// 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); diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index c5942e93c46..aa8c7b28617 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -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 @@ -25,53 +25,106 @@ package java.lang.invoke; import jdk.internal.foreign.AbstractMemorySegmentImpl; -import jdk.internal.foreign.Utils; -import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; -import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -import java.lang.ref.Reference; -import java.util.Objects; - -import static java.lang.invoke.MethodHandleStatics.UNSAFE; +import static java.lang.invoke.SegmentVarHandle.*; #warn -final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { - - static final boolean BE = UNSAFE.isBigEndian(); - - static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess(); +{#if[byte]?final:sealed} class VarHandleSegmentAs$Type$s { +#if[!byte] static final int NON_PLAIN_ACCESS_MIN_ALIGN_MASK = $BoxType$.BYTES - 1; - static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class); - - VarHandleSegmentAs$Type$s(boolean be, long alignmentMask, boolean exact) { - super(FORM, be, alignmentMask, exact); +#end[byte] + static VarForm selectForm(long alignmentMask, boolean constantOffset) { +#if[byte] + return constantOffset ? CONSTANT_OFFSET_FORM : VARIABLE_OFFSET_FORM; +#else[byte] + return (alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK ? + (constantOffset ? CONSTANT_OFFSET_FORM : VARIABLE_OFFSET_FORM) : + (constantOffset ? VarHandleSegmentAs$Type$sAligned.CONSTANT_OFFSET_FORM : VarHandleSegmentAs$Type$sAligned.VARIABLE_OFFSET_FORM); +#end[byte] } - @Override - final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) { - return accessType.accessModeType(MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class); + static final VarForm CONSTANT_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class); + static final VarForm VARIABLE_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class, long.class); + + VarHandleSegmentAs$Type$s() { throw new AssertionError(); } + + @ForceInline + static $type$ get(VarHandle ob, Object obb, long base) { + return get(ob, obb, base, ((SegmentVarHandle) ob).offset); } - @Override - public VarHandleSegmentAs$Type$s withInvokeExactBehavior() { - return hasInvokeExactBehavior() ? - this : - new VarHandleSegmentAs$Type$s(be, alignmentMask, true); + @ForceInline + static $type$ get(VarHandle ob, Object obb, long base, long offset) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true); +#if[floatingPoint] + $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset), + handle.be); + return $Type$.$rawType$BitsTo$Type$(rawValue); +#else[floatingPoint] +#if[byte] + return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset)); +#else[byte] + return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset), + handle.be); +#end[byte] +#end[floatingPoint] } - @Override - public VarHandleSegmentAs$Type$s withInvokeBehavior() { - return !hasInvokeExactBehavior() ? - this : - new VarHandleSegmentAs$Type$s(be, alignmentMask, false); + @ForceInline + static void set(VarHandle ob, Object obb, long base, $type$ value) { + set(ob, obb, base, ((SegmentVarHandle) ob).offset, value); } + @ForceInline + static void set(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[floatingPoint] + SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset), + $Type$.$type$ToRaw$RawType$Bits(value), + handle.be); +#else[floatingPoint] +#if[byte] + SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset), + value); +#else[byte] + SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset), + value, + handle.be); +#end[byte] +#end[floatingPoint] + } +#if[!byte] +} + +// This class must be accessed through non-aligned VarHandleSegmentAs$Type$s +final class VarHandleSegmentAs$Type$sAligned extends VarHandleSegmentAs$Type$s { + + static final VarForm CONSTANT_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$sAligned.class, VarHandleSegmentAs$Type$s.CONSTANT_OFFSET_FORM); + static final VarForm VARIABLE_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$sAligned.class, VarHandleSegmentAs$Type$s.VARIABLE_OFFSET_FORM); + + VarHandleSegmentAs$Type$sAligned() { throw new AssertionError(); } +#end[byte] + #if[floatingPoint] @ForceInline static $rawType$ convEndian(boolean big, $type$ v) { @@ -99,296 +152,338 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { #end[floatingPoint] @ForceInline - static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { - AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - oo.checkEnclosingLayout(base, (MemoryLayout)encl, ro); - return oo; + static $type$ getVolatile(VarHandle ob, Object obb, long base) { + return getVolatile(ob, obb, base, ((SegmentVarHandle) ob).offset); } @ForceInline - static long offsetNonPlain(AbstractMemorySegmentImpl bb, long base, long offset, long alignmentMask) { - if ((alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK) { - throw VarHandleSegmentViewBase.newUnsupportedAccessModeForAlignment(alignmentMask + 1); - } - return offsetPlain(bb, base, offset); - } - - @ForceInline - static long offsetPlain(AbstractMemorySegmentImpl bb, long base, long offset) { - long segment_base = bb.unsafeGetOffset(); - return segment_base + base + offset; - } - - @ForceInline - static $type$ get(VarHandle ob, Object obb, Object encl, long base, long offset) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); -#if[floatingPoint] - $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset), - handle.be); - return $Type$.$rawType$BitsTo$Type$(rawValue); -#else[floatingPoint] -#if[byte] - return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset)); -#else[byte] - return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset), - handle.be); -#end[byte] -#end[floatingPoint] - } - - @ForceInline - static void set(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); -#if[floatingPoint] - SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset), - $Type$.$type$ToRaw$RawType$Bits(value), - handle.be); -#else[floatingPoint] -#if[byte] - SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset), - value); -#else[byte] - SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetPlain(bb, base, offset), - value, - handle.be); -#end[byte] -#end[floatingPoint] - } - - @ForceInline - static $type$ getVolatile(VarHandle ob, Object obb, Object encl, long base, long offset) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); + static $type$ getVolatile(VarHandle ob, Object obb, long base, long offset) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask))); + offset(bb, base, offset))); } @ForceInline - static void setVolatile(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) { + setVolatile(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static void setVolatile(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value)); } @ForceInline - static $type$ getAcquire(VarHandle ob, Object obb, Object encl, long base, long offset) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); + static $type$ getAcquire(VarHandle ob, Object obb, long base) { + return getAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset); + } + + @ForceInline + static $type$ getAcquire(VarHandle ob, Object obb, long base, long offset) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask))); + offset(bb, base, offset))); } @ForceInline - static void setRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static void setRelease(VarHandle ob, Object obb, long base, $type$ value) { + setRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static void setRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value)); } @ForceInline - static $type$ getOpaque(VarHandle ob, Object obb, Object encl, long base, long offset) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); - return convEndian(handle.be, - SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(), - bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask))); + static $type$ getOpaque(VarHandle ob, Object obb, long base) { + return getOpaque(ob, obb, base, ((SegmentVarHandle) ob).offset); } @ForceInline - static void setOpaque(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getOpaque(VarHandle ob, Object obb, long base, long offset) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true); + return convEndian(handle.be, + SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(), + bb.unsafeGetBase(), + offset(bb, base, offset))); + } + + @ForceInline + static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) { + setOpaque(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static void setOpaque(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value)); } #if[CAS] @ForceInline - static boolean compareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return compareAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static boolean compareAndSet(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static $type$ compareAndExchange(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return compareAndExchange(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static $type$ compareAndExchange(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return compareAndExchangeAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return compareAndExchangeRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value))); } @ForceInline - static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return weakCompareAndSetPlain(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return weakCompareAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return weakCompareAndSetAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { + return weakCompareAndSetRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value); + } + + @ForceInline + static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, expected), convEndian(handle.be, value)); } @ForceInline - static $type$ getAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) { + return getAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndSet(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value))); } @ForceInline - static $type$ getAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) { + return getAndSetAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value))); } @ForceInline - static $type$ getAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) { + return getAndSetRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), convEndian(handle.be, value))); } #end[CAS] #if[AtomicAdd] @ForceInline - static $type$ getAndAdd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ value) { + return getAndAdd(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndAdd(VarHandle ob, Object obb, long base, long offset, $type$ delta) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), delta); +#if[!byte] } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta); } +#end[byte] } @ForceInline - static $type$ getAndAddAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ value) { + return getAndAddAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, long offset, $type$ delta) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), delta); +#if[!byte] } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta); } +#end[byte] } @ForceInline - static $type$ getAndAddRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ value) { + return getAndAddRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, long offset, $type$ delta) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), delta); +#if[!byte] } else { - return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); + return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta); } +#end[byte] } +#if[!byte] @ForceInline static $type$ getAndAddConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ delta) { @@ -398,53 +493,82 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, - nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta))); + nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue + delta)))); return expectedValue; } +#end[byte] #end[AtomicAdd] #if[Bitwise] @ForceInline - static $type$ getAndBitwiseOr(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseOr(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseOrRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseOrAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } +#if[!byte] @ForceInline static $type$ getAndBitwiseOrConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { @@ -454,51 +578,81 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, - nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value))); + nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue | value)))); return expectedValue; } +#end[byte] @ForceInline - static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseAnd(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseAndRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseAndAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + + @ForceInline + static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } +#if[!byte] @ForceInline static $type$ getAndBitwiseAndConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { @@ -508,52 +662,80 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, - nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value))); + nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue & value)))); return expectedValue; } - +#end[byte] @ForceInline - static $type$ getAndBitwiseXor(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseXor(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseXorRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } @ForceInline - static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { - VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); + static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) { + return getAndBitwiseXorAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value); + } + + @ForceInline + static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) { + SegmentVarHandle handle = (SegmentVarHandle)ob; + AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false); +#if[!byte] if (handle.be == BE) { +#end[byte] return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), - offsetNonPlain(bb, base, offset, handle.alignmentMask), + offset(bb, base, offset), value); +#if[!byte] } else { - return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); + return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value); } +#end[byte] } +#if[!byte] @ForceInline static $type$ getAndBitwiseXorConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { @@ -563,8 +745,9 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, - nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value))); + nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue ^ value)))); return expectedValue; } +#end[byte] #end[Bitwise] } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java index 563870381fe..722447eece6 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.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 @@ -27,8 +27,8 @@ package jdk.internal.access; import jdk.internal.foreign.abi.NativeEntryPoint; +import java.lang.foreign.MemoryLayout; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.lang.reflect.Constructor; @@ -75,7 +75,7 @@ public interface JavaLangInvokeAccess { * Used by {@code jdk.internal.foreign.LayoutPath} and * {@code java.lang.invoke.MethodHandles}. */ - VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, ByteOrder order); + VarHandle memorySegmentViewHandle(Class carrier, MemoryLayout enclosing, long alignmentMask, ByteOrder order, boolean constantOffset, long offset); /** * Var handle carrier combinator. diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 58552d44ea4..11407de93a9 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -59,6 +59,7 @@ public class LayoutPath { private static final long[] EMPTY_STRIDES = new long[0]; private static final long[] EMPTY_BOUNDS = new long[0]; private static final MethodHandle[] EMPTY_DEREF_HANDLES = new MethodHandle[0]; + public static final MemoryLayout.PathElement[] EMPTY_PATH_ELEMENTS = new MemoryLayout.PathElement[0]; private static final MethodHandle MH_ADD_SCALED_OFFSET; private static final MethodHandle MH_SLICE; @@ -205,15 +206,13 @@ public class LayoutPath { String.format("Path does not select a value layout: %s", breadcrumbs())); } - VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); // (MS, ML, long, long) - handle = MethodHandles.insertCoordinates(handle, 1, rootLayout()); // (MS, long, long) - if (strides.length > 0) { - MethodHandle offsetAdapter = offsetHandle(); + boolean constantOffset = strides.length == 0; + // (MS, long, long) if variable offset, (MS, long) if constant offset + VarHandle handle = Utils.makeRawSegmentViewVarHandle(rootLayout(), valueLayout, constantOffset, offset); + if (!constantOffset) { + MethodHandle offsetAdapter = offsetHandle(); // Adapter performs the bound checks offsetAdapter = MethodHandles.insertArguments(offsetAdapter, 0, 0L); handle = MethodHandles.collectCoordinates(handle, 2, offsetAdapter); // (MS, long) - } else { - // simpler adaptation - handle = MethodHandles.insertCoordinates(handle, 2, offset); // (MS, long) } if (adapt) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index 391a46c092c..4214b0395b8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * 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. 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 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). + * 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. + * 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.foreign; @@ -34,7 +33,6 @@ import sun.invoke.util.Wrapper; import java.lang.foreign.AddressLayout; import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; import java.lang.foreign.StructLayout; import java.lang.foreign.ValueLayout; @@ -46,6 +44,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.function.Supplier; /** @@ -56,25 +55,31 @@ public final class Utils { // Suppresses default constructor, ensuring non-instantiability. private Utils() {} - private static final MethodHandle BYTE_TO_BOOL; - private static final MethodHandle BOOL_TO_BYTE; - private static final MethodHandle ADDRESS_TO_LONG; + private static final Class ADDRESS_CARRIER_TYPE; + private static final MethodHandle LONG_TO_CARRIER; private static final MethodHandle LONG_TO_ADDRESS_TARGET; private static final MethodHandle LONG_TO_ADDRESS_NO_TARGET; static { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + String unboxSegmentName; + Class rawAddressType; + if (Unsafe.getUnsafe().addressSize() == 8) { + unboxSegmentName = "unboxSegment"; + rawAddressType = long.class; + } else { + assert Unsafe.getUnsafe().addressSize() == 4 : Unsafe.getUnsafe().addressSize(); + unboxSegmentName = "unboxSegment32"; + rawAddressType = int.class; + } + ADDRESS_CARRIER_TYPE = rawAddressType; try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean", - MethodType.methodType(boolean.class, byte.class)); - BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte", - MethodType.methodType(byte.class, boolean.class)); - ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment", - MethodType.methodType(long.class, MemorySegment.class)); + LONG_TO_CARRIER = lookup.findStatic(SharedUtils.class, unboxSegmentName, + MethodType.methodType(rawAddressType, MemorySegment.class)); LONG_TO_ADDRESS_TARGET = lookup.findStatic(Utils.class, "longToAddress", - MethodType.methodType(MemorySegment.class, long.class, AddressLayout.class)); + MethodType.methodType(MemorySegment.class, rawAddressType, AddressLayout.class)); LONG_TO_ADDRESS_NO_TARGET = lookup.findStatic(Utils.class, "longToAddress", - MethodType.methodType(MemorySegment.class, long.class)); + MethodType.methodType(MemorySegment.class, rawAddressType)); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } @@ -90,48 +95,57 @@ public final class Utils { } /** - * This method returns a raw var handle, that is, a var handle that does not perform any size - * or alignment checks. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}. + * This method returns a var handle that accesses a target layout in an enclosing layout, taking the memory offset + * and the base offset of the enclosing layout in the segment. + *

+ * If the offset of the target layout in the enclosing layout is constant, the coordinates are (MS, long). + * If the offset of the target layout in the enclosing layout is variable, the coordinates are (MS, long, long). + * The trailing long is a pre-validated, variable extra offset, which the var handle does not perform any size or + * alignment checks against. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}. *

* We provide two level of caching of the generated var handles. First, the var handle associated * with a {@link ValueLayout#varHandle()} call is cached inside a stable field of the value layout implementation. * This optimizes common code idioms like {@code JAVA_INT.varHandle().getInt(...)}. A second layer of caching - * is then provided by this method: after all, var handles constructed by {@link MemoryLayout#varHandle(PathElement...)} - * will be obtained by adapting some raw var handle generated by this method. + * is then provided by this method, so different value layouts with same effects can reuse var handle instances. + * (The 2nd layer may be redundant in the long run) * - * @param layout the value layout for which a raw memory segment var handle is to be created. - * @return a raw memory segment var handle. + * @param enclosing the enclosing context of the value layout + * @param layout the value layout for which a raw memory segment var handle is to be created + * @param constantOffset if the VH carries a constant offset instead of taking a variable offset + * @param offset the offset if it is a constant + * @return a raw memory segment var handle */ - public static VarHandle makeRawSegmentViewVarHandle(ValueLayout layout) { - final class VarHandleCache { - private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + public static VarHandle makeRawSegmentViewVarHandle(MemoryLayout enclosing, ValueLayout layout, boolean constantOffset, long offset) { + if (enclosing instanceof ValueLayout direct) { + assert direct.equals(layout) && constantOffset && offset == 0; + record VarHandleCache() implements Function { + private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + private static final VarHandleCache INSTANCE = new VarHandleCache(); + + @Override + public VarHandle apply(ValueLayout valueLayout) { + return Utils.makeRawSegmentViewVarHandleInternal(valueLayout, valueLayout, true, 0); + } + } + return VarHandleCache.HANDLE_MAP.computeIfAbsent(direct.withoutName(), VarHandleCache.INSTANCE); } - return VarHandleCache.HANDLE_MAP - .computeIfAbsent(layout.withoutName(), Utils::makeRawSegmentViewVarHandleInternal); + return makeRawSegmentViewVarHandleInternal(enclosing, layout, constantOffset, offset); } - private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) { + private static VarHandle makeRawSegmentViewVarHandleInternal(MemoryLayout enclosing, ValueLayout layout, boolean constantOffset, long offset) { Class baseCarrier = layout.carrier(); if (layout.carrier() == MemorySegment.class) { - baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) { - case Long.BYTES -> long.class; - case Integer.BYTES -> int.class; - default -> throw new UnsupportedOperationException("Unsupported address layout"); - }; - } else if (layout.carrier() == boolean.class) { - baseCarrier = byte.class; + baseCarrier = ADDRESS_CARRIER_TYPE; } VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier, - layout.byteAlignment() - 1, layout.order()); + enclosing, layout.byteAlignment() - 1, layout.order(), constantOffset, offset); - if (layout.carrier() == boolean.class) { - handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL); - } else if (layout instanceof AddressLayout addressLayout) { + if (layout instanceof AddressLayout addressLayout) { MethodHandle longToAddressAdapter = addressLayout.targetLayout().isPresent() ? MethodHandles.insertArguments(LONG_TO_ADDRESS_TARGET, 1, addressLayout) : LONG_TO_ADDRESS_NO_TARGET; - handle = MethodHandles.filterValue(handle, ADDRESS_TO_LONG, longToAddressAdapter); + handle = MethodHandles.filterValue(handle, LONG_TO_CARRIER, longToAddressAdapter); } return handle; } @@ -149,11 +163,23 @@ public final class Utils { return longToAddress(addr, 0, 1); } + // 32 bit + @ForceInline + public static MemorySegment longToAddress(int addr) { + return longToAddress(addr, 0, 1); + } + @ForceInline public static MemorySegment longToAddress(long addr, AddressLayout layout) { return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout)); } + // 32 bit + @ForceInline + public static MemorySegment longToAddress(int addr, AddressLayout layout) { + return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout)); + } + @ForceInline public static MemorySegment longToAddress(long addr, long size, long align) { if (!isAligned(addr, align)) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 9078920f677..17324894ac5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -321,11 +321,20 @@ public final class SharedUtils { } } + @ForceInline public static long unboxSegment(MemorySegment segment) { checkNative(segment); return segment.address(); } + @ForceInline + public static int unboxSegment32(MemorySegment segment) { + // This cast to 'int' is safe, because we only call this method on 32-bit + // platforms, where we know the address of a segment is truncated to 32-bits. + // There's a similar cast for 4-byte addresses in Unsafe.putAddress. + return (int) unboxSegment(segment); + } + public static void checkExceptions(MethodHandle target) { Class[] exceptions = JLIA.exceptionTypes(target); if (exceptions != null && exceptions.length != 0) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java index e546773c429..685b95691ba 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.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 @@ -25,6 +25,7 @@ */ package jdk.internal.foreign.layout; +import jdk.internal.foreign.LayoutPath; import jdk.internal.foreign.Utils; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; @@ -38,10 +39,8 @@ import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; /** * A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as integral types @@ -159,19 +158,13 @@ public final class ValueLayouts { @ForceInline public final VarHandle varHandle() { - final class VarHandleCache { - private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + var vh = handle; + if (vh == null) { + vh = varHandleInternal(LayoutPath.EMPTY_PATH_ELEMENTS); + // benign race stable field store is safe because VarHandle is thread safe + handle = vh; } - if (handle == null) { - // this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity - handle = VarHandleCache.HANDLE_MAP.computeIfAbsent(self().withoutName(), _ -> varHandleInternal()); - } - return handle; - } - - @SuppressWarnings("unchecked") - final V self() { - return (V) this; + return vh; } } diff --git a/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java b/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java index 16a4e10221c..4a8cb785470 100644 --- a/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java +++ b/src/java.base/share/classes/jdk/internal/invoke/MhUtil.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 @@ -33,6 +33,9 @@ import java.lang.invoke.VarHandle; /** * Static factories for certain VarHandle/MethodHandle variants. *

+ * Some methods take no receiver argument. In these cases, the receiver is the + * lookup class. + *

* The methods will throw an {@link InternalError} if the lookup fails. *

* Here is an example of how one of these methods could be used: @@ -63,6 +66,11 @@ public final class MhUtil { } } + public static MethodHandle findVirtual(MethodHandles.Lookup lookup, + String name, + MethodType type) { + return findVirtual(lookup, lookup.lookupClass(), name, type); + } public static MethodHandle findVirtual(MethodHandles.Lookup lookup, Class refc, @@ -75,4 +83,21 @@ public final class MhUtil { } } + public static MethodHandle findStatic(MethodHandles.Lookup lookup, + String name, + MethodType type) { + return findStatic(lookup, lookup.lookupClass(), name, type); + } + + public static MethodHandle findStatic(MethodHandles.Lookup lookup, + Class refc, + String name, + MethodType type) { + try { + return lookup.findStatic(refc, name, type); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + } diff --git a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template index c2f5f7fabd0..158df7c8bb3 100644 --- a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template +++ b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template @@ -75,7 +75,7 @@ import jdk.internal.vm.vector.VectorSupport; * which might be deemed to expensive; in other words, this approach prioritizes the performance of memory access over * that of releasing a shared memory resource. */ -public class ScopedMemoryAccess { +public final class ScopedMemoryAccess { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); diff --git a/test/jdk/java/foreign/TestAccessModes.java b/test/jdk/java/foreign/TestAccessModes.java index 0cedcc9058e..a721c87484d 100644 --- a/test/jdk/java/foreign/TestAccessModes.java +++ b/test/jdk/java/foreign/TestAccessModes.java @@ -61,6 +61,7 @@ public class TestAccessModes { // access is unaligned assertTrue(segment.maxByteAlignment() < layout.byteAlignment()); } + assertEquals(varHandle.isAccessModeSupported(mode), compatible); } static ValueLayout accessLayout(MemoryLayout layout) { From a87dd1a75f78cf872df49bea83ba48af8acfa2fd Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Fri, 28 Feb 2025 20:22:23 +0000 Subject: [PATCH 175/587] 8347139: [macos] Test tools/jpackage/share/InOutPathTest.java failed: "execution error: Finder got an error: AppleEvent timed out." Reviewed-by: asemenyuk --- test/jdk/tools/jpackage/share/IconTest.java | 2 +- test/jdk/tools/jpackage/share/InOutPathTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index f5498500c0b..6d84714f28b 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=540 -Xmx512m + * @run main/othervm/timeout=720 -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 2d9fa1671de..f5fe3c618ae 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=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=InOutPathTest */ public final class InOutPathTest { From 6b719eeebc346fd4655fc718d7d033b3ebf54d9e Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Fri, 28 Feb 2025 21:22:20 +0000 Subject: [PATCH 176/587] 8348596: Update FreeType to 2.13.3 Reviewed-by: azvegint, dnguyen, prr --- src/java.desktop/share/legal/freetype.md | 46 +- .../include/freetype/config/ftconfig.h | 2 +- .../include/freetype/config/ftheader.h | 2 +- .../include/freetype/config/ftoption.h | 18 +- .../include/freetype/config/ftstdlib.h | 2 +- .../include/freetype/config/integer-types.h | 2 +- .../include/freetype/config/mac-support.h | 2 +- .../include/freetype/config/public-macros.h | 2 +- .../libfreetype/include/freetype/freetype.h | 118 +- .../libfreetype/include/freetype/ftadvanc.h | 2 +- .../libfreetype/include/freetype/ftbbox.h | 2 +- .../libfreetype/include/freetype/ftbdf.h | 2 +- .../libfreetype/include/freetype/ftbitmap.h | 2 +- .../libfreetype/include/freetype/ftcid.h | 2 +- .../libfreetype/include/freetype/ftcolor.h | 2 +- .../libfreetype/include/freetype/ftdriver.h | 76 +- .../libfreetype/include/freetype/fterrdef.h | 2 +- .../libfreetype/include/freetype/fterrors.h | 2 +- .../libfreetype/include/freetype/ftfntfmt.h | 2 +- .../libfreetype/include/freetype/ftgasp.h | 2 +- .../libfreetype/include/freetype/ftglyph.h | 2 +- .../libfreetype/include/freetype/ftgzip.h | 2 +- .../libfreetype/include/freetype/ftimage.h | 29 +- .../libfreetype/include/freetype/ftincrem.h | 2 +- .../libfreetype/include/freetype/ftlcdfil.h | 2 +- .../libfreetype/include/freetype/ftlist.h | 2 +- .../libfreetype/include/freetype/ftlogging.h | 2 +- .../libfreetype/include/freetype/ftmac.h | 2 +- .../libfreetype/include/freetype/ftmm.h | 33 +- .../libfreetype/include/freetype/ftmodapi.h | 2 +- .../libfreetype/include/freetype/ftmoderr.h | 2 +- .../libfreetype/include/freetype/ftoutln.h | 4 +- .../libfreetype/include/freetype/ftparams.h | 2 +- .../libfreetype/include/freetype/ftrender.h | 2 +- .../libfreetype/include/freetype/ftsizes.h | 2 +- .../libfreetype/include/freetype/ftsnames.h | 2 +- .../libfreetype/include/freetype/ftstroke.h | 2 +- .../libfreetype/include/freetype/ftsynth.h | 2 +- .../libfreetype/include/freetype/ftsystem.h | 2 +- .../libfreetype/include/freetype/fttrigon.h | 2 +- .../libfreetype/include/freetype/fttypes.h | 2 +- .../include/freetype/internal/autohint.h | 2 +- .../include/freetype/internal/cffotypes.h | 2 +- .../include/freetype/internal/cfftypes.h | 10 +- .../freetype/internal/compiler-macros.h | 2 +- .../include/freetype/internal/ftcalc.h | 21 +- .../include/freetype/internal/ftdebug.h | 2 +- .../include/freetype/internal/ftdrv.h | 2 +- .../include/freetype/internal/ftgloadr.h | 2 +- .../include/freetype/internal/ftmemory.h | 9 +- .../include/freetype/internal/ftmmtypes.h | 2 +- .../include/freetype/internal/ftobjs.h | 8 +- .../include/freetype/internal/ftpsprop.h | 2 +- .../include/freetype/internal/ftrfork.h | 2 +- .../include/freetype/internal/ftserv.h | 2 +- .../include/freetype/internal/ftstream.h | 2 +- .../include/freetype/internal/fttrace.h | 3 +- .../include/freetype/internal/ftvalid.h | 2 +- .../include/freetype/internal/psaux.h | 21 +- .../include/freetype/internal/pshints.h | 2 +- .../freetype/internal/services/svbdf.h | 2 +- .../freetype/internal/services/svcfftl.h | 2 +- .../freetype/internal/services/svcid.h | 2 +- .../freetype/internal/services/svfntfmt.h | 2 +- .../freetype/internal/services/svgldict.h | 2 +- .../freetype/internal/services/svgxval.h | 2 +- .../freetype/internal/services/svkern.h | 2 +- .../freetype/internal/services/svmetric.h | 2 +- .../include/freetype/internal/services/svmm.h | 2 +- .../freetype/internal/services/svotval.h | 2 +- .../freetype/internal/services/svpfr.h | 2 +- .../freetype/internal/services/svpostnm.h | 2 +- .../freetype/internal/services/svprop.h | 2 +- .../freetype/internal/services/svpscmap.h | 2 +- .../freetype/internal/services/svpsinfo.h | 2 +- .../freetype/internal/services/svsfnt.h | 2 +- .../freetype/internal/services/svttcmap.h | 2 +- .../freetype/internal/services/svtteng.h | 2 +- .../freetype/internal/services/svttglyf.h | 2 +- .../freetype/internal/services/svwinfnt.h | 2 +- .../include/freetype/internal/sfnt.h | 9 +- .../include/freetype/internal/svginterface.h | 2 +- .../include/freetype/internal/t1types.h | 52 +- .../include/freetype/internal/tttypes.h | 12 +- .../include/freetype/internal/wofftypes.h | 2 +- .../libfreetype/include/freetype/otsvg.h | 2 +- .../libfreetype/include/freetype/t1tables.h | 60 +- .../libfreetype/include/freetype/ttnameid.h | 2 +- .../libfreetype/include/freetype/tttables.h | 7 +- .../libfreetype/include/freetype/tttags.h | 2 +- .../native/libfreetype/include/ft2build.h | 2 +- .../native/libfreetype/src/autofit/afblue.c | 2 +- .../native/libfreetype/src/autofit/afblue.cin | 2 +- .../native/libfreetype/src/autofit/afblue.dat | 2 +- .../native/libfreetype/src/autofit/afblue.h | 2 +- .../native/libfreetype/src/autofit/afblue.hin | 2 +- .../native/libfreetype/src/autofit/afcjk.c | 2 +- .../native/libfreetype/src/autofit/afcjk.h | 4 +- .../native/libfreetype/src/autofit/afcover.h | 2 +- .../native/libfreetype/src/autofit/afdummy.c | 2 +- .../native/libfreetype/src/autofit/afdummy.h | 2 +- .../native/libfreetype/src/autofit/aferrors.h | 2 +- .../native/libfreetype/src/autofit/afglobal.c | 2 +- .../native/libfreetype/src/autofit/afglobal.h | 2 +- .../native/libfreetype/src/autofit/afhints.c | 18 +- .../native/libfreetype/src/autofit/afhints.h | 2 +- .../native/libfreetype/src/autofit/afindic.c | 2 +- .../native/libfreetype/src/autofit/afindic.h | 2 +- .../native/libfreetype/src/autofit/aflatin.c | 9 +- .../native/libfreetype/src/autofit/aflatin.h | 4 +- .../native/libfreetype/src/autofit/afloader.c | 2 +- .../native/libfreetype/src/autofit/afloader.h | 2 +- .../native/libfreetype/src/autofit/afmodule.c | 4 +- .../native/libfreetype/src/autofit/afmodule.h | 2 +- .../native/libfreetype/src/autofit/afranges.c | 2 +- .../native/libfreetype/src/autofit/afranges.h | 2 +- .../native/libfreetype/src/autofit/afscript.h | 2 +- .../native/libfreetype/src/autofit/afshaper.c | 2 +- .../native/libfreetype/src/autofit/afshaper.h | 2 +- .../native/libfreetype/src/autofit/afstyles.h | 2 +- .../native/libfreetype/src/autofit/aftypes.h | 2 +- .../libfreetype/src/autofit/afws-decl.h | 2 +- .../libfreetype/src/autofit/afws-iter.h | 2 +- .../native/libfreetype/src/base/ftadvanc.c | 2 +- .../native/libfreetype/src/base/ftbase.h | 2 +- .../native/libfreetype/src/base/ftbbox.c | 4 +- .../native/libfreetype/src/base/ftbitmap.c | 2 +- .../native/libfreetype/src/base/ftcalc.c | 169 +- .../share/native/libfreetype/src/base/ftcid.c | 2 +- .../native/libfreetype/src/base/ftcolor.c | 2 +- .../native/libfreetype/src/base/ftdbgmem.c | 2 +- .../native/libfreetype/src/base/ftdebug.c | 2 +- .../native/libfreetype/src/base/ftfntfmt.c | 2 +- .../native/libfreetype/src/base/ftfstype.c | 2 +- .../native/libfreetype/src/base/ftgasp.c | 2 +- .../native/libfreetype/src/base/ftgloadr.c | 35 +- .../native/libfreetype/src/base/ftglyph.c | 2 +- .../native/libfreetype/src/base/ftinit.c | 2 +- .../native/libfreetype/src/base/ftlcdfil.c | 2 +- .../share/native/libfreetype/src/base/ftmac.c | 21 +- .../share/native/libfreetype/src/base/ftmm.c | 2 +- .../native/libfreetype/src/base/ftobjs.c | 9 +- .../native/libfreetype/src/base/ftoutln.c | 18 +- .../native/libfreetype/src/base/ftpatent.c | 2 +- .../native/libfreetype/src/base/ftpsprop.c | 2 +- .../native/libfreetype/src/base/ftrfork.c | 2 +- .../native/libfreetype/src/base/ftsnames.c | 2 +- .../native/libfreetype/src/base/ftstream.c | 8 +- .../native/libfreetype/src/base/ftstroke.c | 16 +- .../native/libfreetype/src/base/ftsynth.c | 2 +- .../native/libfreetype/src/base/ftsystem.c | 2 +- .../native/libfreetype/src/base/fttrigon.c | 2 +- .../native/libfreetype/src/base/fttype1.c | 2 +- .../native/libfreetype/src/base/ftutil.c | 2 +- .../native/libfreetype/src/cff/cffcmap.c | 2 +- .../native/libfreetype/src/cff/cffcmap.h | 2 +- .../native/libfreetype/src/cff/cffdrivr.c | 2 +- .../native/libfreetype/src/cff/cffdrivr.h | 2 +- .../native/libfreetype/src/cff/cfferrs.h | 2 +- .../native/libfreetype/src/cff/cffgload.c | 2 +- .../native/libfreetype/src/cff/cffgload.h | 2 +- .../native/libfreetype/src/cff/cffload.c | 77 +- .../native/libfreetype/src/cff/cffload.h | 2 +- .../native/libfreetype/src/cff/cffobjs.c | 95 +- .../native/libfreetype/src/cff/cffobjs.h | 2 +- .../native/libfreetype/src/cff/cffparse.c | 97 +- .../native/libfreetype/src/cff/cffparse.h | 3 +- .../native/libfreetype/src/cff/cfftoken.h | 74 +- .../native/libfreetype/src/cid/ciderrs.h | 2 +- .../native/libfreetype/src/cid/cidgload.c | 2 +- .../native/libfreetype/src/cid/cidgload.h | 2 +- .../native/libfreetype/src/cid/cidload.c | 41 +- .../native/libfreetype/src/cid/cidload.h | 2 +- .../native/libfreetype/src/cid/cidobjs.c | 2 +- .../native/libfreetype/src/cid/cidobjs.h | 2 +- .../native/libfreetype/src/cid/cidparse.c | 69 +- .../native/libfreetype/src/cid/cidparse.h | 2 +- .../native/libfreetype/src/cid/cidriver.c | 2 +- .../native/libfreetype/src/cid/cidriver.h | 2 +- .../native/libfreetype/src/cid/cidtoken.h | 2 +- .../native/libfreetype/src/psaux/afmparse.c | 2 +- .../native/libfreetype/src/psaux/afmparse.h | 2 +- .../native/libfreetype/src/psaux/cffdecode.c | 20 +- .../native/libfreetype/src/psaux/cffdecode.h | 2 +- .../native/libfreetype/src/psaux/psauxerr.h | 2 +- .../native/libfreetype/src/psaux/psauxmod.c | 2 +- .../native/libfreetype/src/psaux/psauxmod.h | 2 +- .../native/libfreetype/src/psaux/psblues.c | 48 +- .../native/libfreetype/src/psaux/psconv.c | 2 +- .../native/libfreetype/src/psaux/psconv.h | 2 +- .../share/native/libfreetype/src/psaux/psft.c | 16 +- .../share/native/libfreetype/src/psaux/psft.h | 8 +- .../native/libfreetype/src/psaux/psintrp.c | 27 +- .../native/libfreetype/src/psaux/psobjs.c | 46 +- .../native/libfreetype/src/psaux/psobjs.h | 2 +- .../native/libfreetype/src/psaux/t1cmap.c | 2 +- .../native/libfreetype/src/psaux/t1cmap.h | 2 +- .../native/libfreetype/src/psaux/t1decode.c | 2 +- .../native/libfreetype/src/psaux/t1decode.h | 2 +- .../native/libfreetype/src/pshinter/pshalgo.c | 10 +- .../native/libfreetype/src/pshinter/pshalgo.h | 2 +- .../native/libfreetype/src/pshinter/pshglob.c | 2 +- .../native/libfreetype/src/pshinter/pshglob.h | 2 +- .../native/libfreetype/src/pshinter/pshmod.c | 2 +- .../native/libfreetype/src/pshinter/pshmod.h | 2 +- .../libfreetype/src/pshinter/pshnterr.h | 2 +- .../native/libfreetype/src/pshinter/pshrec.c | 4 +- .../native/libfreetype/src/pshinter/pshrec.h | 2 +- .../native/libfreetype/src/psnames/psmodule.c | 2 +- .../native/libfreetype/src/psnames/psmodule.h | 2 +- .../native/libfreetype/src/psnames/psnamerr.h | 2 +- .../native/libfreetype/src/psnames/pstables.h | 2 +- .../native/libfreetype/src/raster/ftmisc.h | 23 +- .../native/libfreetype/src/raster/ftraster.c | 1868 ++++++----------- .../native/libfreetype/src/raster/ftraster.h | 2 +- .../native/libfreetype/src/raster/ftrend1.c | 2 +- .../native/libfreetype/src/raster/ftrend1.h | 2 +- .../native/libfreetype/src/raster/rasterrs.h | 2 +- .../native/libfreetype/src/sfnt/pngshim.c | 2 +- .../native/libfreetype/src/sfnt/pngshim.h | 2 +- .../native/libfreetype/src/sfnt/sfdriver.c | 17 +- .../native/libfreetype/src/sfnt/sfdriver.h | 2 +- .../native/libfreetype/src/sfnt/sferrors.h | 2 +- .../native/libfreetype/src/sfnt/sfobjs.c | 21 +- .../native/libfreetype/src/sfnt/sfobjs.h | 2 +- .../native/libfreetype/src/sfnt/sfwoff.c | 20 +- .../native/libfreetype/src/sfnt/sfwoff.h | 2 +- .../native/libfreetype/src/sfnt/sfwoff2.c | 54 +- .../native/libfreetype/src/sfnt/sfwoff2.h | 2 +- .../native/libfreetype/src/sfnt/ttcmap.c | 2 +- .../native/libfreetype/src/sfnt/ttcmap.h | 2 +- .../native/libfreetype/src/sfnt/ttcmapc.h | 2 +- .../native/libfreetype/src/sfnt/ttcolr.c | 38 +- .../native/libfreetype/src/sfnt/ttcolr.h | 2 +- .../native/libfreetype/src/sfnt/ttcpal.c | 2 +- .../native/libfreetype/src/sfnt/ttcpal.h | 2 +- .../native/libfreetype/src/sfnt/ttkern.c | 2 +- .../native/libfreetype/src/sfnt/ttkern.h | 2 +- .../native/libfreetype/src/sfnt/ttload.c | 4 +- .../native/libfreetype/src/sfnt/ttload.h | 2 +- .../share/native/libfreetype/src/sfnt/ttmtx.c | 2 +- .../share/native/libfreetype/src/sfnt/ttmtx.h | 2 +- .../native/libfreetype/src/sfnt/ttpost.c | 50 +- .../native/libfreetype/src/sfnt/ttpost.h | 2 +- .../native/libfreetype/src/sfnt/ttsbit.c | 2 +- .../native/libfreetype/src/sfnt/ttsbit.h | 2 +- .../native/libfreetype/src/sfnt/woff2tags.c | 2 +- .../native/libfreetype/src/sfnt/woff2tags.h | 2 +- .../native/libfreetype/src/smooth/ftgrays.c | 461 ++-- .../native/libfreetype/src/smooth/ftgrays.h | 2 +- .../native/libfreetype/src/smooth/ftsmerrs.h | 2 +- .../native/libfreetype/src/smooth/ftsmooth.c | 2 +- .../native/libfreetype/src/smooth/ftsmooth.h | 2 +- .../libfreetype/src/truetype/ttdriver.c | 17 +- .../libfreetype/src/truetype/ttdriver.h | 2 +- .../libfreetype/src/truetype/tterrors.h | 2 +- .../native/libfreetype/src/truetype/ttgload.c | 51 +- .../native/libfreetype/src/truetype/ttgload.h | 2 +- .../native/libfreetype/src/truetype/ttgxvar.c | 419 ++-- .../native/libfreetype/src/truetype/ttgxvar.h | 2 +- .../libfreetype/src/truetype/ttinterp.c | 16 +- .../libfreetype/src/truetype/ttinterp.h | 2 +- .../native/libfreetype/src/truetype/ttobjs.c | 52 +- .../native/libfreetype/src/truetype/ttobjs.h | 4 +- .../native/libfreetype/src/truetype/ttpload.c | 2 +- .../native/libfreetype/src/truetype/ttpload.h | 2 +- .../native/libfreetype/src/type1/t1afm.c | 2 +- .../native/libfreetype/src/type1/t1afm.h | 2 +- .../native/libfreetype/src/type1/t1driver.c | 10 +- .../native/libfreetype/src/type1/t1driver.h | 2 +- .../native/libfreetype/src/type1/t1errors.h | 2 +- .../native/libfreetype/src/type1/t1gload.c | 2 +- .../native/libfreetype/src/type1/t1gload.h | 2 +- .../native/libfreetype/src/type1/t1load.c | 28 +- .../native/libfreetype/src/type1/t1load.h | 2 +- .../native/libfreetype/src/type1/t1objs.c | 2 +- .../native/libfreetype/src/type1/t1objs.h | 2 +- .../native/libfreetype/src/type1/t1parse.c | 2 +- .../native/libfreetype/src/type1/t1parse.h | 2 +- .../native/libfreetype/src/type1/t1tokens.h | 2 +- 280 files changed, 2212 insertions(+), 2863 deletions(-) diff --git a/src/java.desktop/share/legal/freetype.md b/src/java.desktop/share/legal/freetype.md index 0ddbe9b1136..5df525e2f67 100644 --- a/src/java.desktop/share/legal/freetype.md +++ b/src/java.desktop/share/legal/freetype.md @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.13.2 +## The FreeType Project: Freetype v2.13.3 ### FreeType Notice @@ -21,23 +21,23 @@ which fits your needs best. ### FreeType License ``` -Copyright (C) 1996-2023 by David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2007-2023 by Dereg Clegg and Michael Toftdal. -Copyright (C) 1996-2023 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2022-2023 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and -Copyright (C) 2004-2023 by Masatake YAMATO and Redhat K.K. -Copyright (C) 2007-2023 by Derek Clegg and Michael Toftdal. -Copyright (C) 2003-2023 by Masatake YAMATO, Red Hat K.K., -Copyright (C) 1996-2023 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. -Copyright (C) 2007-2023 by David Turner. -Copyright (C) 2022-2023 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. -Copyright (C) 2007-2023 by Rahul Bhalerao , . -Copyright (C) 2008-2023 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. -Copyright (C) 2013-2023 by Google, Inc. -Copyright (C) 2019-2023 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2009-2023 by Oran Agra and Mickey Gabel. -Copyright (C) 2018-2023 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. -Copyright (C) 2004-2023 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. +Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2007-2024 by Dereg Clegg and Michael Toftdal. +Copyright (C) 1996-2024 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and +Copyright (C) 2004-2024 by Masatake YAMATO and Redhat K.K. +Copyright (C) 2007-2024 by Derek Clegg and Michael Toftdal. +Copyright (C) 2003-2024 by Masatake YAMATO, Red Hat K.K., +Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. +Copyright (C) 2007-2024 by David Turner. +Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. +Copyright (C) 2007-2024 by Rahul Bhalerao , . +Copyright (C) 2008-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. +Copyright (C) 2013-2024 by Google, Inc. +Copyright (C) 2019-2024 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2009-2024 by Oran Agra and Mickey Gabel. +Copyright (C) 2018-2024 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. +Copyright (C) 2004-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. The FreeType Project LICENSE @@ -559,7 +559,7 @@ Public License instead of this License. ``` --------------------------------- -The below license applies to the following files: +The below applies to the following file(s): libfreetype/src/psaux/psarrst.c libfreetype/src/psaux/psarrst.h libfreetype/src/psaux/psblues.c @@ -582,7 +582,7 @@ libfreetype/src/psaux/psstack.c libfreetype/src/psaux/psstack.h libfreetype/src/psaux/pstypes.h -Copyright 2006-2014 Adobe Systems Incorporated. +Copyright (C) 2006-2014 Adobe Systems Incorporated. This software, and all works of authorship, whether in source or object code form as indicated by the copyright notice(s) included @@ -618,12 +618,12 @@ and you accept them fully. ``` --------------------------------- -The below license applies to the following files: +The below applies to the following file(s): libfreetype/include/freetype/internal/fthash.h libfreetype/src/base/fthash.c -Copyright 2000 Computing Research Labs, New Mexico State University -Copyright 2001-2015 +Copyright (C) 2000 Computing Research Labs, New Mexico State University +Copyright (C) 2001-2015 Francesco Zappa Nardelli diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h index a85151699d0..0667493fec6 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h @@ -4,7 +4,7 @@ * * ANSI-specific configuration file (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h index e607bce15c5..f6ef2618ded 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h @@ -4,7 +4,7 @@ * * Build macros of the FreeType 2 library. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h index 4375c7a6ff3..d29a0a7cefb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h @@ -4,7 +4,7 @@ * * User-selectable configuration macros (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -757,6 +757,22 @@ FT_BEGIN_HEADER #endif + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning + * implementation (for TrueType fonts only). With this defined, FreeType + * is able to get kerning pair data from the GPOS 'kern' feature as well as + * legacy 'kern' tables; without this defined, FreeType will only be able + * to use legacy 'kern' tables. + * + * Note that FreeType does not support more advanced GPOS layout features; + * even the 'kern' feature implemented here doesn't handle more + * sophisticated kerning variants. Use a higher-level library like + * HarfBuzz instead for that. + */ +/* #define TT_CONFIG_OPTION_GPOS_KERNING */ + + /*************************************************************************/ /*************************************************************************/ /**** ****/ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h index f65148a902e..e17aa7b89d5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h @@ -5,7 +5,7 @@ * ANSI-specific library and header configuration file (specification * only). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h index 7258b508541..c27505ffc4b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h @@ -4,7 +4,7 @@ * * FreeType integer types definitions. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h index b77b96d5db8..07b6f915bd8 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h @@ -4,7 +4,7 @@ * * Mac/OS X support configuration header. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h index 23d0fa6a329..f56581a6ee7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h @@ -4,7 +4,7 @@ * * Define a set of compiler macros used in public FreeType headers. * - * Copyright (C) 2020-2023 by + * Copyright (C) 2020-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h index 92acf3794a7..58fc33dfe60 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h @@ -4,7 +4,7 @@ * * FreeType high-level API and common types (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1322,9 +1322,13 @@ FT_BEGIN_HEADER * FT_FACE_FLAG_KERNING :: * The face contains kerning information. If set, the kerning distance * can be retrieved using the function @FT_Get_Kerning. Otherwise the - * function always returns the vector (0,0). Note that FreeType - * doesn't handle kerning data from the SFNT 'GPOS' table (as present - * in many OpenType fonts). + * function always returns the vector (0,0). + * + * Note that for TrueType fonts only, FreeType supports both the 'kern' + * table and the basic, pair-wise kerning feature from the 'GPOS' table + * (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though FreeType does + * not support the more advanced GPOS layout features; use a library + * like HarfBuzz for those instead. * * FT_FACE_FLAG_FAST_GLYPHS :: * THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. @@ -3767,87 +3771,18 @@ FT_BEGIN_HEADER * pixels and use the @FT_PIXEL_MODE_LCD_V mode. * * FT_RENDER_MODE_SDF :: - * This mode corresponds to 8-bit, single-channel signed distance field - * (SDF) bitmaps. Each pixel in the SDF grid is the value from the - * pixel's position to the nearest glyph's outline. The distances are - * calculated from the center of the pixel and are positive if they are - * filled by the outline (i.e., inside the outline) and negative - * otherwise. Check the note below on how to convert the output values - * to usable data. + * The positive (unsigned) 8-bit bitmap values can be converted to the + * single-channel signed distance field (SDF) by subtracting 128, with + * the positive and negative results corresponding to the inside and + * the outside of a glyph contour, respectively. The distance units are + * arbitrarily determined by an adjustable @spread property. * * @note: - * The selected render mode only affects vector glyphs of a font. + * The selected render mode only affects scalable vector glyphs of a font. * Embedded bitmaps often have a different pixel mode like * @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them * into 8-bit pixmaps. * - * For @FT_RENDER_MODE_SDF the output bitmap buffer contains normalized - * distances that are packed into unsigned 8-bit values. To get pixel - * values in floating point representation use the following pseudo-C - * code for the conversion. - * - * ``` - * // Load glyph and render using FT_RENDER_MODE_SDF, - * // then use the output buffer as follows. - * - * ... - * FT_Byte buffer = glyph->bitmap->buffer; - * - * - * for pixel in buffer - * { - * // `sd` is the signed distance and `spread` is the current spread; - * // the default spread is 2 and can be changed. - * - * float sd = (float)pixel - 128.0f; - * - * - * // Convert to pixel values. - * sd = ( sd / 128.0f ) * spread; - * - * // Store `sd` in a buffer or use as required. - * } - * - * ``` - * - * FreeType has two rasterizers for generating SDF, namely: - * - * 1. `sdf` for generating SDF directly from glyph's outline, and - * - * 2. `bsdf` for generating SDF from rasterized bitmaps. - * - * Depending on the glyph type (i.e., outline or bitmap), one of the two - * rasterizers is chosen at runtime and used for generating SDFs. To - * force the use of `bsdf` you should render the glyph with any of the - * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and - * then re-render with `FT_RENDER_MODE_SDF`. - * - * There are some issues with stability and possible failures of the SDF - * renderers (specifically `sdf`). - * - * 1. The `sdf` rasterizer is sensitive to really small features (e.g., - * sharp turns that are less than 1~pixel) and imperfections in the - * glyph's outline, causing artifacts in the final output. - * - * 2. The `sdf` rasterizer has limited support for handling intersecting - * contours and *cannot* handle self-intersecting contours whatsoever. - * Self-intersection happens when a single connected contour - * intersects itself at some point; having these in your font - * definitely poses a problem to the rasterizer and cause artifacts, - * too. - * - * 3. Generating SDF for really small glyphs may result in undesirable - * output; the pixel grid (which stores distance information) becomes - * too coarse. - * - * 4. Since the output buffer is normalized, precision at smaller spreads - * is greater than precision at larger spread values because the - * output range of [0..255] gets mapped to a smaller SDF range. A - * spread of~2 should be sufficient in most cases. - * - * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, - * which is more stable than the `sdf` rasterizer in general. - * */ typedef enum FT_Render_Mode_ { @@ -4058,9 +3993,26 @@ FT_BEGIN_HEADER * out of the scope of this API function -- they can be implemented * through format-specific interfaces. * - * Kerning for OpenType fonts implemented in a 'GPOS' table is not - * supported; use @FT_HAS_KERNING to find out whether a font has data - * that can be extracted with `FT_Get_Kerning`. + * Note that, for TrueType fonts only, this can extract data from both + * the 'kern' table and the basic, pair-wise kerning feature from the + * GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though + * FreeType does not support the more advanced GPOS layout features; use + * a library like HarfBuzz for those instead. If a font has both a + * 'kern' table and kern features of a GPOS table, the 'kern' table will + * be used. + * + * Also note for right-to-left scripts, the functionality may differ for + * fonts with GPOS tables vs. 'kern' tables. For GPOS, right-to-left + * fonts typically use both a placement offset and an advance for pair + * positioning, which this API does not support, so it would output + * kerning values of zero; though if the right-to-left font used only + * advances in GPOS pair positioning, then this API could output kerning + * values for it, but it would use `left_glyph` to mean the first glyph + * for that case. Whereas 'kern' tables are always advance-only and + * always store the left glyph first. + * + * Use @FT_HAS_KERNING to find out whether a font has data that can be + * extracted with `FT_Get_Kerning`. */ FT_EXPORT( FT_Error ) FT_Get_Kerning( FT_Face face, @@ -5222,7 +5174,7 @@ FT_BEGIN_HEADER */ #define FREETYPE_MAJOR 2 #define FREETYPE_MINOR 13 -#define FREETYPE_PATCH 2 +#define FREETYPE_PATCH 3 /************************************************************************** diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h index 4560ded6dcb..85b8ba2554b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h @@ -4,7 +4,7 @@ * * Quick computation of advance widths (specification only). * - * Copyright (C) 2008-2023 by + * Copyright (C) 2008-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h index fc21740fc2b..12bbfa63a62 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h @@ -4,7 +4,7 @@ * * FreeType exact bbox computation (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h index e8ce6431285..6f63b0b1e78 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h index eb6b4b1eebe..df9d462652e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (specification). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h index ef229390224..96b2a90fc59 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information (specification). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * Dereg Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h index eae200fdf14..420720ddf22 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h @@ -4,7 +4,7 @@ * * FreeType's glyph color management (specification). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h index 7af7465bc76..1b7f539f5e2 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h @@ -4,7 +4,7 @@ * * FreeType API for controlling driver modules (specification only). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -817,6 +817,80 @@ FT_BEGIN_HEADER * 2.5 */ + + /************************************************************************** + * + * @property: + * spread + * + * @description: + * This property of the 'sdf' and 'bsdf' renderers defines how the signed + * distance field (SDF) is represented in the output bitmap. The output + * values are calculated as follows, '128 * ( SDF / spread + 1 )', with + * the result clamped to the 8-bit range [0..255]. Therefore, 'spread' + * is also the maximum euclidean distance from the edge after which the + * values are clamped. The spread is specified in pixels with the + * default value of 8. For accurate SDF texture mapping (interpolation), + * the spread should be large enough to accommodate the target grid unit. + * + * @example: + * The following example code demonstrates how to set the SDF spread + * (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_Int spread = 2; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "sdf", "spread", &spread ); + * ``` + * + * @note: + * FreeType has two rasterizers for generating SDF, namely: + * + * 1. `sdf` for generating SDF directly from glyph's outline, and + * + * 2. `bsdf` for generating SDF from rasterized bitmaps. + * + * Depending on the glyph type (i.e., outline or bitmap), one of the two + * rasterizers is chosen at runtime and used for generating SDFs. To + * force the use of `bsdf` you should render the glyph with any of the + * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and + * then re-render with `FT_RENDER_MODE_SDF`. + * + * There are some issues with stability and possible failures of the SDF + * renderers (specifically `sdf`). + * + * 1. The `sdf` rasterizer is sensitive to really small features (e.g., + * sharp turns that are less than 1~pixel) and imperfections in the + * glyph's outline, causing artifacts in the final output. + * + * 2. The `sdf` rasterizer has limited support for handling intersecting + * contours and *cannot* handle self-intersecting contours whatsoever. + * Self-intersection happens when a single connected contour + * intersects itself at some point; having these in your font + * definitely poses a problem to the rasterizer and cause artifacts, + * too. + * + * 3. Generating SDF for really small glyphs may result in undesirable + * output; the pixel grid (which stores distance information) becomes + * too coarse. + * + * 4. Since the output buffer is normalized, precision at smaller spreads + * is greater than precision at larger spread values because the + * output range of [0..255] gets mapped to a smaller SDF range. A + * spread of~2 should be sufficient in most cases. + * + * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, + * which is more stable than the `sdf` rasterizer in general. + * + * @since: + * 2.11 + */ + + /************************************************************************** * * @property: diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h index d59b3cc2da2..710ca91bbdd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h @@ -4,7 +4,7 @@ * * FreeType error codes (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h index 15ef3f76b59..27c0ece5c1c 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h @@ -4,7 +4,7 @@ * * FreeType error code handling (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h index c0018fc830c..7c8b0874a81 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h @@ -4,7 +4,7 @@ * * Support functions for font formats. * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h index d5f19add8f2..30e5a9bf82b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h @@ -4,7 +4,7 @@ * * Access of TrueType's 'gasp' table (specification). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h index 4658895f7a9..dc1eb8873ae 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h index 443ec29db1b..9516dc030ac 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h @@ -4,7 +4,7 @@ * * Gzip-compressed stream support. * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h index 6baa812560e..2b4b4ac60ae 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h @@ -5,7 +5,7 @@ * FreeType glyph image formats and default raster interface * (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,6 +21,11 @@ * Note: A 'raster' is simply a scan-line converter, used to render * `FT_Outline`s into `FT_Bitmap`s. * + * Note: This file can be used for `STANDALONE_` compilation of raster + * (B/W) and smooth (anti-aliased) renderers. Therefore, it must + * rely on standard variable types only instead of aliases in + * `fttypes.h`. + * */ @@ -318,7 +323,7 @@ FT_BEGIN_HEADER * * If bit~2 is set, bits 5-7 contain the drop-out mode (as defined in * the OpenType specification; the value is the same as the argument to - * the 'SCANMODE' instruction). + * the 'SCANTYPE' instruction). * * Bits 3 and~4 are reserved for internal purposes. * @@ -341,14 +346,14 @@ FT_BEGIN_HEADER */ typedef struct FT_Outline_ { - short n_contours; /* number of contours in glyph */ - short n_points; /* number of points in the glyph */ + unsigned short n_contours; /* number of contours in glyph */ + unsigned short n_points; /* number of points in the glyph */ - FT_Vector* points; /* the outline's points */ - char* tags; /* the points flags */ - short* contours; /* the contour end points */ + FT_Vector* points; /* the outline's points */ + unsigned char* tags; /* the points flags */ + unsigned short* contours; /* the contour end points */ - int flags; /* outline masks */ + int flags; /* outline masks */ } FT_Outline; @@ -356,8 +361,8 @@ FT_BEGIN_HEADER /* Following limits must be consistent with */ /* FT_Outline.{n_contours,n_points} */ -#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX -#define FT_OUTLINE_POINTS_MAX SHRT_MAX +#define FT_OUTLINE_CONTOURS_MAX USHRT_MAX +#define FT_OUTLINE_POINTS_MAX USHRT_MAX /************************************************************************** @@ -434,8 +439,8 @@ FT_BEGIN_HEADER * rasterizer; see the `tags` field in @FT_Outline. * * Please refer to the description of the 'SCANTYPE' instruction in the - * OpenType specification (in file `ttinst1.doc`) how simple drop-outs, - * smart drop-outs, and stubs are defined. + * [OpenType specification](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#scantype) + * how simple drop-outs, smart drop-outs, and stubs are defined. */ #define FT_OUTLINE_NONE 0x0 #define FT_OUTLINE_OWNER 0x1 diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h index 2d4f5def241..816581b78eb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h @@ -4,7 +4,7 @@ * * FreeType incremental loading (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h index d3723e16f67..25274dc4ac2 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h @@ -5,7 +5,7 @@ * FreeType API for color filtering of subpixel bitmap glyphs * (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h index b5531313359..972fbfa2fe4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h @@ -4,7 +4,7 @@ * * Generic list support for FreeType (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h index 53b8b896427..1813cfc2c27 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h @@ -4,7 +4,7 @@ * * Additional debugging APIs. * - * Copyright (C) 2020-2023 by + * Copyright (C) 2020-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h index a91e38f9ea7..e4efde33dd8 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h @@ -4,7 +4,7 @@ * * Additional Mac-specific API. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h index d145128a9bc..35ed039c89b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h @@ -4,7 +4,7 @@ * * FreeType Multiple Master font interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,13 @@ #ifndef FTMM_H_ #define FTMM_H_ +#include -#include +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif FT_BEGIN_HEADER @@ -53,6 +58,30 @@ FT_BEGIN_HEADER */ + /************************************************************************** + * + * @enum: + * T1_MAX_MM_XXX + * + * @description: + * Multiple Masters limits as defined in their specifications. + * + * @values: + * T1_MAX_MM_AXIS :: + * The maximum number of Multiple Masters axes. + * + * T1_MAX_MM_DESIGNS :: + * The maximum number of Multiple Masters designs. + * + * T1_MAX_MM_MAP_POINTS :: + * The maximum number of elements in a design map. + * + */ +#define T1_MAX_MM_AXIS 4 +#define T1_MAX_MM_DESIGNS 16 +#define T1_MAX_MM_MAP_POINTS 20 + + /************************************************************************** * * @struct: diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h index c8f0c2c2a45..0ee715898f7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h @@ -4,7 +4,7 @@ * * FreeType modules public interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h index c8c892dcce8..6722fbf8b70 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h @@ -4,7 +4,7 @@ * * FreeType module error offsets (specification). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h index f9329ca40c9..44e94b4f5bb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h @@ -5,7 +5,7 @@ * Support for the FT_Outline type used to store glyph shapes of * most scalable font formats (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -112,7 +112,7 @@ FT_BEGIN_HEADER * Degenerate contours, segments, and Bezier arcs may be reported. In * most cases, it is best to filter these out before using the outline * for stroking or other path modification purposes (which may cause - * degenerate segments to become non-degenrate and visible, like when + * degenerate segments to become non-degenerate and visible, like when * stroke caps are used or the path is otherwise outset). Some glyph * outlines may contain deliberate degenerate single points for mark * attachement. diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h index 6a9f243bc90..43bf69c202f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h @@ -4,7 +4,7 @@ * * FreeType API for possible FT_Parameter tags (specification only). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h index 0b6fad32e84..dc5018a1b54 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h @@ -4,7 +4,7 @@ * * FreeType renderer modules public interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h index 7bfb1aed4c2..4ef5c7955df 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h @@ -4,7 +4,7 @@ * * FreeType size objects management (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h index 9d5d22bb255..d5d5cd93103 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h index b3d90802a56..41626dc9d7b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h @@ -4,7 +4,7 @@ * * FreeType path stroker (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h index af90967dda0..43081b6c330 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h @@ -5,7 +5,7 @@ * FreeType synthesizing code for emboldening and slanting * (specification). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h index 3a08f4912c9..1eacb3af398 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h @@ -4,7 +4,7 @@ * * FreeType low-level system interface definition (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h index 294981a6f31..a5299e938d4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (specification). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h index 5b109f0c73c..27815143a64 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h @@ -4,7 +4,7 @@ * * FreeType simple types definitions (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h index bf9c8b7cf2a..8865d53b389 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h @@ -4,7 +4,7 @@ * * High-level 'autohint' module-specific interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h index 50d53538498..36b0390a5a5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h @@ -4,7 +4,7 @@ * * Basic OpenType/CFF object type definitions (specification). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h index c2521764caa..ef2e8e7569c 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h @@ -5,7 +5,7 @@ * Basic OpenType/CFF type definitions and interface (specification * only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -248,10 +248,10 @@ FT_BEGIN_HEADER FT_Byte num_family_blues; FT_Byte num_family_other_blues; - FT_Pos blue_values[14]; - FT_Pos other_blues[10]; - FT_Pos family_blues[14]; - FT_Pos family_other_blues[10]; + FT_Fixed blue_values[14]; + FT_Fixed other_blues[10]; + FT_Fixed family_blues[14]; + FT_Fixed family_other_blues[10]; FT_Fixed blue_scale; FT_Pos blue_shift; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h index 6f67650979e..876f66e2561 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h @@ -4,7 +4,7 @@ * * Compiler-specific macro definitions used internally by FreeType. * - * Copyright (C) 2020-2023 by + * Copyright (C) 2020-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h index d9aea236024..71128a2df90 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h @@ -4,7 +4,7 @@ * * Arithmetic computations (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -415,7 +415,7 @@ FT_BEGIN_HEADER #define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) -#elif defined( _M_ARM64 ) || defined( _M_ARM ) +#elif defined( _M_ARM64 ) || defined( _M_ARM ) || defined( _M_ARM64EC ) #include #pragma intrinsic( _CountLeadingZeros ) @@ -455,6 +455,12 @@ FT_BEGIN_HEADER #define FT_MSB( x ) FT_MSB_i386( x ) +#elif defined( __SunOS_5_11 ) + +#include + +#define FT_MSB( x ) ( fls( x ) - 1 ) + #elif defined( __DECC ) || defined( __DECCXX ) #include @@ -489,8 +495,6 @@ FT_BEGIN_HEADER FT_Fixed y ); -#if 0 - /************************************************************************** * * @function: @@ -507,12 +511,11 @@ FT_BEGIN_HEADER * The result of 'sqrt(x)'. * * @note: - * This function is not very fast. + * This function is slow and should be avoided. Consider @FT_Hypot or + * @FT_Vector_NormLen instead. */ - FT_BASE( FT_Int32 ) - FT_SqrtFixed( FT_Int32 x ); - -#endif /* 0 */ + FT_BASE( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 x ); #define INT_TO_F26DOT6( x ) ( (FT_Long)(x) * 64 ) /* << 6 */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h index 4e013ba1e26..d7fa8dc93cf 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h @@ -4,7 +4,7 @@ * * Debugging and logging component (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h index 9001c07ad0b..5609b3ef12b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h @@ -4,7 +4,7 @@ * * FreeType internal font driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h index 36e5509f9ea..f1c155b162c 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h @@ -4,7 +4,7 @@ * * The FreeType glyph loader (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h index 5eb1d21ff67..4e05a29f13a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h @@ -4,7 +4,7 @@ * * The FreeType memory management macros (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -371,8 +371,11 @@ extern "C++" #define FT_STRDUP( dst, str ) \ FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) -#define FT_MEM_DUP( dst, address, size ) \ - (dst) = ft_mem_dup( memory, (address), (FT_ULong)(size), &error ) +#define FT_MEM_DUP( dst, address, size ) \ + FT_ASSIGNP_INNER( dst, ft_mem_dup( memory, \ + (address), \ + (FT_ULong)(size), \ + &error ) ) #define FT_DUP( dst, address, size ) \ FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h index c4b21d6144e..8449e7a010d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h @@ -5,7 +5,7 @@ * OpenType Variations type definitions for internal use * with the multi-masters service (specification). * - * Copyright (C) 2022-2023 by + * Copyright (C) 2022-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and * Dominik Röttsches. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h index 28bc9b65f05..a1e93298fdb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h @@ -4,7 +4,7 @@ * * The FreeType private base classes (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -604,12 +604,6 @@ FT_BEGIN_HEADER #define FT_FACE_MEMORY( x ) FT_FACE( x )->memory #define FT_FACE_STREAM( x ) FT_FACE( x )->stream -#define FT_SIZE_FACE( x ) FT_SIZE( x )->face -#define FT_SLOT_FACE( x ) FT_SLOT( x )->face - -#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph -#define FT_FACE_SIZE( x ) FT_FACE( x )->size - /************************************************************************** * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h index 1d5b287ad20..4f11aa16ba1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h @@ -4,7 +4,7 @@ * * Get and set properties of PostScript drivers (specification). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h index e96459921ef..05c1d6c48b5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (specification). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * Masatake YAMATO and Redhat K.K. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h index 1e85d6d3856..8c35dbd7139 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h @@ -4,7 +4,7 @@ * * The FreeType services (specification only). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h index 88e19287c80..fd52f767ef7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h @@ -4,7 +4,7 @@ * * Stream handling (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h index 319fe56fd2d..42595a29ff3 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h @@ -4,7 +4,7 @@ * * Tracing handling (specification only). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -64,6 +64,7 @@ FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */ FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */ FT_TRACE_DEF( ttcpal ) /* color palette table (ttcpal.c) */ +FT_TRACE_DEF( ttgpos ) /* GPOS handler (ttgpos.c) */ FT_TRACE_DEF( ttsvg ) /* OpenType SVG table (ttsvg.c) */ FT_TRACE_DEF( ttkern ) /* kerning handler (ttkern.c) */ FT_TRACE_DEF( ttload ) /* basic TrueType tables (ttload.c) */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h index e98ee4e4737..a1312f2aba6 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h @@ -4,7 +4,7 @@ * * FreeType validation support (specification). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h index dfb1987f868..745d2cb56b7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h @@ -5,7 +5,7 @@ * Auxiliary functions and data structures related to PostScript fonts * (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -225,6 +225,7 @@ FT_BEGIN_HEADER typedef enum T1_FieldLocation_ { + T1_FIELD_LOCATION_NONE = 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_LOCATION_FONT_DICT, T1_FIELD_LOCATION_FONT_EXTRA, @@ -249,6 +250,7 @@ FT_BEGIN_HEADER /* structure type used to model object fields */ typedef struct T1_FieldRec_ { + FT_UInt len; /* field identifier length */ const char* ident; /* field identifier */ T1_FieldLocation location; T1_FieldType type; /* type of field */ @@ -273,8 +275,9 @@ FT_BEGIN_HEADER #define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, \ @@ -283,6 +286,7 @@ FT_BEGIN_HEADER #define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ (T1_Field_ParseFunc)_reader, \ 0, 0, \ @@ -292,8 +296,9 @@ FT_BEGIN_HEADER #define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _max, \ @@ -303,8 +308,9 @@ FT_BEGIN_HEADER #define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _max, 0, \ @@ -354,6 +360,13 @@ FT_BEGIN_HEADER #define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) +#define T1_FIELD_ZERO \ + { \ + 0, \ + NULL, T1_FIELD_LOCATION_NONE, T1_FIELD_TYPE_NONE, \ + NULL, 0, 0, 0, 0, 0 \ + } + /*************************************************************************/ /*************************************************************************/ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h index ededc4c72e7..dba6c7303fd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h @@ -6,7 +6,7 @@ * recorders (specification only). These are used to support native * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h index bf0c1dcc714..89e9c2e5de8 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h @@ -4,7 +4,7 @@ * * The FreeType BDF services (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h index 4a20498ee0c..3cb483c344f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h @@ -4,7 +4,7 @@ * * The FreeType CFF tables loader service (specification). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h index 06d0cb8fd62..8362cb8724d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h @@ -4,7 +4,7 @@ * * The FreeType CID font services (specification). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h index bc45e80568f..6b837e79fcd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h @@ -4,7 +4,7 @@ * * The FreeType font format service (specification only). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h index 6437abfbf2e..6126ec9ada4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h @@ -4,7 +4,7 @@ * * The FreeType glyph dictionary services (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h index 31016afe0d0..29cf5528189 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (specification). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h index bcabbc3e68f..ac1bc30c412 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h @@ -4,7 +4,7 @@ * * The FreeType Kerning service (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h index 167617ebb3d..8b3563b25ca 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h @@ -4,7 +4,7 @@ * * The FreeType services for metrics variations (specification). * - * Copyright (C) 2016-2023 by + * Copyright (C) 2016-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h index 7e76ab8324e..5288fadf375 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h @@ -4,7 +4,7 @@ * * The FreeType Multiple Masters and GX var services (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h index a4683cd5fb6..7aea7ec11f0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h @@ -4,7 +4,7 @@ * * The FreeType OpenType validation service (specification). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h index fd189c7de77..b2fac6d086b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h @@ -4,7 +4,7 @@ * * Internal PFR service functions (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h index 2b8f6dfecfb..d19f3adc6d5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h @@ -4,7 +4,7 @@ * * The FreeType PostScript name services (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h index 932ce32e03d..ba39c0dd4da 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h @@ -4,7 +4,7 @@ * * The FreeType property service (specification). * - * Copyright (C) 2012-2023 by + * Copyright (C) 2012-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h index 6e599f3aabe..d4908ee41aa 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h @@ -4,7 +4,7 @@ * * The FreeType PostScript charmap service (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h index 09c4cdccc53..2aadcdd02a1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h @@ -4,7 +4,7 @@ * * The FreeType PostScript info service (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h index f98df2ef5fe..9e0f4ff202e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h @@ -4,7 +4,7 @@ * * The FreeType SFNT table loading service (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h index 5f9eb02d665..250886bcc5d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h @@ -4,7 +4,7 @@ * * The FreeType TrueType/sfnt cmap extra information service. * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * Masatake YAMATO, Redhat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h index ad577cb2904..14967529a9a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h @@ -4,7 +4,7 @@ * * The FreeType TrueType engine query service (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h index ca6fff74444..f190b3985d0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h @@ -4,7 +4,7 @@ * * The FreeType TrueType glyph service. * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h index 002923f8c91..49f3fb7f775 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h @@ -4,7 +4,7 @@ * * The FreeType Windows FNT/FONT service (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h index a2d4e15baaf..35e4e73af02 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h @@ -4,7 +4,7 @@ * * High-level 'sfnt' driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -924,6 +924,7 @@ FT_BEGIN_HEADER /* this field was called `load_kerning' up to version 2.1.10 */ TT_Load_Table_Func load_kern; + TT_Load_Table_Func load_gpos; TT_Load_Table_Func load_gasp; TT_Load_Table_Func load_pclt; @@ -944,6 +945,8 @@ FT_BEGIN_HEADER /* new elements introduced after version 2.1.10 */ + TT_Face_GetKerningFunc get_gpos_kerning; + /* load the font directory, i.e., the offset table and */ /* the table directory */ TT_Load_Table_Func load_font_dir; @@ -1002,6 +1005,7 @@ FT_BEGIN_HEADER load_name_, \ free_name_, \ load_kern_, \ + load_gpos_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ @@ -1009,6 +1013,7 @@ FT_BEGIN_HEADER get_psname_, \ free_psnames_, \ get_kerning_, \ + get_gpos_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ @@ -1050,6 +1055,7 @@ FT_BEGIN_HEADER load_name_, \ free_name_, \ load_kern_, \ + load_gpos_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ @@ -1057,6 +1063,7 @@ FT_BEGIN_HEADER get_psname_, \ free_psnames_, \ get_kerning_, \ + get_gpos_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h index f464b2c0583..68c99efb10a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h @@ -4,7 +4,7 @@ * * Interface of ot-svg module (specification only). * - * Copyright (C) 2022-2023 by + * Copyright (C) 2022-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h index b9c94398fd1..1821ae5cc83 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h @@ -5,7 +5,7 @@ * Basic Type1/Type2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,7 +21,7 @@ #define T1TYPES_H_ -#include +#include #include #include #include @@ -137,6 +137,54 @@ FT_BEGIN_HEADER } CID_SubrsRec, *CID_Subrs; + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + + } PS_DesignMapRec, *PS_DesignMap; + + /* backward compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + + + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + + FT_ULong blend_bitflags; + + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + + /* since 2.3.0 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + + } PS_BlendRec, *PS_Blend; + + + /* backward compatible definition */ + typedef PS_BlendRec T1_Blend; + + /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h index b9788c7831e..7053e656a7e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType type definitions and interface (specification * only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -24,6 +24,7 @@ #include #include #include +#include "freetype/fttypes.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include @@ -1581,6 +1582,11 @@ FT_BEGIN_HEADER FT_UInt32 kern_avail_bits; FT_UInt32 kern_order_bits; +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + FT_Byte* gpos_table; + FT_Bool gpos_kerning_available; +#endif + #ifdef TT_CONFIG_OPTION_BDF TT_BDFRec bdf; #endif /* TT_CONFIG_OPTION_BDF */ @@ -1649,9 +1655,9 @@ FT_BEGIN_HEADER { FT_Memory memory; FT_UShort max_points; - FT_Short max_contours; + FT_UShort max_contours; FT_UShort n_points; /* number of points in zone */ - FT_Short n_contours; /* number of contours */ + FT_UShort n_contours; /* number of contours */ FT_Vector* org; /* original point coordinates */ FT_Vector* cur; /* current point coordinates */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h index 0c1d8eeaf8c..4a169d12f57 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h @@ -5,7 +5,7 @@ * Basic WOFF/WOFF2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h index bfe9a6ab74e..9d356938cc7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h @@ -4,7 +4,7 @@ * * Interface for OT-SVG support related things (specification). * - * Copyright (C) 2022-2023 by + * Copyright (C) 2022-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h index 1aecfbbd902..fbd558aa34d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h @@ -5,7 +5,7 @@ * Basic Type 1/Type 2 tables definitions and interface (specification * only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -269,64 +269,6 @@ FT_BEGIN_HEADER /* */ - /* maximum number of Multiple Masters designs, as defined in the spec */ -#define T1_MAX_MM_DESIGNS 16 - - /* maximum number of Multiple Masters axes, as defined in the spec */ -#define T1_MAX_MM_AXIS 4 - - /* maximum number of elements in a design map */ -#define T1_MAX_MM_MAP_POINTS 20 - - - /* this structure is used to store the BlendDesignMap entry for an axis */ - typedef struct PS_DesignMap_ - { - FT_Byte num_points; - FT_Long* design_points; - FT_Fixed* blend_points; - - } PS_DesignMapRec, *PS_DesignMap; - - /* backward compatible definition */ - typedef PS_DesignMapRec T1_DesignMap; - - - typedef struct PS_BlendRec_ - { - FT_UInt num_designs; - FT_UInt num_axis; - - FT_String* axis_names[T1_MAX_MM_AXIS]; - FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; - PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; - - FT_Fixed* weight_vector; - FT_Fixed* default_weight_vector; - - PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; - PS_Private privates [T1_MAX_MM_DESIGNS + 1]; - - FT_ULong blend_bitflags; - - FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; - - /* since 2.3.0 */ - - /* undocumented, optional: the default design instance; */ - /* corresponds to default_weight_vector -- */ - /* num_default_design_vector == 0 means it is not present */ - /* in the font and associated metrics files */ - FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; - FT_UInt num_default_design_vector; - - } PS_BlendRec, *PS_Blend; - - - /* backward compatible definition */ - typedef PS_BlendRec T1_Blend; - - /************************************************************************** * * @struct: diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h index e31c68b9baf..d5d470e380f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h @@ -4,7 +4,7 @@ * * TrueType name ID definitions (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h index a9f60e76201..2cf0ff1bc61 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType tables definitions and interface * (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -838,8 +838,9 @@ FT_BEGIN_HEADER * The target charmap. * * @return: - * The format of `charmap`. If `charmap` doesn't belong to an SFNT face, - * return -1. + * The format of `charmap`. If `charmap` doesn't belong to an SFNT face + * (including the synthetic Unicode charmap sometimes created by + * FreeType), return -1. */ FT_EXPORT( FT_Long ) FT_Get_CMap_Format( FT_CharMap charmap ); diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h index 9bf4fca23fb..da0af5d3f23 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h @@ -4,7 +4,7 @@ * * Tags for TrueType and OpenType tables (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/ft2build.h b/src/java.desktop/share/native/libfreetype/include/ft2build.h index 58491ceea1f..d3d7685039c 100644 --- a/src/java.desktop/share/native/libfreetype/include/ft2build.h +++ b/src/java.desktop/share/native/libfreetype/include/ft2build.h @@ -4,7 +4,7 @@ * * FreeType 2 build and setup macros. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c index d7655b9b99e..ea83969cdc9 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin index d561c5093b7..d2270fac744 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat index 8299baa2591..88bab2632ab 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat @@ -2,7 +2,7 @@ // // Auto-fitter data for blue strings. // -// Copyright (C) 2013-2023 by +// Copyright (C) 2013-2024 by // David Turner, Robert Wilhelm, and Werner Lemberg. // // This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h index 76f2f47cb00..2aa9d0984ef 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin index 6a31298e65f..38031505a85 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c index f414289adcd..869b60487c2 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (body). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h index f380ef6e032..bc5aaf12e6e 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -84,7 +84,7 @@ FT_BEGIN_HEADER /* used for horizontal metrics too for CJK */ FT_Bool control_overshoot; FT_UInt blue_count; - AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX]; + AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; FT_Fixed org_scale; FT_Pos org_delta; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h index 102ed427828..7980cf2e979 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h @@ -4,7 +4,7 @@ * * Auto-fitter coverages (specification only). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c index a4629b528dc..ad667d2edc7 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h index a7af3f62c9e..613c2f88a38 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h index 88faf05c950..ae584ff06db 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h @@ -4,7 +4,7 @@ * * Autofitter error codes (specification only). * - * Copyright (C) 2005-2023 by + * Copyright (C) 2005-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c index b1957570f03..b7403fa65e1 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to compute global hinting values (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h index 66170e419dd..ddb54c89b27 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h @@ -5,7 +5,7 @@ * Auto-fitter routines to compute global hinting values * (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c index e4a378fbf74..96ffe343aa4 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -979,8 +979,8 @@ /* compute coordinates & Bezier flags, next and prev */ { FT_Vector* vec = outline->points; - char* tag = outline->tags; - FT_Short endpoint = outline->contours[0]; + FT_Byte* tag = outline->tags; + FT_UShort endpoint = outline->contours[0]; AF_Point end = points + endpoint; AF_Point prev = end; FT_Int contour_index = 0; @@ -1046,16 +1046,16 @@ /* set up the contours array */ { - AF_Point* contour = hints->contours; - AF_Point* contour_limit = contour + hints->num_contours; - short* end = outline->contours; - short idx = 0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UShort* end = outline->contours; + FT_Int idx = 0; for ( ; contour < contour_limit; contour++, end++ ) { contour[0] = points + idx; - idx = (short)( end[0] + 1 ); + idx = *end + 1; } } @@ -1292,7 +1292,7 @@ AF_Point point = hints->points; AF_Point limit = point + hints->num_points; FT_Vector* vec = outline->points; - char* tag = outline->tags; + FT_Byte* tag = outline->tags; for ( ; point < limit; point++, vec++, tag++ ) diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h index d1cf9529bf1..76fe83006a5 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c index 7fb12c63d5a..c6d23efd86f 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for Indic writing system (body). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h index 3eb67f63b00..a7f73f25153 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for Indic writing system * (specification). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c index b86367aa94d..89287f7ea5a 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for latin writing system (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -981,7 +981,7 @@ /* `ref' and `shoot' values of two blue zones must not overlap */ FT_UInt i; - AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN + 2]; + AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN]; for ( i = 0; i < axis->blue_count; i++ ) @@ -1263,10 +1263,9 @@ max_height = FT_MAX( max_height, -Axis->blues[nn].descender ); } - dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) ); - dist &= ~127; + dist = FT_MulFix( max_height, new_scale - scale ); - if ( dist == 0 ) + if ( -128 < dist && dist < 128 ) { FT_TRACE5(( "af_latin_metrics_scale_dim:" " x height alignment (style `%s'):\n", diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h index 31aa91d3bdb..54e50615021 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for latin writing system * (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -98,7 +98,7 @@ FT_BEGIN_HEADER /* ignored for horizontal metrics */ FT_UInt blue_count; - AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]; + AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; FT_Fixed org_scale; FT_Pos org_delta; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c index 7c47d562af6..af1d59a6896 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h index e4e197e374f..99f0e15f92b 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c index 20a6b96bc4f..726f6ca2b78 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (body). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -438,7 +438,7 @@ AF_Module module = (AF_Module)module_; FT_Error error = FT_Err_Ok; - FT_Memory memory = module->root.library->memory; + FT_Memory memory = module->root.memory; #ifdef FT_DEBUG_AUTOFIT diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h index 4b8b4562c67..91a1abfef1f 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (specification). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c index cfcaf340a79..007b4328189 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (body). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h index 5775738bc0b..813b3ee78ef 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (specification). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h index 3a101937d70..0a83d771501 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h @@ -4,7 +4,7 @@ * * Auto-fitter scripts (specification only). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c index abc6f1d292d..df0f46ada89 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (body). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h index 054a18ffbc2..2eb03bb5d98 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (specification). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h index 73ebef01716..7a33f37a856 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h @@ -4,7 +4,7 @@ * * Auto-fitter styles (specification only). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h index 66151944965..27e4185e9f8 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h @@ -4,7 +4,7 @@ * * Auto-fitter types (specification only). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h index 48c888afed8..b78745af74e 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h @@ -4,7 +4,7 @@ * * Auto-fitter writing system declarations (specification only). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h index a0a686f8cee..c86d609a352 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h @@ -4,7 +4,7 @@ * * Auto-fitter writing systems iterator (specification only). * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c index de25476fe92..717f7d08b35 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c @@ -4,7 +4,7 @@ * * Quick computation of advance widths (body). * - * Copyright (C) 2008-2023 by + * Copyright (C) 2008-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h index 00790d3b226..1d98b26dd51 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h @@ -4,7 +4,7 @@ * * Private functions used in the `base' module (specification). * - * Copyright (C) 2008-2023 by + * Copyright (C) 2008-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c index 385fea40401..d6aa5d56df8 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c @@ -4,7 +4,7 @@ * * FreeType bbox computation (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -489,7 +489,7 @@ return FT_THROW( Invalid_Outline ); /* if outline is empty, return (0,0,0,0) */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) { abbox->xMin = abbox->xMax = 0; abbox->yMin = abbox->yMax = 0; diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c index 1c93648dcbc..4be145679fd 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (body). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c index c5bc7e3b14e..92de09ed877 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c @@ -4,7 +4,7 @@ * * Arithmetic computations (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -69,13 +69,15 @@ /* transfer sign, leaving a positive number; */ /* we need an unsigned value to safely negate INT_MIN (or LONG_MIN) */ -#define FT_MOVE_SIGN( x, x_unsigned, s ) \ - FT_BEGIN_STMNT \ - if ( x < 0 ) \ - { \ - x_unsigned = 0U - (x_unsigned); \ - s = -s; \ - } \ +#define FT_MOVE_SIGN( utype, x, x_unsigned, s ) \ + FT_BEGIN_STMNT \ + if ( x < 0 ) \ + { \ + x_unsigned = 0U - (utype)x; \ + s = -s; \ + } \ + else \ + x_unsigned = (utype)x; \ FT_END_STMNT /* The following three functions are available regardless of whether */ @@ -179,13 +181,9 @@ FT_Long d_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - c = (FT_UInt64)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); d = c > 0 ? ( a * b + ( c >> 1 ) ) / c : 0x7FFFFFFFUL; @@ -208,13 +206,9 @@ FT_Long d_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - c = (FT_UInt64)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); d = c > 0 ? a * b / c : 0x7FFFFFFFUL; @@ -257,11 +251,8 @@ FT_Long q_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); q = b > 0 ? ( ( a << 16 ) + ( b >> 1 ) ) / b : 0x7FFFFFFFUL; @@ -422,13 +413,9 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - c = (FT_UInt32)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); if ( c == 0 ) a = 0x7FFFFFFFUL; @@ -470,13 +457,9 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - c = (FT_UInt32)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); if ( c == 0 ) a = 0x7FFFFFFFUL; @@ -575,11 +558,8 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); if ( a + ( b >> 8 ) <= 8190UL ) a = ( a * b + 0x8000UL ) >> 16; @@ -614,11 +594,8 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); if ( b == 0 ) { @@ -829,11 +806,8 @@ FT_Int sx = 1, sy = 1, shift; - x = (FT_UInt32)x_; - y = (FT_UInt32)y_; - - FT_MOVE_SIGN( x_, x, sx ); - FT_MOVE_SIGN( y_, y, sy ); + FT_MOVE_SIGN( FT_UInt32, x_, x, sx ); + FT_MOVE_SIGN( FT_UInt32, y_, y, sy ); /* trivial cases */ if ( x == 0 ) @@ -913,44 +887,72 @@ } -#if 0 - /* documentation is in ftcalc.h */ - FT_BASE_DEF( FT_Int32 ) - FT_SqrtFixed( FT_Int32 x ) + FT_BASE_DEF( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 v ) { - FT_UInt32 root, rem_hi, rem_lo, test_div; - FT_Int count; + if ( v == 0 ) + return 0; +#ifndef FT_INT64 - root = 0; - - if ( x > 0 ) + /* Algorithm by Christophe Meessen (1993) with overflow fixed and */ + /* rounding added. Any unsigned fixed 16.16 argument is acceptable. */ + /* However, this algorithm is slower than the Babylonian method with */ + /* a good initial guess. We only use it for large 32-bit values when */ + /* 64-bit computations are not desirable. */ + else if ( v > 0x10000U ) { - rem_hi = 0; - rem_lo = (FT_UInt32)x; - count = 24; + FT_UInt32 r = v >> 1; + FT_UInt32 q = ( v & 1 ) << 15; + FT_UInt32 b = 0x20000000; + FT_UInt32 t; + + do { - rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 ); - rem_lo <<= 2; - root <<= 1; - test_div = ( root << 1 ) + 1; - - if ( rem_hi >= test_div ) + t = q + b; + if ( r >= t ) { - rem_hi -= test_div; - root += 1; + r -= t; + q = t + b; /* equivalent to q += 2*b */ } - } while ( --count ); + r <<= 1; + b >>= 1; + + } while ( b > 0x10 ); /* exactly 25 cycles */ + + return ( q + 0x40 ) >> 7; } + else + { + FT_UInt32 r = ( v << 16 ) - 1; - return (FT_Int32)root; +#else /* FT_INT64 */ + + else + { + FT_UInt64 r = ( (FT_UInt64)v << 16 ) - 1; + +#endif /* FT_INT64 */ + + FT_UInt32 q = 1 << ( ( 17 + FT_MSB( v ) ) >> 1 ); + FT_UInt32 t; + + + /* Babylonian method with rounded-up division */ + do + { + t = q; + q = ( t + (FT_UInt32)( r / t ) + 1 ) >> 1; + + } while ( q != t ); /* less than 6 cycles */ + + return q; + } } -#endif /* 0 */ - /* documentation is in ftcalc.h */ @@ -1094,11 +1096,8 @@ FT_UInt32 factor; - scalar = (FT_UInt32)s[i]; - factor = (FT_UInt32)f[i]; - - FT_MOVE_SIGN( s[i], scalar, sign ); - FT_MOVE_SIGN( f[i], factor, sign ); + FT_MOVE_SIGN( FT_UInt32, s[i], scalar, sign ); + FT_MOVE_SIGN( FT_UInt32, f[i], factor, sign ); ft_multo64( scalar, factor, &multResult ); diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c index 866cd23e91b..4f2deb19a05 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information. * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c index bcd6e893d4a..c6bf2a3cd1a 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c @@ -4,7 +4,7 @@ * * FreeType's glyph color management (body). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c index 8fab50dd017..902a5dc8bbc 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c @@ -4,7 +4,7 @@ * * Memory debugger (body). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c index 61c4563b0c4..11307eaace4 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c @@ -4,7 +4,7 @@ * * Debugging and logging component (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c index 0b41f7cc83d..77b4089e7e2 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c @@ -4,7 +4,7 @@ * * FreeType utility file for font formats (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c index ea24e64c6ea..1565c3b7e25 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c @@ -4,7 +4,7 @@ * * FreeType utility file to access FSType data (body). * - * Copyright (C) 2008-2023 by + * Copyright (C) 2008-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c index 29b7b08b787..c63d30e978c 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c @@ -4,7 +4,7 @@ * * Access of TrueType's `gasp' table (body). * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c index 9823d09e41a..484d98f1722 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c @@ -4,7 +4,7 @@ * * The FreeType glyph loader (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -355,34 +355,25 @@ FT_BASE_DEF( void ) FT_GlyphLoader_Add( FT_GlyphLoader loader ) { - FT_GlyphLoad base; - FT_GlyphLoad current; - - FT_Int n_curr_contours; - FT_Int n_base_points; - FT_Int n; + FT_Outline* base; + FT_Outline* current; + FT_Int n; if ( !loader ) return; - base = &loader->base; - current = &loader->current; - - n_curr_contours = current->outline.n_contours; - n_base_points = base->outline.n_points; - - base->outline.n_points = - (short)( base->outline.n_points + current->outline.n_points ); - base->outline.n_contours = - (short)( base->outline.n_contours + current->outline.n_contours ); - - base->num_subglyphs += current->num_subglyphs; + base = &loader->base.outline; + current = &loader->current.outline; /* adjust contours count in newest outline */ - for ( n = 0; n < n_curr_contours; n++ ) - current->outline.contours[n] = - (short)( current->outline.contours[n] + n_base_points ); + for ( n = 0; n < current->n_contours; n++ ) + current->contours[n] += base->n_points; + + base->n_points += current->n_points; + base->n_contours += current->n_contours; + + loader->base.num_subglyphs += loader->current.num_subglyphs; /* prepare for another new glyph image */ FT_GlyphLoader_Prepare( loader ); diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c index 393d4949f84..1b5849f99af 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c index c9c71d24bf9..9a6c00e13ef 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c @@ -4,7 +4,7 @@ * * FreeType initialization layer (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c index 6c3fd66e0bb..1e69d4da70f 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c @@ -4,7 +4,7 @@ * * FreeType API for color filtering of subpixel bitmap glyphs (body). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c index 492d0553845..e8e35627b50 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c @@ -8,7 +8,7 @@ * This file is for Mac OS X only; see builds/mac/ftoldmac.c for * classic platforms built by MPW. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -812,6 +812,7 @@ ResourceIndex res_index; Handle fond; short num_faces_in_res; + FT_Long count; if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) @@ -821,8 +822,10 @@ if ( ResError() ) return FT_THROW( Cannot_Open_Resource ); + res_index = 1; num_faces_in_res = 0; - for ( res_index = 1; ; res_index++ ) + count = face_index; + while ( count >= 0 ) { short num_faces_in_fond; @@ -834,15 +837,21 @@ num_faces_in_fond = count_faces( fond, pathname ); num_faces_in_res += num_faces_in_fond; - if ( 0 <= face_index && face_index < num_faces_in_fond && error ) - error = FT_New_Face_From_FOND( library, fond, face_index, aface ); + if ( count < num_faces_in_fond ) + error = FT_New_Face_From_FOND( library, fond, count, aface ); - face_index -= num_faces_in_fond; + res_index++; + count -= num_faces_in_fond; } CloseResFile( res_ref ); + if ( !error && aface && *aface ) - (*aface)->num_faces = num_faces_in_res; + { + (*aface)->num_faces = num_faces_in_res; + (*aface)->face_index = face_index; + } + return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c index 9e2dd7ee79d..cc4ca22fba3 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c @@ -4,7 +4,7 @@ * * Multiple Master font support (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c index 89a25bc732d..9b97820c379 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c @@ -4,7 +4,7 @@ * * The FreeType private base classes (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -2302,7 +2302,10 @@ face_index_internal, aface ); FT_FREE( data_offsets ); if ( !error ) - (*aface)->num_faces = count; + { + (*aface)->num_faces = count; + (*aface)->face_index = face_index_internal; + } } return error; @@ -5791,7 +5794,7 @@ ttface = (TT_Face)face; sfnt = (SFNT_Service)ttface->sfnt; - if ( sfnt->get_colr_layer ) + if ( sfnt->get_colr_glyph_paint ) return sfnt->get_colr_glyph_paint( ttface, base_glyph, root_transform, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c index 134f39d2b1f..ef699b3c7cd 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c @@ -4,7 +4,7 @@ * * FreeType outline management (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -53,7 +53,7 @@ FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; FT_Error error; @@ -332,8 +332,8 @@ FT_NEW_ARRAY( anoutline->contours, numContours ) ) goto Fail; - anoutline->n_points = (FT_Short)numPoints; - anoutline->n_contours = (FT_Short)numContours; + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_UShort)numContours; anoutline->flags |= FT_OUTLINE_OWNER; return FT_Err_Ok; @@ -359,12 +359,14 @@ FT_Int n; + FT_TRACE5(( "FT_Outline_Check: contours = %d, points = %d\n", + n_contours, n_points )); /* empty glyph? */ if ( n_points == 0 && n_contours == 0 ) return FT_Err_Ok; /* check point and contour counts */ - if ( n_points <= 0 || n_contours <= 0 ) + if ( n_points == 0 || n_contours == 0 ) goto Bad; end0 = -1; @@ -576,13 +578,13 @@ /* reverse tags table */ { - char* p = outline->tags + first; - char* q = outline->tags + last; + FT_Byte* p = outline->tags + first; + FT_Byte* q = outline->tags + last; while ( p < q ) { - char swap; + FT_Byte swap; swap = *p; diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c index cb5efadffb1..2055757e023 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c @@ -5,7 +5,7 @@ * FreeType API for checking patented TrueType bytecode instructions * (body). Obsolete, retained for backward compatibility. * - * Copyright (C) 2007-2023 by + * Copyright (C) 2007-2024 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c index cefdf489d7f..37a6cee6cc9 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c @@ -5,7 +5,7 @@ * Get and set properties of PostScript drivers (body). * See `ftdriver.h' for available properties. * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c index 2ab430195f2..dc9b043d8bb 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (body). * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * Masatake YAMATO and Redhat K.K. * * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c index 1917a3f1dff..f7231fd61cc 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c index 64826acebe5..66722246128 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c @@ -4,7 +4,7 @@ * * I/O stream support (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -763,10 +763,10 @@ case ft_frame_bytes: /* read a byte sequence */ case ft_frame_skip: /* skip some bytes */ { - FT_UInt len = fields->size; + FT_Offset len = fields->size; - if ( cursor + len > stream->limit ) + if ( len > (FT_Offset)( stream->limit - cursor ) ) { error = FT_THROW( Invalid_Stream_Operation ); goto Exit; @@ -830,7 +830,7 @@ goto Exit; } - /* now, compute the signed value is necessary */ + /* now, compute the signed value if necessary */ if ( fields->value & FT_FRAME_OP_SIGNED ) value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c index 92f1e43080f..64f46ce43e7 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c @@ -4,7 +4,7 @@ * * FreeType path stroker (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -711,7 +711,7 @@ { FT_UInt count = border->num_points; FT_Byte* read = border->tags; - FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* write = outline->tags + outline->n_points; for ( ; count > 0; count--, read++, write++ ) @@ -727,10 +727,10 @@ /* copy contours */ { - FT_UInt count = border->num_points; - FT_Byte* tags = border->tags; - FT_Short* write = outline->contours + outline->n_contours; - FT_Short idx = (FT_Short)outline->n_points; + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_UShort* write = outline->contours + outline->n_contours; + FT_UShort idx = outline->n_points; for ( ; count > 0; count--, tags++, idx++ ) @@ -743,7 +743,7 @@ } } - outline->n_points += (short)border->num_points; + outline->n_points += (FT_UShort)border->num_points; FT_ASSERT( FT_Outline_Check( outline ) == 0 ); } @@ -2050,7 +2050,7 @@ FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; FT_Error error; diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c index f32edd3388b..ec05bce33a9 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c @@ -4,7 +4,7 @@ * * FreeType synthesizing code for emboldening and slanting (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c index 61c99e36357..eee3642334f 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c @@ -4,7 +4,7 @@ * * ANSI-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c index 2dd2c3459e5..4b1aced1cba 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c +++ b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (body). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c index 637c5cf775e..cedf7c40505 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c +++ b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c @@ -4,7 +4,7 @@ * * FreeType utility file for PS names support (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c index 6120846d2ca..b13512f8704 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c @@ -4,7 +4,7 @@ * * FreeType utility file for memory and list management (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c index 10d287bc81f..ea5f8ed2885 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h index b2afc2fab62..1dd8700cd8b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c index 9898d625ca4..f6ebdb3810a 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c @@ -4,7 +4,7 @@ * * OpenType font driver implementation (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h index ab1f147bb2a..fd5bc37ecd4 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h @@ -4,7 +4,7 @@ * * High-level OpenType driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h index bc9a3043fcf..128adc3b716 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h @@ -4,7 +4,7 @@ * * CFF error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c index c483d1d1a59..cbb071abdfe 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h index 3b8cf236ddc..346d4b11c31 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c index af79082e98c..979fd45f6ca 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c @@ -4,7 +4,7 @@ * * OpenType and CFF data/program tables loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1202,17 +1202,21 @@ { CFF_AxisCoords* axis = ®ion->axisList[j]; - FT_Int16 start14, peak14, end14; + FT_Int start, peak, end; - if ( FT_READ_SHORT( start14 ) || - FT_READ_SHORT( peak14 ) || - FT_READ_SHORT( end14 ) ) + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) goto Exit; - axis->startCoord = FT_fdot14ToFixed( start14 ); - axis->peakCoord = FT_fdot14ToFixed( peak14 ); - axis->endCoord = FT_fdot14ToFixed( end14 ); + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; + + axis->startCoord = FT_fdot14ToFixed( start ); + axis->peakCoord = FT_fdot14ToFixed( peak ); + axis->endCoord = FT_fdot14ToFixed( end ); } } @@ -1379,10 +1383,10 @@ /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */ /* decode of this, which rounds to an integer. */ *subFont->blend_top++ = 255; - *subFont->blend_top++ = (FT_Byte)( sum >> 24 ); - *subFont->blend_top++ = (FT_Byte)( sum >> 16 ); - *subFont->blend_top++ = (FT_Byte)( sum >> 8 ); - *subFont->blend_top++ = (FT_Byte)sum; + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 24 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 16 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 8 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum ); } /* leave only numBlends results on parser stack */ @@ -1495,44 +1499,31 @@ for ( j = 0; j < lenNDV; j++ ) { CFF_AxisCoords* axis = &varRegion->axisList[j]; - FT_Fixed axisScalar; - /* compute the scalar contribution of this axis; */ - /* ignore invalid ranges */ - if ( axis->startCoord > axis->peakCoord || - axis->peakCoord > axis->endCoord ) - axisScalar = FT_FIXED_ONE; - - else if ( axis->startCoord < 0 && - axis->endCoord > 0 && - axis->peakCoord != 0 ) - axisScalar = FT_FIXED_ONE; - - /* peak of 0 means ignore this axis */ - else if ( axis->peakCoord == 0 ) - axisScalar = FT_FIXED_ONE; + /* compute the scalar contribution of this axis */ + /* with peak of 0 used for invalid axes */ + if ( axis->peakCoord == NDV[j] || + axis->peakCoord == 0 ) + continue; /* ignore this region if coords are out of range */ - else if ( NDV[j] < axis->startCoord || - NDV[j] > axis->endCoord ) - axisScalar = 0; - - /* calculate a proportional factor */ - else + else if ( NDV[j] <= axis->startCoord || + NDV[j] >= axis->endCoord ) { - if ( NDV[j] == axis->peakCoord ) - axisScalar = FT_FIXED_ONE; - else if ( NDV[j] < axis->peakCoord ) - axisScalar = FT_DivFix( NDV[j] - axis->startCoord, - axis->peakCoord - axis->startCoord ); - else - axisScalar = FT_DivFix( axis->endCoord - NDV[j], - axis->endCoord - axis->peakCoord ); + blend->BV[master] = 0; + break; } - /* take product of all the axis scalars */ - blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar ); + /* adjust proportionally */ + else if ( NDV[j] < axis->peakCoord ) + blend->BV[master] = FT_MulDiv( blend->BV[master], + NDV[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* NDV[j] > axis->peakCoord ) */ + blend->BV[master] = FT_MulDiv( blend->BV[master], + axis->endCoord - NDV[j], + axis->endCoord - axis->peakCoord ); } FT_TRACE4(( ", %f ", diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h index b5286b0c8cb..02209245421 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h @@ -4,7 +4,7 @@ * * OpenType & CFF data/program tables loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c index 6d08620c487..7c6713739a1 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c @@ -4,7 +4,7 @@ * * OpenType objects manager (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -42,6 +42,8 @@ #include #include +#define CFF_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) /************************************************************************** * @@ -124,19 +126,20 @@ count = priv->num_blue_values = cpriv->num_blue_values; for ( n = 0; n < count; n++ ) - priv->blue_values[n] = (FT_Short)cpriv->blue_values[n]; + priv->blue_values[n] = CFF_fixedToInt( cpriv->blue_values[n] ); count = priv->num_other_blues = cpriv->num_other_blues; for ( n = 0; n < count; n++ ) - priv->other_blues[n] = (FT_Short)cpriv->other_blues[n]; + priv->other_blues[n] = CFF_fixedToInt( cpriv->other_blues[n] ); count = priv->num_family_blues = cpriv->num_family_blues; for ( n = 0; n < count; n++ ) - priv->family_blues[n] = (FT_Short)cpriv->family_blues[n]; + priv->family_blues[n] = CFF_fixedToInt( cpriv->family_blues[n] ); count = priv->num_family_other_blues = cpriv->num_family_other_blues; for ( n = 0; n < count; n++ ) - priv->family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n]; + priv->family_other_blues[n] = + CFF_fixedToInt( cpriv->family_other_blues[n] ); priv->blue_scale = cpriv->blue_scale; priv->blue_shift = (FT_Int)cpriv->blue_shift; @@ -421,32 +424,23 @@ static void remove_subset_prefix( FT_String* name ) { - FT_Int32 idx = 0; - FT_Int32 length = (FT_Int32)ft_strlen( name ) + 1; - FT_Bool continue_search = 1; + FT_UInt32 i = 0, idx = 0; - while ( continue_search ) + /* six ASCII uppercase letters followed by a plus sign */ + while ( 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + name[i++] == '+' ) { - if ( length >= 7 && name[6] == '+' ) - { - for ( idx = 0; idx < 6; idx++ ) - { - /* ASCII uppercase letters */ - if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) ) - continue_search = 0; - } - - if ( continue_search ) - { - for ( idx = 7; idx < length; idx++ ) - name[idx - 7] = name[idx]; - length -= 7; - } - } - else - continue_search = 0; + idx = i; } + + if ( idx ) + FT_MEM_MOVE( name, name + idx, ft_strlen( name + idx ) + 1 ); } @@ -456,42 +450,20 @@ remove_style( FT_String* family_name, const FT_String* style_name ) { - FT_Int32 family_name_length, style_name_length; + FT_String* f = family_name + ft_strlen( family_name ); + const FT_String* s = style_name + ft_strlen( style_name ); - family_name_length = (FT_Int32)ft_strlen( family_name ); - style_name_length = (FT_Int32)ft_strlen( style_name ); + /* compare strings moving backwards */ + while ( s > style_name ) + if ( f == family_name || *--s != *--f ) + return; - if ( family_name_length > style_name_length ) - { - FT_Int idx; - - - for ( idx = 1; idx <= style_name_length; idx++ ) - { - if ( family_name[family_name_length - idx] != - style_name[style_name_length - idx] ) - break; - } - - if ( idx > style_name_length ) - { - /* family_name ends with style_name; remove it */ - idx = family_name_length - style_name_length - 1; - - /* also remove special characters */ - /* between real family name and style */ - while ( idx > 0 && - ( family_name[idx] == '-' || - family_name[idx] == ' ' || - family_name[idx] == '_' || - family_name[idx] == '+' ) ) - idx--; - - if ( idx > 0 ) - family_name[idx + 1] = '\0'; - } - } + /* terminate and remove special characters */ + do + *f = '\0'; + while ( f-- > family_name && + ( *f == '-' || *f == ' ' || *f == '_' || *f == '+' ) ); } @@ -722,8 +694,7 @@ FT_UInt instance_index = (FT_UInt)face_index >> 16; - if ( FT_HAS_MULTIPLE_MASTERS( cffface ) && - instance_index > 0 ) + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) ) { error = FT_Set_Named_Instance( cffface, instance_index ); if ( error ) diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h index 8f05f6132bc..91ad83b1cd0 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h @@ -4,7 +4,7 @@ * * OpenType objects manager (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c index 3b076704cf7..92a69c3b516 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c @@ -4,7 +4,7 @@ * * CFF token stream parser (body) * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -501,10 +501,10 @@ return cff_parse_real( *d, parser->limit, scaling, NULL ); else if ( **d == 255 ) { - FT_Fixed val = ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | - ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | - ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | - (FT_UInt32)*( d[0] + 4 ) ) ); + FT_Fixed val = (FT_Int32)( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) ); if ( scaling ) { @@ -1031,10 +1031,14 @@ CFF_FIELD( code, name, id, cff_kind_string ) #define CFF_FIELD_BOOL( code, name, id ) \ CFF_FIELD( code, name, id, cff_kind_bool ) +#define CFF_FIELD_DELTA( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta ) +#define CFF_FIELD_DELTA_FIXED( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta_fixed ) #undef CFF_FIELD -#undef CFF_FIELD_DELTA +#undef CFF_FIELD_DELTA_KIND #ifndef FT_DEBUG_LEVEL_TRACE @@ -1064,18 +1068,18 @@ code | CFFCODE, \ FT_FIELD_OFFSET( name ), \ FT_FIELD_SIZE( name ), \ - 0, 0, 0 \ + NULL, 0, 0 \ }, -#define CFF_FIELD_DELTA( code, name, max, id ) \ - { \ - cff_kind_delta, \ - code | CFFCODE, \ - FT_FIELD_OFFSET( name ), \ - FT_FIELD_SIZE_DELTA( name ), \ - 0, \ - max, \ - FT_FIELD_OFFSET( num_ ## name ) \ +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ }, static const CFF_Field_Handler cff_field_handlers[] = @@ -1083,7 +1087,7 @@ #include "cfftoken.h" - { 0, 0, 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, NULL, 0, 0 } }; @@ -1117,20 +1121,20 @@ code | CFFCODE, \ FT_FIELD_OFFSET( name ), \ FT_FIELD_SIZE( name ), \ - 0, 0, 0, \ + NULL, 0, 0, \ id \ }, -#define CFF_FIELD_DELTA( code, name, max, id ) \ - { \ - cff_kind_delta, \ - code | CFFCODE, \ - FT_FIELD_OFFSET( name ), \ - FT_FIELD_SIZE_DELTA( name ), \ - 0, \ - max, \ - FT_FIELD_OFFSET( num_ ## name ), \ - id \ +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ), \ + id \ }, static const CFF_Field_Handler cff_field_handlers[] = @@ -1138,7 +1142,7 @@ #include "cfftoken.h" - { 0, 0, 0, 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, NULL, 0, 0, NULL } }; @@ -1356,7 +1360,8 @@ /* check that we have enough arguments -- except for */ /* delta encoded arrays, which can be empty */ - if ( field->kind != cff_kind_delta && num_args < 1 ) + if ( field->kind != cff_kind_delta && + field->kind != cff_kind_delta_fixed && num_args < 1 ) goto Stack_Underflow; switch ( field->kind ) @@ -1471,6 +1476,38 @@ } break; + case cff_kind_delta_fixed: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + + FT_Byte** data = parser->stack; + + + if ( num_args > field->array_max ) + num_args = field->array_max; + + FT_TRACE4(( " [" )); + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val = ADD_LONG( val, cff_parse_fixed( parser, data++ ) ); + *(FT_Long*)q = val; + + FT_TRACE4(( " %f\n", (double)val / 65536 )); + + q += field->size; + num_args--; + } + + FT_TRACE4(( "]\n" )); + } + break; + default: /* callback or blend */ error = field->reader( parser ); if ( error ) diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h index 418caacc68c..ca6b18af6aa 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h @@ -4,7 +4,7 @@ * * CFF token stream parser (specification) * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -107,6 +107,7 @@ FT_BEGIN_HEADER cff_kind_string, cff_kind_bool, cff_kind_delta, + cff_kind_delta_fixed, cff_kind_callback, cff_kind_blend, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h index b61cb0e66e8..da45faa7f4e 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h @@ -4,7 +4,7 @@ * * CFF token definitions (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -80,26 +80,26 @@ #undef CFFCODE #define CFFCODE CFF_CODE_PRIVATE - CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) - CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) - CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) - CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) - CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) - CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) - CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) - CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) - CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) - CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) - CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) - CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) - CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) - CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) - CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) - CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) - CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) - CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) - CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) - CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) + CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) + CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) + CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) #undef FT_STRUCTURE @@ -129,22 +129,22 @@ #undef CFFCODE #define CFFCODE CFF2_CODE_PRIVATE - CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) - CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) - CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) - CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) - CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) - CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) - CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) - CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) - CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) - CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) - CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) - CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) - CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) - CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) - CFF_FIELD_BLEND ( 23, "blend" ) - CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) + CFF_FIELD_BLEND ( 23, "blend" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) /* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h index 40a1097d0ac..c439a8c4a0b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h @@ -4,7 +4,7 @@ * * CID error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c index eaca765ad06..7b571322d45 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 Glyph Loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h index edd6229234c..9fdc9db5892 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c index a7da8ea39d5..722f5a34ddf 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -388,7 +388,7 @@ T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) - { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + T1_FIELD_ZERO }; @@ -469,36 +469,23 @@ T1_Field keyword = (T1_Field)cid_field_records; - for (;;) + while ( keyword->len ) { - FT_Byte* name; + FT_Byte* name = (FT_Byte*)keyword->ident; - name = (FT_Byte*)keyword->ident; - if ( !name ) - break; - - if ( cur[0] == name[0] && - len == ft_strlen( (const char*)name ) ) + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) { - FT_UInt n; - - - for ( n = 1; n < len; n++ ) - if ( cur[n] != name[n] ) - break; - - if ( n >= len ) - { - /* we found it - run the parsing callback */ - parser->root.error = cid_load_keyword( face, - loader, - keyword ); - if ( parser->root.error ) - return parser->root.error; - break; - } + /* we found it - run the parsing callback */ + parser->root.error = cid_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; } + keyword++; } } diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h index d12d2962a68..7f030b32df7 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c index f698a419289..8d337c41128 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c @@ -4,7 +4,7 @@ * * CID objects manager (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h index 83c0c61c3ca..d371cbe9954 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h @@ -4,7 +4,7 @@ * * CID objects manager (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c index 171a886215a..73a3ade893b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -90,10 +90,15 @@ if ( error ) goto Exit; - Again: - /* now, read the rest of the file until we find */ - /* `StartData' or `/sfnts' */ + if ( !stream->read ) { + /* just parse memory-based streams */ + offset = stream->size; + } + else { + /* Find the last `StartData` or `/sfnts`. The parser requires */ + /* contiguous memory; attempt to pin as little as necessary. */ + /* * The algorithm is as follows (omitting the case with less than 256 * bytes to fill for simplicity). @@ -119,7 +124,8 @@ FT_Byte* p = buffer; - for ( offset = FT_STREAM_POS(); ; offset += 256 ) + offset = 0; + while ( 1 ) { FT_ULong stream_len; @@ -127,7 +133,7 @@ stream_len = stream->size - FT_STREAM_POS(); read_len = FT_MIN( read_len, stream_len ); - if ( FT_STREAM_READ( p, read_len ) ) + if ( read_len && FT_STREAM_READ( p, read_len ) ) goto Exit; /* ensure that we do not compare with data beyond the buffer */ @@ -141,20 +147,23 @@ ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) { /* save offset of binary data after `StartData' */ - offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; - goto Found; + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; } else if ( p[1] == 's' && ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) { - offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; - goto Found; + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; } } - if ( read_offset + read_len < STARTDATA_LEN ) + if ( read_offset + read_len <= STARTDATA_LEN ) { - FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); + if ( offset ) + goto Found; + + FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -171,9 +180,9 @@ } Found: - /* We have found the start of the binary data or the `/sfnts' token. */ - /* Now rewind and extract the frame corresponding to this PostScript */ - /* section. */ + /* We have found an efficient range to look for the binary data or */ + /* `/sfnts' token. Now rewind and extract the frame corresponding to */ + /* this PostScript section. */ ps_len = offset - base_offset; if ( FT_STREAM_SEEK( base_offset ) || @@ -187,8 +196,8 @@ parser->root.limit = parser->root.cursor + ps_len; parser->num_dict = FT_UINT_MAX; - /* Finally, we check whether `StartData' or `/sfnts' was real -- */ - /* it could be in a comment or string. We also get the arguments */ + /* Find the first real `StartData' or `/sfnts' -- the last one */ + /* could be in a comment or string. We also get the arguments */ /* of `StartData' to find out whether the data is represented in */ /* binary or hex format. */ @@ -216,6 +225,7 @@ { T1_TokenRec type_token; FT_Long binary_length; + FT_ULong found_offset; parser->root.cursor = arg1; @@ -234,6 +244,24 @@ parser->binary_length = (FT_ULong)binary_length; } + /* set the real values for the parser, if different */ + found_offset = (FT_ULong)( cur - parser->postscript ) + + STARTDATA_LEN + 1; + if ( found_offset != offset ) + { + FT_FRAME_RELEASE( parser->postscript ); + + ps_len = found_offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = found_offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + } goto Exit; } else if ( cur[1] == 's' && @@ -251,11 +279,8 @@ cur = parser->root.cursor; } - /* we haven't found the correct `StartData'; go back and continue */ - /* searching */ - FT_FRAME_RELEASE( parser->postscript ); - if ( !FT_STREAM_SEEK( offset ) ) - goto Again; + FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" )); + error = FT_THROW( Invalid_File_Format ); Exit: return error; diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h index 2fd4e7a9310..0f5baddcb92 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c index 99e7b118395..4be8a5c00d5 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c @@ -4,7 +4,7 @@ * * CID driver interface (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h index a6249385c81..7ddce431c5b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h @@ -4,7 +4,7 @@ * * High-level CID driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h index 925951acdbd..160897d1447 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h @@ -4,7 +4,7 @@ * * CID token definitions (specification only). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c index db08941def7..e2f6a8e5adb 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c @@ -4,7 +4,7 @@ * * AFM parser (body). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h index 2d3b6e6e169..b7766372821 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h @@ -4,7 +4,7 @@ * * AFM parser (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c index 562d17d2216..9556e11a586 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (body). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -1752,22 +1753,9 @@ /* without upper limit the loop below might not finish */ if ( args[0] > 0x7FFFFFFFL ) - args[0] = 46341; + args[0] = 0xB504F4L; /* sqrt( 32768.0044 ) */ else if ( args[0] > 0 ) - { - FT_Fixed root = args[0]; - FT_Fixed new_root; - - - for (;;) - { - new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; - if ( new_root == root ) - break; - root = new_root; - } - args[0] = new_root; - } + args[0] = (FT_Fixed)FT_SqrtFixed( args[0] ); else args[0] = 0; args++; diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h index e8bb4001cba..038f7235c3d 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (specification). * - * Copyright (C) 2017-2023 by + * Copyright (C) 2017-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h index 895ffa48c2c..18428c40d5a 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h @@ -4,7 +4,7 @@ * * PS auxiliary module error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c index 45e35aa53c4..6826f9d8d3e 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h index 94dbf48813c..82d7e348af8 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (specification). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c b/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c index f9c864fea9a..213b943b465 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psblues.c @@ -54,14 +54,6 @@ #define FT_COMPONENT cf2blues - /* - * For blue values, the FreeType parser produces an array of integers, - * while the Adobe CFF engine produces an array of fixed. - * Define a macro to convert FreeType to fixed. - */ -#define cf2_blueToFixed( x ) cf2_intToFixed( x ) - - FT_LOCAL_DEF( void ) cf2_blues_init( CF2_Blues blues, CF2_Font font ) @@ -78,10 +70,10 @@ size_t numFamilyBlues; size_t numFamilyOtherBlues; - FT_Pos* blueValues; - FT_Pos* otherBlues; - FT_Pos* familyBlues; - FT_Pos* familyOtherBlues; + FT_Fixed* blueValues; + FT_Fixed* otherBlues; + FT_Fixed* familyBlues; + FT_Fixed* familyOtherBlues; size_t i; CF2_Fixed emBoxBottom, emBoxTop; @@ -138,13 +130,13 @@ emBoxTop = CF2_ICF_Top; } - if ( cf2_getLanguageGroup( decoder ) == 1 && - ( numBlueValues == 0 || - ( numBlueValues == 4 && - cf2_blueToFixed( blueValues[0] ) < emBoxBottom && - cf2_blueToFixed( blueValues[1] ) < emBoxBottom && - cf2_blueToFixed( blueValues[2] ) > emBoxTop && - cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) + if ( cf2_getLanguageGroup( decoder ) == 1 && + ( numBlueValues == 0 || + ( numBlueValues == 4 && + blueValues[0] < emBoxBottom && + blueValues[1] < emBoxBottom && + blueValues[2] > emBoxTop && + blueValues[3] > emBoxTop ) ) ) { /* * Construct hint edges suitable for synthetic ghost hints at top @@ -189,10 +181,8 @@ /* bottom zones */ for ( i = 0; i < numBlueValues; i += 2 ) { - blues->zone[blues->count].csBottomEdge = - cf2_blueToFixed( blueValues[i] ); - blues->zone[blues->count].csTopEdge = - cf2_blueToFixed( blueValues[i + 1] ); + blues->zone[blues->count].csBottomEdge = blueValues[i]; + blues->zone[blues->count].csTopEdge = blueValues[i + 1]; zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, blues->zone[blues->count].csBottomEdge ); @@ -238,10 +228,8 @@ for ( i = 0; i < numOtherBlues; i += 2 ) { - blues->zone[blues->count].csBottomEdge = - cf2_blueToFixed( otherBlues[i] ); - blues->zone[blues->count].csTopEdge = - cf2_blueToFixed( otherBlues[i + 1] ); + blues->zone[blues->count].csBottomEdge = otherBlues[i]; + blues->zone[blues->count].csTopEdge = otherBlues[i + 1]; zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, blues->zone[blues->count].csBottomEdge ); @@ -299,7 +287,7 @@ for ( j = 0; j < numFamilyOtherBlues; j += 2 ) { /* top edge */ - flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); + flatFamilyEdge = familyOtherBlues[j + 1]; diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); @@ -317,7 +305,7 @@ if ( numFamilyBlues >= 2 ) { /* top edge */ - flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); + flatFamilyEdge = familyBlues[1]; diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); @@ -337,7 +325,7 @@ for ( j = 2; j < numFamilyBlues; j += 2 ) { /* bottom edge */ - flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); + flatFamilyEdge = familyBlues[j]; /* adjust edges of top zone upward by twice darkening amount */ flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c index b9c7138d846..56c0ecd1d7f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c @@ -4,7 +4,7 @@ * * Some convenience conversions (body). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h index b7c3ee00be8..91fcd15a1c9 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h @@ -4,7 +4,7 @@ * * Some convenience conversions (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psft.c b/src/java.desktop/share/native/libfreetype/src/psaux/psft.c index 618864e6e07..fd0abe17154 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psft.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psft.c @@ -566,12 +566,12 @@ FT_LOCAL_DEF( void ) cf2_getBlueValues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_blue_values; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.blue_values; } @@ -579,12 +579,12 @@ FT_LOCAL_DEF( void ) cf2_getOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_other_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.other_blues; } @@ -592,12 +592,12 @@ FT_LOCAL_DEF( void ) cf2_getFamilyBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_family_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.family_blues; } @@ -605,12 +605,12 @@ FT_LOCAL_DEF( void ) cf2_getFamilyOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_family_other_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.family_other_blues; } diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psft.h b/src/java.desktop/share/native/libfreetype/src/psaux/psft.h index 3da454e6012..d9082f3a2be 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psft.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psft.h @@ -92,19 +92,19 @@ FT_BEGIN_HEADER FT_LOCAL( void ) cf2_getBlueValues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getFamilyBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getFamilyOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( CF2_Int ) cf2_getLanguageGroup( PS_Decoder* decoder ); diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c index 6c640eebd5a..7572e225e37 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c @@ -37,6 +37,7 @@ #include "psft.h" +#include #include #include @@ -428,6 +429,8 @@ base = cf2_stack_count( opStack ) - numOperands; delta = base + numBlends; + FT_TRACE6(( " (" )); + for ( i = 0; i < numBlends; i++ ) { const CF2_Fixed* weight = &blend->BV[1]; @@ -442,10 +445,14 @@ cf2_stack_getReal( opStack, delta++ ) ) ); + FT_TRACE6(( "%f ", (double)sum / 65536 )); + /* store blended result */ cf2_stack_setReal( opStack, i + base, sum ); } + FT_TRACE6(( "blended)\n" )); + /* leave only `numBlends' results on stack */ cf2_stack_pop( opStack, numOperands - numBlends ); } @@ -734,7 +741,7 @@ FT_UInt numBlends; - FT_TRACE4(( " blend\n" )); + FT_TRACE4(( " blend" )); if ( !font->isCFF2 ) break; /* clear stack & ignore */ @@ -2275,23 +2282,7 @@ arg = cf2_stack_popFixed( opStack ); if ( arg > 0 ) - { - /* use a start value that doesn't make */ - /* the algorithm's addition overflow */ - FT_Fixed root = arg < 10 ? arg : arg >> 1; - FT_Fixed new_root; - - - /* Babylonian method */ - for (;;) - { - new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; - if ( new_root == root ) - break; - root = new_root; - } - arg = new_root; - } + arg = (CF2_F16Dot16)FT_SqrtFixed( (FT_UInt32)arg ); else arg = 0; diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c index 8da755d0e57..eca465f009e 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,6 +23,7 @@ #include "psobjs.h" #include "psconv.h" +#include "psft.h" #include "psauxerr.h" #include "psauxmod.h" @@ -200,7 +201,9 @@ /* add the object to the base block and adjust offset */ table->elements[idx] = FT_OFFSET( table->block, table->cursor ); table->lengths [idx] = length; - FT_MEM_COPY( table->block + table->cursor, object, length ); + /* length == 0 also implies a NULL destination, so skip the copy call */ + if ( length > 0 ) + FT_MEM_COPY( table->block + table->cursor, object, length ); table->cursor += length; return FT_Err_Ok; @@ -1624,7 +1627,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; point->x = FIXED_TO_INT( x ); @@ -1677,8 +1680,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -1740,7 +1742,7 @@ { FT_Vector* p1 = outline->points + first; FT_Vector* p2 = outline->points + outline->n_points - 1; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -1760,8 +1762,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -1899,7 +1900,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); @@ -1959,8 +1960,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -2019,7 +2019,7 @@ { FT_Vector* p1 = outline->points + first; FT_Vector* p2 = outline->points + outline->n_points - 1; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -2039,8 +2039,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -2188,7 +2187,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); @@ -2267,8 +2266,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -2327,7 +2325,7 @@ { FT_Vector* p1 = outline->points + first; FT_Vector* p2 = outline->points + outline->n_points - 1; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -2347,8 +2345,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -2463,19 +2460,20 @@ count = cpriv->num_blue_values = priv->num_blue_values; for ( n = 0; n < count; n++ ) - cpriv->blue_values[n] = (FT_Pos)priv->blue_values[n]; + cpriv->blue_values[n] = cf2_intToFixed( priv->blue_values[n] ); count = cpriv->num_other_blues = priv->num_other_blues; for ( n = 0; n < count; n++ ) - cpriv->other_blues[n] = (FT_Pos)priv->other_blues[n]; + cpriv->other_blues[n] = cf2_intToFixed( priv->other_blues[n] ); count = cpriv->num_family_blues = priv->num_family_blues; for ( n = 0; n < count; n++ ) - cpriv->family_blues[n] = (FT_Pos)priv->family_blues[n]; + cpriv->family_blues[n] = cf2_intToFixed( priv->family_blues[n] ); count = cpriv->num_family_other_blues = priv->num_family_other_blues; for ( n = 0; n < count; n++ ) - cpriv->family_other_blues[n] = (FT_Pos)priv->family_other_blues[n]; + cpriv->family_other_blues[n] = + cf2_intToFixed( priv->family_other_blues[n] ); cpriv->blue_scale = priv->blue_scale; cpriv->blue_shift = (FT_Pos)priv->blue_shift; diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h index d5bce541082..345fc8a7335 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c index c4bcf599ea3..5681c3bd0fd 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c @@ -4,7 +4,7 @@ * * Type 1 character map support (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h index b3702498a55..445e6a2784f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h @@ -4,7 +4,7 @@ * * Type 1 character map support (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c index 4b6b969bcb9..c74baa8038f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h index 0970def960b..16203b8f734 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (specification). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c index 4f622e1e440..967767b3485 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (body). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -1118,7 +1118,7 @@ FT_UInt n; PSH_Point point = glyph->points; FT_Vector* vec = glyph->outline->points; - char* tags = glyph->outline->tags; + FT_Byte* tags = glyph->outline->tags; for ( n = 0; n < glyph->num_points; n++ ) @@ -1171,8 +1171,8 @@ FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) goto Exit; - glyph->num_points = (FT_UInt)outline->n_points; - glyph->num_contours = (FT_UInt)outline->n_contours; + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; { FT_UInt first = 0, next, n; @@ -1186,7 +1186,7 @@ PSH_Point point; - next = (FT_UInt)outline->contours[n] + 1; + next = outline->contours[n] + 1; count = next - first; contour->start = points + first; diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h index 3f0ba28a693..fb362f061b6 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (specification). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c index d4c5eb32b1c..435f45838ff 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c @@ -5,7 +5,7 @@ * PostScript hinter global hinting management (body). * Inspired by the new auto-hinter module. * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h index 579eb2148a5..c5a5c913168 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h @@ -4,7 +4,7 @@ * * PostScript hinter global hinting management. * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c index 974a99e0186..9965d5b16bf 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c @@ -4,7 +4,7 @@ * * FreeType PostScript hinter module implementation (body). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h index 4bd781a35d7..62ac0a60fdc 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h @@ -4,7 +4,7 @@ * * PostScript hinter module interface (specification). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h index 97624952d8c..e9641340e53 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h @@ -4,7 +4,7 @@ * * PS Hinter error codes (specification only). * - * Copyright (C) 2003-2023 by + * Copyright (C) 2003-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c index 680e6d01358..0b2b549fc29 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c @@ -4,7 +4,7 @@ * * FreeType PostScript hints recorder (body). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -806,7 +806,7 @@ ps_hints_stem( PS_Hints hints, FT_UInt dimension, FT_Int count, - FT_Long* stems ) + FT_Pos* stems ) { PS_Dimension dim; diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h index 0b2484af121..7e375af7ba8 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h @@ -4,7 +4,7 @@ * * Postscript (Type1/Type2) hints recorder (specification). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c index 8203a0465d2..35d054d1cfb 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c @@ -4,7 +4,7 @@ * * psnames module implementation (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h index 0904700bfb8..770458316b1 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h @@ -4,7 +4,7 @@ * * High-level psnames module interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h index 0073f822848..e123eb65e39 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h @@ -4,7 +4,7 @@ * * PS names module error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h index 7f92cce6039..2a941b04609 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h @@ -4,7 +4,7 @@ * * PostScript glyph names. * - * Copyright (C) 2005-2023 by + * Copyright (C) 2005-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h index 33dbfd631e9..943f2aa0a50 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h @@ -5,7 +5,7 @@ * Miscellaneous macros for stand-alone rasterizer (specification * only). * - * Copyright (C) 2005-2023 by + * Copyright (C) 2005-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -92,27 +92,6 @@ #endif - static FT_Long - FT_MulDiv( FT_Long a, - FT_Long b, - FT_Long c ) - { - FT_Int s; - FT_Long d; - - - s = 1; - if ( a < 0 ) { a = -a; s = -1; } - if ( b < 0 ) { b = -b; s = -s; } - if ( c < 0 ) { c = -c; s = -s; } - - d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c - : 0x7FFFFFFFL ); - - return ( s > 0 ) ? d : -d; - } - - static FT_Long FT_MulDiv_No_Round( FT_Long a, FT_Long b, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c index 192ca0701a2..e4b7b937d5a 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -63,8 +63,7 @@ #else /* !STANDALONE_ */ #include "ftraster.h" -#include /* for FT_MulDiv and FT_MulDiv_No_Round */ -#include /* for FT_Outline_Get_CBox */ +#include /* for FT_MulDiv_No_Round */ #endif /* !STANDALONE_ */ @@ -115,12 +114,12 @@ * a change of direction is detected in the outline, a new profile is * generated until the end of the outline. * - * Note that when all profiles have been generated, the function - * Finalize_Profile_Table() is used to record, for each profile, its - * bottom-most scanline as well as the scanline above its upmost - * boundary. These positions are called `y-turns' because they (sort - * of) correspond to local extrema. They are stored in a sorted list - * built from the top of the render pool as a downwards stack: + * Note that, for all generated profiles, the function End_Profile() + * is used to record all their bottom-most scanlines as well as the + * scanline above their upmost boundary. These positions are called + * `y-turns' because they (sort of) correspond to local extrema. + * They are stored in a sorted list built from the top of the render + * pool as a downwards stack: * * _ _ _______________________________________ * | | @@ -136,7 +135,7 @@ * optimize performance (see technical note on the sweep below). * * Of course, the raster detects whether the two stacks collide and - * handles the situation properly. + * handles the situation by bisecting the job and restarting. * */ @@ -252,7 +251,6 @@ /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ /* for clipping computations. It simply uses the FT_MulDiv() function */ /* defined in `ftcalc.h'. */ -#define SMulDiv FT_MulDiv #define SMulDiv_No_Round FT_MulDiv_No_Round /* The rasterizer is a very general purpose component; please leave */ @@ -305,16 +303,6 @@ typedef unsigned char Byte, *PByte; typedef char Bool; - - typedef union Alignment_ - { - Long l; - void* p; - void (*f)(void); - - } Alignment, *PAlignment; - - typedef struct TPoint_ { Long x; @@ -327,6 +315,7 @@ #define Flow_Up 0x08U #define Overshoot_Top 0x10U #define Overshoot_Bottom 0x20U +#define Dropout 0x40U /* States of each line, arc, and profile */ @@ -345,31 +334,28 @@ struct TProfile_ { - FT_F26Dot6 X; /* current coordinate during sweep */ PProfile link; /* link to next profile (various purposes) */ - PLong offset; /* start of profile's data in render pool */ + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + Int offset; /* bottom or currently scanned array index */ + Int height; /* profile's height in scanlines */ + Int start; /* profile's starting scanline, also use */ + /* as activation counter */ UShort flags; /* Bit 0-2: drop-out mode */ /* Bit 3: profile orientation (up/down) */ /* Bit 4: is top profile? */ /* Bit 5: is bottom profile? */ - Long height; /* profile's height in scanlines */ - Long start; /* profile's starting scanline */ + /* Bit 6: dropout detected */ - Int countL; /* number of lines to step before this */ - /* profile becomes drawable */ - - PProfile next; /* next profile in same contour, used */ - /* during drop-out control */ + FT_F26Dot6 X; /* current coordinate during sweep */ + Long x[1]; /* actually variable array of scanline */ + /* intersections with `height` elements */ }; typedef PProfile TProfileList; typedef PProfile* PProfileList; -#define AlignProfileSize \ - ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( Long ) ) - - #undef RAS_ARG #undef RAS_ARGS #undef RAS_VAR @@ -407,15 +393,13 @@ /* prototypes used for sweep function dispatch */ typedef void - Function_Sweep_Init( RAS_ARGS Short min, - Short max ); + Function_Sweep_Init( RAS_ARGS Int min, + Int max ); typedef void - Function_Sweep_Span( RAS_ARGS Short y, + Function_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ); + FT_F26Dot6 x2 ); typedef void Function_Sweep_Step( RAS_ARG ); @@ -441,8 +425,7 @@ (Bool)( x - FLOOR( x ) >= ras.precision_half ) /* Smart dropout rounding to find which pixel is closer to span ends. */ - /* To mimick Windows, symmetric cases break down indepenently of the */ - /* precision. */ + /* To mimic Windows, symmetric cases do not depend on the precision. */ #define SMART( p, q ) FLOOR( ( (p) + (q) + ras.precision * 63 / 64 ) >> 1 ) #if FT_RENDER_POOL_SIZE > 2048 @@ -462,7 +445,6 @@ Int precision_half; Int precision_scale; Int precision_step; - Int precision_jitter; PLong buff; /* The profiles buffer */ PLong sizeBuff; /* Render pool size */ @@ -471,24 +453,14 @@ FT_Error error; - Int numTurns; /* number of Y-turns in outline */ - Byte dropOutControl; /* current drop_out control method */ - UShort bWidth; /* target bitmap width */ - PByte bOrigin; /* target bitmap bottom-left origin */ - PByte bLine; /* target bitmap current line */ - Long lastX, lastY; Long minY, maxY; UShort num_Profs; /* current number of profiles */ + Int numTurns; /* number of Y-turns in outline */ - Bool fresh; /* signals a fresh new profile which */ - /* `start' field must be completed */ - Bool joint; /* signals that the last arc ended */ - /* exactly on a scanline. Allows */ - /* removal of doublets */ PProfile cProfile; /* current profile */ PProfile fProfile; /* head of linked list of profiles */ PProfile gProfile; /* contour's first profile in case */ @@ -496,9 +468,14 @@ TStates state; /* rendering state */ - FT_Bitmap target; /* description of target bit/pixmap */ FT_Outline outline; + Int bTop; /* target bitmap max line index */ + Int bRight; /* target bitmap rightmost index */ + Int bPitch; /* target bitmap pitch */ + PByte bOrigin; /* target bitmap bottom-left origin */ + PByte bLine; /* target bitmap current line */ + /* dispatch variables */ Function_Sweep_Init* Proc_Sweep_Init; @@ -563,187 +540,25 @@ * * 256 / (1 << 12) = 0.0625 pixels. * - * `precision_jitter' is an epsilon threshold used in - * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier - * decomposition (after all, we are working with approximations only); - * it avoids switching on additional pixels which would cause artifacts - * otherwise. - * - * The value of `precision_jitter' has been determined heuristically. - * */ if ( High ) { ras.precision_bits = 12; ras.precision_step = 256; - ras.precision_jitter = 30; } else { ras.precision_bits = 6; ras.precision_step = 32; - ras.precision_jitter = 2; } - FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); - ras.precision = 1 << ras.precision_bits; ras.precision_half = ras.precision >> 1; ras.precision_scale = ras.precision >> Pixel_Bits; } - /************************************************************************** - * - * @Function: - * New_Profile - * - * @Description: - * Create a new profile in the render pool. - * - * @Input: - * aState :: - * The state/orientation of the new profile. - * - * overshoot :: - * Whether the profile's unrounded start position - * differs by at least a half pixel. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow or of incoherent - * profile. - */ - static Bool - New_Profile( RAS_ARGS TStates aState, - Bool overshoot ) - { - if ( !ras.fProfile ) - { - ras.cProfile = (PProfile)ras.top; - ras.fProfile = ras.cProfile; - ras.top += AlignProfileSize; - } - - if ( ras.top >= ras.maxBuff ) - { - ras.error = FT_THROW( Raster_Overflow ); - return FAILURE; - } - - ras.cProfile->start = 0; - ras.cProfile->height = 0; - ras.cProfile->offset = ras.top; - ras.cProfile->link = (PProfile)0; - ras.cProfile->next = (PProfile)0; - ras.cProfile->flags = ras.dropOutControl; - - switch ( aState ) - { - case Ascending_State: - ras.cProfile->flags |= Flow_Up; - if ( overshoot ) - ras.cProfile->flags |= Overshoot_Bottom; - - FT_TRACE6(( " new ascending profile = %p\n", (void *)ras.cProfile )); - break; - - case Descending_State: - if ( overshoot ) - ras.cProfile->flags |= Overshoot_Top; - FT_TRACE6(( " new descending profile = %p\n", (void *)ras.cProfile )); - break; - - default: - FT_ERROR(( "New_Profile: invalid profile direction\n" )); - ras.error = FT_THROW( Invalid_Outline ); - return FAILURE; - } - - if ( !ras.gProfile ) - ras.gProfile = ras.cProfile; - - ras.state = aState; - ras.fresh = TRUE; - ras.joint = FALSE; - - return SUCCESS; - } - - - /************************************************************************** - * - * @Function: - * End_Profile - * - * @Description: - * Finalize the current profile. - * - * @Input: - * overshoot :: - * Whether the profile's unrounded end position differs - * by at least a half pixel. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow or incoherency. - */ - static Bool - End_Profile( RAS_ARGS Bool overshoot ) - { - Long h; - - - h = (Long)( ras.top - ras.cProfile->offset ); - - if ( h < 0 ) - { - FT_ERROR(( "End_Profile: negative height encountered\n" )); - ras.error = FT_THROW( Raster_Negative_Height ); - return FAILURE; - } - - if ( h > 0 ) - { - PProfile oldProfile; - - - FT_TRACE6(( " ending profile %p, start = %ld, height = %ld\n", - (void *)ras.cProfile, ras.cProfile->start, h )); - - ras.cProfile->height = h; - if ( overshoot ) - { - if ( ras.cProfile->flags & Flow_Up ) - ras.cProfile->flags |= Overshoot_Top; - else - ras.cProfile->flags |= Overshoot_Bottom; - } - - oldProfile = ras.cProfile; - ras.cProfile = (PProfile)ras.top; - - ras.top += AlignProfileSize; - - ras.cProfile->height = 0; - ras.cProfile->offset = ras.top; - - oldProfile->next = ras.cProfile; - ras.num_Profs++; - } - - if ( ras.top >= ras.maxBuff ) - { - FT_TRACE1(( "overflow in End_Profile\n" )); - ras.error = FT_THROW( Raster_Overflow ); - return FAILURE; - } - - ras.joint = FALSE; - - return SUCCESS; - } - - /************************************************************************** * * @Function: @@ -760,31 +575,23 @@ * SUCCESS on success. FAILURE in case of overflow. */ static Bool - Insert_Y_Turn( RAS_ARGS Int y ) + Insert_Y_Turns( RAS_ARGS Int y, + Int top ) { - PLong y_turns; - Int n; + Int n = ras.numTurns; + PLong y_turns = ras.maxBuff; - n = ras.numTurns - 1; - y_turns = ras.sizeBuff - ras.numTurns; + /* update top value */ + if ( n == 0 || top > y_turns[n] ) + y_turns[n] = top; /* look for first y value that is <= */ - while ( n >= 0 && y < y_turns[n] ) - n--; + while ( n-- && y < y_turns[n] ) + ; /* if it is <, simply insert it, ignore if == */ - if ( n >= 0 && y > y_turns[n] ) - do - { - Int y2 = (Int)y_turns[n]; - - - y_turns[n] = y; - y = y2; - } while ( --n >= 0 ); - - if ( n < 0 ) + if ( n < 0 || y > y_turns[n] ) { ras.maxBuff--; if ( ras.maxBuff <= ras.top ) @@ -792,8 +599,170 @@ ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } + + do + { + Int y2 = (Int)y_turns[n]; + + + y_turns[n] = y; + y = y2; + } while ( n-- >= 0 ); + ras.numTurns++; - ras.sizeBuff[-ras.numTurns] = y; + } + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * New_Profile + * + * @Description: + * Create a new profile in the render pool. + * + * @Input: + * aState :: + * The state/orientation of the new profile. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or of incoherent + * profile. + */ + static Bool + New_Profile( RAS_ARGS TStates aState ) + { + Long e; + + + if ( !ras.cProfile || ras.cProfile->height ) + { + ras.cProfile = (PProfile)ras.top; + ras.top = ras.cProfile->x; + + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in New_Profile\n" )); + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + + ras.cProfile->height = 0; + } + + ras.cProfile->flags = ras.dropOutControl; + + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flags |= Flow_Up; + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Bottom; + + e = CEILING( ras.lastY ); + break; + + case Descending_State: + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Top; + + e = FLOOR( ras.lastY ); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction\n" )); + ras.error = FT_THROW( Invalid_Outline ); + return FAILURE; + } + + if ( e > ras.maxY ) + e = ras.maxY; + if ( e < ras.minY ) + e = ras.minY; + ras.cProfile->start = (Int)TRUNC( e ); + + FT_TRACE7(( " new %s profile = %p, start = %d\n", + aState == Ascending_State ? "ascending" : "descending", + (void *)ras.cProfile, ras.cProfile->start )); + + if ( ras.lastY == e ) + *ras.top++ = ras.lastX; + + ras.state = aState; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * End_Profile + * + * @Description: + * Finalize the current profile and record y-turns. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or incoherency. + */ + static Bool + End_Profile( RAS_ARG ) + { + PProfile p = ras.cProfile; + Int h = (Int)( ras.top - p->x ); + Int bottom, top; + + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered\n" )); + ras.error = FT_THROW( Raster_Negative_Height ); + return FAILURE; + } + + if ( h > 0 ) + { + FT_TRACE7(( " ending profile %p, start = %2d, height = %+3d\n", + (void *)p, p->start, p->flags & Flow_Up ? h : -h )); + + p->height = h; + + if ( p->flags & Flow_Up ) + { + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Top; + + bottom = p->start; + top = bottom + h; + p->offset = 0; + p->X = p->x[0]; + } + else + { + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Bottom; + + top = p->start + 1; + bottom = top - h; + p->start = bottom; + p->offset = h - 1; + p->X = p->x[h - 1]; + } + + if ( Insert_Y_Turns( RAS_VARS bottom, top ) ) + return FAILURE; + + if ( !ras.gProfile ) + ras.gProfile = p; + + /* preliminary values to be finalized */ + p->next = ras.gProfile; + p->link = (PProfile)ras.top; + + ras.num_Profs++; } return SUCCESS; @@ -807,56 +776,29 @@ * * @Description: * Adjust all links in the profiles list. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow. */ - static Bool + static void Finalize_Profile_Table( RAS_ARG ) { - UShort n; - PProfile p; + UShort n = ras.num_Profs; + PProfile p = ras.fProfile; + PProfile q; - n = ras.num_Profs; - p = ras.fProfile; - - if ( n > 1 && p ) + /* there should be at least two profiles, up and down */ + while ( --n ) { - do - { - Int bottom, top; + q = p->link; + /* fix the contour loop */ + if ( q->next == p->next ) + p->next = q; - if ( n > 1 ) - p->link = (PProfile)( p->offset + p->height ); - else - p->link = NULL; - - if ( p->flags & Flow_Up ) - { - bottom = (Int)p->start; - top = (Int)( p->start + p->height - 1 ); - } - else - { - bottom = (Int)( p->start - p->height + 1 ); - top = (Int)p->start; - p->start = bottom; - p->offset += p->height - 1; - } - - if ( Insert_Y_Turn( RAS_VARS bottom ) || - Insert_Y_Turn( RAS_VARS top + 1 ) ) - return FAILURE; - - p = p->link; - } while ( --n ); + p = q; } - else - ras.fProfile = NULL; - return SUCCESS; + /* null-terminate */ + p->link = NULL; } @@ -986,107 +928,78 @@ Long miny, Long maxy ) { - Long Dx, Dy; - Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ - Long Ix, Rx, Ax; + Long e, e2, Dx, Dy; + Long Ix, Rx, Ax; + Int size; PLong top; - Dx = x2 - x1; - Dy = y2 - y1; - - if ( Dy <= 0 || y2 < miny || y1 > maxy ) + if ( y2 < miny || y1 > maxy ) return SUCCESS; - if ( y1 < miny ) - { - /* Take care: miny-y1 can be a very large value; we use */ - /* a slow MulDiv function to avoid clipping bugs */ - x1 += SMulDiv( Dx, miny - y1, Dy ); - e1 = (Int)TRUNC( miny ); - f1 = 0; - } - else - { - e1 = (Int)TRUNC( y1 ); - f1 = (Int)FRAC( y1 ); - } + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( y1 ); - if ( y2 > maxy ) - { - /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ - e2 = (Int)TRUNC( maxy ); - f2 = 0; - } - else - { - e2 = (Int)TRUNC( y2 ); - f2 = (Int)FRAC( y2 ); - } + if ( y1 == e ) + e += ras.precision; - if ( f1 > 0 ) - { - if ( e1 == e2 ) - return SUCCESS; - else - { - x1 += SMulDiv( Dx, ras.precision - f1, Dy ); - e1 += 1; - } - } - else - if ( ras.joint ) - { - ras.top--; - ras.joint = FALSE; - } + if ( e2 < e ) /* nothing to do */ + return SUCCESS; - ras.joint = (char)( f2 == 0 ); + size = (Int)TRUNC( e2 - e ) + 1; + top = ras.top; - if ( ras.fresh ) - { - ras.cProfile->start = e1; - ras.fresh = FALSE; - } - - size = e2 - e1 + 1; - if ( ras.top + size >= ras.maxBuff ) + if ( top + size >= ras.maxBuff ) { ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } - if ( Dx > 0 ) + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dx == 0 ) /* very easy */ { - Ix = SMulDiv_No_Round( ras.precision, Dx, Dy ); - Rx = ( ras.precision * Dx ) % Dy; + do + *top++ = x1; + while ( --size ); + goto Fin; + } + + Ix = SMulDiv_No_Round( e - y1, Dx, Dy ); + x1 += Ix; + *top++ = x1; + + if ( --size ) + { + Ax = Dx * ( e - y1 ) - Dy * Ix; /* remainder */ + Ix = FMulDiv( ras.precision, Dx, Dy ); + Rx = Dx * ras.precision - Dy * Ix; /* remainder */ Dx = 1; - } - else - { - Ix = -SMulDiv_No_Round( ras.precision, -Dx, Dy ); - Rx = ( ras.precision * -Dx ) % Dy; - Dx = -1; - } - Ax = -Dy; - top = ras.top; - - while ( size > 0 ) - { - *top++ = x1; - - x1 += Ix; - Ax += Rx; - if ( Ax >= 0 ) + if ( x2 < x1 ) { - Ax -= Dy; - x1 += Dx; + Ax = -Ax; + Rx = -Rx; + Dx = -Dx; } - size--; + + do + { + x1 += Ix; + Ax += Rx; + if ( Ax >= Dy ) + { + Ax -= Dy; + x1 += Dx; + } + *top++ = x1; + } + while ( --size ); } + Fin: ras.top = top; return SUCCESS; } @@ -1131,17 +1044,7 @@ Long miny, Long maxy ) { - Bool result, fresh; - - - fresh = ras.fresh; - - result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); - - if ( fresh && !ras.fresh ) - ras.cProfile->start = -ras.cProfile->start; - - return result; + return Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); } @@ -1181,105 +1084,73 @@ Long miny, Long maxy ) { - Long y1, y2, e, e2, e0; - Short f1; + Long y1, y2, e, e2, dy; + Long dx, x2; - TPoint* start_arc; - - PLong top; + PLong top; y1 = arc[degree].y; y2 = arc[0].y; - top = ras.top; if ( y2 < miny || y1 > maxy ) - goto Fin; + return SUCCESS; - e2 = FLOOR( y2 ); + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( y1 ); - if ( e2 > maxy ) - e2 = maxy; + if ( y1 == e ) + e += ras.precision; - e0 = miny; + if ( e2 < e ) /* nothing to do */ + return SUCCESS; - if ( y1 < miny ) - e = miny; - else - { - e = CEILING( y1 ); - f1 = (Short)( FRAC( y1 ) ); - e0 = e; - - if ( f1 == 0 ) - { - if ( ras.joint ) - { - top--; - ras.joint = FALSE; - } - - *top++ = arc[degree].x; - - e += ras.precision; - } - } - - if ( ras.fresh ) - { - ras.cProfile->start = TRUNC( e0 ); - ras.fresh = FALSE; - } - - if ( e2 < e ) - goto Fin; + top = ras.top; if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) { - ras.top = top; ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } - start_arc = arc; - do { - ras.joint = FALSE; - y2 = arc[0].y; + x2 = arc[0].x; if ( y2 > e ) { - y1 = arc[degree].y; - if ( y2 - y1 >= ras.precision_step ) + dy = y2 - arc[degree].y; + dx = x2 - arc[degree].x; + + /* split condition should be invariant of direction */ + if ( dy > ras.precision_step || + dx > ras.precision_step || + -dx > ras.precision_step ) { splitter( arc ); arc += degree; } else { - *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, - e - y1, y2 - y1 ); + *top++ = x2 - FMulDiv( y2 - e, dx, dy ); + e += ras.precision; arc -= degree; - e += ras.precision; } } else { if ( y2 == e ) { - ras.joint = TRUE; - *top++ = arc[0].x; - - e += ras.precision; + *top++ = x2; + e += ras.precision; } - arc -= degree; + arc -= degree; } - } while ( arc >= start_arc && e <= e2 ); + } + while ( e <= e2 ); - Fin: - ras.top = top; + ras.top = top; return SUCCESS; } @@ -1316,7 +1187,7 @@ Long miny, Long maxy ) { - Bool result, fresh; + Bool result; arc[0].y = -arc[0].y; @@ -1325,13 +1196,8 @@ if ( degree > 2 ) arc[3].y = -arc[3].y; - fresh = ras.fresh; - result = Bezier_Up( RAS_VARS degree, arc, splitter, -maxy, -miny ); - if ( fresh && !ras.fresh ) - ras.cProfile->start = -ras.cProfile->start; - arc[0].y = -arc[0].y; return result; } @@ -1362,74 +1228,50 @@ Line_To( RAS_ARGS Long x, Long y ) { + TStates state; + + + if ( y == ras.lastY ) + goto Fin; + /* First, detect a change of direction */ - switch ( ras.state ) + state = ras.lastY < y ? Ascending_State : Descending_State; + + if ( ras.state != state ) { - case Unknown_State: - if ( y > ras.lastY ) - { - if ( New_Profile( RAS_VARS Ascending_State, - IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - else - { - if ( y < ras.lastY ) - if ( New_Profile( RAS_VARS Descending_State, - IS_TOP_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; - case Ascending_State: - if ( y < ras.lastY ) - { - if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || - New_Profile( RAS_VARS Descending_State, - IS_TOP_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; - - case Descending_State: - if ( y > ras.lastY ) - { - if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || - New_Profile( RAS_VARS Ascending_State, - IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; - - default: - ; + /* create a new profile */ + if ( New_Profile( RAS_VARS state ) ) + goto Fail; } /* Then compute the lines */ - switch ( ras.state ) + if ( state == Ascending_State ) { - case Ascending_State: if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending_State: + goto Fail; + } + else + { if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; + goto Fail; } + Fin: ras.lastX = x; ras.lastY = y; - return SUCCESS; + + Fail: + return FAILURE; } @@ -1500,7 +1342,7 @@ ymax = y1; } - if ( y2 < ymin || y2 > ymax ) + if ( y2 < FLOOR( ymin ) || y2 > CEILING( ymax ) ) { /* this arc has no given direction, split it! */ Split_Conic( arc ); @@ -1508,8 +1350,12 @@ } else if ( y1 == y3 ) { - /* this arc is flat, ignore it and pop it from the Bezier stack */ + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; } else { @@ -1518,18 +1364,13 @@ state_bez = y1 < y3 ? Ascending_State : Descending_State; if ( ras.state != state_bez ) { - Bool o = ( state_bez == Ascending_State ) - ? IS_BOTTOM_OVERSHOOT( y1 ) - : IS_TOP_OVERSHOOT( y1 ); - - /* finalize current profile if any */ if ( ras.state != Unknown_State && - End_Profile( RAS_VARS o ) ) + End_Profile( RAS_VAR ) ) goto Fail; /* create a new profile */ - if ( New_Profile( RAS_VARS state_bez, o ) ) + if ( New_Profile( RAS_VARS state_bez ) ) goto Fail; } @@ -1545,13 +1386,13 @@ ras.minY, ras.maxY ) ) goto Fail; arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; } } while ( arc >= arcs ); - ras.lastX = x3; - ras.lastY = y3; - return SUCCESS; Fail: @@ -1648,7 +1489,7 @@ ymax2 = y2; } - if ( ymin2 < ymin1 || ymax2 > ymax1 ) + if ( ymin2 < FLOOR( ymin1 ) || ymax2 > CEILING( ymax1 ) ) { /* this arc has no given direction, split it! */ Split_Cubic( arc ); @@ -1656,27 +1497,26 @@ } else if ( y1 == y4 ) { - /* this arc is flat, ignore it and pop it from the Bezier stack */ + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; } else { - state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; + state_bez = y1 < y4 ? Ascending_State : Descending_State; /* detect a change of direction */ if ( ras.state != state_bez ) { - Bool o = ( state_bez == Ascending_State ) - ? IS_BOTTOM_OVERSHOOT( y1 ) - : IS_TOP_OVERSHOOT( y1 ); - - /* finalize current profile if any */ if ( ras.state != Unknown_State && - End_Profile( RAS_VARS o ) ) + End_Profile( RAS_VAR ) ) goto Fail; - if ( New_Profile( RAS_VARS state_bez, o ) ) + if ( New_Profile( RAS_VARS state_bez ) ) goto Fail; } @@ -1692,13 +1532,13 @@ ras.minY, ras.maxY ) ) goto Fail; arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; } } while ( arc >= arcs ); - ras.lastX = x4; - ras.lastY = y4; - return SUCCESS; Fail: @@ -1740,6 +1580,11 @@ * * @Return: * SUCCESS on success, FAILURE on error. + * + * @Note: + * Unlike FT_Outline_Decompose(), this function handles the scanmode + * dropout tags in the individual contours. Therefore, it cannot be + * replaced. */ static Bool Decompose_Curve( RAS_ARGS Int first, @@ -1753,7 +1598,7 @@ FT_Vector* points; FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; UInt tag; /* current point's state */ @@ -1974,24 +1819,17 @@ ras.fProfile = NULL; - ras.joint = FALSE; - ras.fresh = FALSE; + ras.cProfile = NULL; - ras.maxBuff = ras.sizeBuff - AlignProfileSize; + ras.top = ras.buff; + ras.maxBuff = ras.sizeBuff - 1; /* top reserve */ - ras.numTurns = 0; - - ras.cProfile = (PProfile)ras.top; - ras.cProfile->offset = ras.top; - ras.num_Profs = 0; + ras.numTurns = 0; + ras.num_Profs = 0; last = -1; for ( i = 0; i < ras.outline.n_contours; i++ ) { - PProfile lastProfile; - Bool o; - - ras.state = Unknown_State; ras.gProfile = NULL; @@ -2001,35 +1839,30 @@ if ( Decompose_Curve( RAS_VARS first, last, flipped ) ) return FAILURE; + /* Note that ras.gProfile can stay nil if the contour was */ + /* too small to be drawn or degenerate. */ + if ( !ras.gProfile ) + continue; + /* we must now check whether the extreme arcs join or not */ if ( FRAC( ras.lastY ) == 0 && ras.lastY >= ras.minY && ras.lastY <= ras.maxY ) - if ( ras.gProfile && - ( ras.gProfile->flags & Flow_Up ) == + if ( ( ras.gProfile->flags & Flow_Up ) == ( ras.cProfile->flags & Flow_Up ) ) ras.top--; - /* Note that ras.gProfile can be nil if the contour was too small */ - /* to be drawn. */ - lastProfile = ras.cProfile; - if ( ras.top != ras.cProfile->offset && - ( ras.cProfile->flags & Flow_Up ) ) - o = IS_TOP_OVERSHOOT( ras.lastY ); - else - o = IS_BOTTOM_OVERSHOOT( ras.lastY ); - if ( End_Profile( RAS_VARS o ) ) + if ( End_Profile( RAS_VAR ) ) return FAILURE; - /* close the `next profile in contour' linked list */ - if ( ras.gProfile ) - lastProfile->next = ras.gProfile; + if ( !ras.fProfile ) + ras.fProfile = ras.gProfile; } - if ( Finalize_Profile_Table( RAS_VAR ) ) - return FAILURE; + if ( ras.fProfile ) + Finalize_Profile_Table( RAS_VAR ); - return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + return SUCCESS; } @@ -2042,24 +1875,11 @@ /*************************************************************************/ - /************************************************************************** - * - * Init_Linked - * - * Initializes an empty linked list. - */ - static void - Init_Linked( TProfileList* l ) - { - *l = NULL; - } - - /************************************************************************** * * InsNew * - * Inserts a new profile in a linked list. + * Inserts a new profile in a linked list, sorted by coordinate. */ static void InsNew( PProfileList list, @@ -2073,10 +1893,8 @@ current = *old; x = profile->X; - while ( current ) + while ( current && current->X < x ) { - if ( x < current->X ) - break; old = ¤t->link; current = *old; } @@ -2088,79 +1906,51 @@ /************************************************************************** * - * DelOld + * Increment * - * Removes an old profile from a linked list. + * Advances all profile in the list to the next scanline. It also + * sorts the trace list in the unlikely case of profile crossing. + * The profiles are inserted in sorted order. We might need a single + * swap to fix it when profiles (contours) cross. + * Bubble sort with immediate restart is good enough and simple. */ static void - DelOld( PProfileList list, - const PProfile profile ) - { - PProfile *old, current; - - - old = list; - current = *old; - - while ( current ) - { - if ( current == profile ) - { - *old = current->link; - return; - } - - old = ¤t->link; - current = *old; - } - - /* we should never get there, unless the profile was not part of */ - /* the list. */ - } - - - /************************************************************************** - * - * Sort - * - * Sorts a trace list. In 95%, the list is already sorted. We need - * an algorithm which is fast in this case. Bubble sort is enough - * and simple. - */ - static void - Sort( PProfileList list ) + Increment( PProfileList list, + Int flow ) { PProfile *old, current, next; - /* First, set the new X coordinate of each profile */ - current = *list; - while ( current ) + /* First, set the new X coordinates and remove exhausted profiles */ + old = list; + while ( *old ) { - current->X = *current->offset; - current->offset += ( current->flags & Flow_Up ) ? 1 : -1; - current->height--; - current = current->link; + current = *old; + if ( --current->height ) + { + current->offset += flow; + current->X = current->x[current->offset]; + old = ¤t->link; + } + else + *old = current->link; /* remove */ } - /* Then sort them */ + /* Then make sure the list remains sorted */ old = list; current = *old; if ( !current ) return; - next = current->link; - - while ( next ) + while ( current->link ) { + next = current->link; + if ( current->X <= next->X ) { old = ¤t->link; - current = *old; - - if ( !current ) - return; + current = next; } else { @@ -2168,11 +1958,10 @@ current->link = next->link; next->link = current; + /* this is likely the only necessary swap -- restart */ old = list; current = *old; } - - next = current->link; } } @@ -2187,74 +1976,51 @@ */ static void - Vertical_Sweep_Init( RAS_ARGS Short min, - Short max ) + Vertical_Sweep_Init( RAS_ARGS Int min, + Int max ) { FT_UNUSED( max ); - ras.bLine = ras.bOrigin - min * ras.target.pitch; + ras.bLine = ras.bOrigin - min * ras.bPitch; } static void - Vertical_Sweep_Span( RAS_ARGS Short y, + Vertical_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2; - - Int dropOutControl = left->flags & 7; + Int e1 = (Int)TRUNC( CEILING( x1 ) ); + Int e2 = (Int)TRUNC( FLOOR( x2 ) ); FT_UNUSED( y ); - FT_UNUSED( left ); - FT_UNUSED( right ); - /* in high-precision mode, we need 12 digits after the comma to */ - /* represent multiples of 1/(1<<12) = 1/4096 */ - FT_TRACE7(( " y=%d x=[% .12f;% .12f]", + FT_TRACE7(( " y=%d x=[% .*f;% .*f]", y, - (double)x1 / (double)ras.precision, - (double)x2 / (double)ras.precision )); + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); - /* Drop-out control */ - - e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); - - /* take care of the special case where both the left */ - /* and right contour lie exactly on pixel centers */ - if ( dropOutControl != 2 && - x2 - x1 - ras.precision <= ras.precision_jitter && - e1 != x1 && e2 != x2 ) - e2 = e1; - - e1 = TRUNC( e1 ); - e2 = TRUNC( e2 ); - - if ( e2 >= 0 && e1 < ras.bWidth ) + if ( e2 >= 0 && e1 <= ras.bRight ) { - Byte* target; + PByte target; - Int c1, c2; - Byte f1, f2; + Int c1, f1, c2, f2; if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bWidth ) - e2 = ras.bWidth - 1; + if ( e2 > ras.bRight ) + e2 = ras.bRight; - FT_TRACE7(( " -> x=[%ld;%ld]", e1, e2 )); + FT_TRACE7(( " -> x=[%d;%d]", e1, e2 )); - c1 = (Short)( e1 >> 3 ); - c2 = (Short)( e2 >> 3 ); + c1 = e1 >> 3; + c2 = e2 >> 3; - f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); - f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); + f1 = 0xFF >> ( e1 & 7 ); + f2 = ~0x7F >> ( e2 & 7 ); target = ras.bLine + c1; c2 -= c1; @@ -2280,163 +2046,50 @@ static void - Vertical_Sweep_Drop( RAS_ARGS Short y, + Vertical_Sweep_Drop( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2, pxl; - Short c1, f1; + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); + Int c1, f1; + + FT_UNUSED( y ); - FT_TRACE7(( " y=%d x=[% .12f;% .12f]", - y, - (double)x1 / (double)ras.precision, - (double)x2 / (double)ras.precision )); + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bRight ) + e1 = e2; - /* Drop-out control */ - - /* e2 x2 x1 e1 */ - /* */ - /* ^ | */ - /* | | */ - /* +-------------+---------------------+------------+ */ - /* | | */ - /* | v */ - /* */ - /* pixel contour contour pixel */ - /* center center */ - - /* drop-out mode scan conversion rules (as defined in OpenType) */ - /* --------------------------------------------------------------- */ - /* 0 1, 2, 3 */ - /* 1 1, 2, 4 */ - /* 2 1, 2 */ - /* 3 same as mode 2 */ - /* 4 1, 2, 5 */ - /* 5 1, 2, 6 */ - /* 6, 7 same as mode 2 */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - pxl = e1; - - if ( e1 > e2 ) + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bRight ) { - Int dropOutControl = left->flags & 7; + c1 = e2 >> 3; + f1 = 0x80 >> ( e2 & 7 ); - - if ( e1 == e2 + ras.precision ) - { - switch ( dropOutControl ) - { - case 0: /* simple drop-outs including stubs */ - pxl = e2; - break; - - case 4: /* smart drop-outs including stubs */ - pxl = SMART( x1, x2 ); - break; - - case 1: /* simple drop-outs excluding stubs */ - case 5: /* smart drop-outs excluding stubs */ - - /* Drop-out Control Rules #4 and #6 */ - - /* The specification neither provides an exact definition */ - /* of a `stub' nor gives exact rules to exclude them. */ - /* */ - /* Here the constraints we use to recognize a stub. */ - /* */ - /* upper stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Right is the successor of P_Left in that contour */ - /* - y is the top of P_Left and P_Right */ - /* */ - /* lower stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Left is the successor of P_Right in that contour */ - /* - y is the bottom of P_Left */ - /* */ - /* We draw a stub if the following constraints are met. */ - /* */ - /* - for an upper or lower stub, there is top or bottom */ - /* overshoot, respectively */ - /* - the covered interval is greater or equal to a half */ - /* pixel */ - - /* upper stub test */ - if ( left->next == right && - left->height <= 0 && - !( left->flags & Overshoot_Top && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - /* lower stub test */ - if ( right->next == left && - left->start == y && - !( left->flags & Overshoot_Bottom && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - if ( dropOutControl == 1 ) - pxl = e2; - else - pxl = SMART( x1, x2 ); - break; - - default: /* modes 2, 3, 6, 7 */ - goto Exit; /* no drop-out control */ - } - - /* undocumented but confirmed: If the drop-out would result in a */ - /* pixel outside of the bounding box, use the pixel inside of the */ - /* bounding box instead */ - if ( pxl < 0 ) - pxl = e1; - else if ( TRUNC( pxl ) >= ras.bWidth ) - pxl = e2; - - /* check that the other pixel isn't set */ - e1 = ( pxl == e1 ) ? e2 : e1; - - e1 = TRUNC( e1 ); - - c1 = (Short)( e1 >> 3 ); - f1 = (Short)( e1 & 7 ); - - if ( e1 >= 0 && e1 < ras.bWidth && - ras.bLine[c1] & ( 0x80 >> f1 ) ) - goto Exit; - } - else - goto Exit; + if ( ras.bLine[c1] & f1 ) + return; } - e1 = TRUNC( pxl ); - - if ( e1 >= 0 && e1 < ras.bWidth ) + if ( e1 >= 0 && e1 <= ras.bRight ) { - FT_TRACE7(( " -> x=%ld", e1 )); + c1 = e1 >> 3; + f1 = 0x80 >> ( e1 & 7 ); - c1 = (Short)( e1 >> 3 ); - f1 = (Short)( e1 & 7 ); + FT_TRACE7(( " y=%d x=%d%s\n", y, e1, + ras.bLine[c1] & f1 ? " redundant" : "" )); - ras.bLine[c1] |= (char)( 0x80 >> f1 ); + ras.bLine[c1] |= f1; } - - Exit: - FT_TRACE7(( " dropout=%d\n", left->flags & 7 )); } static void Vertical_Sweep_Step( RAS_ARG ) { - ras.bLine -= ras.target.pitch; + ras.bLine -= ras.bPitch; } @@ -2450,8 +2103,8 @@ */ static void - Horizontal_Sweep_Init( RAS_ARGS Short min, - Short max ) + Horizontal_Sweep_Init( RAS_ARGS Int min, + Int max ) { /* nothing, really */ FT_UNUSED_RASTER; @@ -2461,22 +2114,18 @@ static void - Horizontal_Sweep_Span( RAS_ARGS Short y, + Horizontal_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2; - - FT_UNUSED( left ); - FT_UNUSED( right ); + Long e1 = CEILING( x1 ); + Long e2 = FLOOR( x2 ); - FT_TRACE7(( " x=%d y=[% .12f;% .12f]", + FT_TRACE7(( " x=%d y=[% .*f;% .*f]", y, - (double)x1 / (double)ras.precision, - (double)x2 / (double)ras.precision )); + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); /* We should not need this procedure but the vertical sweep */ /* mishandles horizontal lines through pixel centers. So we */ @@ -2484,20 +2133,18 @@ /* */ /* XXX: Can we handle horizontal lines better and drop this? */ - e1 = CEILING( x1 ); - if ( x1 == e1 ) { e1 = TRUNC( e1 ); - if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) + if ( e1 >= 0 && e1 <= ras.bTop ) { - Byte f1; + Int f1; PByte bits; - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); FT_TRACE7(( bits[0] & f1 ? " redundant" : " -> y=%ld edge", e1 )); @@ -2506,20 +2153,18 @@ } } - e2 = FLOOR ( x2 ); - if ( x2 == e2 ) { e2 = TRUNC( e2 ); - if ( e2 >= 0 && (ULong)e2 < ras.target.rows ) + if ( e2 >= 0 && e2 <= ras.bTop ) { - Byte f1; + Int f1; PByte bits; - bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); FT_TRACE7(( bits[0] & f1 ? " redundant" : " -> y=%ld edge", e2 )); @@ -2533,122 +2178,42 @@ static void - Horizontal_Sweep_Drop( RAS_ARGS Short y, + Horizontal_Sweep_Drop( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2, pxl; + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); PByte bits; - Byte f1; + Int f1; - FT_TRACE7(( " x=%d y=[% .12f;% .12f]", - y, - (double)x1 / (double)ras.precision, - (double)x2 / (double)ras.precision )); + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bTop ) + e1 = e2; - /* During the horizontal sweep, we only take care of drop-outs */ - - /* e1 + <-- pixel center */ - /* | */ - /* x1 ---+--> <-- contour */ - /* | */ - /* | */ - /* x2 <--+--- <-- contour */ - /* | */ - /* | */ - /* e2 + <-- pixel center */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - pxl = e1; - - if ( e1 > e2 ) + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bTop ) { - Int dropOutControl = left->flags & 7; + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); - - if ( e1 == e2 + ras.precision ) - { - switch ( dropOutControl ) - { - case 0: /* simple drop-outs including stubs */ - pxl = e2; - break; - - case 4: /* smart drop-outs including stubs */ - pxl = SMART( x1, x2 ); - break; - - case 1: /* simple drop-outs excluding stubs */ - case 5: /* smart drop-outs excluding stubs */ - /* see Vertical_Sweep_Drop for details */ - - /* rightmost stub test */ - if ( left->next == right && - left->height <= 0 && - !( left->flags & Overshoot_Top && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - /* leftmost stub test */ - if ( right->next == left && - left->start == y && - !( left->flags & Overshoot_Bottom && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - if ( dropOutControl == 1 ) - pxl = e2; - else - pxl = SMART( x1, x2 ); - break; - - default: /* modes 2, 3, 6, 7 */ - goto Exit; /* no drop-out control */ - } - - /* undocumented but confirmed: If the drop-out would result in a */ - /* pixel outside of the bounding box, use the pixel inside of the */ - /* bounding box instead */ - if ( pxl < 0 ) - pxl = e1; - else if ( (ULong)( TRUNC( pxl ) ) >= ras.target.rows ) - pxl = e2; - - /* check that the other pixel isn't set */ - e1 = ( pxl == e1 ) ? e2 : e1; - - e1 = TRUNC( e1 ); - - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); - - if ( e1 >= 0 && - (ULong)e1 < ras.target.rows && - *bits & f1 ) - goto Exit; - } - else - goto Exit; + if ( *bits & f1 ) + return; } - e1 = TRUNC( pxl ); - - if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) + if ( e1 >= 0 && e1 <= ras.bTop ) { - FT_TRACE7(( " -> y=%ld", e1 )); + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); + FT_TRACE7(( " x=%d y=%d%s\n", y, e1, + *bits & f1 ? " redundant" : "" )); - bits[0] |= f1; + *bits |= f1; } - - Exit: - FT_TRACE7(( " dropout=%d\n", left->flags & 7 )); } @@ -2664,116 +2229,61 @@ * * Generic Sweep Drawing routine * + * Note that this routine is executed with the pool containing at least + * two valid profiles (up and down) and two y-turns (top and bottom). + * */ - static Bool + static void Draw_Sweep( RAS_ARG ) { - Short y, y_change, y_height; + Int min_Y, max_Y, dropouts; + Int y, y_turn; - PProfile P, Q, P_Left, P_Right; + PProfile *Q, P, P_Left, P_Right; - Short min_Y, max_Y, top, bottom, dropouts; - - Long x1, x2, xs, e1, e2; - - TProfileList waiting; - TProfileList draw_left, draw_right; + TProfileList waiting = ras.fProfile; + TProfileList draw_left = NULL; + TProfileList draw_right = NULL; - /* initialize empty linked lists */ + /* use y_turns to set the drawing range */ - Init_Linked( &waiting ); - - Init_Linked( &draw_left ); - Init_Linked( &draw_right ); - - /* first, compute min and max Y */ - - P = ras.fProfile; - max_Y = (Short)TRUNC( ras.minY ); - min_Y = (Short)TRUNC( ras.maxY ); - - while ( P ) - { - Q = P->link; - - bottom = (Short)P->start; - top = (Short)( P->start + P->height - 1 ); - - if ( min_Y > bottom ) - min_Y = bottom; - if ( max_Y < top ) - max_Y = top; - - P->X = 0; - InsNew( &waiting, P ); - - P = Q; - } - - /* check the Y-turns */ - if ( ras.numTurns == 0 ) - { - ras.error = FT_THROW( Invalid_Outline ); - return FAILURE; - } + min_Y = (Int)ras.maxBuff[0]; + max_Y = (Int)ras.maxBuff[ras.numTurns] - 1; /* now initialize the sweep */ ras.Proc_Sweep_Init( RAS_VARS min_Y, max_Y ); - /* then compute the distance of each profile from min_Y */ - - P = waiting; - - while ( P ) - { - P->countL = P->start - min_Y; - P = P->link; - } - /* let's go */ - y = min_Y; - y_height = 0; - - if ( ras.numTurns > 0 && - ras.sizeBuff[-ras.numTurns] == min_Y ) - ras.numTurns--; - - while ( ras.numTurns > 0 ) + for ( y = min_Y; y <= max_Y; ) { - /* check waiting list for new activations */ + /* check waiting list for new profile activations */ - P = waiting; - - while ( P ) + Q = &waiting; + while ( *Q ) { - Q = P->link; - P->countL -= y_height; - if ( P->countL == 0 ) + P = *Q; + if ( P->start == y ) { - DelOld( &waiting, P ); + *Q = P->link; /* remove */ + /* each active list contains profiles with the same flow */ + /* left and right are arbitrary, correspond to TrueType */ if ( P->flags & Flow_Up ) InsNew( &draw_left, P ); else InsNew( &draw_right, P ); } - - P = Q; + else + Q = &P->link; } - /* sort the drawing lists */ + y_turn = (Int)*++ras.maxBuff; - Sort( &draw_left ); - Sort( &draw_right ); - - y_change = (Short)ras.sizeBuff[-ras.numTurns--]; - y_height = (Short)( y_change - y ); - - while ( y < y_change ) + do { /* let's trace */ @@ -2784,9 +2294,13 @@ while ( P_Left && P_Right ) { - x1 = P_Left ->X; - x2 = P_Right->X; + Long x1 = P_Left ->X; + Long x2 = P_Right->X; + Long xs; + + /* TrueType should have x2 > x1, but can be opposite */ + /* by mistake or in CFF/Type1, fix it then */ if ( x1 > x2 ) { xs = x1; @@ -2794,205 +2308,130 @@ x2 = xs; } - e1 = FLOOR( x1 ); - e2 = CEILING( x2 ); + if ( CEILING( x1 ) <= FLOOR( x2 ) ) + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2 ); - if ( x2 - x1 <= ras.precision && - e1 != x1 && e2 != x2 ) + /* otherwise, bottom ceiling > top floor, it is a drop-out */ + else { - if ( e1 > e2 || e2 == e1 + ras.precision ) + Int dropOutControl = P_Left->flags & 7; + + + /* Drop-out control */ + + /* e2 x2 x1 e1 */ + /* */ + /* ^ | */ + /* | | */ + /* +-------------+---------------------+------------+ */ + /* | | */ + /* | v */ + /* */ + /* pixel contour contour pixel */ + /* center center */ + + /* drop-out mode scan conversion rules (OpenType specs) */ + /* ------------------------------------------------------- */ + /* bit 0 exclude stubs if set */ + /* bit 1 ignore drop-outs if set */ + /* bit 2 smart rounding if set */ + + if ( dropOutControl & 2 ) + goto Next_Pair; + + /* The specification neither provides an exact definition */ + /* of a `stub' nor gives exact rules to exclude them. */ + /* */ + /* Here the constraints we use to recognize a stub. */ + /* */ + /* upper stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Right is the successor of P_Left in that contour */ + /* - y is the top of P_Left and P_Right */ + /* */ + /* lower stub: */ + /* */ + /* - P_Left and P_Right are in the same contour */ + /* - P_Left is the successor of P_Right in that contour */ + /* - y is the bottom of P_Left */ + /* */ + /* We draw a stub if the following constraints are met. */ + /* */ + /* - for an upper or lower stub, there is top or bottom */ + /* overshoot, respectively */ + /* - the covered interval is greater or equal to a half */ + /* pixel */ + + if ( dropOutControl & 1 ) { - Int dropOutControl = P_Left->flags & 7; + /* upper stub test */ + if ( P_Left->height == 1 && + P_Left->next == P_Right && + !( P_Left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; - - if ( dropOutControl != 2 ) - { - /* a drop-out was detected */ - - P_Left ->X = x1; - P_Right->X = x2; - - /* mark profile for drop-out processing */ - P_Left->countL = 1; - dropouts++; - } - - goto Skip_To_Next; + /* lower stub test */ + if ( P_Left->offset == 0 && + P_Right->next == P_Left && + !( P_Left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; } + + /* select the pixel to set and the other pixel */ + if ( dropOutControl & 4 ) + { + x2 = SMART( x1, x2 ); + x1 = x1 > x2 ? x2 + ras.precision : x2 - ras.precision; + } + else + { + x2 = FLOOR ( x2 ); + x1 = CEILING( x1 ); + } + + P_Left ->X = x2; + P_Right->X = x1; + + /* mark profile for drop-out processing */ + P_Left->flags |= Dropout; + dropouts++; } - ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + Next_Pair: + P_Left = P_Left->link; + P_Right = P_Right->link; + } - Skip_To_Next: + /* handle drop-outs _after_ the span drawing */ + P_Left = draw_left; + P_Right = draw_right; + + while ( dropouts ) + { + if ( P_Left->flags & Dropout ) + { + ras.Proc_Sweep_Drop( RAS_VARS y, P_Left->X, P_Right->X ); + + P_Left->flags &= ~Dropout; + dropouts--; + } P_Left = P_Left->link; P_Right = P_Right->link; } - /* handle drop-outs _after_ the span drawing -- */ - /* drop-out processing has been moved out of the loop */ - /* for performance tuning */ - if ( dropouts > 0 ) - goto Scan_DropOuts; - - Next_Line: - ras.Proc_Sweep_Step( RAS_VAR ); - y++; - - if ( y < y_change ) - { - Sort( &draw_left ); - Sort( &draw_right ); - } + Increment( &draw_left, 1 ); + Increment( &draw_right, -1 ); } - - /* now finalize the profiles that need it */ - - P = draw_left; - while ( P ) - { - Q = P->link; - if ( P->height == 0 ) - DelOld( &draw_left, P ); - P = Q; - } - - P = draw_right; - while ( P ) - { - Q = P->link; - if ( P->height == 0 ) - DelOld( &draw_right, P ); - P = Q; - } - } - - /* for gray-scaling, flush the bitmap scanline cache */ - while ( y <= max_Y ) - { - ras.Proc_Sweep_Step( RAS_VAR ); - y++; - } - - return SUCCESS; - - Scan_DropOuts: - - P_Left = draw_left; - P_Right = draw_right; - - while ( P_Left && P_Right ) - { - if ( P_Left->countL ) - { - P_Left->countL = 0; -#if 0 - dropouts--; /* -- this is useful when debugging only */ -#endif - ras.Proc_Sweep_Drop( RAS_VARS y, - P_Left->X, - P_Right->X, - P_Left, - P_Right ); - } - - P_Left = P_Left->link; - P_Right = P_Right->link; - } - - goto Next_Line; - } - - -#ifdef STANDALONE_ - - /************************************************************************** - * - * The following functions should only compile in stand-alone mode, - * i.e., when building this component without the rest of FreeType. - * - */ - - /************************************************************************** - * - * @Function: - * FT_Outline_Get_CBox - * - * @Description: - * Return an outline's `control box'. The control box encloses all - * the outline's points, including Bézier control points. Though it - * coincides with the exact bounding box for most glyphs, it can be - * slightly larger in some situations (like when rotating an outline - * that contains Bézier outside arcs). - * - * Computing the control box is very fast, while getting the bounding - * box can take much more time as it needs to walk over all segments - * and arcs in the outline. To get the latter, you can use the - * `ftbbox' component, which is dedicated to this single task. - * - * @Input: - * outline :: - * A pointer to the source outline descriptor. - * - * @Output: - * acbox :: - * The outline's control box. - * - * @Note: - * See @FT_Glyph_Get_CBox for a discussion of tricky fonts. - */ - - static void - FT_Outline_Get_CBox( const FT_Outline* outline, - FT_BBox *acbox ) - { - if ( outline && acbox ) - { - Long xMin, yMin, xMax, yMax; - - - if ( outline->n_points == 0 ) - { - xMin = 0; - yMin = 0; - xMax = 0; - yMax = 0; - } - else - { - FT_Vector* vec = outline->points; - FT_Vector* limit = vec + outline->n_points; - - - xMin = xMax = vec->x; - yMin = yMax = vec->y; - vec++; - - for ( ; vec < limit; vec++ ) - { - Long x, y; - - - x = vec->x; - if ( x < xMin ) xMin = x; - if ( x > xMax ) xMax = x; - - y = vec->y; - if ( y < yMin ) yMin = y; - if ( y > yMax ) yMax = y; - } - } - acbox->xMin = xMin; - acbox->xMax = xMax; - acbox->yMin = yMin; - acbox->yMax = yMax; + while ( ++y < y_turn ); } } -#endif /* STANDALONE_ */ - /************************************************************************** * @@ -3019,13 +2458,15 @@ Int band_stack[32]; /* enough to bisect 32-bit int bands */ + FT_TRACE6(( "%s pass [%d..%d]\n", + flipped ? "Horizontal" : "Vertical", + y_min, y_max )); + while ( 1 ) { ras.minY = (Long)y_min * ras.precision; ras.maxY = (Long)y_max * ras.precision; - ras.top = ras.buff; - ras.error = Raster_Err_Ok; if ( Convert_Glyph( RAS_VARS flipped ) ) @@ -3038,6 +2479,9 @@ if ( y_min == y_max ) return ras.error; /* still Raster_Overflow */ + FT_TRACE6(( "band [%d..%d]: to be bisected\n", + y_min, y_max )); + y_mid = ( y_min + y_max ) >> 1; band_stack[band_top++] = y_min; @@ -3045,9 +2489,12 @@ } else { + FT_TRACE6(( "band [%d..%d]: %hd profiles; %td bytes remaining\n", + y_min, y_max, ras.num_Profs, + (char*)ras.maxBuff - (char*)ras.top )); + if ( ras.fProfile ) - if ( Draw_Sweep( RAS_VAR ) ) - return ras.error; + Draw_Sweep( RAS_VAR ); if ( --band_top < 0 ) break; @@ -3076,53 +2523,48 @@ Render_Glyph( RAS_ARG ) { FT_Error error; + Long buffer[FT_MAX_BLACK_POOL]; + ras.buff = buffer; + ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + Set_High_Precision( RAS_VARS ras.outline.flags & FT_OUTLINE_HIGH_PRECISION ); - if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) - ras.dropOutControl = 2; - else - { - if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) - ras.dropOutControl = 4; - else - ras.dropOutControl = 0; + ras.dropOutControl = 0; - if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) - ras.dropOutControl += 1; - } + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) + ras.dropOutControl |= 2; + + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl |= 4; + + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl |= 1; + + FT_TRACE6(( "BW Raster: precision 1/%d, dropout mode %d\n", + ras.precision, ras.dropOutControl )); /* Vertical Sweep */ - FT_TRACE7(( "Vertical pass (ftraster)\n" )); - ras.Proc_Sweep_Init = Vertical_Sweep_Init; ras.Proc_Sweep_Span = Vertical_Sweep_Span; ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; ras.Proc_Sweep_Step = Vertical_Sweep_Step; - ras.bWidth = (UShort)ras.target.width; - ras.bOrigin = (Byte*)ras.target.buffer; - - if ( ras.target.pitch > 0 ) - ras.bOrigin += (Long)( ras.target.rows - 1 ) * ras.target.pitch; - - error = Render_Single_Pass( RAS_VARS 0, 0, (Int)ras.target.rows - 1 ); + error = Render_Single_Pass( RAS_VARS 0, 0, ras.bTop ); if ( error ) return error; /* Horizontal Sweep */ if ( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ) { - FT_TRACE7(( "Horizontal pass (ftraster)\n" )); - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; ras.Proc_Sweep_Span = Horizontal_Sweep_Span; ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - error = Render_Single_Pass( RAS_VARS 1, 0, (Int)ras.target.width - 1 ); + error = Render_Single_Pass( RAS_VARS 1, 0, ras.bRight ); if ( error ) return error; } @@ -3233,8 +2675,6 @@ black_TWorker worker[1]; #endif - Long buffer[FT_MAX_BLACK_POOL]; - if ( !raster ) return FT_THROW( Raster_Uninitialized ); @@ -3243,7 +2683,7 @@ return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) return Raster_Err_Ok; if ( !outline->contours || !outline->points ) @@ -3269,10 +2709,14 @@ return FT_THROW( Invalid_Argument ); ras.outline = *outline; - ras.target = *target_map; - ras.buff = buffer; - ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + ras.bTop = (Int)target_map->rows - 1; + ras.bRight = (Int)target_map->width - 1; + ras.bPitch = (Int)target_map->pitch; + ras.bOrigin = (PByte)target_map->buffer; + + if ( ras.bPitch > 0 ) + ras.bOrigin += ras.bTop * ras.bPitch; return Render_Glyph( RAS_VAR ); } diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h index b511b3a99e9..ad9cb1b9fe0 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c index 6d442b1ff8c..fd9f174f2e1 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h index cec35c8528a..cf3e73c0a24 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h index 989d8b44be1..326d42e0438 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h @@ -4,7 +4,7 @@ * * monochrome renderer error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c index 33712162e00..76181568af9 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h index 903bd2bc348..6e7a5c08e71 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2023 by + * Copyright (C) 2013-2024 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c index 0925940b03f..81072207b49 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -49,6 +49,10 @@ #include #endif +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.h" +#endif + #include "ttcmap.h" #include "ttkern.h" #include "ttmtx.h" @@ -1249,6 +1253,12 @@ #define PUT_PS_NAMES( a ) a #else #define PUT_PS_NAMES( a ) NULL +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#define PUT_GPOS_KERNING( a ) a +#else +#define PUT_GPOS_KERNING( a ) NULL #endif FT_DEFINE_SFNT_INTERFACE( @@ -1274,6 +1284,8 @@ tt_face_free_name, /* TT_Free_Table_Func free_name */ tt_face_load_kern, /* TT_Load_Table_Func load_kern */ + PUT_GPOS_KERNING( tt_face_load_gpos ), + /* TT_Load_Table_Func load_gpos */ tt_face_load_gasp, /* TT_Load_Table_Func load_gasp */ tt_face_load_pclt, /* TT_Load_Table_Func load_init */ @@ -1292,6 +1304,9 @@ /* since version 2.1.8 */ tt_face_get_kerning, /* TT_Face_GetKerningFunc get_kerning */ + PUT_GPOS_KERNING( tt_face_get_gpos_kerning ), + /* TT_Face_GetKerningFunc get_gpos_kerning */ + /* since version 2.2 */ tt_face_load_font_dir, /* TT_Load_Table_Func load_font_dir */ tt_face_load_hmtx, /* TT_Load_Metrics_Func load_hmtx */ diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h index 2445958b69f..6f71489fdc1 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h index e7a8eb04bb8..d3ca1d9aa8b 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c index f5d66ef8403..6ee4e5e939b 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -40,6 +40,10 @@ #include "ttbdf.h" #endif +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.h" +#endif + /************************************************************************** * @@ -1026,6 +1030,10 @@ LOAD_( gasp ); LOAD_( kern ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + LOAD_( gpos ); +#endif + face->root.num_glyphs = face->max_profile.numGlyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ @@ -1119,7 +1127,11 @@ flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ - if ( TT_FACE_HAS_KERNING( face ) ) + if ( TT_FACE_HAS_KERNING( face ) +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + || face->gpos_kerning_available +#endif + ) flags |= FT_FACE_FLAG_KERNING; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT @@ -1470,6 +1482,11 @@ /* freeing the kerning table */ tt_face_done_kern( face ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + /* freeing the GPOS table */ + tt_face_done_gpos( face ); +#endif + /* freeing the collection table */ FT_FREE( face->ttc_header.offsets ); face->ttc_header.count = 0; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h index 906aebbf904..90847d95732 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c index 7c0ce2205e6..14514bf9574 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,6 +18,7 @@ #include "sfwoff.h" #include +#include #include #include #include @@ -149,6 +150,7 @@ /* Miscellaneous checks. */ if ( woff.length != stream->size || woff.num_tables == 0 || + woff.num_tables > 0xFFFU || 44 + woff.num_tables * 20UL >= woff.length || 12 + woff.num_tables * 16UL >= woff.totalSfntSize || ( woff.totalSfntSize & 3 ) != 0 || @@ -169,21 +171,11 @@ /* Write sfnt header. */ { - FT_UInt searchRange, entrySelector, rangeShift, x; + FT_Int entrySelector = FT_MSB( woff.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff.num_tables * 16 - searchRange; - x = woff.num_tables; - entrySelector = 0; - while ( x ) - { - x >>= 1; - entrySelector += 1; - } - entrySelector--; - - searchRange = ( 1 << entrySelector ) * 16; - rangeShift = woff.num_tables * 16 - searchRange; - WRITE_ULONG ( sfnt_header, woff.flavor ); WRITE_USHORT( sfnt_header, woff.num_tables ); WRITE_USHORT( sfnt_header, searchRange ); diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h index d4384227376..a04735ffe28 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c index 2be44a347ad..589b3e0c6b7 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c @@ -4,7 +4,7 @@ * * WOFF2 format management (base). * - * Copyright (C) 2019-2023 by + * Copyright (C) 2019-2024 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,6 +18,7 @@ #include "sfwoff2.h" #include "woff2tags.h" #include +#include #include #include @@ -289,23 +290,15 @@ FT_ULong checksum = 0; FT_ULong aligned_size = size & ~3UL; FT_ULong i; - FT_ULong v; + FT_Int shift; for ( i = 0; i < aligned_size; i += 4 ) - checksum += ( (FT_ULong)buf[i ] << 24 ) | - ( (FT_ULong)buf[i + 1] << 16 ) | - ( (FT_ULong)buf[i + 2] << 8 ) | - ( (FT_ULong)buf[i + 3] << 0 ); + checksum += FT_NEXT_ULONG( buf ); - /* If size is not aligned to 4, treat as if it is padded with 0s. */ - if ( size != aligned_size ) - { - v = 0; - for ( i = aligned_size ; i < size; ++i ) - v |= (FT_ULong)buf[i] << ( 24 - 8 * ( i & 3 ) ); - checksum += v; - } + /* remaining bytes can be shifted and added one at a time */ + for ( shift = 24; i < size; i++, shift -= 8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( buf ) << shift; return checksum; } @@ -1799,7 +1792,6 @@ FT_Byte* sfnt = NULL; FT_Stream sfnt_stream = NULL; - FT_Byte* sfnt_header; FT_ULong sfnt_size; FT_Byte* uncompressed_buf = NULL; @@ -1853,6 +1845,7 @@ /* Miscellaneous checks. */ if ( woff2.length != stream->size || woff2.num_tables == 0 || + woff2.num_tables > 0xFFFU || 48 + woff2.num_tables * 20UL >= woff2.length || ( woff2.metaOffset == 0 && ( woff2.metaLength != 0 || woff2.metaOrigLength != 0 ) ) || @@ -2143,6 +2136,13 @@ WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; + if ( ttc_font->num_tables == 0 || ttc_font->num_tables > 0xFFFU ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 CollectionFontEntry\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + /* Create a temporary array. */ if ( FT_QNEW_ARRAY( temp_indices, ttc_font->num_tables ) ) @@ -2198,27 +2198,15 @@ FT_NEW( sfnt_stream ) ) goto Exit; - sfnt_header = sfnt; - - WRITE_ULONG( sfnt_header, woff2.flavor ); - - if ( woff2.num_tables ) { - FT_UInt searchRange, entrySelector, rangeShift, x; + FT_Byte* sfnt_header = sfnt; + + FT_Int entrySelector = FT_MSB( woff2.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff2.num_tables * 16 - searchRange; - x = woff2.num_tables; - entrySelector = 0; - while ( x ) - { - x >>= 1; - entrySelector += 1; - } - entrySelector--; - - searchRange = ( 1 << entrySelector ) * 16; - rangeShift = ( woff2.num_tables * 16 ) - searchRange; - + WRITE_ULONG ( sfnt_header, woff2.flavor ); WRITE_USHORT( sfnt_header, woff2.num_tables ); WRITE_USHORT( sfnt_header, searchRange ); WRITE_USHORT( sfnt_header, entrySelector ); diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h index 4901286ee08..f41140648dc 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h @@ -4,7 +4,7 @@ * * WOFFF2 format management (specification). * - * Copyright (C) 2019-2023 by + * Copyright (C) 2019-2024 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c index 9ba25dcbc13..28f4d1173c0 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h index ff52917ed5b..e2c5e72bf02 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2023 by + * Copyright (C) 2002-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h index 0af48c2478a..370898363f3 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2023 by + * Copyright (C) 2009-2024 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c index 281e7135eea..b37658dde9e 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -208,18 +208,19 @@ colr->num_base_glyphs = FT_NEXT_USHORT( p ); base_glyph_offset = FT_NEXT_ULONG( p ); - if ( base_glyph_offset >= table_size ) + if ( table_size <= base_glyph_offset ) goto InvalidTable; - if ( colr->num_base_glyphs * BASE_GLYPH_SIZE > - table_size - base_glyph_offset ) + if ( ( table_size - base_glyph_offset ) / BASE_GLYPH_SIZE + < colr->num_base_glyphs ) goto InvalidTable; layer_offset = FT_NEXT_ULONG( p ); colr->num_layers = FT_NEXT_USHORT( p ); - if ( layer_offset >= table_size ) + if ( table_size <= layer_offset ) goto InvalidTable; - if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) + if ( ( table_size - layer_offset ) / LAYER_SIZE + < colr->num_layers ) goto InvalidTable; if ( colr->version == 1 ) @@ -229,14 +230,14 @@ base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); - if ( base_glyphs_offset_v1 >= table_size - 4 ) + if ( table_size - 4 <= base_glyphs_offset_v1 ) goto InvalidTable; p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); - if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE > - table_size - base_glyphs_offset_v1 ) + if ( ( table_size - base_glyphs_offset_v1 ) / BASE_GLYPH_PAINT_RECORD_SIZE + < num_base_glyphs_v1 ) goto InvalidTable; colr->num_base_glyphs_v1 = num_base_glyphs_v1; @@ -244,19 +245,19 @@ layer_offset_v1 = FT_NEXT_ULONG( p ); - if ( layer_offset_v1 >= table_size ) + if ( table_size <= layer_offset_v1 ) goto InvalidTable; if ( layer_offset_v1 ) { - if ( layer_offset_v1 >= table_size - 4 ) + if ( table_size - 4 <= layer_offset_v1 ) goto InvalidTable; p1 = (FT_Byte*)( table + layer_offset_v1 ); num_layers_v1 = FT_PEEK_ULONG( p1 ); - if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE > - table_size - layer_offset_v1 ) + if ( ( table_size - layer_offset_v1 ) / LAYER_V1_LIST_PAINT_OFFSET_SIZE + < num_layers_v1 ) goto InvalidTable; colr->num_layers_v1 = num_layers_v1; @@ -279,7 +280,7 @@ clip_list_offset = FT_NEXT_ULONG( p ); - if ( clip_list_offset >= table_size ) + if ( table_size <= clip_list_offset ) goto InvalidTable; if ( clip_list_offset ) @@ -311,7 +312,7 @@ goto InvalidTable; var_store_offset = FT_NEXT_ULONG( p ); - if ( var_store_offset >= table_size ) + if ( table_size <= var_store_offset ) goto InvalidTable; if ( var_store_offset ) @@ -661,6 +662,7 @@ FT_UInt32 first_layer_index; + ENSURE_READ_BYTES( 5 ); num_layers = FT_NEXT_BYTE( p ); if ( num_layers > colr->num_layers_v1 ) return 0; @@ -1278,7 +1280,8 @@ while ( min < max ) { - FT_UInt mid = min + ( max - min ) / 2; + FT_UInt mid = min + ( max - min ) / 2; + FT_UShort gid; /* * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; @@ -1287,8 +1290,7 @@ */ FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; - FT_UShort gid = FT_NEXT_USHORT( p ); - + gid = FT_NEXT_USHORT( p ); if ( gid < glyph_id ) min = mid + 1; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h index 20c85f0359f..30031464c73 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c index 46ae08596f3..997eb869ffc 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h index 8e9913f0ccd..bb301ae88b6 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2023 by + * Copyright (C) 2018-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c index a47d08bd6de..f0411366af4 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h index 960c7da4946..a54e51df12d 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c index 7b44e9cd2e7..c3a5fae2cb9 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1046,7 +1046,7 @@ FT_LOCAL_DEF( void ) tt_face_free_name( TT_Face face ) { - FT_Memory memory = face->root.driver->root.memory; + FT_Memory memory = face->root.memory; TT_NameTable table = &face->name_table; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h index 1499dd5735f..2b1d62d9bd9 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c index 38ee9ae728a..27884118563 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h index 56d2b627661..34b3c0e18f2 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2023 by + * Copyright (C) 2006-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c index 1dfad4298bd..5698a62c8d1 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -204,8 +204,8 @@ /* now load the name strings */ if ( num_names ) { - FT_ULong p; - FT_Byte* strings; + FT_Byte* p; + FT_Byte* p_end; post_len -= (FT_ULong)num_glyphs * 2; @@ -214,36 +214,36 @@ post_len + 1 ) ) goto Fail; - strings = (FT_Byte*)( name_strings + num_names ); - if ( FT_STREAM_READ( strings, post_len ) ) + p = (FT_Byte*)( name_strings + num_names ); + if ( FT_STREAM_READ( p, post_len ) ) goto Fail; + p_end = p + post_len; + /* convert from Pascal- to C-strings and set pointers */ - for ( p = 0, n = 0; p < post_len && n < num_names; n++ ) + for ( n = 0; p < p_end && n < num_names; n++ ) { - FT_UInt len = strings[p]; + FT_UInt len = *p; - if ( len > 63U ) - { - error = FT_THROW( Invalid_File_Format ); - goto Fail; - } + /* names in the Adobe Glyph List are shorter than 40 characters */ + if ( len >= 40U ) + FT_TRACE4(( "load_format_20: unusual %u-char name found\n", len )); - strings[p] = 0; - name_strings[n] = strings + p + 1; - p += len + 1; + *p++ = 0; + name_strings[n] = p; + p += len; } - strings[post_len] = 0; + *p_end = 0; /* deal with missing or insufficient string data */ if ( n < num_names ) { FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n", - num_names - n )); + (FT_UShort)( num_names - n ) )); for ( ; n < num_names; n++ ) - name_strings[n] = strings + post_len; + name_strings[n] = p_end; } } @@ -436,13 +436,8 @@ format = face->postscript.FormatType; - if ( format == 0x00010000L ) - { - if ( idx < 258 ) /* paranoid checking */ - *PSname = MAC_NAME( idx ); - } - else if ( format == 0x00020000L || - format == 0x00025000L ) + if ( format == 0x00020000L || + format == 0x00025000L ) { TT_Post_Names names = &face->postscript_names; @@ -466,6 +461,11 @@ } } + /* version 1.0 is only valid with 258 glyphs */ + else if ( format == 0x00010000L && + face->max_profile.numGlyphs == 258 ) + *PSname = MAC_NAME( idx ); + /* nothing to do for format == 0x00030000L */ End: diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h index 528f1c5f2f2..150db6c3981 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c index 03f90a628d6..cb3a8abf182 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2023 by + * Copyright (C) 2005-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h index 07e2db461a5..96f80a58424 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c index eeedd9906be..532ccfa1737 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (base). * - * Copyright (C) 2019-2023 by + * Copyright (C) 2019-2024 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h index 1201848e5ec..d03b4b41bc9 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (specification). * - * Copyright (C) 2019-2023 by + * Copyright (C) 2019-2024 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c index 0918272f870..b7c0632a6fa 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c @@ -4,7 +4,7 @@ * * A new `perfect' anti-aliasing renderer (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -489,7 +489,7 @@ typedef ptrdiff_t FT_PtrDist; typedef struct gray_TWorker_ { - ft_jmp_buf jump_buffer; + FT_BBox cbox; TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ TCoord min_ey, max_ey; @@ -510,6 +510,8 @@ typedef ptrdiff_t FT_PtrDist; FT_Raster_Span_Func render_span; void* render_span_data; + ft_jmp_buf jump_buffer; + } gray_TWorker, *gray_PWorker; #if defined( _MSC_VER ) @@ -997,49 +999,12 @@ typedef ptrdiff_t FT_PtrDist; #endif /* - * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs - * is slightly faster in the following cases: - * - * - When the host CPU is 64-bit. - * - When SSE2 SIMD registers and instructions are available (even on - * x86). - * - * For other cases, using binary splits is actually slightly faster. + * For now, the code that uses DDA to render conic curves requires + * `FT_Int64` to be defined. See for example + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. */ -#if ( defined( __SSE2__ ) || \ - defined( __x86_64__ ) || \ - defined( _M_AMD64 ) || \ - ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \ - !defined( __VMS ) -# define FT_SSE2 1 -#else -# define FT_SSE2 0 -#endif -#if FT_SSE2 || \ - defined( __aarch64__ ) || \ - defined( _M_ARM64 ) -# define BEZIER_USE_DDA 1 -#else -# define BEZIER_USE_DDA 0 -#endif - - /* - * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64` - * to be defined. If `FT_INT64` is not defined, meaning there is no - * 64-bit type available, disable it to avoid compilation errors. See for - * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. - */ -#if !defined( FT_INT64 ) -# undef BEZIER_USE_DDA -# define BEZIER_USE_DDA 0 -#endif - -#if BEZIER_USE_DDA - -#if FT_SSE2 -# include -#endif +#ifdef FT_INT64 #define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) @@ -1095,16 +1060,17 @@ typedef ptrdiff_t FT_PtrDist; return; } - /* We can calculate the number of necessary bisections because */ + /* We can calculate the number of necessary segments because */ /* each bisection predictably reduces deviation exactly 4-fold. */ /* Even 32-bit deviation would vanish after 16 bisections. */ - shift = 0; + shift = 16; do { - dx >>= 2; - shift += 1; + dx >>= 2; + shift--; } while ( dx > ONE_PIXEL / 4 ); + count = 0x10000U >> shift; /* * The (P0,P1,P2) arc equation, for t in [0,1] range: @@ -1150,75 +1116,19 @@ typedef ptrdiff_t FT_PtrDist; * = (B << (33 - N)) + (A << (32 - 2*N)) */ -#if FT_SSE2 - /* Experience shows that for small shift values, */ - /* SSE2 is actually slower. */ - if ( shift > 2 ) - { - union - { - struct { FT_Int64 ax, ay, bx, by; } i; - struct { __m128i a, b; } vec; + rx = LEFT_SHIFT( ax, shift + shift ); + ry = LEFT_SHIFT( ay, shift + shift ); - } u; + qx = LEFT_SHIFT( bx, shift + 17 ) + rx; + qy = LEFT_SHIFT( by, shift + 17 ) + ry; - union - { - struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i; - __m128i vec; - - } v; - - __m128i a, b; - __m128i r, q, q2; - __m128i p; - - - u.i.ax = ax; - u.i.ay = ay; - u.i.bx = bx; - u.i.by = by; - - a = _mm_load_si128( &u.vec.a ); - b = _mm_load_si128( &u.vec.b ); - - r = _mm_slli_epi64( a, 33 - 2 * shift ); - q = _mm_slli_epi64( b, 33 - shift ); - q2 = _mm_slli_epi64( a, 32 - 2 * shift ); - - q = _mm_add_epi64( q2, q ); - - v.i.px_lo = 0; - v.i.px_hi = p0.x; - v.i.py_lo = 0; - v.i.py_hi = p0.y; - - p = _mm_load_si128( &v.vec ); - - for ( count = 1U << shift; count > 0; count-- ) - { - p = _mm_add_epi64( p, q ); - q = _mm_add_epi64( q, r ); - - _mm_store_si128( &v.vec, p ); - - gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi ); - } - - return; - } -#endif /* FT_SSE2 */ - - rx = LEFT_SHIFT( ax, 33 - 2 * shift ); - ry = LEFT_SHIFT( ay, 33 - 2 * shift ); - - qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift ); - qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift ); + rx *= 2; + ry *= 2; px = LEFT_SHIFT( p0.x, 32 ); py = LEFT_SHIFT( p0.y, 32 ); - for ( count = 1U << shift; count > 0; count-- ) + do { px += qx; py += qy; @@ -1227,10 +1137,10 @@ typedef ptrdiff_t FT_PtrDist; gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), (FT_Pos)( py >> 32 ) ); - } + } while ( --count ); } -#else /* !BEZIER_USE_DDA */ +#else /* !FT_INT64 */ /* * Note that multiple attempts to speed up the function below @@ -1324,7 +1234,7 @@ typedef ptrdiff_t FT_PtrDist; } while ( --draw ); } -#endif /* !BEZIER_USE_DDA */ +#endif /* !FT_INT64 */ /* @@ -1486,139 +1396,6 @@ typedef ptrdiff_t FT_PtrDist; } - static void - gray_sweep( RAS_ARG ) - { - int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 - : INT_MIN; - int coverage; - int y; - - - for ( y = ras.min_ey; y < ras.max_ey; y++ ) - { - PCell cell = ras.ycells[y - ras.min_ey]; - TCoord x = ras.min_ex; - TArea cover = 0; - - unsigned char* line = ras.target.origin - ras.target.pitch * y; - - - for ( ; cell != ras.cell_null; cell = cell->next ) - { - TArea area; - - - if ( cover != 0 && cell->x > x ) - { - FT_FILL_RULE( coverage, cover, fill ); - FT_GRAY_SET( line + x, coverage, cell->x - x ); - } - - cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); - area = cover - cell->area; - - if ( area != 0 && cell->x >= ras.min_ex ) - { - FT_FILL_RULE( coverage, area, fill ); - line[cell->x] = (unsigned char)coverage; - } - - x = cell->x + 1; - } - - if ( cover != 0 ) /* only if cropped */ - { - FT_FILL_RULE( coverage, cover, fill ); - FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); - } - } - } - - - static void - gray_sweep_direct( RAS_ARG ) - { - int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 - : INT_MIN; - int coverage; - int y; - - FT_Span span[FT_MAX_GRAY_SPANS]; - int n = 0; - - - for ( y = ras.min_ey; y < ras.max_ey; y++ ) - { - PCell cell = ras.ycells[y - ras.min_ey]; - TCoord x = ras.min_ex; - TArea cover = 0; - - - for ( ; cell != ras.cell_null; cell = cell->next ) - { - TArea area; - - - if ( cover != 0 && cell->x > x ) - { - FT_FILL_RULE( coverage, cover, fill ); - - span[n].coverage = (unsigned char)coverage; - span[n].x = (short)x; - span[n].len = (unsigned short)( cell->x - x ); - - if ( ++n == FT_MAX_GRAY_SPANS ) - { - /* flush the span buffer and reset the count */ - ras.render_span( y, n, span, ras.render_span_data ); - n = 0; - } - } - - cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); - area = cover - cell->area; - - if ( area != 0 && cell->x >= ras.min_ex ) - { - FT_FILL_RULE( coverage, area, fill ); - - span[n].coverage = (unsigned char)coverage; - span[n].x = (short)cell->x; - span[n].len = 1; - - if ( ++n == FT_MAX_GRAY_SPANS ) - { - /* flush the span buffer and reset the count */ - ras.render_span( y, n, span, ras.render_span_data ); - n = 0; - } - } - - x = cell->x + 1; - } - - if ( cover != 0 ) /* only if cropped */ - { - FT_FILL_RULE( coverage, cover, fill ); - - span[n].coverage = (unsigned char)coverage; - span[n].x = (short)x; - span[n].len = (unsigned short)( ras.max_ex - x ); - - ++n; - } - - if ( n ) - { - /* flush the span buffer and reset the count */ - ras.render_span( y, n, span, ras.render_span_data ); - n = 0; - } - } - } - - #ifdef STANDALONE_ /************************************************************************** @@ -1934,7 +1711,7 @@ typedef ptrdiff_t FT_PtrDist; if ( continued ) FT_Trace_Enable(); - FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n", + FT_TRACE7(( "band [%d..%d]: %td cell%s remaining\n", ras.min_ey, ras.max_ey, ras.cell_null - ras.cell_free, @@ -1952,14 +1729,144 @@ typedef ptrdiff_t FT_PtrDist; } + static void + gray_sweep( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + unsigned char* line = ras.target.origin - ras.target.pitch * y; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, cell->x - x ); + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + line[cell->x] = (unsigned char)coverage; + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); + } + } + } + + + static void + gray_sweep_direct( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + FT_Span span[FT_MAX_GRAY_SPANS]; + int n = 0; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( cell->x - x ); + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)cell->x; + span[n].len = 1; + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( ras.max_ex - x ); + + ++n; + } + + if ( n ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + } + + static int gray_convert_glyph( RAS_ARG ) { - const TCoord yMin = ras.min_ey; - const TCoord yMax = ras.max_ey; - TCell buffer[FT_MAX_GRAY_POOL]; - size_t height = (size_t)( yMax - yMin ); + size_t height = (size_t)( ras.cbox.yMax - ras.cbox.yMin ); size_t n = FT_MAX_GRAY_POOL / 8; TCoord y; TCoord bands[32]; /* enough to accommodate bisections */ @@ -1985,35 +1892,36 @@ typedef ptrdiff_t FT_PtrDist; height = ( height + n - 1 ) / n; } - for ( y = yMin; y < yMax; ) + for ( y = ras.cbox.yMin; y < ras.cbox.yMax; ) { ras.min_ey = y; y += height; - ras.max_ey = FT_MIN( y, yMax ); + ras.max_ey = FT_MIN( y, ras.cbox.yMax ); + + ras.count_ey = ras.max_ey - ras.min_ey; band = bands; - band[1] = ras.min_ey; - band[0] = ras.max_ey; + band[1] = ras.cbox.xMin; + band[0] = ras.cbox.xMax; do { - TCoord width = band[0] - band[1]; - TCoord w; + TCoord i; int error; - for ( w = 0; w < width; ++w ) - ras.ycells[w] = ras.cell_null; + ras.min_ex = band[1]; + ras.max_ex = band[0]; - /* memory management: skip ycells */ - n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / - sizeof ( TCell ); + /* memory management: zero out and skip ycells */ + for ( i = 0; i < ras.count_ey; ++i ) + ras.ycells[i] = ras.cell_null; + + n = ( (size_t)ras.count_ey * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) + / sizeof ( TCell ); ras.cell_free = buffer + n; ras.cell = ras.cell_null; - ras.min_ey = band[1]; - ras.max_ey = band[0]; - ras.count_ey = width; error = gray_convert_glyph_inner( RAS_VAR_ continued ); continued = 1; @@ -2031,10 +1939,10 @@ typedef ptrdiff_t FT_PtrDist; return error; /* render pool overflow; we will reduce the render band by half */ - width >>= 1; + i = ( band[0] - band[1] ) >> 1; /* this should never happen even with tiny rendering pool */ - if ( width == 0 ) + if ( i == 0 ) { FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); return FT_THROW( Raster_Overflow ); @@ -2042,7 +1950,7 @@ typedef ptrdiff_t FT_PtrDist; band++; band[1] = band[0]; - band[0] += width; + band[0] += i; } while ( band >= bands ); } @@ -2073,7 +1981,7 @@ typedef ptrdiff_t FT_PtrDist; return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) return Smooth_Err_Ok; if ( !outline->contours || !outline->points ) @@ -2093,10 +2001,7 @@ typedef ptrdiff_t FT_PtrDist; ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; - ras.min_ex = params->clip_box.xMin; - ras.min_ey = params->clip_box.yMin; - ras.max_ex = params->clip_box.xMax; - ras.max_ey = params->clip_box.yMax; + ras.cbox = params->clip_box; } else { @@ -2122,14 +2027,14 @@ typedef ptrdiff_t FT_PtrDist; ras.render_span = (FT_Raster_Span_Func)NULL; ras.render_span_data = NULL; - ras.min_ex = 0; - ras.min_ey = 0; - ras.max_ex = (FT_Pos)target_map->width; - ras.max_ey = (FT_Pos)target_map->rows; + ras.cbox.xMin = 0; + ras.cbox.yMin = 0; + ras.cbox.xMax = (FT_Pos)target_map->width; + ras.cbox.yMax = (FT_Pos)target_map->rows; } /* exit if nothing to do */ - if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) + if ( ras.cbox.xMin >= ras.cbox.xMax || ras.cbox.yMin >= ras.cbox.yMax ) return Smooth_Err_Ok; return gray_convert_glyph( RAS_VAR ); diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h index a5001bf40d3..940fbe8c79b 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h @@ -4,7 +4,7 @@ * * FreeType smooth renderer declaration * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h index f4ac93dc410..6d41fb8e0fd 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h @@ -4,7 +4,7 @@ * * smooth renderer error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c index 9b0e8886cb3..f0acc1ea4a6 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (body). * - * Copyright (C) 2000-2023 by + * Copyright (C) 2000-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h index f8bdc9938b3..d7b61a9e60e 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c index d1496fec7fa..4ab68eb9a12 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c @@ -4,7 +4,7 @@ * * TrueType font driver implementation (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -217,7 +217,20 @@ kerning->y = 0; if ( sfnt ) - kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph ); + { + /* Use 'kern' table if available since that can be faster; otherwise */ + /* use GPOS kerning pairs if available. */ + if ( ttface->kern_avail_bits != 0 ) + kerning->x = sfnt->get_kerning( ttface, + left_glyph, + right_glyph ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + else if ( ttface->gpos_kerning_available ) + kerning->x = sfnt->get_gpos_kerning( ttface, + left_glyph, + right_glyph ); +#endif + } return 0; } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h index 757a66f425d..3e1cf234fcf 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h @@ -4,7 +4,7 @@ * * High-level TrueType driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h index 008ee99853c..7ad937bd04d 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h @@ -4,7 +4,7 @@ * * TrueType error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c index dc427e8a116..b656ccf04e3 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -353,7 +353,8 @@ FT_Byte c, count; FT_Vector *vec, *vec_limit; FT_Pos x, y; - FT_Short *cont, *cont_limit, last; + FT_UShort *cont, *cont_limit; + FT_Int last; /* check that we can add the contours to the glyph */ @@ -372,7 +373,7 @@ last = -1; for ( ; cont < cont_limit; cont++ ) { - *cont = FT_NEXT_SHORT( p ); + *cont = FT_NEXT_USHORT( p ); if ( *cont <= last ) goto Invalid_Outline; @@ -418,11 +419,9 @@ /* and thus allocate the bytecode array size by ourselves */ if ( n_ins ) { - if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) ) + if ( FT_DUP( exec->glyphIns, p, n_ins ) ) return error; - FT_MEM_COPY( exec->glyphIns, p, (FT_Long)n_ins ); - exec->glyphSize = n_ins; } } @@ -432,7 +431,7 @@ p += n_ins; /* reading the point tags */ - flag = (FT_Byte*)outline->tags; + flag = outline->tags; flag_limit = flag + n_points; FT_ASSERT( flag ); @@ -465,7 +464,7 @@ vec = outline->points; vec_limit = vec + n_points; - flag = (FT_Byte*)outline->tags; + flag = outline->tags; x = 0; for ( ; vec < vec_limit; vec++, flag++ ) @@ -499,7 +498,7 @@ vec = outline->points; vec_limit = vec + n_points; - flag = (FT_Byte*)outline->tags; + flag = outline->tags; y = 0; for ( ; vec < vec_limit; vec++, flag++ ) @@ -532,8 +531,8 @@ *flag = (FT_Byte)( f & ON_CURVE_POINT ); } - outline->n_points = (FT_Short)n_points; - outline->n_contours = (FT_Short)n_contours; + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_UShort)n_contours; load->cursor = p; @@ -754,15 +753,13 @@ FT_UInt start_point, FT_UInt start_contour ) { - zone->n_points = (FT_UShort)load->outline.n_points + 4 - - (FT_UShort)start_point; - zone->n_contours = load->outline.n_contours - - (FT_Short)start_contour; + zone->n_points = load->outline.n_points + 4 - (FT_UShort)start_point; + zone->n_contours = load->outline.n_contours - (FT_UShort)start_contour; zone->org = load->extra_points + start_point; zone->cur = load->outline.points + start_point; zone->orus = load->extra_points2 + start_point; - zone->tags = (FT_Byte*)load->outline.tags + start_point; - zone->contours = (FT_UShort*)load->outline.contours + start_contour; + zone->tags = load->outline.tags + start_point; + zone->contours = load->outline.contours + start_contour; zone->first_point = (FT_UShort)start_point; } @@ -1046,7 +1043,7 @@ current.points = gloader->base.outline.points + num_base_points; current.n_points = gloader->base.outline.n_points - - (short)num_base_points; + (FT_UShort)num_base_points; have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | WE_HAVE_AN_XY_SCALE | @@ -1059,7 +1056,7 @@ /* get offset */ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) { - FT_UInt num_points = (FT_UInt)gloader->base.outline.n_points; + FT_UInt num_points = gloader->base.outline.n_points; FT_UInt k = (FT_UInt)subglyph->arg1; FT_UInt l = (FT_UInt)subglyph->arg2; FT_Vector* p1; @@ -1721,8 +1718,8 @@ FT_List_Add( &loader->composites, node ); } - start_point = (FT_UInt)gloader->base.outline.n_points; - start_contour = (FT_UInt)gloader->base.outline.n_contours; + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; /* for each subglyph, read composite header */ error = face->read_composite_glyph( loader ); @@ -1741,14 +1738,14 @@ if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || FT_IS_VARIATION( FT_FACE( face ) ) ) { - short i, limit; + FT_UShort i, limit; FT_SubGlyph subglyph; FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 }; FT_Vector* unrounded = NULL; - limit = (short)gloader->current.num_subglyphs; + limit = (FT_UShort)gloader->current.num_subglyphs; /* construct an outline structure for */ /* communication with `TT_Vary_Apply_Glyph_Deltas' */ @@ -1874,7 +1871,7 @@ linear_hadvance = loader->linear; linear_vadvance = loader->vadvance; - num_base_points = (FT_UInt)gloader->base.outline.n_points; + num_base_points = gloader->base.outline.n_points; error = load_truetype_glyph( loader, (FT_UInt)subglyph->index, @@ -1898,7 +1895,7 @@ loader->vadvance = linear_vadvance; } - num_points = (FT_UInt)gloader->base.outline.n_points; + num_points = gloader->base.outline.n_points; if ( num_points == num_base_points ) continue; @@ -2313,7 +2310,7 @@ * * 1) we have a `tricky' font that heavily relies on the interpreter to * render glyphs correctly, for example DFKai-SB, or - * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. + * 2) FT_RENDER_MODE_MONO (i.e, monochrome rendering) is requested. * * In those cases, backward compatibility needs to be turned off to get * correct rendering. The rendering is then completely up to the @@ -2719,7 +2716,7 @@ size->metrics->y_ppem < 24 ) glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - FT_TRACE1(( " subglyphs = %u, contours = %hd, points = %hd," + FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu," " flags = 0x%.3x\n", loader.gloader->base.num_subglyphs, glyph->outline.n_contours, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h index f18637dce33..22ea967f301 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c index 9d149ea365c..4f0083c96b7 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -129,9 +129,6 @@ * stream :: * The data stream. * - * size :: - * The size of the table holding the data. - * * @Output: * point_cnt :: * The number of points read. A zero value means that @@ -144,14 +141,14 @@ */ static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, - FT_ULong size, FT_UInt *point_cnt ) { FT_UShort *points = NULL; FT_UInt n; - FT_UInt runcnt; + FT_UInt runcnt, cnt; FT_UInt i, j; FT_UShort first; + FT_Byte* p; FT_Memory memory = stream->memory; FT_Error error; @@ -169,56 +166,60 @@ n |= FT_GET_BYTE(); } - if ( n > size ) - { - FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" )); - return NULL; - } - - /* in the nested loops below we increase `i' twice; */ - /* it is faster to simply allocate one more slot */ - /* than to add another test within the loop */ - if ( FT_QNEW_ARRAY( points, n + 1 ) ) + if ( FT_QNEW_ARRAY( points, n ) ) return NULL; - *point_cnt = n; - + p = stream->cursor; first = 0; i = 0; while ( i < n ) { - runcnt = FT_GET_BYTE(); + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); + cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; + + /* first point not included in run count */ + cnt++; + if ( cnt > n - i ) + cnt = n - i; + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) { - runcnt &= GX_PT_POINT_RUN_COUNT_MASK; - first += FT_GET_USHORT(); - points[i++] = first; + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; - /* first point not included in run count */ - for ( j = 0; j < runcnt; j++ ) + for ( j = 0; j < cnt; j++ ) { - first += FT_GET_USHORT(); + first += FT_NEXT_USHORT( p ); points[i++] = first; - if ( i >= n ) - break; } } else { - first += FT_GET_BYTE(); - points[i++] = first; + if ( cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; - for ( j = 0; j < runcnt; j++ ) + for ( j = 0; j < cnt; j++ ) { - first += FT_GET_BYTE(); + first += FT_NEXT_BYTE( p ); points[i++] = first; - if ( i >= n ) - break; } } } + stream->cursor = p; + + *point_cnt = n; + return points; + + Fail: + FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" )); + + FT_FREE( points ); + return NULL; } @@ -240,9 +241,6 @@ * stream :: * The data stream. * - * size :: - * The size of the table holding the data. - * * delta_cnt :: * The number of deltas to be read. * @@ -258,13 +256,12 @@ */ static FT_Fixed* ft_var_readpackeddeltas( FT_Stream stream, - FT_ULong size, FT_UInt delta_cnt ) { FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; FT_UInt i, j; - FT_UInt bytes_used; + FT_Byte* p; FT_Memory memory = stream->memory; FT_Error error; @@ -272,68 +269,51 @@ if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) return NULL; - i = 0; - bytes_used = 0; - - while ( i < delta_cnt && bytes_used < size ) + p = stream->cursor; + i = 0; + while ( i < delta_cnt ) { - runcnt = FT_GET_BYTE(); + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; - bytes_used++; + /* first point not included in run count */ + cnt++; + if ( cnt > delta_cnt - i ) + cnt = delta_cnt - i; if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) { - /* `cnt` + 1 zeroes get added */ - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) + for ( j = 0; j < cnt; j++ ) deltas[i++] = 0; } else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) { - /* `cnt` + 1 shorts from the stack */ - bytes_used += 2 * ( cnt + 1 ); - if ( bytes_used > size ) - { - FT_TRACE1(( "ft_var_readpackeddeltas:" - " number of short deltas too large\n" )); + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) goto Fail; - } - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) ); } else { - /* `cnt` + 1 signed bytes from the stack */ - bytes_used += cnt + 1; - if ( bytes_used > size ) - { - FT_TRACE1(( "ft_var_readpackeddeltas:" - " number of byte deltas too large\n" )); + if ( cnt > (FT_UInt)( stream->limit - p ) ) goto Fail; - } - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); - } - - if ( j <= cnt ) - { - FT_TRACE1(( "ft_var_readpackeddeltas:" - " number of deltas too large\n" )); - goto Fail; + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_CHAR( p ) ); } } - if ( i < delta_cnt ) - { - FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" )); - goto Fail; - } + stream->cursor = p; return deltas; Fail: + FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" )); + FT_FREE( deltas ); return NULL; } @@ -596,7 +576,7 @@ for ( j = 0; j < itemStore->axisCount; j++ ) { - FT_Short start, peak, end; + FT_Int start, peak, end; if ( FT_READ_SHORT( start ) || @@ -604,6 +584,10 @@ FT_READ_SHORT( end ) ) goto Exit; + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; + axisCoords[j].startCoord = FT_fdot14ToFixed( start ); axisCoords[j].peakCoord = FT_fdot14ToFixed( peak ); axisCoords[j].endCoord = FT_fdot14ToFixed( end ); @@ -1024,6 +1008,9 @@ if ( innerIndex >= varData->itemCount ) return 0; /* Out of range. */ + if ( varData->regionIdxCount == 0 ) + return 0; /* Avoid "applying zero offset to null pointer". */ + if ( varData->regionIdxCount < 16 ) { deltaSet = deltaSetStack; @@ -1074,43 +1061,32 @@ /* inner loop steps through axes in this region */ for ( j = 0; j < itemStore->axisCount; j++, axis++ ) { - /* compute the scalar contribution of this axis; */ - /* ignore invalid ranges */ - if ( axis->startCoord > axis->peakCoord || - axis->peakCoord > axis->endCoord ) - continue; + FT_Fixed ncv = ttface->blend->normalizedcoords[j]; - else if ( axis->startCoord < 0 && - axis->endCoord > 0 && - axis->peakCoord != 0 ) - continue; - /* peak of 0 means ignore this axis */ - else if ( axis->peakCoord == 0 ) - continue; - - else if ( ttface->blend->normalizedcoords[j] == axis->peakCoord ) + /* compute the scalar contribution of this axis */ + /* with peak of 0 used for invalid axes */ + if ( axis->peakCoord == ncv || + axis->peakCoord == 0 ) continue; /* ignore this region if coords are out of range */ - else if ( ttface->blend->normalizedcoords[j] <= axis->startCoord || - ttface->blend->normalizedcoords[j] >= axis->endCoord ) + else if ( ncv <= axis->startCoord || + ncv >= axis->endCoord ) { scalar = 0; break; } /* cumulative product of all the axis scalars */ - else if ( ttface->blend->normalizedcoords[j] < axis->peakCoord ) - scalar = - FT_MulDiv( scalar, - ttface->blend->normalizedcoords[j] - axis->startCoord, - axis->peakCoord - axis->startCoord ); - else - scalar = - FT_MulDiv( scalar, - axis->endCoord - ttface->blend->normalizedcoords[j], - axis->endCoord - axis->peakCoord ); + else if ( ncv < axis->peakCoord ) + scalar = FT_MulDiv( scalar, + ncv - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* ncv > axis->peakCoord */ + scalar = FT_MulDiv( scalar, + axis->endCoord - ncv, + axis->endCoord - axis->peakCoord ); } /* per-axis loop */ @@ -1920,28 +1896,17 @@ for ( i = 0; i < blend->num_axis; i++ ) { - FT_TRACE6(( " axis %d coordinate %.5f:\n", - i, (double)blend->normalizedcoords[i] / 65536 )); + FT_Fixed ncv = blend->normalizedcoords[i]; + + + FT_TRACE6(( " axis %d coordinate %.5f:\n", i, (double)ncv / 65536 )); /* It's not clear why (for intermediate tuples) we don't need */ /* to check against start/end -- the documentation says we don't. */ /* Similarly, it's unclear why we don't need to scale along the */ /* axis. */ - if ( tuple_coords[i] == 0 ) - { - FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); - continue; - } - - if ( blend->normalizedcoords[i] == 0 ) - { - FT_TRACE6(( " axis coordinate is zero, stop\n" )); - apply = 0; - break; - } - - if ( blend->normalizedcoords[i] == tuple_coords[i] ) + if ( tuple_coords[i] == ncv ) { FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n", (double)tuple_coords[i] / 65536 )); @@ -1949,31 +1914,37 @@ continue; } + if ( tuple_coords[i] == 0 ) + { + FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); + continue; + } + if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) { /* not an intermediate tuple */ - if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) || - blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) ) + if ( ( tuple_coords[i] > ncv && ncv > 0 ) || + ( tuple_coords[i] < ncv && ncv < 0 ) ) + { + FT_TRACE6(( " tuple coordinate %.5f fits\n", + (double)tuple_coords[i] / 65536 )); + apply = FT_MulDiv( apply, ncv, tuple_coords[i] ); + } + else { FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n", (double)tuple_coords[i] / 65536 )); apply = 0; break; } - - FT_TRACE6(( " tuple coordinate %.5f fits\n", - (double)tuple_coords[i] / 65536 )); - apply = FT_MulDiv( apply, - blend->normalizedcoords[i], - tuple_coords[i] ); } else { /* intermediate tuple */ - if ( blend->normalizedcoords[i] <= im_start_coords[i] || - blend->normalizedcoords[i] >= im_end_coords[i] ) + if ( ncv <= im_start_coords[i] || + ncv >= im_end_coords[i] ) { FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ is exceeded," " stop\n", @@ -1986,13 +1957,13 @@ FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n", (double)im_start_coords[i] / 65536, (double)im_end_coords[i] / 65536 )); - if ( blend->normalizedcoords[i] < tuple_coords[i] ) + if ( ncv < tuple_coords[i] ) apply = FT_MulDiv( apply, - blend->normalizedcoords[i] - im_start_coords[i], + ncv - im_start_coords[i], tuple_coords[i] - im_start_coords[i] ); - else + else /* ncv > tuple_coords[i] */ apply = FT_MulDiv( apply, - im_end_coords[i] - blend->normalizedcoords[i], + im_end_coords[i] - ncv, im_end_coords[i] - tuple_coords[i] ); } } @@ -2141,11 +2112,12 @@ outerIndex, innerIndex ); - v += delta << 2; + /* Convert delta in F2DOT14 to 16.16 before adding. */ + v += MUL_INT( delta, 4 ); - /* Clamp value range. */ - v = v >= 0x10000L ? 0x10000 : v; - v = v <= -0x10000L ? -0x10000 : v; + /* Clamp value to range [-1, 1]. */ + v = v >= 0x10000L ? 0x10000 : v; + v = v <= -0x10000L ? -0x10000 : v; new_normalized[i] = v; } @@ -2721,9 +2693,8 @@ FT_UInt n; - if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) ) + if ( FT_DUP( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ) ) goto Exit; - FT_MEM_COPY( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ); axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); @@ -3533,9 +3504,10 @@ FT_ULong here; FT_UInt i, j; - FT_Fixed* tuple_coords = NULL; - FT_Fixed* im_start_coords = NULL; - FT_Fixed* im_end_coords = NULL; + FT_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; GX_Blend blend = face->blend; @@ -3556,16 +3528,16 @@ { FT_TRACE2(( "\n" )); FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); - error = FT_Err_Ok; - goto Exit; + + return FT_Err_Ok; } if ( !face->cvt ) { FT_TRACE2(( "\n" )); FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); - error = FT_Err_Ok; - goto Exit; + + return FT_Err_Ok; } error = face->goto_table( face, TTAG_cvar, stream, &table_len ); @@ -3573,15 +3545,11 @@ { FT_TRACE2(( "is missing\n" )); - error = FT_Err_Ok; - goto Exit; + return FT_Err_Ok; } if ( FT_FRAME_ENTER( table_len ) ) - { - error = FT_Err_Ok; - goto Exit; - } + return FT_Err_Ok; table_start = FT_Stream_FTell( stream ); if ( FT_GET_LONG() != 0x00010000L ) @@ -3594,11 +3562,6 @@ FT_TRACE2(( "loaded\n" )); - if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || - FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || - FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) - goto FExit; - tupleCount = FT_GET_USHORT(); offsetToData = FT_GET_USHORT(); @@ -3621,9 +3584,8 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, - table_len, - &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); @@ -3634,8 +3596,12 @@ tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) - goto FExit; + if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || + FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) + goto Exit; + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) { @@ -3652,32 +3618,19 @@ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + tuple_coords = peak_coords; } - else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + else { FT_TRACE2(( "tt_face_vary_cvt:" " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto FExit; - } - else - { - if ( !blend->tuplecoords ) - { - FT_TRACE2(( "tt_face_vary_cvt:" - " no valid tuple coordinates available\n" )); - - error = FT_THROW( Invalid_Table ); - goto FExit; - } - - FT_MEM_COPY( - tuple_coords, - blend->tuplecoords + - ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, - blend->num_axis * sizeof ( FT_Fixed ) ); + goto Exit; } if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) @@ -3706,9 +3659,7 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, - table_len, - &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); points = localpoints; } else @@ -3719,7 +3670,6 @@ } deltas = ft_var_readpackeddeltas( stream, - table_len, point_count == 0 ? face->cvt_size : point_count ); @@ -3820,22 +3770,20 @@ for ( i = 0; i < face->cvt_size; i++ ) face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] ); - FExit: - FT_FRAME_EXIT(); + /* Iterate over all `FT_Size` objects and set `cvt_ready` to -1 */ + /* to trigger rescaling of all CVT values. */ + FT_List_Iterate( &root->sizes_list, + tt_cvt_ready_iterator, + NULL ); Exit: if ( sharedpoints != ALL_POINTS ) FT_FREE( sharedpoints ); - FT_FREE( tuple_coords ); - FT_FREE( im_start_coords ); - FT_FREE( im_end_coords ); FT_FREE( cvt_deltas ); + FT_FREE( peak_coords ); - /* iterate over all FT_Size objects and set `cvt_ready' to -1 */ - /* to trigger rescaling of all CVT values */ - FT_List_Iterate( &root->sizes_list, - tt_cvt_ready_iterator, - NULL ); + FExit: + FT_FRAME_EXIT(); return error; @@ -4099,9 +4047,10 @@ FT_ULong here; FT_UInt i, j; - FT_Fixed* tuple_coords = NULL; - FT_Fixed* im_start_coords = NULL; - FT_Fixed* im_end_coords = NULL; + FT_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; GX_Blend blend = face->blend; @@ -4136,27 +4085,17 @@ return FT_Err_Ok; } - if ( FT_NEW_ARRAY( points_org, n_points ) || - FT_NEW_ARRAY( points_out, n_points ) || - FT_NEW_ARRAY( has_delta, n_points ) ) - goto Fail1; - dataSize = blend->glyphoffsets[glyph_index + 1] - blend->glyphoffsets[glyph_index]; if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || FT_FRAME_ENTER( dataSize ) ) - goto Fail1; + return error; glyph_start = FT_Stream_FTell( stream ); /* each set of glyph variation data is formatted similarly to `cvar' */ - if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || - FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || - FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) - goto Fail2; - tupleCount = FT_GET_USHORT(); offsetToData = FT_GET_USHORT(); @@ -4168,7 +4107,7 @@ " invalid glyph variation array header\n" )); error = FT_THROW( Invalid_Table ); - goto Fail2; + goto FExit; } offsetToData += glyph_start; @@ -4179,9 +4118,8 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, - blend->gvar_size, - &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); @@ -4192,9 +4130,16 @@ tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - if ( FT_NEW_ARRAY( point_deltas_x, n_points ) || - FT_NEW_ARRAY( point_deltas_y, n_points ) ) - goto Fail3; + if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || + FT_NEW_ARRAY( point_deltas_x, 2 * n_points ) || + FT_QNEW_ARRAY( points_org, n_points ) || + FT_QNEW_ARRAY( points_out, n_points ) || + FT_QNEW_ARRAY( has_delta, n_points ) ) + goto Exit; + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; + point_deltas_y = point_deltas_x + n_points; for ( j = 0; j < n_points; j++ ) { @@ -4217,22 +4162,20 @@ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + tuple_coords = peak_coords; } - else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + else { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto Fail3; + goto Exit; } - else - FT_MEM_COPY( - tuple_coords, - blend->tuplecoords + - ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, - blend->num_axis * sizeof ( FT_Fixed ) ); if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { @@ -4260,9 +4203,7 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, - blend->gvar_size, - &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); points = localpoints; } else @@ -4272,11 +4213,9 @@ } deltas_x = ft_var_readpackeddeltas( stream, - blend->gvar_size, point_count == 0 ? n_points : point_count ); deltas_y = ft_var_readpackeddeltas( stream, - blend->gvar_size, point_count == 0 ? n_points : point_count ); @@ -4460,23 +4399,17 @@ unrounded[n_points - 2].y ) / 64; } - Fail3: - FT_FREE( point_deltas_x ); - FT_FREE( point_deltas_y ); - - Fail2: + Exit: if ( sharedpoints != ALL_POINTS ) FT_FREE( sharedpoints ); - FT_FREE( tuple_coords ); - FT_FREE( im_start_coords ); - FT_FREE( im_end_coords ); - - FT_FRAME_EXIT(); - - Fail1: FT_FREE( points_org ); FT_FREE( points_out ); FT_FREE( has_delta ); + FT_FREE( peak_coords ); + FT_FREE( point_deltas_x ); + + FExit: + FT_FRAME_EXIT(); return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h index e3da6d1705c..9326011e3a2 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader (specification) * - * Copyright (C) 2004-2023 by + * Copyright (C) 2004-2024 by * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c index 79df4555d94..951891dbf51 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -5270,11 +5270,11 @@ FT_UShort refp; FT_F26Dot6 dx, dy; - FT_Short contour, bounds; + FT_UShort contour, bounds; FT_UShort start, limit, i; - contour = (FT_Short)args[0]; + contour = (FT_UShort)args[0]; bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours; if ( BOUNDS( contour, bounds ) ) @@ -5290,15 +5290,13 @@ if ( contour == 0 ) start = 0; else - start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 - - exc->zp2.first_point ); + start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point; /* we use the number of points if in the twilight zone */ if ( exc->GS.gep2 == 0 ) limit = exc->zp2.n_points; else - limit = (FT_UShort)( exc->zp2.contours[contour] - - exc->zp2.first_point + 1 ); + limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point; for ( i = start; i < limit; i++ ) { @@ -5341,9 +5339,9 @@ /* Normal zone's `n_points' includes phantoms, so must */ /* use end of last contour. */ if ( exc->GS.gep2 == 0 ) - limit = (FT_UShort)exc->zp2.n_points; + limit = exc->zp2.n_points; else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) - limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 ); + limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; else limit = 0; diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h index e98e258fe7e..4f1a9bbc679 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c index 5b56af711df..d0ac3181204 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ * * Objects manager (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -115,7 +115,7 @@ FT_LOCAL_DEF( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort maxContours, TT_GlyphZone zone ) { FT_Error error; @@ -152,18 +152,20 @@ static const FT_String* tt_skip_pdffont_random_tag( const FT_String* name ) { - unsigned int i; + if ( ft_isupper( name[0] ) && + ft_isupper( name[1] ) && + ft_isupper( name[2] ) && + ft_isupper( name[3] ) && + ft_isupper( name[4] ) && + ft_isupper( name[5] ) && + '+' == name[6] && + name[7] ) + { + FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); + return name + 7; + } - - if ( ft_strlen( name ) < 8 || name[6] != '+' ) - return name; - - for ( i = 0; i < 6; i++ ) - if ( !ft_isupper( name[i] ) ) - return name; - - FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); - return name + 7; + return name; } @@ -254,17 +256,20 @@ { FT_Error error; FT_UInt32 checksum = 0; - FT_UInt i; + FT_Byte* p; + FT_Int shift; if ( FT_FRAME_ENTER( length ) ) return 0; - for ( ; length > 3; length -= 4 ) - checksum += (FT_UInt32)FT_GET_ULONG(); + p = (FT_Byte*)stream->cursor; - for ( i = 3; length > 0; length--, i-- ) - checksum += (FT_UInt32)FT_GET_BYTE() << ( i * 8 ); + for ( ; length > 3; length -= 4 ) + checksum += FT_NEXT_ULONG( p ); + + for ( shift = 24; length > 0; length--, shift -=8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( p ) << shift; FT_FRAME_EXIT(); @@ -782,8 +787,7 @@ FT_UInt instance_index = (FT_UInt)face_index >> 16; - if ( FT_HAS_MULTIPLE_MASTERS( ttface ) && - instance_index > 0 ) + if ( FT_HAS_MULTIPLE_MASTERS( ttface ) ) { error = FT_Set_Named_Instance( ttface, instance_index ); if ( error ) @@ -990,16 +994,16 @@ FT_Error error; FT_UInt i; - /* unscaled CVT values are already stored in 26.6 format */ - FT_Fixed scale = size->ttmetrics.scale >> 6; - /* Scale the cvt values to the new ppem. */ /* By default, we use the y ppem value for scaling. */ FT_TRACE6(( "CVT values:\n" )); for ( i = 0; i < size->cvt_size; i++ ) { - size->cvt[i] = FT_MulFix( face->cvt[i], scale ); + /* Unscaled CVT values are already stored in 26.6 format. */ + /* Note that this scaling operation is very sensitive to rounding; */ + /* the integer division by 64 must be applied to the first argument. */ + size->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale ); FT_TRACE6(( " %3d: %f (%f)\n", i, (double)face->cvt[i] / 64, (double)size->cvt[i] / 64 )); } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h index 40eb37b4c43..9c36ca78362 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ * * Objects manager (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -105,7 +105,7 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort maxContours, TT_GlyphZone zone ); #endif /* TT_USE_BYTECODE_INTERPRETER */ diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c index 54a64c7b462..9505b5f179f 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h index ed229fa4616..bc32b58020c 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c index d9b9398b013..a63cd4dc48a 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h index e0d5aa5a882..7f5cdda191f 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c index a4cdf372a9e..8ed01914a5a 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c @@ -4,7 +4,7 @@ * * Type 1 driver interface (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -312,10 +312,7 @@ { retval = ft_strlen( type1->glyph_names[idx] ) + 1; if ( value && value_len >= retval ) - { ft_memcpy( value, (void *)( type1->glyph_names[idx] ), retval ); - ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; - } } break; @@ -344,11 +341,8 @@ { retval = ft_strlen( type1->encoding.char_name[idx] ) + 1; if ( value && value_len >= retval ) - { ft_memcpy( value, (void *)( type1->encoding.char_name[idx] ), - retval - 1 ); - ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; - } + retval ); } break; diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h index ee7fcf43e01..5ff52b55b1a 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h @@ -4,7 +4,7 @@ * * High-level Type 1 driver interface (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h index 2fbd1e513f3..8aeb24ae188 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h @@ -4,7 +4,7 @@ * * Type 1 error codes (specification only). * - * Copyright (C) 2001-2023 by + * Copyright (C) 2001-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c index a32a4649d6d..c29e682510c 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h index c06484758a5..17a6a5941e3 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c index be7cd0fd5e9..ee7fb42a517 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c @@ -4,7 +4,7 @@ * * Type 1 font loader (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -751,6 +751,7 @@ PS_DesignMap dmap = blend->design_map + n; + FT_FREE( dmap->blend_points ); FT_FREE( dmap->design_points ); dmap->num_points = 0; } @@ -1043,9 +1044,9 @@ } /* allocate design map data */ - if ( FT_QNEW_ARRAY( map->design_points, num_points * 2 ) ) + if ( FT_QNEW_ARRAY( map->design_points, num_points ) || + FT_QNEW_ARRAY( map->blend_points, num_points ) ) goto Exit; - map->blend_points = map->design_points + num_points; map->num_points = (FT_Byte)num_points; for ( p = 0; p < num_points; p++ ) @@ -1876,9 +1877,8 @@ } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_QALLOC( temp, size ) ) + if ( FT_DUP( temp, base, size ) ) goto Fail; - FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); size -= (FT_ULong)t1face->type1.private_dict.lenIV; error = T1_Add_Table( table, @@ -2090,9 +2090,8 @@ } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_QALLOC( temp, size ) ) + if ( FT_DUP( temp, base, size ) ) goto Fail; - FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); size -= (FT_ULong)t1face->type1.private_dict.lenIV; error = T1_Add_Table( code_table, @@ -2284,7 +2283,7 @@ T1_FIELD_DICT_PRIVATE ) #endif - { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + T1_FIELD_ZERO }; @@ -2392,18 +2391,13 @@ T1_Field keyword = (T1_Field)t1_keywords; - for (;;) + while ( keyword->len ) { - FT_Byte* name; + FT_Byte* name = (FT_Byte*)keyword->ident; - name = (FT_Byte*)keyword->ident; - if ( !name ) - break; - - if ( cur[0] == name[0] && - len == ft_strlen( (const char *)name ) && - ft_memcmp( cur, name, len ) == 0 ) + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) { /* We found it -- run the parsing callback! */ /* We record every instance of every field */ diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h index d8c9d2d8abe..a45efa7cb7b 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h @@ -4,7 +4,7 @@ * * Type 1 font loader (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c index 69e4fd5065e..b1b27c31fe3 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c @@ -4,7 +4,7 @@ * * Type 1 objects manager (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h index 03847b27e96..3809370c1e0 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h @@ -4,7 +4,7 @@ * * Type 1 objects manager (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c index 6dec6c16c3e..3717ea7c572 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c @@ -4,7 +4,7 @@ * * Type 1 parser (body). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h index 0d9a2865df0..a0a2134d45c 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h @@ -4,7 +4,7 @@ * * Type 1 parser (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h index 40f36092622..5a3d2f1ef08 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h @@ -4,7 +4,7 @@ * * Type 1 tokenizer (specification). * - * Copyright (C) 1996-2023 by + * Copyright (C) 1996-2024 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, From 3c72c04de7a43d265dae7160fe53baaaa8ae6f73 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 28 Feb 2025 22:37:41 +0000 Subject: [PATCH 177/587] 8350818: Improve OperatingSystemMXBean cpu load tests to not accept -1.0 by default Reviewed-by: kevinw --- .../management/OperatingSystemMXBean/GetProcessCpuLoad.java | 4 ++-- .../management/OperatingSystemMXBean/GetSystemCpuLoad.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/jdk/com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java b/test/jdk/com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java index bbf26e099f3..ecb65b7b3ea 100644 --- a/test/jdk/com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java +++ b/test/jdk/com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.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 @@ -39,7 +39,7 @@ public class GetProcessCpuLoad { double load; for(int i=0; i<10; i++) { load = mbean.getProcessCpuLoad(); - if((load<0.0 || load>1.0) && load != -1.0) { + if(load<0.0 || load>1.0) { throw new RuntimeException("getProcessCpuLoad() returns " + load + " which is not in the [0.0,1.0] interval"); } diff --git a/test/jdk/com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java b/test/jdk/com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java index 71ee209258a..7bd9d162cb3 100644 --- a/test/jdk/com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java +++ b/test/jdk/com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.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 @@ -24,7 +24,7 @@ /* * @test * @bug 7028071 - * @summary Basic unit test of OperatingSystemMXBean.getProcessCpuLoad() + * @summary Basic unit test of OperatingSystemMXBean.getSystemCpuLoad() * * @run main GetSystemCpuLoad */ @@ -39,7 +39,7 @@ public class GetSystemCpuLoad { double load; for(int i=0; i<10; i++) { load = mbean.getSystemCpuLoad(); - if((load<0.0 || load>1.0) && load != -1.0) { + if(load<0.0 || load>1.0) { throw new RuntimeException("getSystemCpuLoad() returns " + load + " which is not in the [0.0,1.0] interval"); } From 785e7b47e05a4c6a2b28a16221fbeaa74db4db7d Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 28 Feb 2025 23:34:07 +0000 Subject: [PATCH 178/587] 8350819: Ignore core files Reviewed-by: erikj, dholmes --- .gitignore | 1 + make/conf/jib-profiles.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b57addfccc9..2d82e0d943c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ NashornProfile.txt /.cache /.gdbinit /.lldbinit +**/core.[0-9]* diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 397e75968e4..41da3833293 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -207,7 +207,8 @@ var getJibProfiles = function (input) { // Exclude list to use when Jib creates a source bundle data.src_bundle_excludes = [ "build", "{,**/}webrev*", "{,**/}.hg", "{,**/}JTwork*", "{,**/}JTreport*", - "{,**/}.git" + "{,**/}.git", + "{,**/}core.[0-9]*" ]; // Include list to use when creating a minimal jib source bundle which // contains just the jib configuration files. From 157e5ad4a3abc7aea9ec2ec3d2381e42101990b8 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Sun, 2 Mar 2025 03:43:46 +0000 Subject: [PATCH 179/587] 8350916: Remove misleading warning "Cannot dump shared archive while using shared archive" Reviewed-by: ccheung --- src/hotspot/share/cds/cdsConfig.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index a5c5742eaf2..ff11b807910 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -68,9 +68,16 @@ int CDSConfig::get_status() { void CDSConfig::initialize() { if (is_dumping_static_archive() && !is_dumping_final_static_archive()) { - if (RequireSharedSpaces) { - warning("Cannot dump shared archive while using shared archive"); - } + // Note: -Xshare and -XX:AOTMode flags are mutually exclusive. + // - Classic workflow: -Xshare:on and -Xshare:dump cannot take effect at the same time. + // - JEP 483 workflow: -XX:AOTMode:record and -XX:AOTMode=on cannot take effect at the same time. + // So we can never come to here with RequireSharedSpaces==true. + assert(!RequireSharedSpaces, "sanity"); + + // If dumping the classic archive, or making an AOT training run (dumping a preimage archive), + // for sanity, parse all classes from classfiles. + // TODO: in the future, if we want to support re-training on top of an existing AOT cache, this + // needs to be changed. UseSharedSpaces = false; } From 0a1eea112d9f709bac32908f216b8598e918ed33 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 2 Mar 2025 23:36:27 +0000 Subject: [PATCH 180/587] 8345492: Fix -Wzero-as-null-pointer-constant warnings in adlc code Reviewed-by: kvn, dlong --- src/hotspot/share/adlc/formssel.cpp | 12 ++++++------ src/hotspot/share/adlc/formssel.hpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index f18e9eddba5..2edec13c0ff 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1854,14 +1854,14 @@ void InsEncode::output(FILE *fp) { fprintf(fp,"InsEncode: "); _encoding.reset(); - while ( (encoding = (NameAndList*)_encoding.iter()) != 0 ) { + while ( (encoding = (NameAndList*)_encoding.iter()) != nullptr ) { // Output the encoding being used fprintf(fp,"%s(", encoding->name() ); // Output its parameter list, if any bool first_param = true; encoding->reset(); - while ( (parameter = encoding->iter()) != 0 ) { + while ( (parameter = encoding->iter()) != nullptr ) { // Output the ',' between parameters if ( ! first_param ) fprintf(fp,", "); first_param = false; @@ -3305,7 +3305,7 @@ void ComponentList::output(FILE *fp) { MatchNode::MatchNode(ArchDesc &ad, const char *result, const char *mexpr, const char *opType, MatchNode *lChild, MatchNode *rChild) : _AD(ad), _result(result), _name(mexpr), _opType(opType), - _lChild(lChild), _rChild(rChild), _internalop(0), _numleaves(0), + _lChild(lChild), _rChild(rChild), _internalop(nullptr), _numleaves(0), _commutative_id(0) { _numleaves = (lChild ? lChild->_numleaves : 0) + (rChild ? rChild->_numleaves : 0); @@ -3314,14 +3314,14 @@ MatchNode::MatchNode(ArchDesc &ad, const char *result, const char *mexpr, MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode) : _AD(ad), _result(mnode._result), _name(mnode._name), _opType(mnode._opType), _lChild(mnode._lChild), _rChild(mnode._rChild), - _internalop(0), _numleaves(mnode._numleaves), + _internalop(nullptr), _numleaves(mnode._numleaves), _commutative_id(mnode._commutative_id) { } MatchNode::MatchNode(ArchDesc &ad, MatchNode& mnode, int clone) : _AD(ad), _result(mnode._result), _name(mnode._name), _opType(mnode._opType), - _internalop(0), _numleaves(mnode._numleaves), + _internalop(nullptr), _numleaves(mnode._numleaves), _commutative_id(mnode._commutative_id) { if (mnode._lChild) { _lChild = new MatchNode(ad, *mnode._lChild, clone); @@ -3624,7 +3624,7 @@ void MatchNode::dump() { } void MatchNode::output(FILE *fp) { - if (_lChild==0 && _rChild==0) { + if (_lChild==nullptr && _rChild==nullptr) { fprintf(fp," %s",_name); // operand } else { diff --git a/src/hotspot/share/adlc/formssel.hpp b/src/hotspot/share/adlc/formssel.hpp index 61d0fb40f18..dca1a50991b 100644 --- a/src/hotspot/share/adlc/formssel.hpp +++ b/src/hotspot/share/adlc/formssel.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 @@ -973,8 +973,8 @@ public: int _commutative_id; // id of commutative operation // Public Methods - MatchNode(ArchDesc &ad, const char *result = 0, const char *expr = 0, - const char *opType=0, MatchNode *lChild=nullptr, + MatchNode(ArchDesc &ad, const char *result = nullptr, const char *expr = nullptr, + const char *opType=nullptr, MatchNode *lChild=nullptr, MatchNode *rChild=nullptr); MatchNode(ArchDesc &ad, MatchNode& mNode); // Shallow copy constructor; MatchNode(ArchDesc &ad, MatchNode& mNode, int clone); // Construct clone From d48ddfe49a4e0b07949912d3c91d6f4737658b3e Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Mon, 3 Mar 2025 02:22:15 +0000 Subject: [PATCH 181/587] 8350748: VectorAPI: Method "checkMaskFromIndexSize" should be force inlined Reviewed-by: psandoz --- .../jdk/incubator/vector/ByteVector.java | 38 +++++----------- .../jdk/incubator/vector/DoubleVector.java | 32 ++++---------- .../jdk/incubator/vector/FloatVector.java | 32 ++++---------- .../jdk/incubator/vector/IntVector.java | 34 ++++---------- .../jdk/incubator/vector/LongVector.java | 32 ++++---------- .../jdk/incubator/vector/ShortVector.java | 38 +++++----------- .../incubator/vector/X-Vector.java.template | 44 +++++++------------ 7 files changed, 73 insertions(+), 177 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index e3829141683..678ae25f29a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -3060,7 +3060,8 @@ public abstract class ByteVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3249,7 +3250,8 @@ public abstract class ByteVector extends AbstractVector { return vsp.dummyVector().fromBooleanArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromBooleanArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3431,7 +3433,8 @@ public abstract class ByteVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 1, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 1); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3499,7 +3502,8 @@ public abstract class ByteVector extends AbstractVector { } else { ByteSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3656,7 +3660,8 @@ public abstract class ByteVector extends AbstractVector { } else { ByteSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoBooleanArray0(a, offset, m); } @@ -3788,7 +3793,8 @@ public abstract class ByteVector extends AbstractVector { } ByteSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 1, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 1); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -4040,26 +4046,6 @@ public abstract class ByteVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - ByteSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - ByteSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, ByteSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index cbb21667a15..9f1e7f9ece4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -2836,7 +2836,8 @@ public abstract class DoubleVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3064,7 +3065,8 @@ public abstract class DoubleVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 8, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 8); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3132,7 +3134,8 @@ public abstract class DoubleVector extends AbstractVector { } else { DoubleSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3290,7 +3293,8 @@ public abstract class DoubleVector extends AbstractVector { } DoubleSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 8, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 8); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -3554,26 +3558,6 @@ public abstract class DoubleVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - DoubleSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - DoubleSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, DoubleSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 78259e7698b..cef1b431bf0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -2860,7 +2860,8 @@ public abstract class FloatVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3070,7 +3071,8 @@ public abstract class FloatVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 4, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 4); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3138,7 +3140,8 @@ public abstract class FloatVector extends AbstractVector { } else { FloatSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3277,7 +3280,8 @@ public abstract class FloatVector extends AbstractVector { } FloatSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 4, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 4); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -3504,26 +3508,6 @@ public abstract class FloatVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - FloatSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - FloatSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, FloatSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index d68bba1d7e2..e11381e82c5 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.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 @@ -3038,7 +3038,8 @@ public abstract class IntVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3248,7 +3249,8 @@ public abstract class IntVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 4, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 4); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3316,7 +3318,8 @@ public abstract class IntVector extends AbstractVector { } else { IntSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3455,7 +3458,8 @@ public abstract class IntVector extends AbstractVector { } IntSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 4, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 4); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -3682,26 +3686,6 @@ public abstract class IntVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - IntSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - IntSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, IntSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 1fa1cafac4e..4d54fbf7ad3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -2899,7 +2899,8 @@ public abstract class LongVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3127,7 +3128,8 @@ public abstract class LongVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 8, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 8); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3195,7 +3197,8 @@ public abstract class LongVector extends AbstractVector { } else { LongSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3353,7 +3356,8 @@ public abstract class LongVector extends AbstractVector { } LongSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 8, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 8); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -3617,26 +3621,6 @@ public abstract class LongVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - LongSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - LongSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, LongSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index 19d7fa1d95e..92ca4b1ca70 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -3061,7 +3061,8 @@ public abstract class ShortVector extends AbstractVector { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3242,7 +3243,8 @@ public abstract class ShortVector extends AbstractVector { return vsp.dummyVector().fromCharArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromCharArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3430,7 +3432,8 @@ public abstract class ShortVector extends AbstractVector { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, 2, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 2); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -3498,7 +3501,8 @@ public abstract class ShortVector extends AbstractVector { } else { ShortSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -3647,7 +3651,8 @@ public abstract class ShortVector extends AbstractVector { } else { ShortSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoCharArray0(a, offset, m); } @@ -3774,7 +3779,8 @@ public abstract class ShortVector extends AbstractVector { } ShortSpecies vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, 2, ms.byteSize()); + ((AbstractMask)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), 2); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -4026,26 +4032,6 @@ public abstract class ShortVector extends AbstractVector { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - ShortSpecies vsp, - VectorMask m, - int scale, - int limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - ShortSpecies vsp, - VectorMask m, - int scale, - long limit) { - ((AbstractMask)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, ShortSpecies vsp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index 05979330ab1..235641b57a0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -3666,7 +3666,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -3902,7 +3903,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return vsp.dummyVector().fromCharArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromCharArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -4061,7 +4063,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return vsp.dummyVector().fromBooleanArray0(a, offset, m, OFFSET_IN_RANGE); } - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); return vsp.dummyVector().fromBooleanArray0(a, offset, m, OFFSET_OUT_OF_RANGE); } @@ -4253,7 +4256,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_IN_RANGE).maybeSwap(bo); } - checkMaskFromIndexSize(offset, vsp, m, $sizeInBytes$, ms.byteSize()); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), $sizeInBytes$); return vsp.dummyVector().fromMemorySegment0(ms, offset, m, OFFSET_OUT_OF_RANGE).maybeSwap(bo); } @@ -4321,7 +4325,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } else { $Type$Species vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoArray0(a, offset, m); } @@ -4541,7 +4546,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } else { $Type$Species vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoCharArray0(a, offset, m); } @@ -4705,7 +4711,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } else { $Type$Species vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.length(), a.length)) { - checkMaskFromIndexSize(offset, vsp, m, 1, a.length); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, a.length, vsp.iota(), 1); } intoBooleanArray0(a, offset, m); } @@ -4838,7 +4845,8 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { } $Type$Species vsp = vspecies(); if (!VectorIntrinsics.indexInRange(offset, vsp.vectorByteSize(), ms.byteSize())) { - checkMaskFromIndexSize(offset, vsp, m, $sizeInBytes$, ms.byteSize()); + ((AbstractMask<$Boxtype$>)m) + .checkIndexByLane(offset, ms.byteSize(), vsp.iota(), $sizeInBytes$); } maybeSwap(bo).intoMemorySegment0(ms, offset, m); } @@ -5263,26 +5271,6 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { // End of low-level memory operations. - private static - void checkMaskFromIndexSize(int offset, - $Type$Species vsp, - VectorMask<$Boxtype$> m, - int scale, - int limit) { - ((AbstractMask<$Boxtype$>)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - - private static - void checkMaskFromIndexSize(long offset, - $Type$Species vsp, - VectorMask<$Boxtype$> m, - int scale, - long limit) { - ((AbstractMask<$Boxtype$>)m) - .checkIndexByLane(offset, limit, vsp.iota(), scale); - } - @ForceInline private void conditionalStoreNYI(int offset, $Type$Species vsp, From 93c878455bfffc07f115f9e20ee11b20186eb2be Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Mon, 3 Mar 2025 03:12:37 +0000 Subject: [PATCH 182/587] 8350716: [s390] intrinsify Thread.currentThread() Reviewed-by: lucy, mdoerr --- .../cpu/s390/templateInterpreterGenerator_s390.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index c40be5edec7..06ff4b363f5 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -2006,8 +2006,20 @@ address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(Abstract return __ addr_at(entry_off); } +address TemplateInterpreterGenerator::generate_currentThread() { + uint64_t entry_off = __ offset(); + + __ z_lg(Z_RET, Address(Z_thread, JavaThread::threadObj_offset())); + __ resolve_oop_handle(Z_RET); + + // Restore caller sp for c2i case. + __ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started. + __ z_br(Z_R14); + + return __ addr_at(entry_off); +} + // Not supported -address TemplateInterpreterGenerator::generate_currentThread() { return nullptr; } address TemplateInterpreterGenerator::generate_Float_intBitsToFloat_entry() { return nullptr; } address TemplateInterpreterGenerator::generate_Float_floatToRawIntBits_entry() { return nullptr; } address TemplateInterpreterGenerator::generate_Double_longBitsToDouble_entry() { return nullptr; } From 3657e92ead1e678942fcb272e77c3867eb5aa13e Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Mon, 3 Mar 2025 05:18:55 +0000 Subject: [PATCH 183/587] 8349637: Integer.numberOfLeadingZeros outputs incorrectly in certain cases Reviewed-by: thartmann, qamai, jbhateja --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 14 +- .../TestNumberOfContinuousZeros.java | 87 +++++++++++- .../vectorization/TestVectorZeroCount.java | 128 ++++++++++++++++++ 3 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 7356f5a1913..b8ddbfe5120 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -6227,15 +6227,21 @@ void C2_MacroAssembler::vector_count_leading_zeros_int_avx(XMMRegister dst, XMMR // Since IEEE 754 floating point format represents mantissa in 1.0 format // hence biased exponent can be used to compute leading zero count as per // following formula:- - // LZCNT = 32 - (biased_exp - 127) + // LZCNT = 31 - (biased_exp - 127) // Special handling has been introduced for Zero, Max_Int and -ve source values. // Broadcast 0xFF vpcmpeqd(xtmp1, xtmp1, xtmp1, vec_enc); vpsrld(xtmp1, xtmp1, 24, vec_enc); + // Remove the bit to the right of the highest set bit ensuring that the conversion to float cannot round up to a higher + // power of 2, which has a higher exponent than the input. This transformation is valid as only the highest set bit + // contributes to the leading number of zeros. + vpsrld(xtmp2, src, 1, vec_enc); + vpandn(xtmp3, xtmp2, src, vec_enc); + // Extract biased exponent. - vcvtdq2ps(dst, src, vec_enc); + vcvtdq2ps(dst, xtmp3, vec_enc); vpsrld(dst, dst, 23, vec_enc); vpand(dst, dst, xtmp1, vec_enc); @@ -6244,7 +6250,7 @@ void C2_MacroAssembler::vector_count_leading_zeros_int_avx(XMMRegister dst, XMMR // Exponent = biased_exp - 127 vpsubd(dst, dst, xtmp1, vec_enc); - // Exponent = Exponent + 1 + // Exponent_plus_one = Exponent + 1 vpsrld(xtmp3, xtmp1, 6, vec_enc); vpaddd(dst, dst, xtmp3, vec_enc); @@ -6257,7 +6263,7 @@ void C2_MacroAssembler::vector_count_leading_zeros_int_avx(XMMRegister dst, XMMR vpslld(xtmp1, xtmp3, 5, vec_enc); // Exponent is 32 if corresponding source lane contains max_int value. vpcmpeqd(xtmp2, dst, xtmp1, vec_enc); - // LZCNT = 32 - exponent + // LZCNT = 32 - exponent_plus_one vpsubd(dst, xtmp1, dst, vec_enc); // Replace LZCNT with a value 1 if corresponding source lane diff --git a/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java b/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java index db0b563d1fe..3a273c7be8c 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestNumberOfContinuousZeros.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. 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,6 +24,7 @@ /** * @test +* @bug 8297172 8331993 8349637 * @key randomness * @summary Test vectorization of numberOfTrailingZeros/numberOfLeadingZeros for Long * @requires vm.compiler2.enabled @@ -30,16 +32,20 @@ * (os.simpleArch == "aarch64" & vm.cpu.features ~= ".*sve.*") | * (os.simpleArch == "riscv64" & vm.cpu.features ~= ".*zvbb.*") * @library /test/lib / +* @modules jdk.incubator.vector * @run driver compiler.vectorization.TestNumberOfContinuousZeros */ package compiler.vectorization; +import jdk.incubator.vector.*; import compiler.lib.ir_framework.*; import java.util.Random; import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestNumberOfContinuousZeros { + private static final int[] SPECIAL = { 0x01FFFFFF, 0x03FFFFFE, 0x07FFFFFC, 0x0FFFFFF8, 0x1FFFFFF0, 0x3FFFFFE0, 0xFFFFFFFF }; private long[] inputLong; private int[] outputLong; private int[] inputInt; @@ -47,8 +53,8 @@ public class TestNumberOfContinuousZeros { private static final int LEN = 1024; private Random rng; - public static void main(String args[]) { - TestFramework.run(); + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); } public TestNumberOfContinuousZeros() { @@ -56,7 +62,7 @@ public class TestNumberOfContinuousZeros { outputLong = new int[LEN]; inputInt = new int[LEN]; outputInt = new int[LEN]; - rng = new Random(42); + rng = Utils.getRandomInstance(); for (int i = 0; i < LEN; ++i) { inputLong[i] = rng.nextLong(); inputInt[i] = rng.nextInt(); @@ -119,5 +125,80 @@ public class TestNumberOfContinuousZeros { Asserts.assertEquals(outputInt[i], Integer.numberOfLeadingZeros(inputInt[i])); } } + + @Setup + static Object[] setupSpecialIntArray() { + int[] res = new int[LEN]; + + for (int i = 0; i < LEN; i++) { + res[i] = SPECIAL[i % SPECIAL.length]; + } + + return new Object[] { res }; + } + + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_VI, "> 0"}) + @Arguments(setup = "setupSpecialIntArray") + public Object[] testSpecialIntLeadingZeros(int[] ints) { + int[] res = new int[LEN]; + + for (int i = 0; i < LEN; ++i) { + res[i] = Integer.numberOfLeadingZeros(ints[i]); + } + + return new Object[] { ints, res }; + } + + @Check(test = "testSpecialIntLeadingZeros") + public void checkSpecialIntLeadingZeros(Object[] vals) { + int[] in = (int[]) vals[0]; + int[] out = (int[]) vals[1]; + + for (int i = 0; i < LEN; ++i) { + int value = Integer.numberOfLeadingZeros(in[i]); + + if (out[i] != value) { + throw new IllegalStateException("Expected lzcnt(" + in[i] + ") to be " + value + " but got " + out[i]); + } + } + } + + private static final VectorSpecies SPECIES = IntVector.SPECIES_PREFERRED; + + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_VI, "> 0"}) + @Arguments(setup = "setupSpecialIntArray") + public Object[] checkSpecialIntLeadingZerosVector(int[] ints) { + int[] res = new int[LEN]; + + for (int i = 0; i < ints.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, ints, i); + av.lanewise(VectorOperators.LEADING_ZEROS_COUNT).intoArray(res, i); + } + + return new Object[] { ints, res }; + } + + @Check(test = "checkSpecialIntLeadingZerosVector") + public void checkSpecialIntLeadingZerosVector(Object[] vals) { + int[] ints = (int[]) vals[0]; + int[] res = (int[]) vals[1]; + + // Verification + + int[] check = new int[LEN]; + + for (int i = 0; i < ints.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, ints, i); + av.lanewise(VectorOperators.LEADING_ZEROS_COUNT).intoArray(check, i); + } + + for (int i = 0; i < LEN; i++) { + if (res[i] != check[i]) { + throw new IllegalStateException("Expected " + check[i] + " but got " + res[i]); + } + } + } } diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java new file mode 100644 index 00000000000..a29ade54008 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java @@ -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. + */ + +/* @test + * @bug 8349637 + * @summary Ensure that vectorization of numberOfLeadingZeros and numberOfTrailingZeros outputs correct values + * @library /test/lib / + * @run main/othervm compiler.vectorization.TestVectorZeroCount + */ + +package compiler.vectorization; + +import java.util.Random; + +import jdk.test.lib.Utils; + +public class TestVectorZeroCount { + private static final int SIZE = 1024; + private static final Random RANDOM = Utils.getRandomInstance(); + + private static final int[] INT_VALUES = new int[SIZE]; + private static final int[] INT_EXPECTED_LEADING = new int[SIZE]; + private static final int[] INT_RESULT_LEADING = new int[SIZE]; + private static final int[] INT_EXPECTED_TRAILING = new int[SIZE]; + private static final int[] INT_RESULT_TRAILING = new int[SIZE]; + + private static final long[] LONG_VALUES = new long[SIZE]; + private static final long[] LONG_EXPECTED_LEADING = new long[SIZE]; + private static final long[] LONG_RESULT_LEADING = new long[SIZE]; + private static final long[] LONG_EXPECTED_TRAILING = new long[SIZE]; + private static final long[] LONG_RESULT_TRAILING = new long[SIZE]; + + private static int intCounter = Integer.MIN_VALUE; + private static int longIterations = 100_000_000; + + public static boolean testInt() { + boolean done = false; + + // Non-vectorized loop as baseline (not vectorized because source array is initialized) + for (int i = 0; i < SIZE; ++i) { + INT_VALUES[i] = intCounter++; + if (intCounter == Integer.MAX_VALUE) { + done = true; + } + INT_EXPECTED_LEADING[i] = Integer.numberOfLeadingZeros(INT_VALUES[i]); + INT_EXPECTED_TRAILING[i] = Integer.numberOfTrailingZeros(INT_VALUES[i]); + } + // Vectorized loop + for (int i = 0; i < SIZE; ++i) { + INT_RESULT_LEADING[i] = Integer.numberOfLeadingZeros(INT_VALUES[i]); + } + for (int i = 0; i < SIZE; ++i) { + INT_RESULT_TRAILING[i] = Integer.numberOfTrailingZeros(INT_VALUES[i]); + } + + // Compare results + for (int i = 0; i < SIZE; ++i) { + if (INT_RESULT_LEADING[i] != INT_EXPECTED_LEADING[i]) { + throw new RuntimeException("Unexpected result for Integer.numberOfLeadingZeros(" + INT_VALUES[i] + "): " + INT_RESULT_LEADING[i] + ", expected " + INT_EXPECTED_LEADING[i]); + } + if (INT_RESULT_TRAILING[i] != INT_EXPECTED_TRAILING[i]) { + throw new RuntimeException("Unexpected result for Integer.numberOfTrailingZeros(" + INT_VALUES[i] + "): " + INT_RESULT_TRAILING[i] + ", expected " + INT_EXPECTED_TRAILING[i]); + } + } + return done; + } + + public static boolean testLong() { + boolean done = false; + + // Non-vectorized loop as baseline (not vectorized because source array is initialized) + for (int i = 0; i < SIZE; ++i) { + // Use random values because the long range is too large to iterate over it + LONG_VALUES[i] = RANDOM.nextLong(); + if (longIterations-- == 0) { + done = true; + } + LONG_EXPECTED_LEADING[i] = Long.numberOfLeadingZeros(LONG_VALUES[i]); + LONG_EXPECTED_TRAILING[i] = Long.numberOfTrailingZeros(LONG_VALUES[i]); + } + // Vectorized loop + for (int i = 0; i < SIZE; ++i) { + LONG_RESULT_LEADING[i] = Long.numberOfLeadingZeros(LONG_VALUES[i]); + } + for (int i = 0; i < SIZE; ++i) { + LONG_RESULT_TRAILING[i] = Long.numberOfTrailingZeros(LONG_VALUES[i]); + } + + // Compare results + for (int i = 0; i < SIZE; ++i) { + if (LONG_RESULT_LEADING[i] != LONG_EXPECTED_LEADING[i]) { + throw new RuntimeException("Unexpected result for Long.numberOfLeadingZeros(" + LONG_VALUES[i] + "): " + LONG_RESULT_LEADING[i] + ", expected " + LONG_EXPECTED_LEADING[i]); + } + if (LONG_RESULT_TRAILING[i] != LONG_EXPECTED_TRAILING[i]) { + throw new RuntimeException("Unexpected result for Long.numberOfTrailingZeros(" + LONG_VALUES[i] + "): " + LONG_RESULT_TRAILING[i] + ", expected " + LONG_EXPECTED_TRAILING[i]); + } + } + return done; + } + + public static void main(String[] args) { + // Run twice to make sure compiled code is used from the beginning + for (int i = 0; i < 2; ++i) { + while (!testLong()) ; + while (!testInt()) ; + } + } +} From 717c4997a2ba4df4e7c66db9efc6b9b4d5336424 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 3 Mar 2025 06:41:59 +0000 Subject: [PATCH 184/587] 8351014: ProblemList the com/sun/management/OperatingSystemMXBean cpuLoad tests on Windows Reviewed-by: lmesnik --- test/jdk/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6f111ddcbfd..37401913840 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -541,6 +541,9 @@ java/io/IO/IO.java 8337935 linux-pp com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java 8030957 aix-all +com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8351002 windows-all +com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java 8351002 windows-all + java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all java/lang/management/MemoryMXBean/PendingAllGC.sh 8158837 generic-all java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8247426 generic-all From b054d24df55a73bae70c784f6e75b3eb56d4be8b Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 3 Mar 2025 07:48:12 +0000 Subject: [PATCH 185/587] 8350584: Check the usage of LOG_PLEASE Reviewed-by: stuefe --- test/hotspot/gtest/metaspace/test_clms.cpp | 2 +- test/hotspot/gtest/metaspace/test_metaspacearena.cpp | 2 +- test/hotspot/gtest/runtime/test_os_reserve_between.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/gtest/metaspace/test_clms.cpp b/test/hotspot/gtest/metaspace/test_clms.cpp index ca126b7f615..a1bcb65eaed 100644 --- a/test/hotspot/gtest/metaspace/test_clms.cpp +++ b/test/hotspot/gtest/metaspace/test_clms.cpp @@ -38,7 +38,7 @@ #ifdef _LP64 -#define LOG_PLEASE +// #define LOG_PLEASE #include "metaspaceGtestCommon.hpp" #include "metaspaceGtestContexts.hpp" #include "metaspaceGtestRangeHelpers.hpp" diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index e44e3abe398..e99c22abf88 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -40,7 +40,7 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#define LOG_PLEASE +// #define LOG_PLEASE #include "metaspaceGtestCommon.hpp" #include "metaspaceGtestContexts.hpp" #include "metaspaceGtestRangeHelpers.hpp" diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index 7e326fda439..34dd26dcf17 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -30,7 +30,7 @@ #include "utilities/macros.hpp" #include "utilities/resourceHash.hpp" -#define LOG_PLEASE +// #define LOG_PLEASE #include "testutils.hpp" #include "unittest.hpp" From 4109c73a78c424d409e9fdd96913a772467666c8 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 3 Mar 2025 09:32:54 +0000 Subject: [PATCH 186/587] 8349523: Unused runtime calls to drem/frem should be removed Reviewed-by: thartmann, kvn, chagedorn --- src/hotspot/share/opto/compile.cpp | 3 + src/hotspot/share/opto/divnode.cpp | 40 ++++++--- src/hotspot/share/opto/divnode.hpp | 2 +- src/hotspot/share/opto/node.cpp | 21 +++++ src/hotspot/share/opto/node.hpp | 4 + src/hotspot/share/opto/phaseX.cpp | 2 + .../compiler/c2/irTests/ModDNodeTests.java | 89 ++++++++++++++++++- .../compiler/c2/irTests/ModFNodeTests.java | 89 ++++++++++++++++++- .../compiler/lib/ir_framework/IRNode.java | 20 +++++ 9 files changed, 253 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7a03ac418a8..7c9d8250e5c 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -436,6 +436,9 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis n->raw_del_out(j); --j; --max; + if (child->is_data_proj_of_pure_function(n)) { + worklist.push(n); + } } } if (n->outcnt() == 1 && n->has_special_unique_user()) { diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index bb66ad47ed7..90b5d7f9e27 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -1515,6 +1515,12 @@ Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (!can_reshape) { return nullptr; } + PhaseIterGVN* igvn = phase->is_IterGVN(); + + bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; + if (result_is_unused) { + return replace_with_con(igvn, TypeF::make(0.)); + } // Either input is TOP ==> the result is TOP const Type* t1 = phase->type(dividend()); @@ -1535,10 +1541,10 @@ Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { // If either is a NaN, return an input NaN if (g_isnan(f1)) { - return replace_with_con(phase, t1); + return replace_with_con(igvn, t1); } if (g_isnan(f2)) { - return replace_with_con(phase, t2); + return replace_with_con(igvn, t2); } // If an operand is infinity or the divisor is +/- zero, punt. @@ -1553,13 +1559,19 @@ Node* ModFNode::Ideal(PhaseGVN* phase, bool can_reshape) { xr ^= min_jint; } - return replace_with_con(phase, TypeF::make(jfloat_cast(xr))); + return replace_with_con(igvn, TypeF::make(jfloat_cast(xr))); } Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (!can_reshape) { return nullptr; } + PhaseIterGVN* igvn = phase->is_IterGVN(); + + bool result_is_unused = proj_out_or_null(TypeFunc::Parms) == nullptr; + if (result_is_unused) { + return replace_with_con(igvn, TypeD::make(0.)); + } // Either input is TOP ==> the result is TOP const Type* t1 = phase->type(dividend()); @@ -1580,10 +1592,10 @@ Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { // If either is a NaN, return an input NaN if (g_isnan(f1)) { - return replace_with_con(phase, t1); + return replace_with_con(igvn, t1); } if (g_isnan(f2)) { - return replace_with_con(phase, t2); + return replace_with_con(igvn, t2); } // If an operand is infinity or the divisor is +/- zero, punt. @@ -1598,33 +1610,33 @@ Node* ModDNode::Ideal(PhaseGVN* phase, bool can_reshape) { xr ^= min_jlong; } - return replace_with_con(phase, TypeD::make(jdouble_cast(xr))); + return replace_with_con(igvn, TypeD::make(jdouble_cast(xr))); } -Node* ModFloatingNode::replace_with_con(PhaseGVN* phase, const Type* con) { +Node* ModFloatingNode::replace_with_con(PhaseIterGVN* phase, const Type* con) { Compile* C = phase->C; Node* con_node = phase->makecon(con); CallProjections projs; extract_projections(&projs, false, false); - C->gvn_replace_by(projs.fallthrough_proj, in(TypeFunc::Control)); + phase->replace_node(projs.fallthrough_proj, in(TypeFunc::Control)); if (projs.fallthrough_catchproj != nullptr) { - C->gvn_replace_by(projs.fallthrough_catchproj, in(TypeFunc::Control)); + phase->replace_node(projs.fallthrough_catchproj, in(TypeFunc::Control)); } if (projs.fallthrough_memproj != nullptr) { - C->gvn_replace_by(projs.fallthrough_memproj, in(TypeFunc::Memory)); + phase->replace_node(projs.fallthrough_memproj, in(TypeFunc::Memory)); } if (projs.catchall_memproj != nullptr) { - C->gvn_replace_by(projs.catchall_memproj, C->top()); + phase->replace_node(projs.catchall_memproj, C->top()); } if (projs.fallthrough_ioproj != nullptr) { - C->gvn_replace_by(projs.fallthrough_ioproj, in(TypeFunc::I_O)); + phase->replace_node(projs.fallthrough_ioproj, in(TypeFunc::I_O)); } assert(projs.catchall_ioproj == nullptr, "no exceptions from floating mod"); assert(projs.catchall_catchproj == nullptr, "no exceptions from floating mod"); if (projs.resproj != nullptr) { - C->gvn_replace_by(projs.resproj, con_node); + phase->replace_node(projs.resproj, con_node); } - C->gvn_replace_by(this, C->top()); + phase->replace_node(this, C->top()); C->remove_macro_node(this); disconnect_inputs(C); return nullptr; diff --git a/src/hotspot/share/opto/divnode.hpp b/src/hotspot/share/opto/divnode.hpp index a926f4ab122..127e2431b0b 100644 --- a/src/hotspot/share/opto/divnode.hpp +++ b/src/hotspot/share/opto/divnode.hpp @@ -158,7 +158,7 @@ public: // Base class for float and double modulus class ModFloatingNode : public CallLeafNode { protected: - Node* replace_with_con(PhaseGVN* phase, const Type* con); + Node* replace_with_con(PhaseIterGVN* phase, const Type* con); public: ModFloatingNode(Compile* C, const TypeFunc* tf, const char *name); diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 0e2957ac66e..d1b3d96b76b 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -1452,6 +1452,8 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { // The restriction (outcnt() <= 2) is the same as in set_req_X() // and remove_globally_dead_node(). igvn->add_users_to_worklist( n ); + } else if (dead->is_data_proj_of_pure_function(n)) { + igvn->_worklist.push(n); } else { BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(igvn, n); } @@ -2931,6 +2933,25 @@ bool Node::is_dead_loop_safe() const { bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) || Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } +bool Node::is_pure_function() const { + switch (Opcode()) { + case Op_ModD: + case Op_ModF: + return true; + default: + return false; + } +} + +// `maybe_pure_function` is assumed to be the input of `this`. This is a bit redundant, +// but we already have and need maybe_pure_function in all the call sites, so +// it makes it obvious that the `maybe_pure_function` is the same node as in the caller, +// while it takes more thinking to realize that a locally computed in(0) must be equal to +// the local in the caller. +bool Node::is_data_proj_of_pure_function(const Node* maybe_pure_function) const { + return Opcode() == Op_Proj && as_Proj()->_con == TypeFunc::Parms && maybe_pure_function->is_pure_function(); +} + //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 941b816d8e0..e89ec9455a6 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1284,6 +1284,10 @@ public: bool is_div_or_mod(BasicType bt) const; + bool is_pure_function() const; + + bool is_data_proj_of_pure_function(const Node* maybe_pure_function) const; + //----------------- Printing, etc #ifndef PRODUCT public: diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 0dd2acd8664..397b1e52e93 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1342,6 +1342,8 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { } assert(!(i < imax), "sanity"); } + } else if (dead->is_data_proj_of_pure_function(in)) { + _worklist.push(in); } else { BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(this, in); } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java index 4cdae04c39c..3c28c936d31 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java @@ -41,7 +41,13 @@ public class ModDNodeTests { TestFramework.run(); } - @Run(test = {"constant", "notConstant", "veryNotConstant"}) + @Run(test = {"constant", "notConstant", "veryNotConstant", + "unusedResult", + "repeatedlyUnused", + "unusedResultAfterLoopOpt1", + "unusedResultAfterLoopOpt2", + "unusedResultAfterLoopOpt3", + }) public void runMethod() { Asserts.assertEQ(constant(), q % 72.0d % 30.0d); Asserts.assertEQ(alsoConstant(), q % 31.432d); @@ -49,6 +55,11 @@ public class ModDNodeTests { Asserts.assertTrue(Double.isNaN(nanRightConstant())); Asserts.assertEQ(notConstant(37.5d), 37.5d % 32.0d); Asserts.assertEQ(veryNotConstant(531.25d, 14.5d), 531.25d % 32.0d % 14.5d); + unusedResult(1.1d, 2.2d); + repeatedlyUnused(1.1d, 2.2d); + Asserts.assertEQ(unusedResultAfterLoopOpt1(1.1d, 2.2d), 0.d); + Asserts.assertEQ(unusedResultAfterLoopOpt2(1.1d, 2.2d), 0.d); + Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1d, 2.2d), 0.d); } @Test @@ -114,4 +125,80 @@ public class ModDNodeTests { public double veryNotConstant(double x, double y) { return x % 32.0d % y; } + + @Test + @IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1) + @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING) + public void unusedResult(double x, double y) { + double unused = x % y; + } + + @Test + @IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1) + @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING) + public void repeatedlyUnused(double x, double y) { + double unused = 1.d; + for (int i = 0; i < 100_000; i++) { + unused = x % y; + } + } + + // The difference between unusedResultAfterLoopOpt1 and unusedResultAfterLoopOpt2 + // is that they exercise a slightly different reason why the node is being removed, + // and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is + // used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not. + @Test + @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.ITER_GVN2) + @IR(failOn = IRNode.MOD_D, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + public double unusedResultAfterLoopOpt1(double x, double y) { + double unused = x % y; + + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + if (b == 78) { // dead + return unused; + } + return 0.d; + } + + @Test + @IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_CLOOPS) + @IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1) + public double unusedResultAfterLoopOpt2(double x, double y) { + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + double unused = x % y; + + if (b == 78) { // dead + return unused; + } + return 0.d; + } + + @Test + @IR(counts = {IRNode.MOD_D, "2"}, phase = CompilePhase.AFTER_CLOOPS) + @IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1) + public double unusedResultAfterLoopOpt3(double x, double y) { + double unused = x % y; + + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + int other = (b - 77) * (int)(x % y % 1.d); + return (double)other; + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java index f3adf5ca44f..1b5e14b4835 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java @@ -41,7 +41,13 @@ public class ModFNodeTests { TestFramework.run(); } - @Run(test = {"constant", "notConstant", "veryNotConstant"}) + @Run(test = {"constant", "notConstant", "veryNotConstant", + "unusedResult", + "repeatedlyUnused", + "unusedResultAfterLoopOpt1", + "unusedResultAfterLoopOpt2", + "unusedResultAfterLoopOpt3", + }) public void runMethod() { Asserts.assertEQ(constant(), q % 72.0f % 30.0f); Asserts.assertEQ(alsoConstant(), q % 31.432f); @@ -49,6 +55,11 @@ public class ModFNodeTests { Asserts.assertTrue(Float.isNaN(nanRightConstant())); Asserts.assertEQ(notConstant(37.5f), 37.5f % 32.0f); Asserts.assertEQ(veryNotConstant(531.25f, 14.5f), 531.25f % 32.0f % 14.5f); + unusedResult(1.1f, 2.2f); + repeatedlyUnused(1.1f, 2.2f); + Asserts.assertEQ(unusedResultAfterLoopOpt1(1.1f, 2.2f), 0.f); + Asserts.assertEQ(unusedResultAfterLoopOpt2(1.1f, 2.2f), 0.f); + Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1f, 2.2f), 0.f); } @Test @@ -114,4 +125,80 @@ public class ModFNodeTests { public float veryNotConstant(float x, float y) { return x % 32.0f % y; } + + @Test + @IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1) + @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING) + public void unusedResult(float x, float y) { + float unused = x % y; + } + + @Test + @IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1) + @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING) + public void repeatedlyUnused(float x, float y) { + float unused = 1.f; + for (int i = 0; i < 100_000; i++) { + unused = x % y; + } + } + + // The difference between unusedResultAfterLoopOpt1 and unusedResultAfterLoopOpt2 + // is that they exercise a slightly different reason why the node is being removed, + // and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is + // used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not. + @Test + @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.ITER_GVN2) + @IR(failOn = IRNode.MOD_F, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + public float unusedResultAfterLoopOpt1(float x, float y) { + float unused = x % y; + + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + if (b == 78) { // dead + return unused; + } + return 0.f; + } + + @Test + @IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_CLOOPS) + @IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1) + public float unusedResultAfterLoopOpt2(float x, float y) { + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + float unused = x % y; + + if (b == 78) { // dead + return unused; + } + return 0.f; + } + + @Test + @IR(counts = {IRNode.MOD_F, "2"}, phase = CompilePhase.AFTER_CLOOPS) + @IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1) + public float unusedResultAfterLoopOpt3(float x, float y) { + float unused = x % y; + + int a = 77; + int b = 0; + do { + a--; + b++; + } while (a > 0); + + int other = (b - 77) * (int)(x % y % 1.f); + return (float)other; + } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 8f28294a986..6e373207d9c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2531,6 +2531,16 @@ public class IRNode { machOnlyNameRegex(X86_CMOVEL_IMM01UCF, "cmovL_imm_01UCF"); } + public static final String MOD_F = PREFIX + "MOD_F" + POSTFIX; + static { + macroNodes(MOD_F, "ModF"); + } + + public static final String MOD_D = PREFIX + "MOD_D" + POSTFIX; + static { + macroNodes(MOD_D, "ModD"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ @@ -2576,6 +2586,16 @@ public class IRNode { IR_NODE_MAPPINGS.put(irNode, entry); } + /** + * Apply {@code regex} on all ideal graph phases up to and including {@link CompilePhase#BEFORE_MACRO_EXPANSION}. + */ + private static void macroNodes(String irNodePlaceholder, String irNodeRegex) { + String regex = START + irNodeRegex + MID + END; + IR_NODE_MAPPINGS.put(irNodePlaceholder, new SinglePhaseRangeEntry(CompilePhase.BEFORE_MACRO_EXPANSION, regex, + CompilePhase.BEFORE_STRINGOPTS, + CompilePhase.BEFORE_MACRO_EXPANSION)); + } + private static void callOfNodes(String irNodePlaceholder, String callRegex) { String regex = START + callRegex + MID + IS_REPLACED + " " + END; IR_NODE_MAPPINGS.put(irNodePlaceholder, new RegexTypeEntry(RegexType.IDEAL_INDEPENDENT, regex)); From 8b0468faf1c38f2d1d887ab92b76dfff625482ef Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 3 Mar 2025 12:08:18 +0000 Subject: [PATCH 187/587] 8315488: Remove outdated and unused ciReplay support from SA Reviewed-by: kvn, cjplummer, yzheng --- src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp | 10 +- src/hotspot/cpu/arm/vmStructs_arm.hpp | 10 +- src/hotspot/cpu/ppc/vmStructs_ppc.hpp | 10 +- src/hotspot/cpu/riscv/vmStructs_riscv.hpp | 10 +- src/hotspot/cpu/s390/vmStructs_s390.hpp | 10 +- src/hotspot/cpu/x86/vmStructs_x86.hpp | 10 +- src/hotspot/cpu/zero/vmStructs_zero.hpp | 10 +- src/hotspot/os/aix/vmStructs_aix.hpp | 10 +- src/hotspot/os/bsd/vmStructs_bsd.hpp | 10 +- src/hotspot/os/linux/vmStructs_linux.hpp | 10 +- src/hotspot/os/windows/vmStructs_windows.hpp | 10 +- .../os_cpu/aix_ppc/vmStructs_aix_ppc.hpp | 10 +- .../bsd_aarch64/vmStructs_bsd_aarch64.hpp | 10 +- .../os_cpu/bsd_x86/vmStructs_bsd_x86.hpp | 10 +- .../os_cpu/bsd_zero/vmStructs_bsd_zero.hpp | 11 +- .../linux_aarch64/vmStructs_linux_aarch64.hpp | 10 +- .../os_cpu/linux_arm/vmStructs_linux_arm.hpp | 10 +- .../os_cpu/linux_ppc/vmStructs_linux_ppc.hpp | 10 +- .../linux_riscv/vmStructs_linux_riscv.hpp | 10 +- .../linux_s390/vmStructs_linux_s390.hpp | 10 +- .../os_cpu/linux_x86/vmStructs_linux_x86.hpp | 10 +- .../linux_zero/vmStructs_linux_zero.hpp | 10 +- .../vmStructs_windows_aarch64.hpp | 8 +- .../windows_x86/vmStructs_windows_x86.hpp | 10 +- src/hotspot/share/c1/c1_Runtime1.hpp | 3 +- src/hotspot/share/ci/ciClassList.hpp | 4 +- src/hotspot/share/ci/ciConstant.hpp | 3 +- src/hotspot/share/ci/ciObjectFactory.hpp | 3 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 32 +- src/hotspot/share/opto/block.hpp | 10 +- src/hotspot/share/opto/callnode.hpp | 4 - src/hotspot/share/opto/chaitin.hpp | 5 +- src/hotspot/share/opto/compile.hpp | 4 +- src/hotspot/share/opto/node.hpp | 6 - src/hotspot/share/opto/optoreg.hpp | 3 +- src/hotspot/share/opto/regalloc.hpp | 3 +- src/hotspot/share/opto/type.hpp | 1 - src/hotspot/share/runtime/vmStructs.cpp | 947 +----------------- src/jdk.hotspot.agent/doc/cireplay.html | 41 - src/jdk.hotspot.agent/doc/clhsdb.html | 9 - src/jdk.hotspot.agent/doc/index.html | 6 - .../sun/jvm/hotspot/CommandProcessor.java | 144 +-- .../classes/sun/jvm/hotspot/c1/Runtime1.java | 67 -- .../sun/jvm/hotspot/ci/ciArrayKlass.java | 55 - .../sun/jvm/hotspot/ci/ciBaseObject.java | 59 -- .../sun/jvm/hotspot/ci/ciConstant.java | 69 -- .../classes/sun/jvm/hotspot/ci/ciEnv.java | 110 -- .../classes/sun/jvm/hotspot/ci/ciField.java | 64 -- .../sun/jvm/hotspot/ci/ciInstance.java | 53 - .../sun/jvm/hotspot/ci/ciInstanceKlass.java | 165 --- .../classes/sun/jvm/hotspot/ci/ciKlass.java | 65 -- .../sun/jvm/hotspot/ci/ciMetadata.java | 67 -- .../classes/sun/jvm/hotspot/ci/ciMethod.java | 114 --- .../sun/jvm/hotspot/ci/ciMethodData.java | 361 ------- .../sun/jvm/hotspot/ci/ciObjArrayKlass.java | 57 -- .../classes/sun/jvm/hotspot/ci/ciObject.java | 71 -- .../sun/jvm/hotspot/ci/ciObjectFactory.java | 88 -- .../classes/sun/jvm/hotspot/ci/ciSymbol.java | 60 -- .../classes/sun/jvm/hotspot/ci/ciType.java | 54 - .../sun/jvm/hotspot/ci/ciTypeArrayKlass.java | 52 - .../sun/jvm/hotspot/code/CodeBlob.java | 7 - .../classes/sun/jvm/hotspot/code/NMethod.java | 36 - .../sun/jvm/hotspot/compiler/CompileTask.java | 3 +- .../sun/jvm/hotspot/oops/InstanceKlass.java | 82 +- .../sun/jvm/hotspot/oops/Metadata.java | 5 +- .../classes/sun/jvm/hotspot/oops/Method.java | 18 +- .../sun/jvm/hotspot/oops/MethodData.java | 109 +- .../classes/sun/jvm/hotspot/opto/Block.java | 90 -- .../sun/jvm/hotspot/opto/Block_Array.java | 66 -- .../sun/jvm/hotspot/opto/Block_List.java | 58 -- .../jvm/hotspot/opto/CallDynamicJavaNode.java | 52 - .../sun/jvm/hotspot/opto/CallJavaNode.java | 68 -- .../sun/jvm/hotspot/opto/CallNode.java | 67 -- .../sun/jvm/hotspot/opto/CallRuntimeNode.java | 66 -- .../jvm/hotspot/opto/CallStaticJavaNode.java | 77 -- .../classes/sun/jvm/hotspot/opto/Compile.java | 107 -- .../jvm/hotspot/opto/CompilerPhaseType.java | 67 -- .../sun/jvm/hotspot/opto/HaltNode.java | 52 - .../sun/jvm/hotspot/opto/InlineTree.java | 135 --- .../sun/jvm/hotspot/opto/JVMState.java | 112 --- .../sun/jvm/hotspot/opto/LoopNode.java | 52 - .../jvm/hotspot/opto/MachCallJavaNode.java | 72 -- .../sun/jvm/hotspot/opto/MachCallNode.java | 59 -- .../jvm/hotspot/opto/MachCallRuntimeNode.java | 65 -- .../hotspot/opto/MachCallStaticJavaNode.java | 71 -- .../sun/jvm/hotspot/opto/MachIfNode.java | 69 -- .../sun/jvm/hotspot/opto/MachNode.java | 51 - .../sun/jvm/hotspot/opto/MachReturnNode.java | 51 - .../jvm/hotspot/opto/MachSafePointNode.java | 77 -- .../sun/jvm/hotspot/opto/MultiNode.java | 52 - .../classes/sun/jvm/hotspot/opto/Node.java | 271 ----- .../sun/jvm/hotspot/opto/Node_Array.java | 66 -- .../sun/jvm/hotspot/opto/Node_List.java | 58 -- .../classes/sun/jvm/hotspot/opto/Phase.java | 52 - .../sun/jvm/hotspot/opto/PhaseCFG.java | 71 -- .../sun/jvm/hotspot/opto/PhaseRegAlloc.java | 60 -- .../classes/sun/jvm/hotspot/opto/PhiNode.java | 52 - .../sun/jvm/hotspot/opto/ProjNode.java | 52 - .../sun/jvm/hotspot/opto/RegionNode.java | 52 - .../sun/jvm/hotspot/opto/RootNode.java | 52 - .../sun/jvm/hotspot/opto/SafePointNode.java | 70 -- .../sun/jvm/hotspot/opto/TypeNode.java | 52 - .../jvm/hotspot/runtime/CompilerThread.java | 19 +- .../classes/sun/jvm/hotspot/runtime/VM.java | 18 +- .../sun/jvm/hotspot/runtime/VMReg.java | 20 +- test/hotspot/jtreg/ProblemList.txt | 1 - .../jtreg/compiler/ciReplay/SABase.java | 175 ---- .../jtreg/compiler/ciReplay/TestSAClient.java | 35 - .../jtreg/compiler/ciReplay/TestSAServer.java | 35 - 109 files changed, 185 insertions(+), 6020 deletions(-) delete mode 100644 src/jdk.hotspot.agent/doc/cireplay.html delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_Array.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block_List.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java delete mode 100644 test/hotspot/jtreg/compiler/ciReplay/SABase.java delete mode 100644 test/hotspot/jtreg/compiler/ciReplay/TestSAClient.java delete mode 100644 test/hotspot/jtreg/compiler/ciReplay/TestSAServer.java diff --git a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp index ceb40dce921..bf9c965213c 100644 --- a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,17 +30,17 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ static_field(VM_Version, _rop_protection, bool) \ static_field(VM_Version, _pac_mask, uintptr_t) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ declare_toplevel_type(VM_Version) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #define DECLARE_INT_CPU_FEATURE_CONSTANT(id, name, bit) GENERATE_VM_INT_CONSTANT_ENTRY(VM_Version::CPU_##id) #define VM_INT_CPU_FEATURE_CONSTANTS CPU_FEATURE_FLAGS(DECLARE_INT_CPU_FEATURE_CONSTANT) diff --git a/src/hotspot/cpu/arm/vmStructs_arm.hpp b/src/hotspot/cpu/arm/vmStructs_arm.hpp index 4ce78d517e8..453938a824e 100644 --- a/src/hotspot/cpu/arm/vmStructs_arm.hpp +++ b/src/hotspot/cpu/arm/vmStructs_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, 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 @@ -29,7 +29,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ \ /******************************/ \ /* JavaCallWrapper */ \ @@ -39,10 +39,10 @@ /******************************/ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif // CPU_ARM_VMSTRUCTS_ARM_HPP diff --git a/src/hotspot/cpu/ppc/vmStructs_ppc.hpp b/src/hotspot/cpu/ppc/vmStructs_ppc.hpp index c1bdc1b1eb5..efe7fb9ad7b 100644 --- a/src/hotspot/cpu/ppc/vmStructs_ppc.hpp +++ b/src/hotspot/cpu/ppc/vmStructs_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif // CPU_PPC_VMSTRUCTS_PPC_HPP diff --git a/src/hotspot/cpu/riscv/vmStructs_riscv.hpp b/src/hotspot/cpu/riscv/vmStructs_riscv.hpp index 6c89133de02..ba250f77268 100644 --- a/src/hotspot/cpu/riscv/vmStructs_riscv.hpp +++ b/src/hotspot/cpu/riscv/vmStructs_riscv.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. * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,13 +30,13 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif // CPU_RISCV_VMSTRUCTS_RISCV_HPP diff --git a/src/hotspot/cpu/s390/vmStructs_s390.hpp b/src/hotspot/cpu/s390/vmStructs_s390.hpp index 1f65002977a..100fc97560e 100644 --- a/src/hotspot/cpu/s390/vmStructs_s390.hpp +++ b/src/hotspot/cpu/s390/vmStructs_s390.hpp @@ -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. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif // CPU_S390_VMSTRUCTS_S390_HPP diff --git a/src/hotspot/cpu/x86/vmStructs_x86.hpp b/src/hotspot/cpu/x86/vmStructs_x86.hpp index 4569bd9a216..d894d8b09a7 100644 --- a/src/hotspot/cpu/x86/vmStructs_x86.hpp +++ b/src/hotspot/cpu/x86/vmStructs_x86.hpp @@ -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 @@ -29,17 +29,17 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) \ LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ declare_constant(frame::interpreter_frame_sender_sp_offset) \ declare_constant(frame::interpreter_frame_last_sp_offset) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #define DECLARE_LONG_CPU_FEATURE_CONSTANT(id, name, bit) GENERATE_VM_LONG_CONSTANT_ENTRY(VM_Version::CPU_##id) #define VM_LONG_CPU_FEATURE_CONSTANTS CPU_FEATURE_FLAGS(DECLARE_LONG_CPU_FEATURE_CONSTANT) diff --git a/src/hotspot/cpu/zero/vmStructs_zero.hpp b/src/hotspot/cpu/zero/vmStructs_zero.hpp index 64a9300e25c..9100c765e7e 100644 --- a/src/hotspot/cpu/zero/vmStructs_zero.hpp +++ b/src/hotspot/cpu/zero/vmStructs_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif // CPU_ZERO_VMSTRUCTS_ZERO_HPP diff --git a/src/hotspot/os/aix/vmStructs_aix.hpp b/src/hotspot/os/aix/vmStructs_aix.hpp index fb4b6409aaa..c79c9477fff 100644 --- a/src/hotspot/os/aix/vmStructs_aix.hpp +++ b/src/hotspot/os/aix/vmStructs_aix.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 @@ -29,14 +29,14 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ nonstatic_field(OSThread, _thread_id, pthread_t) \ -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ \ /**********************/ \ /* Posix Thread IDs */ \ @@ -44,9 +44,9 @@ \ declare_unsigned_integer_type(pthread_t) -#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) #define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) diff --git a/src/hotspot/os/bsd/vmStructs_bsd.hpp b/src/hotspot/os/bsd/vmStructs_bsd.hpp index b29067a9024..e07f1cd7dd0 100644 --- a/src/hotspot/os/bsd/vmStructs_bsd.hpp +++ b/src/hotspot/os/bsd/vmStructs_bsd.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 @@ -31,7 +31,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ @@ -39,7 +39,7 @@ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ nonstatic_field(OSThread, _unique_thread_id, uint64_t) -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ \ /**********************/ \ /* Thread IDs */ \ @@ -47,9 +47,9 @@ \ declare_unsigned_integer_type(OSThread::thread_id_t) -#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) #define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) diff --git a/src/hotspot/os/linux/vmStructs_linux.hpp b/src/hotspot/os/linux/vmStructs_linux.hpp index 2696a891f56..90bc6517a3f 100644 --- a/src/hotspot/os/linux/vmStructs_linux.hpp +++ b/src/hotspot/os/linux/vmStructs_linux.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 @@ -31,7 +31,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ @@ -39,7 +39,7 @@ nonstatic_field(OSThread, _thread_id, pid_t) \ nonstatic_field(OSThread, _pthread_id, pthread_t) -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ \ /**********************/ \ /* Posix Thread IDs */ \ @@ -48,9 +48,9 @@ declare_integer_type(pid_t) \ declare_unsigned_integer_type(pthread_t) -#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) #define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) diff --git a/src/hotspot/os/windows/vmStructs_windows.hpp b/src/hotspot/os/windows/vmStructs_windows.hpp index 26ad17bb166..7d457c82fe8 100644 --- a/src/hotspot/os/windows/vmStructs_windows.hpp +++ b/src/hotspot/os/windows/vmStructs_windows.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 @@ -29,7 +29,7 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ \ /******************************/ \ /* Threads (NOTE: incomplete) */ \ @@ -38,13 +38,13 @@ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ \ declare_unsigned_integer_type(OSThread::thread_id_t) -#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant) #define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) diff --git a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp index d09b0125f25..df8857a5b84 100644 --- a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp +++ b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.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. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_AIX_PPC_VMSTRUCTS_AIX_PPC_HPP diff --git a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp index 24d5c0f4dc6..fc98519eb82 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,12 +31,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_BSD_AARCH64_VMSTRUCTS_BSD_AARCH64_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp index 4f6c4414f5f..d26921e25ba 100644 --- a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.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 @@ -29,12 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_BSD_X86_VMSTRUCTS_BSD_X86_HPP diff --git a/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp index ea3771b7ce6..b5b523cd0ac 100644 --- a/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp +++ b/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,13 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_BSD_ZERO_VMSTRUCTS_BSD_ZERO_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp index 6cc6d73be77..cf44ce0ca74 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_AARCH64_VMSTRUCTS_LINUX_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp index a1b73bdee8f..9d4c610b45a 100644 --- a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp @@ -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 @@ -29,12 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_ARM_VMSTRUCTS_LINUX_ARM_HPP diff --git a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp index 46288cdeaab..e52dc525e64 100644 --- a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp +++ b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.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. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_PPC_VMSTRUCTS_LINUX_PPC_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp index b39a329335a..02bcf429d42 100644 --- a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.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. * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp index a52bc722579..0a75e6d4b92 100644 --- a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp +++ b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.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. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_S390_VMSTRUCTS_LINUX_S390_HPP diff --git a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp index ddba9daf131..290e30dff68 100644 --- a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.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 @@ -29,12 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_X86_VMSTRUCTS_LINUX_X86_HPP diff --git a/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp index 271193cd705..651846c4b36 100644 --- a/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright 2007 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,12 +30,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_LINUX_ZERO_VMSTRUCTS_LINUX_ZERO_HPP diff --git a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp index 18a5588b743..2462a20568d 100644 --- a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp @@ -29,12 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_WINDOWS_AARCH64_VMSTRUCTS_WINDOWS_AARCH64_HPP diff --git a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp index 4ed62839d51..0ac47bdbd80 100644 --- a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.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 @@ -29,12 +29,12 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) #endif // OS_CPU_WINDOWS_X86_VMSTRUCTS_WINDOWS_X86_HPP diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index 5f1ae4333bc..5fce0ff4228 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -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 @@ -53,7 +53,6 @@ enum class C1StubId :int { #undef C1_STUB_ID_ENUM_DECLARE class Runtime1: public AllStatic { - friend class VMStructs; friend class ArrayCopyStub; public: diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp index ccc99cfa211..618a052765e 100644 --- a/src/hotspot/share/ci/ciClassList.hpp +++ b/src/hotspot/share/ci/ciClassList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -75,13 +75,11 @@ class ciTypeArrayKlass; // Everyone gives access to ciObjectFactory #define CI_PACKAGE_ACCESS \ friend class ciObjectFactory; \ -friend class VMStructs; // These are the packages that have access to ciEnv // Any more access must be given explicitly. #define CI_PACKAGE_ACCESS_TO \ friend class ciObjectFactory; \ -friend class VMStructs; \ friend class ciCallSite; \ friend class ciConstantPoolCache; \ friend class ciField; \ diff --git a/src/hotspot/share/ci/ciConstant.hpp b/src/hotspot/share/ci/ciConstant.hpp index 1d0f60407ed..f07d0a170df 100644 --- a/src/hotspot/share/ci/ciConstant.hpp +++ b/src/hotspot/share/ci/ciConstant.hpp @@ -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 @@ -32,7 +32,6 @@ // // This class represents a constant value. class ciConstant { - friend class VMStructs; private: friend class ciEnv; friend class ciField; diff --git a/src/hotspot/share/ci/ciObjectFactory.hpp b/src/hotspot/share/ci/ciObjectFactory.hpp index f1f6ae24545..d95a7d1ff22 100644 --- a/src/hotspot/share/ci/ciObjectFactory.hpp +++ b/src/hotspot/share/ci/ciObjectFactory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, 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 @@ -37,7 +37,6 @@ // which ensures that for each oop, at most one ciObject is created. // This invariant allows efficient implementation of ciObject. class ciObjectFactory : public ArenaObj { - friend class VMStructs; friend class ciEnv; private: diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 93c3449d0ff..48c9f8a64dc 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -943,7 +943,7 @@ #ifdef AARCH64 -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ static_field(VM_Version, _zva_length, int) \ static_field(StubRoutines::aarch64, _count_positives, address) \ static_field(StubRoutines::aarch64, _count_positives_long, address) \ @@ -957,11 +957,11 @@ #ifdef X86 -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ static_field(VM_Version, _has_intel_jcc_erratum, bool) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) \ LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ declare_constant(frame::interpreter_frame_sender_sp_offset) \ declare_constant(frame::interpreter_frame_last_sp_offset) @@ -975,15 +975,15 @@ * Dummy defines for architectures that don't use these. */ #ifndef VM_STRUCTS_CPU -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) #endif #ifndef VM_INT_CONSTANTS_CPU -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif #ifndef VM_LONG_CONSTANTS_CPU -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) #endif #ifndef VM_ADDRESSES_OS @@ -1010,10 +1010,7 @@ VMStructEntry JVMCIVMStructs::localHotSpotVMStructs[] = { GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) #if INCLUDE_G1GC VM_STRUCTS_JVMCI_G1GC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, @@ -1038,10 +1035,7 @@ VMIntConstantEntry JVMCIVMStructs::localHotSpotVMIntConstants[] = { GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_C1_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #if INCLUDE_G1GC VM_INT_CONSTANTS_JVMCI_G1GC(GENERATE_VM_INT_CONSTANT_ENTRY, @@ -1064,10 +1058,7 @@ VMLongConstantEntry JVMCIVMStructs::localHotSpotVMLongConstants[] = { GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_C1_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) #ifdef VM_LONG_CPU_FEATURE_CONSTANTS VM_LONG_CPU_FEATURE_CONSTANTS #endif @@ -1123,10 +1114,7 @@ void JVMCIVMStructs::init() { CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NO_OP, - CHECK_NO_OP); + CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) #if INCLUDE_G1GC VM_STRUCTS_JVMCI_G1GC(CHECK_NONSTATIC_VM_STRUCT_ENTRY, diff --git a/src/hotspot/share/opto/block.hpp b/src/hotspot/share/opto/block.hpp index 231c0994903..4ac6399d3a0 100644 --- a/src/hotspot/share/opto/block.hpp +++ b/src/hotspot/share/opto/block.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 @@ -47,7 +47,6 @@ struct Tarjan; // Note that the constructor just zeros things, and since I use Arena // allocation I do not need a destructor to reclaim storage. class Block_Array : public ArenaObj { - friend class VMStructs; uint _size; // allocated size, as opposed to formal limit debug_only(uint _limit;) // limit to formal domain Arena *_arena; // Arena to allocate in @@ -75,7 +74,6 @@ public: class Block_List : public Block_Array { - friend class VMStructs; public: uint _cnt; Block_List() : Block_List(Thread::current()->resource_area()) { } @@ -93,7 +91,6 @@ public: class CFGElement : public AnyObj { - friend class VMStructs; public: double _freq; // Execution frequency (estimate) @@ -109,7 +106,6 @@ class CFGElement : public AnyObj { // Basic blocks are used during the output routines, and are not used during // any optimization pass. They are created late in the game. class Block : public CFGElement { - friend class VMStructs; private: // Nodes in this block, in order @@ -372,7 +368,6 @@ public: //------------------------------PhaseCFG--------------------------------------- // Build an array of Basic Block pointers, one per Node. class PhaseCFG : public Phase { - friend class VMStructs; private: // Root of whole program RootNode* _root; @@ -703,7 +698,6 @@ public: //------------------------------CFGLoop------------------------------------------- class CFGLoop : public CFGElement { - friend class VMStructs; int _id; int _depth; CFGLoop *_parent; // root of loop tree is the method level "pseudo" loop, it's parent is null @@ -756,7 +750,6 @@ class CFGLoop : public CFGElement { // A edge between two basic blocks that will be embodied by a branch or a // fall-through. class CFGEdge : public ResourceObj { - friend class VMStructs; private: Block * _from; // Source basic block Block * _to; // Destination basic block @@ -892,7 +885,6 @@ class Trace : public ResourceObj { //------------------------------PhaseBlockLayout------------------------------- // Rearrange blocks into some canonical order, based on edges and their frequencies class PhaseBlockLayout : public Phase { - friend class VMStructs; PhaseCFG &_cfg; // Control flow graph GrowableArray *edges; diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index ad5e9daa8f6..2f1aad60e6f 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -198,7 +198,6 @@ public: // This provides a way to map the optimized program back into the interpreter, // or to let the GC mark the stack. class JVMState : public ResourceObj { - friend class VMStructs; public: typedef enum { Reexecute_Undefined = -1, // not defined -- will be translated into false later @@ -331,7 +330,6 @@ public: class SafePointNode : public MultiNode { friend JVMState; friend class GraphKit; - friend class VMStructs; virtual bool cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger @@ -672,7 +670,6 @@ class CallGenerator; // Call nodes now subsume the function of debug nodes at callsites, so they // contain the functionality of a full scope chain of debug nodes. class CallNode : public SafePointNode { - friend class VMStructs; protected: bool may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase); @@ -760,7 +757,6 @@ public: // convention. (The "Java" calling convention is the compiler's calling // convention, as opposed to the interpreter's or that of native C.) class CallJavaNode : public CallNode { - friend class VMStructs; protected: virtual bool cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index cf02deb6019..4b74420f996 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.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 @@ -47,7 +47,6 @@ class PhaseChaitin; //------------------------------LRG-------------------------------------------- // Live-RanGe structure. class LRG : public ResourceObj { - friend class VMStructs; public: static const uint AllStack_size = 0xFFFFF; // This mask size is used to tell that the mask of this LRG supports stack positions enum { SPILL_REG=29999 }; // Register number of a spilled LRG @@ -236,7 +235,6 @@ public: // abstract! It needs abstraction so I can fiddle with the implementation to // get even more speed. class PhaseIFG : public Phase { - friend class VMStructs; // Current implementation: a triangular adjacency list. // Array of adjacency-lists, indexed by live-range number @@ -417,7 +415,6 @@ public: //------------------------------Chaitin---------------------------------------- // Briggs-Chaitin style allocation, mostly. class PhaseChaitin : public PhaseRegAlloc { - friend class VMStructs; int _trip_cnt; int _alternate; diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 93252891207..2ae3cca218d 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.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 @@ -175,7 +175,6 @@ class CloneMap { class Options { friend class Compile; - friend class VMStructs; private: const bool _subsume_loads; // Load can be matched as part of a larger op. const bool _do_escape_analysis; // Do escape analysis. @@ -222,7 +221,6 @@ class Options { // This class defines a top-level Compiler invocation. class Compile : public Phase { - friend class VMStructs; public: // Fixed alias indexes. (See also MergeMemNode.) diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index e89ec9455a6..f6cb9f692bb 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -241,7 +241,6 @@ typedef ResizeableResourceHashtableresource_area(), max), _cnt(0) {} @@ -1731,7 +1728,6 @@ void Node::visit_uses(Callback callback, Check is_boundary) const { //------------------------------Unique_Node_List------------------------------- class Unique_Node_List : public Node_List { - friend class VMStructs; VectorSet _in_worklist; uint _clock_index; // Index in list where to pop from next public: @@ -1871,7 +1867,6 @@ inline void Compile::remove_for_igvn(Node* n) { //------------------------------Node_Stack------------------------------------- class Node_Stack { - friend class VMStructs; protected: struct INode { Node *node; // Processed node @@ -1947,7 +1942,6 @@ public: // Debugging or profiling annotations loosely and sparsely associated // with some nodes. See Compile::node_notes_at for the accessor. class Node_Notes { - friend class VMStructs; JVMState* _jvms; public: diff --git a/src/hotspot/share/opto/optoreg.hpp b/src/hotspot/share/opto/optoreg.hpp index b079f3473ad..6298eeea39c 100644 --- a/src/hotspot/share/opto/optoreg.hpp +++ b/src/hotspot/share/opto/optoreg.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, 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 @@ -182,7 +182,6 @@ class OptoReg { // and converting that will return OptoReg::Bad losing the identity of the OptoReg. class OptoRegPair { - friend class VMStructs; private: short _second; short _first; diff --git a/src/hotspot/share/opto/regalloc.hpp b/src/hotspot/share/opto/regalloc.hpp index ecdf2e2bee8..86877e18325 100644 --- a/src/hotspot/share/opto/regalloc.hpp +++ b/src/hotspot/share/opto/regalloc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, 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 @@ -39,7 +39,6 @@ class PhaseCFG; //------------------------------PhaseRegAlloc------------------------------------ // Abstract register allocator class PhaseRegAlloc : public Phase { - friend class VMStructs; static void (*_alloc_statistics[MAX_REG_ALLOCATORS])(); static int _num_allocators; diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 67e339d3d2e..6e17ef0db05 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -79,7 +79,6 @@ class VerifyMeet; // different kind of Type exists. Types are never modified after creation, so // all their interesting fields are constant. class Type { - friend class VMStructs; public: enum TYPES { diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index c9d93930d63..5184440499a 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -115,31 +115,7 @@ #include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef COMPILER2 -#include "opto/addnode.hpp" -#include "opto/block.hpp" -#include "opto/callnode.hpp" -#include "opto/castnode.hpp" -#include "opto/cfgnode.hpp" -#include "opto/chaitin.hpp" -#include "opto/convertnode.hpp" -#include "opto/divnode.hpp" -#include "opto/intrinsicnode.hpp" -#include "opto/locknode.hpp" -#include "opto/loopnode.hpp" -#include "opto/machnode.hpp" -#include "opto/matcher.hpp" -#include "opto/mathexactnode.hpp" -#include "opto/movenode.hpp" -#include "opto/mulnode.hpp" -#include "opto/narrowptrnode.hpp" -#include "opto/opaquenode.hpp" #include "opto/optoreg.hpp" -#include "opto/parse.hpp" -#include "opto/phaseX.hpp" -#include "opto/regalloc.hpp" -#include "opto/rootnode.hpp" -#include "opto/subnode.hpp" -#include "opto/vectornode.hpp" #endif // COMPILER2 #include CPU_HEADER(vmStructs) @@ -183,11 +159,7 @@ volatile_static_field, \ unchecked_nonstatic_field, \ volatile_nonstatic_field, \ - nonproduct_nonstatic_field, \ - c1_nonstatic_field, \ - c2_nonstatic_field, \ - unchecked_c1_static_field, \ - unchecked_c2_static_field) \ + nonproduct_nonstatic_field) \ \ /*************/ \ /* GC fields */ \ @@ -595,8 +567,6 @@ nonstatic_field(nmethod, _comp_level, CompLevel) \ volatile_nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ \ - unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ - \ nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ @@ -667,7 +637,6 @@ volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \ nonstatic_field(Thread, _osthread, OSThread*) \ nonstatic_field(Thread, _resource_area, ResourceArea*) \ - nonstatic_field(CompilerThread, _env, ciEnv*) \ \ /************/ \ /* OSThread */ \ @@ -710,75 +679,6 @@ static_field(VMRegImpl, regName[0], const char*) \ static_field(VMRegImpl, stack0, VMReg) \ \ - /*******************************/ \ - /* Runtime1 (NOTE: incomplete) */ \ - /*******************************/ \ - \ - unchecked_c1_static_field(Runtime1, _blobs, sizeof(Runtime1::_blobs)) /* NOTE: no type */ \ - \ - /**************/ \ - /* CI */ \ - /************/ \ - \ - nonstatic_field(ciEnv, _compiler_data, void*) \ - nonstatic_field(ciEnv, _factory, ciObjectFactory*) \ - nonstatic_field(ciEnv, _dependencies, Dependencies*) \ - nonstatic_field(ciEnv, _task, CompileTask*) \ - nonstatic_field(ciEnv, _arena, Arena*) \ - \ - nonstatic_field(ciBaseObject, _ident, uint) \ - \ - nonstatic_field(ciObject, _handle, jobject) \ - nonstatic_field(ciObject, _klass, ciKlass*) \ - \ - nonstatic_field(ciMetadata, _metadata, Metadata*) \ - \ - nonstatic_field(ciSymbol, _symbol, Symbol*) \ - \ - nonstatic_field(ciType, _basic_type, BasicType) \ - \ - nonstatic_field(ciKlass, _name, ciSymbol*) \ - \ - nonstatic_field(ciArrayKlass, _dimension, jint) \ - \ - nonstatic_field(ciObjArrayKlass, _element_klass, ciKlass*) \ - nonstatic_field(ciObjArrayKlass, _base_element_klass, ciKlass*) \ - \ - nonstatic_field(ciInstanceKlass, _init_state, InstanceKlass::ClassState) \ - nonstatic_field(ciInstanceKlass, _is_shared, bool) \ - \ - nonstatic_field(ciMethod, _interpreter_invocation_count, int) \ - nonstatic_field(ciMethod, _interpreter_throwout_count, int) \ - nonstatic_field(ciMethod, _inline_instructions_size, int) \ - \ - nonstatic_field(ciMethodData, _data_size, int) \ - nonstatic_field(ciMethodData, _state, u_char) \ - nonstatic_field(ciMethodData, _extra_data_size, int) \ - nonstatic_field(ciMethodData, _data, intptr_t*) \ - nonstatic_field(ciMethodData, _hint_di, int) \ - nonstatic_field(ciMethodData, _eflags, intx) \ - nonstatic_field(ciMethodData, _arg_local, intx) \ - nonstatic_field(ciMethodData, _arg_stack, intx) \ - nonstatic_field(ciMethodData, _arg_returned, intx) \ - nonstatic_field(ciMethodData, _orig, MethodData::CompilerCounters) \ - \ - nonstatic_field(ciField, _holder, ciInstanceKlass*) \ - nonstatic_field(ciField, _name, ciSymbol*) \ - nonstatic_field(ciField, _signature, ciSymbol*) \ - nonstatic_field(ciField, _offset, int) \ - nonstatic_field(ciField, _is_constant, bool) \ - nonstatic_field(ciField, _constant_value, ciConstant) \ - \ - nonstatic_field(ciObjectFactory, _ci_metadata, GrowableArray) \ - nonstatic_field(ciObjectFactory, _symbols, GrowableArray) \ - \ - nonstatic_field(ciConstant, _type, BasicType) \ - nonstatic_field(ciConstant, _value._int, jint) \ - nonstatic_field(ciConstant, _value._long, jlong) \ - nonstatic_field(ciConstant, _value._float, jfloat) \ - nonstatic_field(ciConstant, _value._double, jdouble) \ - nonstatic_field(ciConstant, _value._object, ciObject*) \ - \ /************/ \ /* Monitors */ \ /************/ \ @@ -798,123 +698,6 @@ volatile_nonstatic_field(MonitorList, _head, ObjectMonitor*) \ \ /*********************/ \ - /* Matcher (C2 only) */ \ - /*********************/ \ - \ - unchecked_c2_static_field(Matcher, _regEncode, sizeof(Matcher::_regEncode)) /* NOTE: no type */ \ - \ - c2_nonstatic_field(Node, _in, Node**) \ - c2_nonstatic_field(Node, _out, Node**) \ - c2_nonstatic_field(Node, _cnt, node_idx_t) \ - c2_nonstatic_field(Node, _max, node_idx_t) \ - c2_nonstatic_field(Node, _outcnt, node_idx_t) \ - c2_nonstatic_field(Node, _outmax, node_idx_t) \ - c2_nonstatic_field(Node, _idx, const node_idx_t) \ - c2_nonstatic_field(Node, _class_id, juint) \ - c2_nonstatic_field(Node, _flags, juint) \ - \ - c2_nonstatic_field(Compile, _root, RootNode*) \ - c2_nonstatic_field(Compile, _unique, uint) \ - c2_nonstatic_field(Compile, _entry_bci, int) \ - c2_nonstatic_field(Compile, _top, Node*) \ - c2_nonstatic_field(Compile, _cfg, PhaseCFG*) \ - c2_nonstatic_field(Compile, _regalloc, PhaseRegAlloc*) \ - c2_nonstatic_field(Compile, _method, ciMethod*) \ - c2_nonstatic_field(Compile, _compile_id, const int) \ - c2_nonstatic_field(Compile, _options, const Options) \ - c2_nonstatic_field(Compile, _ilt, InlineTree*) \ - \ - c2_nonstatic_field(Options, _subsume_loads, const bool) \ - c2_nonstatic_field(Options, _do_escape_analysis, const bool) \ - c2_nonstatic_field(Options, _eliminate_boxing, const bool) \ - c2_nonstatic_field(Options, _do_locks_coarsening, const bool) \ - c2_nonstatic_field(Options, _install_code, const bool) \ - \ - c2_nonstatic_field(InlineTree, _caller_jvms, JVMState*) \ - c2_nonstatic_field(InlineTree, _method, ciMethod*) \ - c2_nonstatic_field(InlineTree, _caller_tree, InlineTree*) \ - c2_nonstatic_field(InlineTree, _subtrees, GrowableArray) \ - \ - c2_nonstatic_field(OptoRegPair, _first, short) \ - c2_nonstatic_field(OptoRegPair, _second, short) \ - \ - c2_nonstatic_field(JVMState, _caller, JVMState*) \ - c2_nonstatic_field(JVMState, _depth, uint) \ - c2_nonstatic_field(JVMState, _locoff, uint) \ - c2_nonstatic_field(JVMState, _stkoff, uint) \ - c2_nonstatic_field(JVMState, _monoff, uint) \ - c2_nonstatic_field(JVMState, _scloff, uint) \ - c2_nonstatic_field(JVMState, _endoff, uint) \ - c2_nonstatic_field(JVMState, _sp, uint) \ - c2_nonstatic_field(JVMState, _bci, int) \ - c2_nonstatic_field(JVMState, _method, ciMethod*) \ - c2_nonstatic_field(JVMState, _map, SafePointNode*) \ - \ - c2_nonstatic_field(SafePointNode, _jvms, JVMState* const) \ - \ - c2_nonstatic_field(MachSafePointNode, _jvms, JVMState*) \ - c2_nonstatic_field(MachSafePointNode, _jvmadj, uint) \ - \ - c2_nonstatic_field(MachIfNode, _prob, jfloat) \ - c2_nonstatic_field(MachIfNode, _fcnt, jfloat) \ - \ - c2_nonstatic_field(MachJumpNode, _probs, jfloat*) \ - \ - c2_nonstatic_field(CallNode, _entry_point, address) \ - \ - c2_nonstatic_field(CallJavaNode, _method, ciMethod*) \ - \ - c2_nonstatic_field(CallRuntimeNode, _name, const char*) \ - \ - c2_nonstatic_field(CallStaticJavaNode, _name, const char*) \ - \ - c2_nonstatic_field(MachCallJavaNode, _method, ciMethod*) \ - \ - c2_nonstatic_field(MachCallStaticJavaNode, _name, const char*) \ - \ - c2_nonstatic_field(MachCallRuntimeNode, _name, const char*) \ - \ - c2_nonstatic_field(PhaseCFG, _number_of_blocks, uint) \ - c2_nonstatic_field(PhaseCFG, _blocks, Block_List) \ - c2_nonstatic_field(PhaseCFG, _node_to_block_mapping, Block_Array) \ - c2_nonstatic_field(PhaseCFG, _root_block, Block*) \ - \ - c2_nonstatic_field(PhaseRegAlloc, _node_regs, OptoRegPair*) \ - c2_nonstatic_field(PhaseRegAlloc, _node_regs_max_index, uint) \ - c2_nonstatic_field(PhaseRegAlloc, _framesize, uint) \ - c2_nonstatic_field(PhaseRegAlloc, _max_reg, OptoReg::Name) \ - \ - c2_nonstatic_field(PhaseChaitin, _trip_cnt, int) \ - c2_nonstatic_field(PhaseChaitin, _alternate, int) \ - c2_nonstatic_field(PhaseChaitin, _lo_degree, uint) \ - c2_nonstatic_field(PhaseChaitin, _lo_stk_degree, uint) \ - c2_nonstatic_field(PhaseChaitin, _hi_degree, uint) \ - c2_nonstatic_field(PhaseChaitin, _simplified, uint) \ - \ - c2_nonstatic_field(Block, _nodes, Node_List) \ - c2_nonstatic_field(Block, _succs, Block_Array) \ - c2_nonstatic_field(Block, _num_succs, uint) \ - c2_nonstatic_field(Block, _pre_order, uint) \ - c2_nonstatic_field(Block, _dom_depth, uint) \ - c2_nonstatic_field(Block, _idom, Block*) \ - c2_nonstatic_field(Block, _freq, jdouble) \ - \ - c2_nonstatic_field(CFGElement, _freq, jdouble) \ - \ - c2_nonstatic_field(Block_List, _cnt, uint) \ - \ - c2_nonstatic_field(Block_Array, _size, uint) \ - c2_nonstatic_field(Block_Array, _blocks, Block**) \ - c2_nonstatic_field(Block_Array, _arena, Arena*) \ - \ - c2_nonstatic_field(Node_List, _cnt, uint) \ - \ - c2_nonstatic_field(Node_Array, _max, uint) \ - c2_nonstatic_field(Node_Array, _nodes, Node**) \ - c2_nonstatic_field(Node_Array, _a, Arena*) \ - \ - \ - /*********************/ \ /* -XX flags */ \ /*********************/ \ \ @@ -1063,10 +846,7 @@ declare_toplevel_type, \ declare_oop_type, \ declare_integer_type, \ - declare_unsigned_integer_type, \ - declare_c1_toplevel_type, \ - declare_c2_type, \ - declare_c2_toplevel_type) \ + declare_unsigned_integer_type) \ \ /*************************************************************/ \ /* Java primitive types -- required by the SA implementation */ \ @@ -1325,8 +1105,8 @@ declare_type(UpcallStub, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ - declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ + COMPILER2_PRESENT(declare_type(ExceptionBlob, SingletonBlob)) \ + COMPILER2_PRESENT(declare_type(UncommonTrapBlob, RuntimeBlob)) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -1374,12 +1154,6 @@ \ declare_toplevel_type(OopStorage) \ \ - /**********************/ \ - /* Runtime1 (C1 only) */ \ - /**********************/ \ - \ - declare_c1_toplevel_type(Runtime1) \ - \ /************/ \ /* Monitors */ \ /************/ \ @@ -1391,465 +1165,11 @@ declare_toplevel_type(BasicObjectLock) \ \ /*********************/ \ - /* Matcher (C2 only) */ \ - /*********************/ \ - \ - declare_c2_toplevel_type(Matcher) \ - declare_c2_toplevel_type(Compile) \ - declare_c2_toplevel_type(Options) \ - declare_c2_toplevel_type(InlineTree) \ - declare_c2_toplevel_type(OptoRegPair) \ - declare_c2_toplevel_type(JVMState) \ - declare_c2_toplevel_type(Phase) \ - declare_c2_type(PhaseCFG, Phase) \ - declare_c2_type(PhaseRegAlloc, Phase) \ - declare_c2_type(PhaseChaitin, PhaseRegAlloc) \ - declare_c2_toplevel_type(CFGElement) \ - declare_c2_type(Block, CFGElement) \ - declare_c2_toplevel_type(Block_Array) \ - declare_c2_type(Block_List, Block_Array) \ - declare_c2_toplevel_type(Node_Array) \ - declare_c2_type(Node_List, Node_Array) \ - declare_c2_type(Unique_Node_List, Node_List) \ - declare_c2_toplevel_type(Node) \ - declare_c2_type(AddNode, Node) \ - declare_c2_type(AddINode, AddNode) \ - declare_c2_type(AddLNode, AddNode) \ - declare_c2_type(AddFNode, AddNode) \ - declare_c2_type(AddDNode, AddNode) \ - declare_c2_type(AddPNode, Node) \ - declare_c2_type(OrINode, AddNode) \ - declare_c2_type(OrLNode, AddNode) \ - declare_c2_type(XorINode, AddNode) \ - declare_c2_type(XorLNode, AddNode) \ - declare_c2_type(MaxNode, AddNode) \ - declare_c2_type(MaxINode, MaxNode) \ - declare_c2_type(MinINode, MaxNode) \ - declare_c2_type(MaxLNode, MaxNode) \ - declare_c2_type(MinLNode, MaxNode) \ - declare_c2_type(MaxFNode, MaxNode) \ - declare_c2_type(MinFNode, MaxNode) \ - declare_c2_type(MaxDNode, MaxNode) \ - declare_c2_type(MinDNode, MaxNode) \ - declare_c2_type(StartNode, MultiNode) \ - declare_c2_type(StartOSRNode, StartNode) \ - declare_c2_type(ParmNode, ProjNode) \ - declare_c2_type(ReturnNode, Node) \ - declare_c2_type(RethrowNode, Node) \ - declare_c2_type(TailCallNode, ReturnNode) \ - declare_c2_type(TailJumpNode, ReturnNode) \ - declare_c2_type(ForwardExceptionNode, ReturnNode) \ - declare_c2_type(SafePointNode, MultiNode) \ - declare_c2_type(CallNode, SafePointNode) \ - declare_c2_type(CallJavaNode, CallNode) \ - declare_c2_type(CallStaticJavaNode, CallJavaNode) \ - declare_c2_type(CallDynamicJavaNode, CallJavaNode) \ - declare_c2_type(CallRuntimeNode, CallNode) \ - declare_c2_type(CallLeafNode, CallRuntimeNode) \ - declare_c2_type(CallLeafNoFPNode, CallLeafNode) \ - declare_c2_type(CallLeafVectorNode, CallLeafNode) \ - declare_c2_type(AllocateNode, CallNode) \ - declare_c2_type(AllocateArrayNode, AllocateNode) \ - declare_c2_type(LockNode, AbstractLockNode) \ - declare_c2_type(UnlockNode, AbstractLockNode) \ - declare_c2_type(FastLockNode, CmpNode) \ - declare_c2_type(FastUnlockNode, CmpNode) \ - declare_c2_type(RegionNode, Node) \ - declare_c2_type(JProjNode, ProjNode) \ - declare_c2_type(PhiNode, TypeNode) \ - declare_c2_type(GotoNode, Node) \ - declare_c2_type(CProjNode, ProjNode) \ - declare_c2_type(MultiBranchNode, MultiNode) \ - declare_c2_type(IfNode, MultiBranchNode) \ - declare_c2_type(IfTrueNode, CProjNode) \ - declare_c2_type(IfFalseNode, CProjNode) \ - declare_c2_type(PCTableNode, MultiBranchNode) \ - declare_c2_type(JumpNode, PCTableNode) \ - declare_c2_type(JumpProjNode, JProjNode) \ - declare_c2_type(CatchNode, PCTableNode) \ - declare_c2_type(CatchProjNode, CProjNode) \ - declare_c2_type(CreateExNode, TypeNode) \ - declare_c2_type(ClearArrayNode, Node) \ - declare_c2_type(NeverBranchNode, MultiBranchNode) \ - declare_c2_type(ConNode, TypeNode) \ - declare_c2_type(ConINode, ConNode) \ - declare_c2_type(ConPNode, ConNode) \ - declare_c2_type(ConNNode, ConNode) \ - declare_c2_type(ConLNode, ConNode) \ - declare_c2_type(ConFNode, ConNode) \ - declare_c2_type(ConDNode, ConNode) \ - declare_c2_type(BinaryNode, Node) \ - declare_c2_type(CMoveNode, TypeNode) \ - declare_c2_type(CMoveDNode, CMoveNode) \ - declare_c2_type(CMoveFNode, CMoveNode) \ - declare_c2_type(CMoveINode, CMoveNode) \ - declare_c2_type(CMoveLNode, CMoveNode) \ - declare_c2_type(CMovePNode, CMoveNode) \ - declare_c2_type(CMoveNNode, CMoveNode) \ - declare_c2_type(EncodePNode, TypeNode) \ - declare_c2_type(DecodeNNode, TypeNode) \ - declare_c2_type(EncodePKlassNode, TypeNode) \ - declare_c2_type(DecodeNKlassNode, TypeNode) \ - declare_c2_type(ConstraintCastNode, TypeNode) \ - declare_c2_type(CastIINode, ConstraintCastNode) \ - declare_c2_type(CastPPNode, ConstraintCastNode) \ - declare_c2_type(CheckCastPPNode, TypeNode) \ - declare_c2_type(Conv2BNode, Node) \ - declare_c2_type(ConvertNode, TypeNode) \ - declare_c2_type(ConvD2FNode, Node) \ - declare_c2_type(ConvD2INode, Node) \ - declare_c2_type(ConvD2LNode, Node) \ - declare_c2_type(ConvF2DNode, Node) \ - declare_c2_type(ConvF2INode, Node) \ - declare_c2_type(ConvF2LNode, Node) \ - declare_c2_type(ConvI2DNode, Node) \ - declare_c2_type(ConvI2FNode, Node) \ - declare_c2_type(ConvI2LNode, TypeNode) \ - declare_c2_type(ConvL2DNode, Node) \ - declare_c2_type(ConvL2FNode, Node) \ - declare_c2_type(ConvL2INode, Node) \ - declare_c2_type(CastX2PNode, Node) \ - declare_c2_type(CastP2XNode, Node) \ - declare_c2_type(MemBarNode, MultiNode) \ - declare_c2_type(MemBarAcquireNode, MemBarNode) \ - declare_c2_type(MemBarReleaseNode, MemBarNode) \ - declare_c2_type(LoadFenceNode, MemBarNode) \ - declare_c2_type(StoreFenceNode, MemBarNode) \ - declare_c2_type(MemBarVolatileNode, MemBarNode) \ - declare_c2_type(MemBarCPUOrderNode, MemBarNode) \ - declare_c2_type(OnSpinWaitNode, MemBarNode) \ - declare_c2_type(BlackholeNode, MultiNode) \ - declare_c2_type(InitializeNode, MemBarNode) \ - declare_c2_type(ThreadLocalNode, Node) \ - declare_c2_type(Opaque1Node, Node) \ - declare_c2_type(PartialSubtypeCheckNode, Node) \ - declare_c2_type(MoveI2FNode, Node) \ - declare_c2_type(MoveL2DNode, Node) \ - declare_c2_type(MoveF2INode, Node) \ - declare_c2_type(MoveD2LNode, Node) \ - declare_c2_type(DivINode, Node) \ - declare_c2_type(DivLNode, Node) \ - declare_c2_type(DivFNode, Node) \ - declare_c2_type(DivDNode, Node) \ - declare_c2_type(UDivINode, Node) \ - declare_c2_type(UDivLNode, Node) \ - declare_c2_type(ModINode, Node) \ - declare_c2_type(ModLNode, Node) \ - declare_c2_type(ModFNode, Node) \ - declare_c2_type(ModDNode, Node) \ - declare_c2_type(UModINode, Node) \ - declare_c2_type(UModLNode, Node) \ - declare_c2_type(DivModNode, MultiNode) \ - declare_c2_type(DivModINode, DivModNode) \ - declare_c2_type(DivModLNode, DivModNode) \ - declare_c2_type(UDivModINode, DivModNode) \ - declare_c2_type(UDivModLNode, DivModNode) \ - declare_c2_type(BoxLockNode, Node) \ - declare_c2_type(LoopNode, RegionNode) \ - declare_c2_type(CountedLoopNode, LoopNode) \ - declare_c2_type(CountedLoopEndNode, IfNode) \ - declare_c2_type(MachNode, Node) \ - declare_c2_type(MachIdealNode, MachNode) \ - declare_c2_type(MachTypeNode, MachNode) \ - declare_c2_type(MachBreakpointNode, MachIdealNode) \ - declare_c2_type(MachUEPNode, MachIdealNode) \ - declare_c2_type(MachPrologNode, MachIdealNode) \ - declare_c2_type(MachEpilogNode, MachIdealNode) \ - declare_c2_type(MachNopNode, MachIdealNode) \ - declare_c2_type(MachSpillCopyNode, MachIdealNode) \ - declare_c2_type(MachNullCheckNode, MachIdealNode) \ - declare_c2_type(MachProjNode, ProjNode) \ - declare_c2_type(MachIfNode, MachNode) \ - declare_c2_type(MachJumpNode, MachNode) \ - declare_c2_type(MachFastLockNode, MachNode) \ - declare_c2_type(MachReturnNode, MachNode) \ - declare_c2_type(MachSafePointNode, MachReturnNode) \ - declare_c2_type(MachCallNode, MachSafePointNode) \ - declare_c2_type(MachCallJavaNode, MachCallNode) \ - declare_c2_type(MachCallStaticJavaNode, MachCallJavaNode) \ - declare_c2_type(MachCallDynamicJavaNode, MachCallJavaNode) \ - declare_c2_type(MachCallRuntimeNode, MachCallNode) \ - declare_c2_type(MachHaltNode, MachReturnNode) \ - declare_c2_type(MachTempNode, MachNode) \ - declare_c2_type(MemNode, Node) \ - declare_c2_type(MergeMemNode, Node) \ - declare_c2_type(LoadNode, MemNode) \ - declare_c2_type(LoadBNode, LoadNode) \ - declare_c2_type(LoadUSNode, LoadNode) \ - declare_c2_type(LoadINode, LoadNode) \ - declare_c2_type(LoadRangeNode, LoadINode) \ - declare_c2_type(LoadLNode, LoadNode) \ - declare_c2_type(LoadL_unalignedNode, LoadLNode) \ - declare_c2_type(LoadFNode, LoadNode) \ - declare_c2_type(LoadDNode, LoadNode) \ - declare_c2_type(LoadD_unalignedNode, LoadDNode) \ - declare_c2_type(LoadPNode, LoadNode) \ - declare_c2_type(LoadNNode, LoadNode) \ - declare_c2_type(LoadKlassNode, LoadPNode) \ - declare_c2_type(LoadNKlassNode, LoadNNode) \ - declare_c2_type(LoadSNode, LoadNode) \ - declare_c2_type(StoreNode, MemNode) \ - declare_c2_type(StoreBNode, StoreNode) \ - declare_c2_type(StoreCNode, StoreNode) \ - declare_c2_type(StoreINode, StoreNode) \ - declare_c2_type(StoreLNode, StoreNode) \ - declare_c2_type(StoreFNode, StoreNode) \ - declare_c2_type(StoreDNode, StoreNode) \ - declare_c2_type(StorePNode, StoreNode) \ - declare_c2_type(StoreNNode, StoreNode) \ - declare_c2_type(StoreNKlassNode, StoreNode) \ - declare_c2_type(SCMemProjNode, ProjNode) \ - declare_c2_type(LoadStoreNode, Node) \ - declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ - declare_c2_type(CompareAndSwapBNode, CompareAndSwapNode) \ - declare_c2_type(CompareAndSwapSNode, CompareAndSwapNode) \ - declare_c2_type(CompareAndSwapLNode, CompareAndSwapNode) \ - declare_c2_type(CompareAndSwapINode, CompareAndSwapNode) \ - declare_c2_type(CompareAndSwapPNode, CompareAndSwapNode) \ - declare_c2_type(CompareAndSwapNNode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapBNode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapSNode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapLNode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapINode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapPNode, CompareAndSwapNode) \ - declare_c2_type(WeakCompareAndSwapNNode, CompareAndSwapNode) \ - declare_c2_type(CompareAndExchangeNode, LoadStoreNode) \ - declare_c2_type(CompareAndExchangeBNode, CompareAndExchangeNode) \ - declare_c2_type(CompareAndExchangeSNode, CompareAndExchangeNode) \ - declare_c2_type(CompareAndExchangeLNode, CompareAndExchangeNode) \ - declare_c2_type(CompareAndExchangeINode, CompareAndExchangeNode) \ - declare_c2_type(CompareAndExchangePNode, CompareAndExchangeNode) \ - declare_c2_type(CompareAndExchangeNNode, CompareAndExchangeNode) \ - declare_c2_type(MulNode, Node) \ - declare_c2_type(MulINode, MulNode) \ - declare_c2_type(MulLNode, MulNode) \ - declare_c2_type(MulFNode, MulNode) \ - declare_c2_type(MulDNode, MulNode) \ - declare_c2_type(MulHiLNode, Node) \ - declare_c2_type(UMulHiLNode, Node) \ - declare_c2_type(AndINode, MulINode) \ - declare_c2_type(AndLNode, MulLNode) \ - declare_c2_type(LShiftINode, Node) \ - declare_c2_type(LShiftLNode, Node) \ - declare_c2_type(RShiftINode, Node) \ - declare_c2_type(RShiftLNode, Node) \ - declare_c2_type(URShiftINode, Node) \ - declare_c2_type(URShiftLNode, Node) \ - declare_c2_type(MultiNode, Node) \ - declare_c2_type(ProjNode, Node) \ - declare_c2_type(TypeNode, Node) \ - declare_c2_type(RootNode, LoopNode) \ - declare_c2_type(HaltNode, Node) \ - declare_c2_type(SubNode, Node) \ - declare_c2_type(SubINode, SubNode) \ - declare_c2_type(SubLNode, SubNode) \ - declare_c2_type(SubFPNode, SubNode) \ - declare_c2_type(SubFNode, SubFPNode) \ - declare_c2_type(SubDNode, SubFPNode) \ - declare_c2_type(CmpNode, SubNode) \ - declare_c2_type(CmpINode, CmpNode) \ - declare_c2_type(CmpUNode, CmpNode) \ - declare_c2_type(CmpU3Node, CmpUNode) \ - declare_c2_type(CmpPNode, CmpNode) \ - declare_c2_type(CmpNNode, CmpNode) \ - declare_c2_type(CmpLNode, CmpNode) \ - declare_c2_type(CmpULNode, CmpNode) \ - declare_c2_type(CmpL3Node, CmpLNode) \ - declare_c2_type(CmpUL3Node, CmpULNode) \ - declare_c2_type(CmpFNode, CmpNode) \ - declare_c2_type(CmpF3Node, CmpFNode) \ - declare_c2_type(CmpDNode, CmpNode) \ - declare_c2_type(CmpD3Node, CmpDNode) \ - declare_c2_type(BoolNode, Node) \ - declare_c2_type(AbsNode, Node) \ - declare_c2_type(AbsINode, AbsNode) \ - declare_c2_type(AbsFNode, AbsNode) \ - declare_c2_type(AbsDNode, AbsNode) \ - declare_c2_type(CmpLTMaskNode, Node) \ - declare_c2_type(NegNode, Node) \ - declare_c2_type(NegINode, NegNode) \ - declare_c2_type(NegLNode, NegNode) \ - declare_c2_type(NegFNode, NegNode) \ - declare_c2_type(NegDNode, NegNode) \ - declare_c2_type(AtanDNode, Node) \ - declare_c2_type(SqrtFNode, Node) \ - declare_c2_type(SqrtDNode, Node) \ - declare_c2_type(ReverseBytesINode, Node) \ - declare_c2_type(ReverseBytesLNode, Node) \ - declare_c2_type(ReductionNode, Node) \ - declare_c2_type(VectorNode, Node) \ - declare_c2_type(AbsVFNode, VectorNode) \ - declare_c2_type(AbsVDNode, VectorNode) \ - declare_c2_type(AbsVBNode, VectorNode) \ - declare_c2_type(AbsVSNode, VectorNode) \ - declare_c2_type(AbsVINode, VectorNode) \ - declare_c2_type(AbsVLNode, VectorNode) \ - declare_c2_type(AddVBNode, VectorNode) \ - declare_c2_type(AddVSNode, VectorNode) \ - declare_c2_type(AddVINode, VectorNode) \ - declare_c2_type(AddReductionVINode, ReductionNode) \ - declare_c2_type(AddVLNode, VectorNode) \ - declare_c2_type(AddReductionVLNode, ReductionNode) \ - declare_c2_type(AddVFNode, VectorNode) \ - declare_c2_type(AddReductionVFNode, ReductionNode) \ - declare_c2_type(AddVDNode, VectorNode) \ - declare_c2_type(AddReductionVDNode, ReductionNode) \ - declare_c2_type(SubVBNode, VectorNode) \ - declare_c2_type(SubVSNode, VectorNode) \ - declare_c2_type(SubVINode, VectorNode) \ - declare_c2_type(SubVLNode, VectorNode) \ - declare_c2_type(SubVFNode, VectorNode) \ - declare_c2_type(SubVDNode, VectorNode) \ - declare_c2_type(MulVBNode, VectorNode) \ - declare_c2_type(MulVSNode, VectorNode) \ - declare_c2_type(MulVLNode, VectorNode) \ - declare_c2_type(MulReductionVLNode, ReductionNode) \ - declare_c2_type(MulVINode, VectorNode) \ - declare_c2_type(MulReductionVINode, ReductionNode) \ - declare_c2_type(MulVFNode, VectorNode) \ - declare_c2_type(MulReductionVFNode, ReductionNode) \ - declare_c2_type(MulVDNode, VectorNode) \ - declare_c2_type(NegVNode, VectorNode) \ - declare_c2_type(NegVINode, NegVNode) \ - declare_c2_type(NegVLNode, NegVNode) \ - declare_c2_type(NegVFNode, NegVNode) \ - declare_c2_type(NegVDNode, NegVNode) \ - declare_c2_type(FmaVDNode, VectorNode) \ - declare_c2_type(FmaVFNode, VectorNode) \ - declare_c2_type(CompressVNode, VectorNode) \ - declare_c2_type(CompressMNode, VectorNode) \ - declare_c2_type(ExpandVNode, VectorNode) \ - declare_c2_type(CompressBitsVNode, VectorNode) \ - declare_c2_type(ExpandBitsVNode, VectorNode) \ - declare_c2_type(MulReductionVDNode, ReductionNode) \ - declare_c2_type(DivVFNode, VectorNode) \ - declare_c2_type(DivVDNode, VectorNode) \ - declare_c2_type(PopCountVINode, VectorNode) \ - declare_c2_type(PopCountVLNode, VectorNode) \ - declare_c2_type(LShiftVBNode, VectorNode) \ - declare_c2_type(LShiftVSNode, VectorNode) \ - declare_c2_type(LShiftVINode, VectorNode) \ - declare_c2_type(LShiftVLNode, VectorNode) \ - declare_c2_type(RShiftVBNode, VectorNode) \ - declare_c2_type(RShiftVSNode, VectorNode) \ - declare_c2_type(RShiftVINode, VectorNode) \ - declare_c2_type(RShiftVLNode, VectorNode) \ - declare_c2_type(URShiftVBNode, VectorNode) \ - declare_c2_type(URShiftVSNode, VectorNode) \ - declare_c2_type(URShiftVINode, VectorNode) \ - declare_c2_type(URShiftVLNode, VectorNode) \ - declare_c2_type(MinReductionVNode, ReductionNode) \ - declare_c2_type(MaxReductionVNode, ReductionNode) \ - declare_c2_type(AndVNode, VectorNode) \ - declare_c2_type(AndReductionVNode, ReductionNode) \ - declare_c2_type(OrVNode, VectorNode) \ - declare_c2_type(OrReductionVNode, ReductionNode) \ - declare_c2_type(XorVNode, VectorNode) \ - declare_c2_type(XorReductionVNode, ReductionNode) \ - declare_c2_type(MaxVNode, VectorNode) \ - declare_c2_type(MinVNode, VectorNode) \ - declare_c2_type(LoadVectorNode, LoadNode) \ - declare_c2_type(StoreVectorNode, StoreNode) \ - declare_c2_type(ReplicateNode, VectorNode) \ - declare_c2_type(PopulateIndexNode, VectorNode) \ - declare_c2_type(PackNode, VectorNode) \ - declare_c2_type(PackBNode, PackNode) \ - declare_c2_type(PackSNode, PackNode) \ - declare_c2_type(PackINode, PackNode) \ - declare_c2_type(PackLNode, PackNode) \ - declare_c2_type(PackFNode, PackNode) \ - declare_c2_type(PackDNode, PackNode) \ - declare_c2_type(Pack2LNode, PackNode) \ - declare_c2_type(Pack2DNode, PackNode) \ - declare_c2_type(ExtractNode, Node) \ - declare_c2_type(ExtractBNode, ExtractNode) \ - declare_c2_type(ExtractUBNode, ExtractNode) \ - declare_c2_type(ExtractCNode, ExtractNode) \ - declare_c2_type(ExtractSNode, ExtractNode) \ - declare_c2_type(ExtractINode, ExtractNode) \ - declare_c2_type(ExtractLNode, ExtractNode) \ - declare_c2_type(ExtractFNode, ExtractNode) \ - declare_c2_type(ExtractDNode, ExtractNode) \ - declare_c2_type(OverflowNode, CmpNode) \ - declare_c2_type(OverflowINode, OverflowNode) \ - declare_c2_type(OverflowAddINode, OverflowINode) \ - declare_c2_type(OverflowSubINode, OverflowINode) \ - declare_c2_type(OverflowMulINode, OverflowINode) \ - declare_c2_type(OverflowLNode, OverflowNode) \ - declare_c2_type(OverflowAddLNode, OverflowLNode) \ - declare_c2_type(OverflowSubLNode, OverflowLNode) \ - declare_c2_type(OverflowMulLNode, OverflowLNode) \ - declare_c2_type(FmaDNode, Node) \ - declare_c2_type(FmaFNode, Node) \ - declare_c2_type(CopySignDNode, Node) \ - declare_c2_type(CopySignFNode, Node) \ - declare_c2_type(SignumDNode, Node) \ - declare_c2_type(SignumFNode, Node) \ - declare_c2_type(IsInfiniteFNode, Node) \ - declare_c2_type(IsInfiniteDNode, Node) \ - declare_c2_type(IsFiniteFNode, Node) \ - declare_c2_type(IsFiniteDNode, Node) \ - declare_c2_type(LoadVectorGatherNode, LoadVectorNode) \ - declare_c2_type(StoreVectorScatterNode, StoreVectorNode) \ - declare_c2_type(VectorLoadMaskNode, VectorNode) \ - declare_c2_type(VectorLoadShuffleNode, VectorNode) \ - declare_c2_type(VectorStoreMaskNode, VectorNode) \ - declare_c2_type(VectorBlendNode, VectorNode) \ - declare_c2_type(VectorRearrangeNode, VectorNode) \ - declare_c2_type(VectorMaskWrapperNode, VectorNode) \ - declare_c2_type(VectorMaskCmpNode, VectorNode) \ - declare_c2_type(VectorCastB2XNode, VectorNode) \ - declare_c2_type(VectorCastS2XNode, VectorNode) \ - declare_c2_type(VectorCastI2XNode, VectorNode) \ - declare_c2_type(VectorCastL2XNode, VectorNode) \ - declare_c2_type(VectorCastF2XNode, VectorNode) \ - declare_c2_type(VectorCastD2XNode, VectorNode) \ - declare_c2_type(VectorUCastB2XNode, VectorNode) \ - declare_c2_type(VectorUCastS2XNode, VectorNode) \ - declare_c2_type(VectorUCastI2XNode, VectorNode) \ - declare_c2_type(VectorInsertNode, VectorNode) \ - declare_c2_type(VectorUnboxNode, VectorNode) \ - declare_c2_type(VectorReinterpretNode, VectorNode) \ - declare_c2_type(VectorMaskCastNode, VectorNode) \ - declare_c2_type(CountLeadingZerosVNode, VectorNode) \ - declare_c2_type(CountTrailingZerosVNode, VectorNode) \ - declare_c2_type(ReverseBytesVNode, VectorNode) \ - declare_c2_type(ReverseVNode, VectorNode) \ - declare_c2_type(MaskAllNode, VectorNode) \ - declare_c2_type(AndVMaskNode, VectorNode) \ - declare_c2_type(OrVMaskNode, VectorNode) \ - declare_c2_type(XorVMaskNode, VectorNode) \ - declare_c2_type(VectorBoxNode, Node) \ - declare_c2_type(VectorBoxAllocateNode, CallStaticJavaNode) \ - declare_c2_type(VectorTestNode, CmpNode) \ - \ - /*********************/ \ /* Adapter Blob Entries */ \ /*********************/ \ declare_toplevel_type(AdapterHandlerEntry) \ declare_toplevel_type(AdapterHandlerEntry*) \ \ - /*********************/ \ - /* CI */ \ - /*********************/ \ - declare_toplevel_type(ciEnv) \ - declare_toplevel_type(ciObjectFactory) \ - declare_toplevel_type(ciConstant) \ - declare_toplevel_type(ciField) \ - declare_toplevel_type(ciSymbol) \ - declare_toplevel_type(ciBaseObject) \ - declare_type(ciObject, ciBaseObject) \ - declare_type(ciInstance, ciObject) \ - declare_type(ciMetadata, ciBaseObject) \ - declare_type(ciMethod, ciMetadata) \ - declare_type(ciMethodData, ciMetadata) \ - declare_type(ciType, ciMetadata) \ - declare_type(ciKlass, ciType) \ - declare_type(ciInstanceKlass, ciKlass) \ - declare_type(ciArrayKlass, ciKlass) \ - declare_type(ciTypeArrayKlass, ciArrayKlass) \ - declare_type(ciObjArrayKlass, ciArrayKlass) \ - \ /********************/ \ /* -XX flags */ \ /********************/ \ @@ -1894,7 +1214,6 @@ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ declare_integer_type(JVMFlag::Flags) \ - COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ declare_type(Array, MetaspaceObj) \ @@ -1946,7 +1265,6 @@ declare_toplevel_type(Mutex) \ declare_toplevel_type(Mutex*) \ declare_toplevel_type(nmethod*) \ - COMPILER2_PRESENT(declare_unsigned_integer_type(node_idx_t)) \ declare_toplevel_type(ObjectMonitor*) \ declare_toplevel_type(oop*) \ declare_toplevel_type(OopMapCache*) \ @@ -1986,10 +1304,7 @@ #define VM_INT_CONSTANTS(declare_constant, \ declare_constant_with_value, \ - declare_preprocessor_constant, \ - declare_c1_constant, \ - declare_c2_constant, \ - declare_c2_preprocessor_constant) \ + declare_preprocessor_constant) \ \ /****************/ \ /* GC constants */ \ @@ -2003,6 +1318,7 @@ /******************/ \ \ declare_preprocessor_constant("ASSERT", DEBUG_ONLY(1) NOT_DEBUG(0)) \ + declare_preprocessor_constant("COMPILER2", COMPILER2_PRESENT(1) NOT_COMPILER2(0)) \ \ /****************/ \ /* Object sizes */ \ @@ -2352,12 +1668,6 @@ declare_constant(LM_LEGACY) \ declare_constant(LM_LIGHTWEIGHT) \ \ - /*********************/ \ - /* Matcher (C2 only) */ \ - /*********************/ \ - \ - declare_c2_preprocessor_constant("Matcher::interpreter_frame_pointer_reg", Matcher::interpreter_frame_pointer_reg()) \ - \ /*********************************************/ \ /* MethodCompilation (globalDefinitions.hpp) */ \ /*********************************************/ \ @@ -2457,8 +1767,8 @@ \ declare_constant(ConcreteRegisterImpl::number_of_registers) \ declare_preprocessor_constant("REG_COUNT", REG_COUNT) \ - declare_c2_preprocessor_constant("SAVED_ON_ENTRY_REG_COUNT", SAVED_ON_ENTRY_REG_COUNT) \ - declare_c2_preprocessor_constant("C_SAVED_ON_ENTRY_REG_COUNT", C_SAVED_ON_ENTRY_REG_COUNT) \ + COMPILER2_PRESENT(declare_preprocessor_constant("SAVED_ON_ENTRY_REG_COUNT", SAVED_ON_ENTRY_REG_COUNT)) \ + COMPILER2_PRESENT(declare_preprocessor_constant("C_SAVED_ON_ENTRY_REG_COUNT", C_SAVED_ON_ENTRY_REG_COUNT)) \ \ /************/ \ /* PerfData */ \ @@ -2509,7 +1819,7 @@ // enums, etc., while "declare_preprocessor_constant" must be used for // all #defined constants. -#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ +#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant) \ \ /****************/ \ /* GC constants */ \ @@ -2575,108 +1885,6 @@ # define ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT(a, b, c) #endif /* PRODUCT */ -// Generate and check a nonstatic field in C1 builds -#ifdef COMPILER1 -# define GENERATE_C1_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) GENERATE_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define CHECK_C1_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) CHECK_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define ENSURE_C1_FIELD_TYPE_PRESENT(a, b, c) ENSURE_FIELD_TYPE_PRESENT(a, b, c) -#else -# define GENERATE_C1_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define CHECK_C1_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define ENSURE_C1_FIELD_TYPE_PRESENT(a, b, c) -#endif /* COMPILER1 */ -// Generate and check a nonstatic field in C2 builds -#ifdef COMPILER2 -# define GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) GENERATE_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) CHECK_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define ENSURE_C2_FIELD_TYPE_PRESENT(a, b, c) ENSURE_FIELD_TYPE_PRESENT(a, b, c) -#else -# define GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY(a, b, c) -# define ENSURE_C2_FIELD_TYPE_PRESENT(a, b, c) -#endif /* COMPILER2 */ - -// Generate but do not check a static field in C1 builds -#ifdef COMPILER1 -# define GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) -#else -# define GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) -#endif /* COMPILER1 */ - -// Generate but do not check a static field in C2 builds -#ifdef COMPILER2 -# define GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) -#else -# define GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY(a, b, c) -#endif /* COMPILER2 */ - -//-------------------------------------------------------------------------------- -// VMTypeEntry build-specific macros -// - -#ifdef COMPILER1 -# define GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY(a) GENERATE_TOPLEVEL_VM_TYPE_ENTRY(a) -# define CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY(a) -#else -# define GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY(a) -# define CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY(a) -#endif /* COMPILER1 */ - -#ifdef COMPILER2 -# define GENERATE_C2_VM_TYPE_ENTRY(a, b) GENERATE_VM_TYPE_ENTRY(a, b) -# define CHECK_C2_VM_TYPE_ENTRY(a, b) CHECK_VM_TYPE_ENTRY(a, b) -# define GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY(a) GENERATE_TOPLEVEL_VM_TYPE_ENTRY(a) -# define CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY(a) -#else -# define GENERATE_C2_VM_TYPE_ENTRY(a, b) -# define CHECK_C2_VM_TYPE_ENTRY(a, b) -# define GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY(a) -# define CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY(a) -#endif /* COMPILER2 */ - - -//-------------------------------------------------------------------------------- -// VMIntConstantEntry build-specific macros -// - -// Generate an int constant for a C1 build -#ifdef COMPILER1 -# define GENERATE_C1_VM_INT_CONSTANT_ENTRY(name) GENERATE_VM_INT_CONSTANT_ENTRY(name) -#else -# define GENERATE_C1_VM_INT_CONSTANT_ENTRY(name) -#endif /* COMPILER1 */ - -// Generate an int constant for a C2 build -#ifdef COMPILER2 -# define GENERATE_C2_VM_INT_CONSTANT_ENTRY(name) GENERATE_VM_INT_CONSTANT_ENTRY(name) -# define GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) -#else -# define GENERATE_C2_VM_INT_CONSTANT_ENTRY(name) -# define GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) -#endif /* COMPILER1 */ - - -//-------------------------------------------------------------------------------- -// VMLongConstantEntry build-specific macros -// - -// Generate a long constant for a C1 build -#ifdef COMPILER1 -# define GENERATE_C1_VM_LONG_CONSTANT_ENTRY(name) GENERATE_VM_LONG_CONSTANT_ENTRY(name) -#else -# define GENERATE_C1_VM_LONG_CONSTANT_ENTRY(name) -#endif /* COMPILER1 */ - -// Generate a long constant for a C2 build -#ifdef COMPILER2 -# define GENERATE_C2_VM_LONG_CONSTANT_ENTRY(name) GENERATE_VM_LONG_CONSTANT_ENTRY(name) -# define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) -#else -# define GENERATE_C2_VM_LONG_CONSTANT_ENTRY(name) -# define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) -#endif /* COMPILER1 */ - - // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries // @@ -2690,39 +1898,26 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_VOLATILE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, - GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) GENERATE_VM_STRUCT_LAST_ENTRY() }; @@ -2737,38 +1932,25 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, GENERATE_INTEGER_VM_TYPE_ENTRY, - GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, - GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) - + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, GENERATE_INTEGER_VM_TYPE_ENTRY, - GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, - GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, GENERATE_INTEGER_VM_TYPE_ENTRY, - GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, - GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, GENERATE_INTEGER_VM_TYPE_ENTRY, - GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, - GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_C2_VM_TYPE_ENTRY, - GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) GENERATE_VM_TYPE_LAST_ENTRY() }; @@ -2781,28 +1963,16 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { VM_INT_CONSTANTS(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_C1_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_C1_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_C1_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_OS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, - GENERATE_C1_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_VM_INT_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #ifdef VM_INT_CPU_FEATURE_CONSTANTS VM_INT_CPU_FEATURE_CONSTANTS #endif @@ -2817,28 +1987,16 @@ size_t VMStructs::localHotSpotVMIntConstantsLength() { VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { VM_LONG_CONSTANTS(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_C1_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_C1_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_C1_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) VM_LONG_CONSTANTS_OS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, - GENERATE_C1_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_VM_LONG_CONSTANT_ENTRY, - GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) #ifdef VM_LONG_CPU_FEATURE_CONSTANTS VM_LONG_CPU_FEATURE_CONSTANTS #endif @@ -2892,58 +2050,38 @@ void VMStructs::init() { CHECK_VOLATILE_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_C1_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NO_OP, - CHECK_NO_OP); - + CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NO_OP, - CHECK_NO_OP); + CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_NO_OP, CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_C2_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NO_OP, - CHECK_NO_OP); + CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) VM_TYPES(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); + CHECK_SINGLE_ARG_VM_TYPE_NO_OP) VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); + CHECK_SINGLE_ARG_VM_TYPE_NO_OP) VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_C1_TOPLEVEL_VM_TYPE_ENTRY, - CHECK_C2_VM_TYPE_ENTRY, - CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); + CHECK_SINGLE_ARG_VM_TYPE_NO_OP) // // Split VM_STRUCTS() invocation into two parts to allow MS VC++ 6.0 @@ -2967,39 +2105,26 @@ void VMStructs::init() { CHECK_NO_OP, CHECK_NO_OP, CHECK_NO_OP, - CHECK_NO_OP, - CHECK_NO_OP, - CHECK_NO_OP, - CHECK_NO_OP, - CHECK_NO_OP); + CHECK_NO_OP) VM_STRUCTS(CHECK_NO_OP, ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, ENSURE_FIELD_TYPE_PRESENT, - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, - ENSURE_C1_FIELD_TYPE_PRESENT, - ENSURE_C2_FIELD_TYPE_PRESENT, - CHECK_NO_OP, - CHECK_NO_OP); + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT) VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, ENSURE_FIELD_TYPE_PRESENT, - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, - ENSURE_C2_FIELD_TYPE_PRESENT, - CHECK_NO_OP, - CHECK_NO_OP); + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT) + VM_STRUCTS_OS_CPU(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, ENSURE_FIELD_TYPE_PRESENT, - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT, - ENSURE_C2_FIELD_TYPE_PRESENT, - CHECK_NO_OP, - CHECK_NO_OP); + ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT) #endif // !_WINDOWS } diff --git a/src/jdk.hotspot.agent/doc/cireplay.html b/src/jdk.hotspot.agent/doc/cireplay.html deleted file mode 100644 index 71da428e58e..00000000000 --- a/src/jdk.hotspot.agent/doc/cireplay.html +++ /dev/null @@ -1,41 +0,0 @@ - - - -Replay - - - - -

Compiler replay

-

-The compiler replay is a function to repeat the compiling process from a crashed java process in compiled method
-This function only exists in debug version of VM -

-

Usage

-
-First, use SA to attach to the core file, if succeeded, do
-       hsdb> dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
-       create file replay.txt, address is address of Method, or nmethod(CodeBlob)
-       hsdb> buildreplayjars [all | boot | app]
-       create files:
-         all:
-           app.jar, boot.jar
-         boot:
-           boot.jar
-         app:
-           app.jar
-       exit SA now.
-Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
-       java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
-       This will replay the compiling process.
-
-       With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
-
-notes:
-       1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
-       2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
-
-       Use this tool to dump VM type library:
-       vmstructsdump libjvm.so > <type_name>.db
-
-       set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
diff --git a/src/jdk.hotspot.agent/doc/clhsdb.html b/src/jdk.hotspot.agent/doc/clhsdb.html
index 69fd228a52e..a225530774f 100644
--- a/src/jdk.hotspot.agent/doc/clhsdb.html
+++ b/src/jdk.hotspot.agent/doc/clhsdb.html
@@ -38,9 +38,6 @@ Available commands:
   dumpclass { address | name } [ directory ] dump .class file for given Klass* or class name
   dumpcodecache dump codecache contents
   dumpheap [ file ] dump heap in hprof binary format
-  dumpideal -a | id dump ideal graph like debug flag -XX:+PrintIdeal
-  dumpilt -a | id dump inline tree for C2 compilation
-  dumpreplaydata <address> | -a | <thread_id> [>replay.txt] dump replay data into a file
   echo [ true | false ] turn on/off command echo mode
   examine { address[/count] | address,address } show contents of memory range
   field [ type [ name fieldtype isStatic offset address ] ] print info about a field of HotSpot type
@@ -84,11 +81,5 @@ Available commands:
 
 
-

Compilation Replay

-

-When a java process crashes in compiled method, usually a core file is saved. -The replay function can reproduce the compiling process in the core. -cireplay.html - diff --git a/src/jdk.hotspot.agent/doc/index.html b/src/jdk.hotspot.agent/doc/index.html index 2e3ba38e4b8..0ce8cd45970 100644 --- a/src/jdk.hotspot.agent/doc/index.html +++ b/src/jdk.hotspot.agent/doc/index.html @@ -40,12 +40,6 @@ More details on the command line interface can be found in the "jhsdb" man page

-

Compilation Replay

-

-When a java process crashes in a compiled method, usually a core file is saved. -The compiler replay function can reproduce the compiling process in the core. -See cireplay.html -

Debugging transported core dumps

When a core dump is moved from the machine where it was produced to a diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java index 79709cce132..01b9a4a447e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.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 @@ -44,7 +44,6 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -import sun.jvm.hotspot.ci.ciEnv; import sun.jvm.hotspot.code.CodeBlob; import sun.jvm.hotspot.code.CodeCacheVisitor; import sun.jvm.hotspot.code.NMethod; @@ -66,8 +65,6 @@ import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.oops.RawHeapVisitor; import sun.jvm.hotspot.oops.Symbol; import sun.jvm.hotspot.oops.UnknownOopException; -import sun.jvm.hotspot.opto.Compile; -import sun.jvm.hotspot.opto.InlineTree; import sun.jvm.hotspot.runtime.CompiledVFrame; import sun.jvm.hotspot.runtime.CompilerThread; import sun.jvm.hotspot.runtime.JavaThread; @@ -562,57 +559,6 @@ public class CommandProcessor { } } }, - new Command("dumpreplaydata", "dumpreplaydata {

| -a | }", false) { - // This is used to dump replay data from ciInstanceKlass, ciMethodData etc - // default file name is replay.txt, also if java crashes in compiler - // thread, this file will be dumped in error processing. - public void doit(Tokens t) { - if (t.countTokens() != 1) { - usage(); - return; - } - String name = t.nextToken(); - Address a = null; - try { - a = VM.getVM().getDebugger().parseAddress(name); - } catch (NumberFormatException e) { } - if (a != null) { - // only nmethod, Method, MethodData and InstanceKlass needed to - // dump replay data - - CodeBlob cb = VM.getVM().getCodeCache().findBlob(a); - if (cb instanceof NMethod nMethod) { - nMethod.dumpReplayData(out); - return; - } - // assume it is Metadata - Metadata meta = Metadata.instantiateWrapperFor(a); - if (meta != null) { - meta.dumpReplayData(out); - } else { - usage(); - return; - } - } - // Not an address - boolean all = name.equals("-a"); - Threads threads = VM.getVM().getThreads(); - for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread thread = threads.getJavaThreadAt(i); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - thread.printThreadIDOn(new PrintStream(bos)); - if (all || bos.toString().equals(name)) { - if (thread instanceof CompilerThread) { - CompilerThread ct = (CompilerThread)thread; - ciEnv env = ct.env(); - if (env != null) { - env.dumpReplayData(out); - } - } - } - } - } - }, new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { // This is used to dump jar files of all the classes // loaded in the core. Everything with null classloader @@ -973,94 +919,6 @@ public class CommandProcessor { } } }, - new Command("dumpideal", "dumpideal { -a | id }", false) { - // Do a full dump of the nodes reachable from root in each compiler thread. - public void doit(Tokens t) { - if (t.countTokens() != 1) { - usage(); - } else { - String name = t.nextToken(); - boolean all = name.equals("-a"); - Threads threads = VM.getVM().getThreads(); - for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread thread = threads.getJavaThreadAt(i); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - thread.printThreadIDOn(new PrintStream(bos)); - if (all || bos.toString().equals(name)) { - if (thread instanceof CompilerThread) { - CompilerThread ct = (CompilerThread)thread; - out.println(ct); - ciEnv env = ct.env(); - if (env != null) { - Compile c = env.compilerData(); - c.root().dump(9999, out); - } else { - out.println(" not compiling"); - } - } - } - } - } - } - }, - new Command("dumpcfg", "dumpcfg { -a | id }", false) { - // Dump the PhaseCFG for every compiler thread that has one live. - public void doit(Tokens t) { - if (t.countTokens() != 1) { - usage(); - } else { - String name = t.nextToken(); - boolean all = name.equals("-a"); - Threads threads = VM.getVM().getThreads(); - for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread thread = threads.getJavaThreadAt(i); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - thread.printThreadIDOn(new PrintStream(bos)); - if (all || bos.toString().equals(name)) { - if (thread instanceof CompilerThread) { - CompilerThread ct = (CompilerThread)thread; - out.println(ct); - ciEnv env = ct.env(); - if (env != null) { - Compile c = env.compilerData(); - c.cfg().dump(out); - } - } - } - } - } - } - }, - new Command("dumpilt", "dumpilt { -a | id }", false) { - // dumps the InlineTree of a C2 compile - public void doit(Tokens t) { - if (t.countTokens() != 1) { - usage(); - } else { - String name = t.nextToken(); - boolean all = name.equals("-a"); - Threads threads = VM.getVM().getThreads(); - for (int i = 0; i < threads.getNumberOfThreads(); i++) { - JavaThread thread = threads.getJavaThreadAt(i); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - thread.printThreadIDOn(new PrintStream(bos)); - if (all || bos.toString().equals(name)) { - if (thread instanceof CompilerThread) { - CompilerThread ct = (CompilerThread)thread; - ciEnv env = ct.env(); - if (env != null) { - Compile c = env.compilerData(); - InlineTree ilt = c.ilt(); - if (ilt != null) { - ilt.print(out); - } - } - } - } - } - } - } - }, new Command("vmstructsdump", "vmstructsdump", false) { public void doit(Tokens t) { if (t.countTokens() != 0) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java deleted file mode 100644 index b26e42ebfdf..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/c1/Runtime1.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 - * 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 sun.jvm.hotspot.c1; - -import java.util.*; -import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -/** Currently a minimal port to get C1 frame traversal working */ - -public class Runtime1 { - private static Field blobsField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("Runtime1"); - - blobsField = type.getField("_blobs"); - } - - public Runtime1() { - } - - /** FIXME: consider making argument "type-safe" in Java port */ - public Address entryFor(int id) { - return blobFor(id).codeBegin(); - } - - /** FIXME: consider making argument "type-safe" in Java port */ - public CodeBlob blobFor(int id) { - Address blobAddr = blobsField.getStaticFieldAddress().getAddressAt(id * VM.getVM().getAddressSize()); - return VM.getVM().getCodeCache().createCodeBlobWrapper(blobAddr, blobAddr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java deleted file mode 100644 index c0421c39b25..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciArrayKlass extends ciKlass { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciArrayKlass"); - dimensionField = new IntField(type.getJIntField("_dimension"), 0); - } - - private static IntField dimensionField; - - public ciArrayKlass(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java deleted file mode 100644 index c3de39a705a..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciBaseObject extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciBaseObject"); - identField = new CIntField(type.getCIntegerField("_ident"), 0); - } - - private static CIntField identField; - - public ciBaseObject(Address addr) { - super(addr); - } - - public void dumpReplayData(PrintStream out) { - out.println("# Unknown ci type " + getAddress().getAddressAt(0)); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java deleted file mode 100644 index 24029bdd031..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciConstant.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciConstant extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciConstant"); - valueObjectField = type.getAddressField("_value._object"); - valueDoubleField = type.getJDoubleField("_value._double"); - valueFloatField = type.getJFloatField("_value._float"); - valueLongField = type.getJLongField("_value._long"); - valueIntField = type.getJIntField("_value._int"); - typeField = new CIntField(type.getCIntegerField("_type"), 0); - } - - private static AddressField valueObjectField; - private static JDoubleField valueDoubleField; - private static JFloatField valueFloatField; - private static JLongField valueLongField; - private static JIntField valueIntField; - private static CIntField typeField; - - public ciConstant(Address addr) { - super(addr); - } - - public void dumpReplayData(PrintStream out) { - // Nothing to be done - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java deleted file mode 100644 index 9e5aa030046..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciEnv.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.opto.*; -import sun.jvm.hotspot.compiler.CompileTask; -import sun.jvm.hotspot.prims.JvmtiExport; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.GrowableArray; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciEnv extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciEnv"); - dependenciesField = type.getAddressField("_dependencies"); - factoryField = type.getAddressField("_factory"); - compilerDataField = type.getAddressField("_compiler_data"); - taskField = type.getAddressField("_task"); - } - - private static AddressField dependenciesField; - private static AddressField factoryField; - private static AddressField compilerDataField; - private static AddressField taskField; - - public ciEnv(Address addr) { - super(addr); - } - - public Compile compilerData() { - Address addr = compilerDataField.getValue(this.getAddress()); - if (addr == null) { - return null; - } - return new Compile(addr); - } - - public ciObjectFactory factory() { - return new ciObjectFactory(factoryField.getValue(this.getAddress())); - } - - public CompileTask task() { - return new CompileTask(taskField.getValue(this.getAddress())); - } - - public void dumpReplayData(PrintStream out) { - out.println("JvmtiExport can_access_local_variables " + - (JvmtiExport.canAccessLocalVariables() ? '1' : '0')); - out.println("JvmtiExport can_hotswap_or_post_breakpoint " + - (JvmtiExport.canHotswapOrPostBreakpoint() ? '1' : '0')); - out.println("JvmtiExport can_post_on_exceptions " + - (JvmtiExport.canPostOnExceptions() ? '1' : '0')); - - GrowableArray objects = factory().objects(); - out.println("# " + objects.length() + " ciObject found"); - for (int i = 0; i < objects.length(); i++) { - ciMetadata o = objects.at(i); - out.println("# ciMetadata" + i + " @ " + o); - o.dumpReplayData(out); - } - CompileTask task = task(); - Method method = task.method(); - int entryBci = task.osrBci(); - int compLevel = task.compLevel(); - out.print("compile " + method.nameAsAscii() + " " + - entryBci + " " + compLevel); - Compile compiler = compilerData(); - if (compiler != null) { - // Dump inlining data. - compiler.dumpInlineData(out); - } - out.println(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java deleted file mode 100644 index 9c96e20c0ad..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciField.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciField extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciField"); - constantValueField = type.getAddressField("_constant_value"); - isConstantField = type.getAddressField("_is_constant"); - offsetField = new CIntField(type.getCIntegerField("_offset"), 0); - signatureField = type.getAddressField("_signature"); - nameField = type.getAddressField("_name"); - holderField = type.getAddressField("_holder"); - } - - private static AddressField constantValueField; - private static AddressField isConstantField; - private static CIntField offsetField; - private static AddressField signatureField; - private static AddressField nameField; - private static AddressField holderField; - - public ciField(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java deleted file mode 100644 index dcf69cacdbb..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstance.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciInstance extends ciObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciInstance"); - } - - - public ciInstance(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java deleted file mode 100644 index febf476e6a6..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2011, 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 - * 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 sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.memory.SystemDictionary; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.Type; -import sun.jvm.hotspot.types.TypeDataBase; -import sun.jvm.hotspot.types.WrongTypeException; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciInstanceKlass extends ciKlass { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciInstanceKlass"); - initStateField = new CIntField(type.getCIntegerField("_init_state"), 0); - isSharedField = new CIntField(type.getCIntegerField("_is_shared"), 0); - CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue(); - CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue(); - } - - private static CIntField initStateField; - private static CIntField isSharedField; - private static int CLASS_STATE_LINKED; - private static int CLASS_STATE_FULLY_INITIALIZED; - - public ciInstanceKlass(Address addr) { - super(addr); - } - - public int initState() { - int initState = (int)initStateField.getValue(getAddress()); - if (isShared() && initState < CLASS_STATE_LINKED) { - InstanceKlass ik = (InstanceKlass)getMetadata(); - initState = ik.getInitStateAsInt(); - } - return initState; - } - - public boolean isShared() { - return isSharedField.getValue(getAddress()) != 0; - } - - public boolean isLinked() { - return initState() >= CLASS_STATE_LINKED; - } - - public boolean isInitialized() { - return initState() == CLASS_STATE_FULLY_INITIALIZED; - } - - public void dumpReplayData(PrintStream out) { - InstanceKlass ik = (InstanceKlass)getMetadata(); - ConstantPool cp = ik.getConstants(); - - // Try to record related loaded classes - Klass sub = ik.getSubklassKlass(); - while (sub != null) { - if (sub instanceof InstanceKlass) { - out.println("instanceKlass " + sub.getName().asString()); - } - sub = sub.getNextSiblingKlass(); - } - - final int length = cp.getLength(); - out.print("ciInstanceKlass " + name() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length); - for (int index = 1; index < length; index++) { - out.print(" " + cp.getTags().at(index)); - } - out.println(); - if (isInitialized()) { - Field[] staticFields = ik.getStaticFields(); - for (int i = 0; i < staticFields.length; i++) { - Field f = staticFields[i]; - Oop mirror = ik.getJavaMirror(); - if (f.isFinal() && !f.hasInitialValue()) { - out.print("staticfield " + name() + " " + - OopUtilities.escapeString(f.getID().getName()) + " " + - f.getFieldType().getSignature().asString() + " "); - if (f instanceof ByteField) { - ByteField bf = (ByteField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof BooleanField) { - BooleanField bf = (BooleanField)f; - out.println(bf.getValue(mirror) ? 1 : 0); - } else if (f instanceof ShortField) { - ShortField bf = (ShortField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof CharField) { - CharField bf = (CharField)f; - out.println(bf.getValue(mirror) & 0xffff); - } else if (f instanceof IntField) { - IntField bf = (IntField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof LongField) { - LongField bf = (LongField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof FloatField) { - FloatField bf = (FloatField)f; - out.println(Float.floatToRawIntBits(bf.getValue(mirror))); - } else if (f instanceof DoubleField) { - DoubleField bf = (DoubleField)f; - out.println(Double.doubleToRawLongBits(bf.getValue(mirror))); - } else if (f instanceof OopField) { - OopField bf = (OopField)f; - Oop value = bf.getValue(mirror); - if (value == null) { - out.println("null"); - } else if (value.isInstance()) { - Instance inst = (Instance)value; - if (inst.isA(SystemDictionary.getStringKlass())) { - out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\""); - } else { - out.println(inst.getKlass().getName().asString()); - } - } else if (value.isObjArray()) { - ObjArray oa = (ObjArray)value; - Klass ek = (ObjArrayKlass)oa.getKlass(); - out.println(oa.getLength() + " " + ek.getName().asString()); - } else if (value.isTypeArray()) { - TypeArray ta = (TypeArray)value; - out.println(ta.getLength()); - } else { - out.println(value); - } - } - } - } - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java deleted file mode 100644 index 168486cecd9..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciKlass.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciKlass extends ciType { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciKlass"); - nameField = type.getAddressField("_name"); - } - - private static AddressField nameField; - - public String name() { - ciSymbol sym = new ciSymbol(nameField.getValue(getAddress())); - return sym.asUtf88(); - } - - public ciKlass(Address addr) { - super(addr); - } - - public void printValueOn(PrintStream tty) { - Klass k = (Klass)getMetadata(); - k.printValueOn(tty); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java deleted file mode 100644 index e64ad9ef8f0..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMetadata.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciMetadata extends ciBaseObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciMetadata"); - metadataField = new MetadataField(type.getAddressField("_metadata"), 0); - } - - private static MetadataField metadataField; - - public Metadata getMetadata() { - return metadataField.getValue(getAddress()); - } - - public ciMetadata(Address addr) { - super(addr); - } - - public void printOn(PrintStream out) { - getMetadata().printValueOn(out); - } - - public String toString() { - return getMetadata().toString(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java deleted file mode 100644 index 132c54d9ba0..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethod.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciMethod extends ciMetadata { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciMethod"); - interpreterThrowoutCountField = new CIntField(type.getCIntegerField("_interpreter_throwout_count"), 0); - interpreterInvocationCountField = new CIntField(type.getCIntegerField("_interpreter_invocation_count"), 0); - try { - // XXX - instructionsSizeField = new CIntField(type.getCIntegerField("_instructions_size"), 0); - } catch (Exception e) { - } - } - - private static CIntField interpreterThrowoutCountField; - private static CIntField interpreterInvocationCountField; - private static CIntField instructionsSizeField; - - public ciMethod(Address addr) { - super(addr); - } - - public Method method() { - return (Method)getMetadata(); - } - - public int interpreterThrowoutCount() { - return (int) interpreterThrowoutCountField.getValue(getAddress()); - } - - public int interpreterInvocationCount() { - return (int) interpreterInvocationCountField.getValue(getAddress()); - } - - public int instructionsSize() { - if (instructionsSizeField == null) { - // XXX - Method method = method(); - NMethod nm = method.getNativeMethod(); - if (nm != null) return (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint()); - return 0; - } - return (int) instructionsSizeField.getValue(getAddress()); - } - - public void printShortName(PrintStream st) { - Method method = method(); - st.printf(" %s::%s", method.getMethodHolder().getName().asString().replace('/', '.'), - method.getName().asString()); - } - - public void dumpReplayData(PrintStream out) { - Method method = (Method)getMetadata(); - NMethod nm = method.getNativeMethod(); - out.println("ciMethod " + - nameAsAscii() + " " + - method.getInvocationCount() + " " + - method.getBackedgeCount() + " " + - interpreterInvocationCount() + " " + - interpreterThrowoutCount() + " " + - instructionsSize()); - } - - public void printValueOn(PrintStream tty) { - tty.print("ciMethod " + method().getName().asString() + method().getSignature().asString() + "@" + getAddress()); - } - - public String nameAsAscii() { - Method method = (Method)getMetadata(); - return method.nameAsAscii(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java deleted file mode 100644 index 237eb6227d9..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.types.Field; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciMethodData extends ciMetadata implements MethodDataInterface { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciMethodData"); - origField = type.getField("_orig"); - argReturnedField = new CIntField(type.getCIntegerField("_arg_returned"), 0); - argStackField = new CIntField(type.getCIntegerField("_arg_stack"), 0); - argLocalField = new CIntField(type.getCIntegerField("_arg_local"), 0); - eflagsField = new CIntField(type.getCIntegerField("_eflags"), 0); - hintDiField = new CIntField(type.getCIntegerField("_hint_di"), 0); - dataField = type.getAddressField("_data"); - extraDataSizeField = new CIntField(type.getCIntegerField("_extra_data_size"), 0); - dataSizeField = new CIntField(type.getCIntegerField("_data_size"), 0); - stateField = new CIntField(type.getCIntegerField("_state"), 0); - Type typeMethodData = db.lookupType("MethodData"); - sizeofMethodDataOopDesc = (int)typeMethodData.getSize(); - parametersTypeDataDi = new CIntField(typeMethodData.getCIntegerField("_parameters_type_data_di"), 0); - } - - private static Field origField; - private static CIntField argReturnedField; - private static CIntField argStackField; - private static CIntField argLocalField; - private static CIntField eflagsField; - private static CIntField hintDiField; - private static AddressField dataField; - private static CIntField extraDataSizeField; - private static CIntField dataSizeField; - private static CIntField stateField; - private static int sizeofMethodDataOopDesc; - private static CIntField parametersTypeDataDi; - - public ciMethodData(Address addr) { - super(addr); - } - - public ciKlass getKlassAtAddress(Address addr) { - return (ciKlass)ciObjectFactory.getMetadata(addr); - } - - public ciMethod getMethodAtAddress(Address addr) { - return (ciMethod)ciObjectFactory.getMetadata(addr); - } - - public void printKlassValueOn(ciKlass klass, PrintStream st) { - klass.printValueOn(st); - } - - public void printMethodValueOn(ciMethod method, PrintStream st) { - method.printValueOn(st); - } - - private byte[] fetchDataAt(Address base, long size) { - byte[] result = new byte[(int)size]; - for (int i = 0; i < size; i++) { - result[i] = base.getJByteAt(i); - } - return result; - } - - public byte[] orig() { - // fetch the orig MethodData data between header and dataSize - Address base = getAddress().addOffsetTo(origField.getOffset()); - byte[] result = new byte[(int)origField.getType().getSize()]; - for (int i = 0; i < result.length; i++) { - result[i] = base.getJByteAt(i); - } - return result; - } - - public long[] data() { - // Read the data as an array of intptr_t elements - Address base = dataField.getValue(getAddress()); - int elements = (dataSize() + extraDataSize()) / MethodData.cellSize; - long[] result = new long[elements]; - for (int i = 0; i < elements; i++) { - Address value = base.getAddressAt(i * MethodData.cellSize); - if (value != null) { - result[i] = value.minus(null); - } - } - return result; - } - - int dataSize() { - return (int)dataSizeField.getValue(getAddress()); - } - - int extraDataSize() { - return (int)extraDataSizeField.getValue(getAddress()); - } - - int state() { - return (int)stateField.getValue(getAddress()); - } - - int currentMileage() { - return 0; - } - - boolean outOfBounds(int dataIndex) { - return dataIndex >= dataSize(); - } - - ParametersTypeData parametersTypeData() { - int di = (int)parametersTypeDataDi.getValue(getMetadata().getAddress()); - if (di == -1 || di == -2) { - return null; - } - DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), di); - return new ParametersTypeData(this, dataLayout); - } - - ProfileData dataAt(int dataIndex) { - if (outOfBounds(dataIndex)) { - return null; - } - DataLayout dataLayout = new DataLayout(dataField.getValue(getAddress()), dataIndex); - - switch (dataLayout.tag()) { - case DataLayout.noTag: - default: - throw new InternalError(); - case DataLayout.bitDataTag: - return new BitData(dataLayout); - case DataLayout.counterDataTag: - return new CounterData(dataLayout); - case DataLayout.jumpDataTag: - return new JumpData(dataLayout); - case DataLayout.receiverTypeDataTag: - return new ReceiverTypeData(this, dataLayout); - case DataLayout.virtualCallDataTag: - return new VirtualCallData(this, dataLayout); - case DataLayout.retDataTag: - return new RetData(dataLayout); - case DataLayout.branchDataTag: - return new BranchData(dataLayout); - case DataLayout.multiBranchDataTag: - return new MultiBranchData(dataLayout); - case DataLayout.callTypeDataTag: - return new CallTypeData(this, dataLayout); - case DataLayout.virtualCallTypeDataTag: - return new VirtualCallTypeData(this, dataLayout); - case DataLayout.parametersTypeDataTag: - return new ParametersTypeData(this, dataLayout); - } - } - - int dpToDi(int dp) { - return dp; - } - - int firstDi() { return 0; } - ProfileData firstData() { return dataAt(firstDi()); } - ProfileData nextData(ProfileData current) { - int currentIndex = dpToDi(current.dp()); - int nextIndex = currentIndex + current.sizeInBytes(); - return dataAt(nextIndex); - } - boolean isValid(ProfileData current) { return current != null; } - - DataLayout limitDataPosition() { - return new DataLayout(dataField.getValue(getAddress()), dataSize()); - } - DataLayout extraDataBase() { - return limitDataPosition(); - } - DataLayout extraDataLimit() { - return new DataLayout(dataField.getValue(getAddress()), dataSize() + extraDataSize()); - } - DataLayout nextExtra(DataLayout dataLayout) { - return new DataLayout(dataField.getValue(getAddress()), dataLayout.dp() + DataLayout.computeSizeInBytes(MethodData.extraNbCells(dataLayout))); - } - - public void printDataOn(PrintStream st) { - if (parametersTypeData() != null) { - parametersTypeData().printDataOn(st); - } - ProfileData data = firstData(); - for ( ; isValid(data); data = nextData(data)) { - st.print(dpToDi(data.dp())); - st.print(" "); - // st->fillTo(6); - data.printDataOn(st); - } - st.println("--- Extra data:"); - DataLayout dp = extraDataBase(); - DataLayout end = extraDataLimit(); - for (;; dp = nextExtra(dp)) { - switch(dp.tag()) { - case DataLayout.noTag: - continue; - case DataLayout.bitDataTag: - data = new BitData(dp); - break; - case DataLayout.speculativeTrapDataTag: - data = new SpeculativeTrapData(this, dp); - break; - case DataLayout.argInfoDataTag: - data = new ArgInfoData(dp); - dp = end; // ArgInfoData is at the end of extra data section. - break; - default: - throw new InternalError("unexpected tag " + dp.tag()); - } - st.print(dpToDi(data.dp())); - st.print(" "); - data.printDataOn(st); - if (dp == end) return; - } - } - - int dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, ciKlass k) { - if (k != null) { - if (round == 0) count++; - else out.print(" " + ((pdata.dp() + pdata.cellOffset(index)) / MethodData.cellSize) + " " + k.name()); - } - return count; - } - - int dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData vdata) { - for (int i = 0; i < vdata.rowLimit(); i++) { - ciKlass k = vdata.receiver(i); - count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k); - } - return count; - } - - int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface callTypeData) { - if (callTypeData.hasArguments()) { - for (int i = 0; i < callTypeData.numberOfArguments(); i++) { - count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i)); - } - } - if (callTypeData.hasReturn()) { - count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType()); - } - return count; - } - - int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) { - DataLayout dp = extraDataBase(); - DataLayout end = extraDataLimit(); - - for (;dp != end; dp = nextExtra(dp)) { - switch(dp.tag()) { - case DataLayout.noTag: - case DataLayout.argInfoDataTag: - return count; - case DataLayout.bitDataTag: - break; - case DataLayout.speculativeTrapDataTag: { - SpeculativeTrapData data = new SpeculativeTrapData(this, dp); - ciMethod m = data.method(); - if (m != null) { - if (round == 0) { - count++; - } else { - out.print(" " + (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / MethodData.cellSize) + " " + m.nameAsAscii()); - } - } - break; - } - default: - throw new InternalError("bad tag " + dp.tag()); - } - } - return count; - } - - public void dumpReplayData(PrintStream out) { - MethodData mdo = (MethodData)getMetadata(); - Method method = mdo.getMethod(); - out.print("ciMethodData " + - method.nameAsAscii() + " " + - state() + " " + currentMileage()); - byte[] orig = orig(); - out.print(" orig " + orig.length); - for (int i = 0; i < orig.length; i++) { - out.print(" " + (orig[i] & 0xff)); - } - - long[] data = data(); - out.print(" data " + data.length); - for (int i = 0; i < data.length; i++) { - out.print(" 0x" + Long.toHexString(data[i])); - } - int count = 0; - ParametersTypeData parameters = parametersTypeData(); - for (int round = 0; round < 2; round++) { - if (round == 1) out.print(" oops " + count); - ProfileData pdata = firstData(); - for ( ; isValid(pdata); pdata = nextData(pdata)) { - if (pdata instanceof ReceiverTypeData) { - @SuppressWarnings("unchecked") - ReceiverTypeData receiverTypeData = (ReceiverTypeData)pdata; - count = dumpReplayDataReceiverTypeHelper(out, round, count, receiverTypeData); - } - if (pdata instanceof CallTypeDataInterface) { - @SuppressWarnings("unchecked") - CallTypeDataInterface callTypeData = (CallTypeDataInterface)pdata; - count = dumpReplayDataCallTypeHelper(out, round, count, callTypeData); - } - } - if (parameters != null) { - for (int i = 0; i < parameters.numberOfParameters(); i++) { - count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i)); - } - } - } - count = 0; - for (int round = 0; round < 2; round++) { - if (round == 1) out.print(" methods " + count); - count = dumpReplayDataExtraDataHelper(out, round, count); - } - out.println(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java deleted file mode 100644 index ce87a98dd20..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciObjArrayKlass extends ciArrayKlass { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciObjArrayKlass"); - elementKlassField = type.getAddressField("_element_klass"); - baseElementKlassField = type.getAddressField("_base_element_klass"); - } - - private static AddressField elementKlassField; - private static AddressField baseElementKlassField; - - public ciObjArrayKlass(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java deleted file mode 100644 index 0d462ce85dc..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObject.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciObject extends ciBaseObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciObject"); - klassField = type.getAddressField("_klass"); - handleField = type.getAddressField("_handle"); - } - - private static AddressField klassField; - private static AddressField handleField; - - public Oop getOop() { - OopHandle oh = handleField.getValue(getAddress()).getOopHandleAt(0); - return VM.getVM().getObjectHeap().newOop(oh); - } - - public ciObject(Address addr) { - super(addr); - } - - public void printOn(PrintStream out) { - getOop().printValueOn(out); - out.println(); - } - - public String toString() { - return getOop().toString(); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java deleted file mode 100644 index 3de3ba908b2..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.lang.reflect.Constructor; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.utilities.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciObjectFactory extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciObjectFactory"); - ciMetadataField = type.getAddressField("_ci_metadata"); - symbolsField = type.getAddressField("_symbols"); - - ciObjectConstructor = new VirtualBaseConstructor(db, db.lookupType("ciObject"), "sun.jvm.hotspot.ci", ciObject.class); - ciMetadataConstructor = new VirtualBaseConstructor(db, db.lookupType("ciMetadata"), "sun.jvm.hotspot.ci", ciMetadata.class); - ciSymbolConstructor = new VirtualBaseConstructor(db, db.lookupType("ciSymbol"), "sun.jvm.hotspot.ci", ciSymbol.class); - } - - private static AddressField ciMetadataField; - private static AddressField symbolsField; - - private static VirtualBaseConstructor ciObjectConstructor; - private static VirtualBaseConstructor ciMetadataConstructor; - private static VirtualBaseConstructor ciSymbolConstructor; - - public static ciObject get(Address addr) { - if (addr == null) return null; - - return ciObjectConstructor.instantiateWrapperFor(addr); - } - - public static ciMetadata getMetadata(Address addr) { - if (addr == null) return null; - - return ciMetadataConstructor.instantiateWrapperFor(addr); - } - - public GrowableArray objects() { - Address addr = getAddress().addOffsetTo(ciMetadataField.getOffset()); - return GrowableArray.create(addr, ciMetadataConstructor); - } - - public GrowableArray symbols() { - Address addr = getAddress().addOffsetTo(symbolsField.getOffset()); - return GrowableArray.create(addr, ciSymbolConstructor); - } - - public ciObjectFactory(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java deleted file mode 100644 index b9f5bcce6fb..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciSymbol.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciSymbol extends ciMetadata { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciSymbol"); - symbolField = type.getAddressField("_symbol"); - } - - private static AddressField symbolField; - - public String asUtf88() { - Symbol sym = Symbol.create(symbolField.getValue(getAddress())); - return sym.asString(); - } - - public ciSymbol(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java deleted file mode 100644 index 656b2e56479..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciType.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciType extends ciMetadata { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciType"); - basicTypeField = new CIntField(type.getCIntegerField("_basic_type"), 0); - } - - private static CIntField basicTypeField; - - public ciType(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java deleted file mode 100644 index 43f546a5da0..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.ci; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ciTypeArrayKlass extends ciArrayKlass { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ciTypeArrayKlass"); - } - - public ciTypeArrayKlass(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java index b401f3656f9..a085edf9936 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -65,8 +65,6 @@ public class CodeBlob extends VMObject { super(addr); } - protected static int matcherInterpreterFramePointerReg; - private static void initialize(TypeDataBase db) { Type type = db.lookupType("CodeBlob"); @@ -83,11 +81,6 @@ public class CodeBlob extends VMObject { oopMapsField = type.getAddressField("_oop_maps"); callerMustGCArgumentsField = type.getCIntegerField("_caller_must_gc_arguments"); - if (VM.getVM().isServerCompiler()) { - matcherInterpreterFramePointerReg = - db.lookupIntConstant("Matcher::interpreter_frame_pointer_reg").intValue(); - } - NMethodKind = db.lookupIntConstant("CodeBlobKind::Nmethod").intValue(); RuntimeStubKind = db.lookupIntConstant("CodeBlobKind::RuntimeStub").intValue(); UpcallKind = db.lookupIntConstant("CodeBlobKind::Upcall").intValue(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index 8cd2342750d..44d51b005ae 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -489,42 +489,6 @@ public class NMethod extends CodeBlob { method.getSignature().asString(); } - public void dumpReplayData(PrintStream out) { - HashMap h = new HashMap<>(); - for (int i = 1; i < getMetadataLength(); i++) { - Metadata meta = Metadata.instantiateWrapperFor(getMetadataAt(i)); - System.err.println(meta); - if (h.get(meta) != null) continue; - h.put(meta, meta); - if (meta instanceof InstanceKlass) { - meta.dumpReplayData(out); - } else if (meta instanceof Method) { - meta.dumpReplayData(out); - MethodData mdo = ((Method)meta).getMethodData(); - if (mdo != null) { - mdo.dumpReplayData(out); - } - } - } - Method method = getMethod(); - if (h.get(method) == null) { - method.dumpReplayData(out); - MethodData mdo = method.getMethodData(); - if (mdo != null) { - mdo.dumpReplayData(out); - } - } - if (h.get(method.getMethodHolder()) == null) { - method.getMethodHolder().dumpReplayData(out); - } - Klass holder = method.getMethodHolder(); - out.println("compile " + holder.getName().asString() + " " + - OopUtilities.escapeString(method.getName().asString()) + " " + - method.getSignature().asString() + " " + - getEntryBCI() + " " + getCompLevel()); - - } - //-------------------------------------------------------------------------------- // Internals only below this point // diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java index 7b5fba44bc2..e54facaeb72 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.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 @@ -29,7 +29,6 @@ import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.opto.*; import sun.jvm.hotspot.prims.JvmtiExport; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.Observable; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 05d511d422f..0cd743372d5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.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 @@ -965,84 +965,4 @@ public class InstanceKlass extends Klass { } return -1; } - - public void dumpReplayData(PrintStream out) { - ConstantPool cp = getConstants(); - - // Try to record related loaded classes - Klass sub = getSubklassKlass(); - while (sub != null) { - if (sub instanceof InstanceKlass) { - out.println("instanceKlass " + sub.getName().asString()); - } - sub = sub.getNextSiblingKlass(); - } - - final int length = cp.getLength(); - out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length); - for (int index = 1; index < length; index++) { - out.print(" " + cp.getTags().at(index)); - } - out.println(); - if (isInitialized()) { - Field[] staticFields = getStaticFields(); - for (int i = 0; i < staticFields.length; i++) { - Field f = staticFields[i]; - Oop mirror = getJavaMirror(); - if (f.isFinal() && !f.hasInitialValue()) { - out.print("staticfield " + getName().asString() + " " + - OopUtilities.escapeString(f.getID().getName()) + " " + - f.getFieldType().getSignature().asString() + " "); - if (f instanceof ByteField) { - ByteField bf = (ByteField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof BooleanField) { - BooleanField bf = (BooleanField)f; - out.println(bf.getValue(mirror) ? 1 : 0); - } else if (f instanceof ShortField) { - ShortField bf = (ShortField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof CharField) { - CharField bf = (CharField)f; - out.println(bf.getValue(mirror) & 0xffff); - } else if (f instanceof IntField) { - IntField bf = (IntField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof LongField) { - LongField bf = (LongField)f; - out.println(bf.getValue(mirror)); - } else if (f instanceof FloatField) { - FloatField bf = (FloatField)f; - out.println(Float.floatToRawIntBits(bf.getValue(mirror))); - } else if (f instanceof DoubleField) { - DoubleField bf = (DoubleField)f; - out.println(Double.doubleToRawLongBits(bf.getValue(mirror))); - } else if (f instanceof OopField) { - OopField bf = (OopField)f; - - Oop value = bf.getValue(mirror); - if (value == null) { - out.println("null"); - } else if (value.isInstance()) { - Instance inst = (Instance)value; - if (inst.isA(SystemDictionary.getStringKlass())) { - out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\""); - } else { - out.println(inst.getKlass().getName().asString()); - } - } else if (value.isObjArray()) { - ObjArray oa = (ObjArray)value; - Klass ek = (ObjArrayKlass)oa.getKlass(); - out.println(oa.getLength() + " " + ek.getName().asString()); - } else if (value.isTypeArray()) { - TypeArray ta = (TypeArray)value; - out.println(ta.getLength()); - } else { - out.println(value); - } - } - } - } - } - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java index ece6bf157b7..dfbd67ae805 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, 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 @@ -89,9 +89,6 @@ public abstract class Metadata extends VMObject { } public abstract void printValueOn(PrintStream tty); - public void dumpReplayData(PrintStream out) { - out.println("# Unknown Metadata"); - } public boolean isShared() { VM vm = VM.getVM(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java index ca7329ad6c9..75dec8edbd1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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 @@ -348,22 +348,6 @@ public class Method extends Metadata { return buf.toString().replace('/', '.'); } - public void dumpReplayData(PrintStream out) { - NMethod nm = getNativeMethod(); - int code_size = 0; - if (nm != null) { - code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint()); - } - Klass holder = getMethodHolder(); - out.println("ciMethod " + - nameAsAscii() + " " + - getInvocationCount() + " " + - getBackedgeCount() + " " + - interpreterInvocationCount() + " " + - interpreterThrowoutCount() + " " + - code_size); - } - public int interpreterThrowoutCount() { return getMethodCounters().interpreterThrowoutCount(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java index 0c05cabe32d..a7c2e2bccb7 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.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 @@ -439,111 +439,4 @@ public class MethodData extends Metadata implements MethodDataInterface vdata) { - for (int i = 0; i < vdata.rowLimit(); i++) { - Klass k = vdata.receiver(i); - count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k); - } - return count; - } - - int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface callTypeData) { - if (callTypeData.hasArguments()) { - for (int i = 0; i < callTypeData.numberOfArguments(); i++) { - count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i)); - } - } - if (callTypeData.hasReturn()) { - count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType()); - } - return count; - } - - int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) { - DataLayout dp = extraDataBase(); - DataLayout end = extraDataLimit(); - - for (;dp != end; dp = nextExtra(dp)) { - switch(dp.tag()) { - case DataLayout.noTag: - case DataLayout.argInfoDataTag: - return count; - case DataLayout.bitDataTag: - break; - case DataLayout.speculativeTrapDataTag: { - SpeculativeTrapData data = new SpeculativeTrapData(this, dp); - Method m = data.method(); - if (m != null) { - if (round == 0) { - count++; - } else { - out.print(" " + (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / cellSize) + " " + m.nameAsAscii()); - } - } - break; - } - default: - throw new InternalError("bad tag " + dp.tag()); - } - } - return count; - } - - public void dumpReplayData(PrintStream out) { - Method method = getMethod(); - out.print("ciMethodData " + method.nameAsAscii() - + " " + "2" + " " + - currentMileage()); - byte[] orig = orig(); - out.print(" orig " + orig.length); - for (int i = 0; i < orig.length; i++) { - out.print(" " + (orig[i] & 0xff)); - } - - long[] data = data(); - out.print(" data " + data.length); - for (int i = 0; i < data.length; i++) { - out.print(" 0x" + Long.toHexString(data[i])); - } - int count = 0; - ParametersTypeData parameters = parametersTypeData(); - for (int round = 0; round < 2; round++) { - if (round == 1) out.print(" oops " + count); - ProfileData pdata = firstData(); - for ( ; isValid(pdata); pdata = nextData(pdata)) { - if (pdata instanceof ReceiverTypeData) { - @SuppressWarnings("unchecked") - ReceiverTypeData receiverTypeData = (ReceiverTypeData)pdata; - count = dumpReplayDataReceiverTypeHelper(out, round, count, receiverTypeData); - } - if (pdata instanceof CallTypeDataInterface) { - @SuppressWarnings("unchecked") - CallTypeDataInterface callTypeData = (CallTypeDataInterface)pdata; - count = dumpReplayDataCallTypeHelper(out, round, count, callTypeData); - } - } - if (parameters != null) { - for (int i = 0; i < parameters.numberOfParameters(); i++) { - count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i)); - } - } - } - count = 0; - for (int round = 0; round < 2; round++) { - if (round == 1) out.print(" methods " + count); - count = dumpReplayDataExtraDataHelper(out, round, count); - } - out.println(); - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java deleted file mode 100644 index 857e6da9bf8..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Block.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2011, 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 - * 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 sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Block extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Block"); - nodesField = type.getAddressField("_nodes"); - succsField = type.getAddressField("_succs"); - numSuccsField = new CIntField(type.getCIntegerField("_num_succs"), 0); - preOrderField = new CIntField(type.getCIntegerField("_pre_order"), 0); - domDepthField = new CIntField(type.getCIntegerField("_dom_depth"), 0); - idomField = type.getAddressField("_idom"); - freqField = type.getJDoubleField("_freq"); - } - - private static AddressField nodesField; - private static AddressField succsField; - private static CIntField numSuccsField; - private static CIntField preOrderField; - private static CIntField domDepthField; - private static AddressField idomField; - private static JDoubleField freqField; - - public Block(Address addr) { - super(addr); - } - - public int preOrder() { - return (int)preOrderField.getValue(getAddress()); - } - - public double freq() { - return freqField.getValue(getAddress()); - } - - public Node_List nodes() { - return new Node_List(getAddress().addOffsetTo(nodesField.getOffset())); - } - - public void dump(PrintStream out) { - out.print("B" + preOrder()); - out.print(" Freq: " + freq()); - out.println(); - Node_List nl = nodes(); - int cnt = nl.size(); - for( int i=0; idumpOn(st); - // if (_cnt != countUnknown) st->print(" C=%f",_cnt); - JVMState jvms = jvms(); - if (jvms != null) jvms.dumpSpec(out); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java deleted file mode 100644 index 3bfd221395e..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.utilities.CStringUtilities; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class CallRuntimeNode extends CallNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("CallRuntimeNode"); - nameField = type.getAddressField("_name"); - } - - private static AddressField nameField; - - public String name() { - return CStringUtilities.getString(nameField.getValue(getAddress())); - } - - public CallRuntimeNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream out) { - out.print(" #"); - out.print(name()); - super.dumpSpec(out); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java deleted file mode 100644 index ab678d0e6c6..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.utilities.CStringUtilities; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class CallStaticJavaNode extends CallJavaNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("CallStaticJavaNode"); - nameField = type.getAddressField("_name"); - } - - private static AddressField nameField; - - public String name() { - return CStringUtilities.getString(nameField.getValue(getAddress())); - } - - public CallStaticJavaNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream out) { - out.print(" Static "); - String name = name(); - if (name != null) { - out.print(name); - // int trapReq = uncommonTrapRequest(); - // if (trapReq != 0) { - // char buf[100]; - // st->print("(%s)", - // Deoptimization::formatTrapRequest(buf, sizeof(buf), - // trapReq)); - // } - out.print(" "); - } - super.dumpSpec(out); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java deleted file mode 100644 index 725c95619fc..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Compile.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.ci.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Compile extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Compile"); - rootField = type.getAddressField("_root"); - uniqueField = new CIntField(type.getCIntegerField("_unique"), 0); - entryBciField = new CIntField(type.getCIntegerField("_entry_bci"), 0); - topField = type.getAddressField("_top"); - cfgField = type.getAddressField("_cfg"); - regallocField = type.getAddressField("_regalloc"); - methodField = type.getAddressField("_method"); - iltField = type.getAddressField("_ilt"); - } - - private static AddressField rootField; - private static CIntField uniqueField; - private static CIntField entryBciField; - private static AddressField topField; - private static AddressField cfgField; - private static AddressField regallocField; - private static AddressField methodField; - private static AddressField iltField; - - public Compile(Address addr) { - super(addr); - } - - public Node root() { - return new RootNode(rootField.getValue(this.getAddress())); - } - - public int entryBci() { - return (int)entryBciField.getValue(getAddress()); - } - - public ciMethod method() { - return (ciMethod) ciObjectFactory.getMetadata(methodField.getValue(getAddress())); - } - - public PhaseCFG cfg() { - Address a = cfgField.getValue(this.getAddress()); - if (a != null) { - return new PhaseCFG(a); - } - return null; - } - - public InlineTree ilt() { - Address a = iltField.getValue(this.getAddress()); - if (a != null) { - return new InlineTree(a); - } - return null; - } - - public void dumpInlineData(PrintStream out) { - InlineTree inlTree = ilt(); - if (inlTree != null) { - out.print(" inline " + inlTree.count()); - inlTree.dumpReplayData(out); - } - } - -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java deleted file mode 100644 index a745d682069..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/CompilerPhaseType.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2014, 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. - * - */ - -package sun.jvm.hotspot.opto; - -//These definitions should be kept in sync with the definitions in the HotSpot code. - -public enum CompilerPhaseType { - PHASE_BEFORE_STRINGOPTS ("Before StringOpts"), - PHASE_AFTER_STRINGOPTS ("After StringOpts"), - PHASE_BEFORE_REMOVEUSELESS ("Before RemoveUseless"), - PHASE_AFTER_PARSING ("After Parsing"), - PHASE_ITER_GVN1 ("Iter GVN 1"), - PHASE_PHASEIDEAL_BEFORE_EA ("PhaseIdealLoop before EA"), - PHASE_ITER_GVN_AFTER_EA ("Iter GVN after EA"), - PHASE_ITER_GVN_AFTER_ELIMINATION ("Iter GVN after eliminating allocations and locks"), - PHASE_PHASEIDEALLOOP1 ("PhaseIdealLoop 1"), - PHASE_PHASEIDEALLOOP2 ("PhaseIdealLoop 2"), - PHASE_PHASEIDEALLOOP3 ("PhaseIdealLoop 3"), - PHASE_CCP1 ("PhaseCCP 1"), - PHASE_ITER_GVN2 ("Iter GVN 2"), - PHASE_PHASEIDEALLOOP_ITERATIONS ("PhaseIdealLoop iterations"), - PHASE_OPTIMIZE_FINISHED ("Optimize finished"), - PHASE_GLOBAL_CODE_MOTION ("Global code motion"), - PHASE_FINAL_CODE ("Final Code"), - PHASE_AFTER_EA ("After Escape Analysis"), - PHASE_BEFORE_CLOOPS ("Before CountedLoop"), - PHASE_AFTER_CLOOPS ("After CountedLoop"), - PHASE_BEFORE_BEAUTIFY_LOOPS ("Before beautify loops"), - PHASE_AFTER_BEAUTIFY_LOOPS ("After beautify loops"), - PHASE_BEFORE_MATCHING ("Before Matching"), - PHASE_INCREMENTAL_INLINE ("Incremental Inline"), - PHASE_INCREMENTAL_BOXING_INLINE ("Incremental Boxing Inline"), - PHASE_END ("End"), - PHASE_FAILURE ("Failure"), - PHASE_NUM_TYPES ("Number of Phase Types"); - - private final String value; - - CompilerPhaseType(String val) { - this.value = val; - } - public String value() { - return value; - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java deleted file mode 100644 index 5c84b2e9a6e..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/HaltNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class HaltNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("HaltNode"); - } - - - public HaltNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java deleted file mode 100644 index 9a11b1c962c..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/InlineTree.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.ci.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.utilities.GrowableArray; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class InlineTree extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("InlineTree"); - callerJvmsField = type.getAddressField("_caller_jvms"); - methodField = type.getAddressField("_method"); - callerTreeField = type.getAddressField("_caller_tree"); - subtreesField = type.getAddressField("_subtrees"); - } - - private static AddressField callerJvmsField; - private static AddressField methodField; - private static AddressField callerTreeField; - private static AddressField subtreesField; - - private static StaticBaseConstructor inlineTreeConstructor = new StaticBaseConstructor<>(InlineTree.class); - - public InlineTree(Address addr) { - super(addr); - } - - public InlineTree callerTree() { - Address addr = callerTreeField.getValue(getAddress()); - if (addr == null) return null; - - return new InlineTree(addr); - } - - public ciMethod method() { - return (ciMethod) ciObjectFactory.getMetadata(methodField.getValue(getAddress())); - } - - public JVMState callerJvms() { - return JVMState.create(callerJvmsField.getValue(getAddress())); - } - - public int callerBci() { - JVMState jvms = callerJvms(); - return (jvms != null) ? jvms.bci() : -1; - } - - public GrowableArray subtrees() { - Address addr = getAddress().addOffsetTo(subtreesField.getOffset()); - - return GrowableArray.create(addr, inlineTreeConstructor); - } - - public int inlineLevel() { - JVMState jvms = callerJvms(); - return (jvms != null) ? jvms.depth() : 0; - } - - public void printImpl(PrintStream st, int indent) { - for (int i = 0; i < indent; i++) st.print(" "); - st.printf(" @ %d ", callerBci()); - method().printShortName(st); - st.println(); - - GrowableArray subt = subtrees(); - for (int i = 0 ; i < subt.length(); i++) { - subt.at(i).printImpl(st, indent + 2); - } - } - public void print(PrintStream st) { - printImpl(st, 2); - } - - // Count number of nodes in this subtree - public int count() { - int result = 1; - GrowableArray subt = subtrees(); - for (int i = 0 ; i < subt.length(); i++) { - result += subt.at(i).count(); - } - return result; - } - - public void dumpReplayData(PrintStream out) { - out.printf(" %d %d ", inlineLevel(), callerBci()); - Method method = (Method)method().getMetadata(); - Klass holder = method.getMethodHolder(); - out.print(holder.getName().asString() + " " + - OopUtilities.escapeString(method.getName().asString()) + " " + - method.getSignature().asString()); - - GrowableArray subt = subtrees(); - for (int i = 0 ; i < subt.length(); i++) { - subt.at(i).dumpReplayData(out); - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java deleted file mode 100644 index d83c1df8b0d..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/JVMState.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.ci.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class JVMState extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("JVMState"); - mapField = type.getAddressField("_map"); - methodField = type.getAddressField("_method"); - bciField = new CIntField(type.getCIntegerField("_bci"), 0); - spField = new CIntField(type.getCIntegerField("_sp"), 0); - endoffField = new CIntField(type.getCIntegerField("_endoff"), 0); - try { - scloffField = new CIntField(type.getCIntegerField("_scloff"), 0); - } catch (Exception e) { - } - monoffField = new CIntField(type.getCIntegerField("_monoff"), 0); - stkoffField = new CIntField(type.getCIntegerField("_stkoff"), 0); - locoffField = new CIntField(type.getCIntegerField("_locoff"), 0); - depthField = new CIntField(type.getCIntegerField("_depth"), 0); - callerField = type.getAddressField("_caller"); - } - - private static AddressField mapField; - private static AddressField methodField; - private static CIntField bciField; - private static CIntField spField; - private static CIntField endoffField; - private static CIntField scloffField; - private static CIntField monoffField; - private static CIntField stkoffField; - private static CIntField locoffField; - private static CIntField depthField; - private static AddressField callerField; - - public static JVMState create(Address addr) { - if (addr == null) return null; - return new JVMState(addr); - } - - public JVMState(Address addr) { - super(addr); - } - - public ciMethod method() { - return (ciMethod) ciObjectFactory.getMetadata(methodField.getValue(getAddress())); - } - - public int bci() { - return (int)bciField.getValue(getAddress()); - } - - public int depth() { - return (int)depthField.getValue(getAddress()); - } - - public JVMState caller() { - return create(callerField.getValue(getAddress())); - } - - public void dumpSpec(PrintStream out) { - ciMethod m = method(); - if (m != null) { - Method meth = m.method(); - out.print(" " + meth.getMethodHolder().getName().asString().replace('/', '.') + "::" + - meth.getName().asString() + " @ bci:" + bci()); - } else { - out.print(" runtime stub"); - } - if (caller() != null) caller().dumpSpec(out); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java deleted file mode 100644 index 96d96d3348c..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/LoopNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class LoopNode extends RegionNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("LoopNode"); - } - - - public LoopNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java deleted file mode 100644 index 29c411da4d7..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.ci.ciMethod; -import sun.jvm.hotspot.ci.ciObjectFactory; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachCallJavaNode extends MachCallNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachCallJavaNode"); - methodField = type.getAddressField("_method"); - bciField = new CIntField(type.getCIntegerField("_bci"), 0); - } - - private static AddressField methodField; - private static CIntField bciField; - - public ciMethod method() { - return (ciMethod) ciObjectFactory.getMetadata(methodField.getValue(getAddress())); - } - - public MachCallJavaNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream st) { - ciMethod m = method(); - if (m != null) { - m.printShortName(st); - st.print(" "); - } - super.dumpSpec(st); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java deleted file mode 100644 index 040616b4b5c..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallNode.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachCallNode extends MachSafePointNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachCallNode"); - } - - public MachCallNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream st) { - st.print("# "); - // tf()->dump_on(st); - // if (_cnt != COUNT_UNKNOWN) st->print(" C=%f",_cnt); - if (jvms() != null) jvms().dumpSpec(st); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java deleted file mode 100644 index 7fff61bb147..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.CStringUtilities; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachCallRuntimeNode extends MachCallJavaNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachCallRuntimeNode"); - nameField = type.getAddressField("_name"); - } - - private static AddressField nameField; - - public String name() { - return CStringUtilities.getString(nameField.getValue(getAddress())); - } - - public MachCallRuntimeNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream out) { - out.printf("%s ", name()); - super.dumpSpec(out); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java deleted file mode 100644 index 6124a0c353d..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.CStringUtilities; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachCallStaticJavaNode extends MachCallJavaNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachCallStaticJavaNode"); - nameField = type.getAddressField("_name"); - } - - private static AddressField nameField; - - public String name() { - return CStringUtilities.getString(nameField.getValue(getAddress())); - } - - public MachCallStaticJavaNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream st) { - st.print("Static "); - String n = name(); - if (n != null) { - st.printf("wrapper for: %s", n); - // dump_trap_args(st); - st.print(" "); - } - super.dumpSpec(st); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java deleted file mode 100644 index dec4fd73f97..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachIfNode.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachIfNode extends MachNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachIfNode"); - probField = type.getJFloatField("_prob"); - fcntField = type.getJFloatField("_fcnt"); - } - - private static JFloatField probField; - private static JFloatField fcntField; - - float prob() { - return probField.getValue(getAddress()); - } - - float cnt() { - return fcntField.getValue(getAddress()); - } - - public MachIfNode(Address addr) { - super(addr); - } - - public void dumpSpec(PrintStream out) { - out.print("P=" + prob() + ", C=" + cnt()); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java deleted file mode 100644 index f300f52864b..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachNode.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachNode"); - } - - public MachNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java deleted file mode 100644 index db3a8398322..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachReturnNode extends MachNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachReturnNode"); - } - - public MachReturnNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java deleted file mode 100644 index 8e54f0c1df0..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MachSafePointNode extends MachReturnNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MachSafePointNode"); - jvmsField = type.getAddressField("_jvms"); - jvmadjField = new CIntField(type.getCIntegerField("_jvmadj"), 0); - } - - private static AddressField jvmsField; - private static CIntField jvmadjField; - - public MachSafePointNode(Address addr) { - super(addr); - } - - public JVMState jvms() { - return JVMState.create(jvmsField.getValue(getAddress())); - } - - public void dumpSpec(PrintStream out) { - try { - JVMState jvms = jvms(); - if (jvms != null) out.print(" !"); - if (jvms == null) out.print("empty jvms"); - while (jvms != null) { - Method m = jvms.method().method(); - int bci = jvms.bci(); - out.print(" " + m.getMethodHolder().getName().asString().replace('/', '.') + "::" + m.getName().asString() + " @ bci:" + bci); - jvms = jvms.caller(); - } - } catch (Exception e) { - out.print(e); - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java deleted file mode 100644 index f82e574dac6..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/MultiNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class MultiNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("MultiNode"); - } - - - public MultiNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java deleted file mode 100644 index e79abaeb1d1..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2011, 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 - * 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 sun.jvm.hotspot.opto; - -import java.io.*; -import java.lang.reflect.Constructor; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Node extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Node"); - outmaxField = new CIntField(type.getCIntegerField("_outmax"), 0); - outcntField = new CIntField(type.getCIntegerField("_outcnt"), 0); - maxField = new CIntField(type.getCIntegerField("_max"), 0); - cntField = new CIntField(type.getCIntegerField("_cnt"), 0); - idxField = new CIntField(type.getCIntegerField("_idx"), 0); - outField = type.getAddressField("_out"); - inField = type.getAddressField("_in"); - - nodeType = db.lookupType("Node"); - - virtualConstructor = new VirtualBaseConstructor<>(db, nodeType, "sun.jvm.hotspot.opto", Node.class); - } - - private static CIntField outmaxField; - private static CIntField outcntField; - private static CIntField maxField; - private static CIntField cntField; - private static CIntField idxField; - private static AddressField outField; - private static AddressField inField; - - private static VirtualBaseConstructor virtualConstructor; - - private static Type nodeType; - - static HashMap nodes = new HashMap<>(); - - static HashMap constructors = new HashMap(); - - abstract static class Instantiator { - abstract Node create(Address addr); - } - - public static Node create(Address addr) { - if (addr == null) return null; - Node result = nodes.get(addr); - if (result == null) { - result = virtualConstructor.instantiateWrapperFor(addr); - nodes.put(addr, result); - } - return result; - } - - public Node(Address addr) { - super(addr); - } - - public int outcnt() { - return (int)outcntField.getValue(this.getAddress()); - } - - public int req() { - return (int)cntField.getValue(this.getAddress()); - } - - public int len() { - return (int)maxField.getValue(this.getAddress()); - } - - public int idx() { - return (int)idxField.getValue(this.getAddress()); - } - - private Node[] _out; - private Node[] _in; - - public Node rawOut(int i) { - if (_out == null) { - int addressSize = (int)VM.getVM().getAddressSize(); - _out = new Node[outcnt()]; - Address ptr = outField.getValue(this.getAddress()); - for (int j = 0; j < outcnt(); j++) { - _out[j] = Node.create(ptr.getAddressAt(j * addressSize)); - } - } - return _out[i]; - } - - public Node in(int i) { - if (_in == null) { - int addressSize = (int)VM.getVM().getAddressSize(); - _in = new Node[len()]; - Address ptr = inField.getValue(this.getAddress()); - for (int j = 0; j < len(); j++) { - _in[j] = Node.create(ptr.getAddressAt(j * addressSize)); - } - } - return _in[i]; - } - - public ArrayList collect(int d, boolean onlyCtrl) { - int depth = Math.abs(d); - ArrayList nstack = new ArrayList<>(); - BitSet set = new BitSet(); - - nstack.add(this); - set.set(idx()); - int begin = 0; - int end = 0; - for (int i = 0; i < depth; i++) { - end = nstack.size(); - for(int j = begin; j < end; j++) { - Node tp = nstack.get(j); - int limit = d > 0 ? tp.len() : tp.outcnt(); - for(int k = 0; k < limit; k++) { - Node n = d > 0 ? tp.in(k) : tp.rawOut(k); - - // if (not_a_node(n)) continue; - if (n == null) continue; - // do not recurse through top or the root (would reach unrelated stuff) - // if (n.isRoot() || n.isTop()) continue; - // if (onlyCtrl && !n.isCfg()) continue; - - if (!set.get(n.idx())) { - nstack.add(n); - set.set(n.idx()); - } - } - } - begin = end; - } - return nstack; - } - - protected void dumpNodes(Node s, int d, boolean onlyCtrl, PrintStream out) { - if (s == null) return; - - ArrayList nstack = s.collect(d, onlyCtrl); - int end = nstack.size(); - if (d > 0) { - for(int j = end-1; j >= 0; j--) { - ((Node)nstack.get(j)).dump(out); - } - } else { - for(int j = 0; j < end; j++) { - ((Node)nstack.get(j)).dump(out); - } - } - } - - public void dump(int depth, PrintStream out) { - dumpNodes(this, depth, false, out); - } - - public String Name() { - Type t = VM.getVM().getTypeDataBase().findDynamicTypeForAddress(getAddress(), nodeType); - String name = null; - if (t != null) { - name = t.toString(); - } else { - Class c = getClass(); - if (c == Node.class) { - // couldn't identify class type - return "UnknownNode<" + getAddress().getAddressAt(0) + ">"; - } - name = getClass().getName(); - if (name.startsWith("sun.jvm.hotspot.opto.")) { - name = name.substring("sun.jvm.hotspot.opto.".length()); - } - } - if (name.endsWith("Node")) { - return name.substring(0, name.length() - 4); - } - return name; - } - - public void dump(PrintStream out) { - out.print(" "); - out.print(idx()); - out.print("\t"); - out.print(Name()); - out.print("\t=== "); - int i = 0; - for (i = 0; i < req(); i++) { - Node n = in(i); - if (n != null) { - out.print(' '); - out.print(in(i).idx()); - } else { - out.print("_"); - } - out.print(" "); - } - if (len() != req()) { - int prec = 0; - for (; i < len(); i++) { - Node n = in(i); - if (n != null) { - if (prec++ == 0) { - out.print("| "); - } - out.print(in(i).idx()); - } - out.print(" "); - } - } - dumpOut(out); - dumpSpec(out); - out.println(); - } - - void dumpOut(PrintStream out) { - // Delimit the output edges - out.print(" [["); - // Dump the output edges - for (int i = 0; i < outcnt(); i++) { // For all outputs - Node u = rawOut(i); - if (u == null) { - out.print("_ "); - // } else if (not_a_node(u)) { - // out.print("not_a_node "); - } else { - // out.print("%c%d ", Compile::current()->nodeArena()->contains(u) ? ' ' : 'o', u->_idx); - out.print(' '); - out.print(u.idx()); - out.print(' '); - } - } - out.print("]] "); - } - - public void dumpSpec(PrintStream out) { - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java deleted file mode 100644 index 35b51cb5833..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_Array.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Node_Array extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Node_Array"); - maxField = new CIntField(type.getCIntegerField("_max"), 0); - nodesField = type.getAddressField("_nodes"); - aField = type.getAddressField("_a"); - } - - private static CIntField maxField; - private static AddressField nodesField; - private static AddressField aField; - - public Node_Array(Address addr) { - super(addr); - } - - public int Size() { - return (int) maxField.getValue(getAddress()); - } - - public Node at(int i) { - return Node.create(nodesField.getValue(getAddress()).getAddressAt(i * (int)VM.getVM().getAddressSize())); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java deleted file mode 100644 index 50abdb75ad1..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Node_List.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Node_List extends Node_Array { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Node_List"); - cntField = new CIntField(type.getCIntegerField("_cnt"), 0); - } - - private static CIntField cntField; - - public Node_List(Address addr) { - super(addr); - } - - public int size() { - return (int) cntField.getValue(getAddress()); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java deleted file mode 100644 index fe23efff73d..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/Phase.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class Phase extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("Phase"); - } - - - public Phase(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java deleted file mode 100644 index c2561edbe40..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import java.io.PrintStream; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class PhaseCFG extends Phase { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("PhaseCFG"); - numBlocksField = new CIntField(type.getCIntegerField("_number_of_blocks"), 0); - blocksField = type.getAddressField("_blocks"); - bbsField = type.getAddressField("_node_to_block_mapping"); - brootField = type.getAddressField("_root_block"); - } - - private static CIntField numBlocksField; - private static AddressField blocksField; - private static AddressField bbsField; - private static AddressField brootField; - - public PhaseCFG(Address addr) { - super(addr); - } - - public void dump(PrintStream out) { - int addressSize = (int)VM.getVM().getAddressSize(); - int numBlocks = (int)numBlocksField.getValue(getAddress()); - Block_List blocks = new Block_List(getAddress().addOffsetTo(blocksField.getOffset())); - int offset = 0; - for (int i = 0; i < numBlocks; i++) { - blocks.at(i).dump(out); - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java deleted file mode 100644 index 1d0f20b34c3..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class PhaseRegAlloc extends Phase { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("PhaseRegAlloc"); - nodeRegsField = type.getAddressField("_node_regs"); - nodeRegsMaxIndexField = new CIntField(type.getCIntegerField("_node_regs_max_index"), 0); - framesizeField = new CIntField(type.getCIntegerField("_framesize"), 0); - maxRegField = new CIntField(type.getCIntegerField("_max_reg"), 0); - } - - private static AddressField nodeRegsField; - private static CIntField nodeRegsMaxIndexField; - private static CIntField framesizeField; - private static CIntField maxRegField; - - public PhaseRegAlloc(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java deleted file mode 100644 index dce9ba1cac3..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/PhiNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class PhiNode extends TypeNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("PhiNode"); - } - - - public PhiNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java deleted file mode 100644 index cd615b4bbfd..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/ProjNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class ProjNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("ProjNode"); - } - - - public ProjNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java deleted file mode 100644 index 6c678c2a686..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RegionNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class RegionNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("RegionNode"); - } - - - public RegionNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java deleted file mode 100644 index 5a39af1388c..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/RootNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class RootNode extends LoopNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("RootNode"); - } - - - public RootNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java deleted file mode 100644 index daea02a9601..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/SafePointNode.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class SafePointNode extends MultiNode { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("SafePointNode"); - jvmsField = type.getAddressField("_jvms"); - } - - private static AddressField jvmsField; - - public SafePointNode(Address addr) { - super(addr); - } - - public JVMState jvms() { - return JVMState.create(jvmsField.getValue(getAddress())); - } - - public void dumpSpec(PrintStream out) { - JVMState jvms = jvms(); - if (jvms != null) out.print(" !"); - while (jvms != null) { - Method m = jvms.method().method(); - int bci = jvms.bci(); - out.print(" " + m.getMethodHolder().getName().asString().replace('/', '.') + "::" + m.getName().asString() + " @ bci:" + bci); - jvms = jvms.caller(); - } - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java deleted file mode 100644 index 5c0e42cf21f..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/opto/TypeNode.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2011, 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. - * - */ - -package sun.jvm.hotspot.opto; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class TypeNode extends Node { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("TypeNode"); - } - - - public TypeNode(Address addr) { - super(addr); - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java index e5c3ec30887..7e129827c52 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompilerThread.java @@ -28,7 +28,6 @@ import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.ci.*; import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; @@ -43,23 +42,7 @@ public class CompilerThread extends JavaThread { private static AddressField envField; - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("CompilerThread"); - - envField = type.getAddressField("_env"); - } - - private ciEnv _env; - - public synchronized ciEnv env() { - if (_env == null) { - Address v = envField.getValue(this.getAddress()); - if (v != null) { - _env = new ciEnv(v); - } - } - return _env; - } + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { } public CompilerThread(Address addr) { super(addr); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 202217b6071..c558374d23c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.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 @@ -29,7 +29,6 @@ import java.net.*; import java.util.*; import java.util.regex.*; import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.c1.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.interpreter.*; @@ -120,8 +119,6 @@ public class VM { private static int Flags_WAS_SET_ON_COMMAND_LINE; /** This is only present in a non-core build */ private CodeCache codeCache; - /** This is only present in a C1 build */ - private Runtime1 runtime1; /** These constants come from globalDefinitions.hpp */ private int invocationEntryBCI; private ReversePtrs revPtrs; @@ -479,7 +476,7 @@ public class VM { usingServerCompiler = false; } else { // Determine whether C2 is present - if (db.lookupType("Matcher", false) != null) { + if (db.lookupIntConstant("COMPILER2") != null) { usingServerCompiler = true; } else { usingClientCompiler = true; @@ -866,17 +863,6 @@ public class VM { return codeCache; } - /** Should only be called for C1 builds */ - public Runtime1 getRuntime1() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(isClientCompiler(), "C1 builds only"); - } - if (runtime1 == null) { - runtime1 = new Runtime1(); - } - return runtime1; - } - /** Test to see whether we're in debugging mode (NOTE: this really should not be tested by this code; currently only used in StackFrameStream) */ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java index 31b2b969530..a3632058b6f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMReg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -38,9 +38,6 @@ import sun.jvm.hotspot.utilities.Observer; public class VMReg { private int value; - // C2 only - public static Address matcherRegEncodeAddr; - static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -49,13 +46,7 @@ public class VMReg { }); } - private static void initialize(TypeDataBase db) { - if (VM.getVM().isServerCompiler()) { - Type type = db.lookupType("Matcher"); - Field f = type.getField("_regEncode"); - matcherRegEncodeAddr = f.getStaticFieldAddress(); - } - } + private static void initialize(TypeDataBase db) { } public VMReg(int i) { value = i; @@ -65,13 +56,6 @@ public class VMReg { return value; } - public int regEncode() { - if (matcherRegEncodeAddr != null) { - return (int) matcherRegEncodeAddr.getCIntegerAt(value, 1, true); - } - return value; - } - public boolean equals(Object arg) { if ((arg != null) || (!(arg instanceof VMReg))) { return false; diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f9ad5dbd1de..856a5381f90 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,7 +43,6 @@ # :hotspot_compiler -compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all diff --git a/test/hotspot/jtreg/compiler/ciReplay/SABase.java b/test/hotspot/jtreg/compiler/ciReplay/SABase.java deleted file mode 100644 index 66f2eb1106f..00000000000 --- a/test/hotspot/jtreg/compiler/ciReplay/SABase.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2016, 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. - */ - -package compiler.ciReplay; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; -import java.io.OutputStream; -import java.util.Arrays; -import jdk.test.lib.Platform; -import jdk.test.lib.Asserts; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -public class SABase extends CiReplayBase { - private static final String REPLAY_FILE_COPY = "replay_vm.txt"; - - public static void main(String args[]) throws Exception { - checkSetLimits(); - SABase base = new SABase(args); - boolean c2 = base.runServer.orElseThrow(() -> new Error("runServer must be set")); - String[] extra = {}; - if (Platform.isTieredSupported()) { - if (c2) { - // Replay produced on first compilation. We want that - // compilation delayed so profile data is produced. - extra = new String[] {"-XX:-TieredCompilation"}; - } else { - extra = new String[] {"-XX:TieredStopAtLevel=1"}; - } - } - base.runTest(/* needCoreDump = */ true, extra); - } - - public SABase(String[] args) { - super(args); - } - - @Override - public void testAction() { - try { - Files.move(Paths.get(REPLAY_FILE_NAME), Paths.get(REPLAY_FILE_COPY)); - } catch (IOException ioe) { - throw new Error("Can't move files: " + ioe, ioe); - } - ProcessBuilder pb; - try { - pb = ProcessTools.createTestJavaProcessBuilder("--add-modules", "jdk.hotspot.agent", - "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED", - "sun.jvm.hotspot.CLHSDB", JDKToolFinder.getTestJDKTool("java"), - TEST_CORE_FILE_NAME); - } catch (Exception e) { - throw new Error("Can't create process builder: " + e, e); - } - Process p; - try { - p = pb.start(); - } catch (IOException ioe) { - throw new Error("Can't start child process: " + ioe, ioe); - } - OutputStream input = p.getOutputStream(); - String str = "dumpreplaydata -a > " + REPLAY_FILE_NAME + "\nquit\n"; - try { - input.write(str.getBytes()); - input.flush(); - } catch (IOException ioe) { - throw new Error("Problem writing process input: " + str, ioe); - } - try { - p.waitFor(); - } catch (InterruptedException ie) { - throw new Error("Problem waitinig child process: " + ie, ie); - } - int exitValue = p.exitValue(); - if (exitValue != 0) { - String output; - try { - output = new OutputAnalyzer(p).getOutput(); - } catch (IOException ioe) { - throw new Error("Can't get failed CLHSDB process output: " + ioe, ioe); - } - throw new AssertionError("CLHSDB wasn't run successfully: " + output); - } - File replay = new File(REPLAY_FILE_NAME); - Asserts.assertTrue(replay.exists() && replay.isFile() && replay.length() > 0, - "Replay data wasn't generated by SA"); - // other than comment lines, content of 2 files should be identical - try { - BufferedReader rep = new BufferedReader(new FileReader(replay)); - BufferedReader repCopy = new BufferedReader(new FileReader(REPLAY_FILE_COPY)); - boolean failure = false; - while (true) { - String l1; - while ((l1 = rep.readLine()) != null) { - if (!l1.startsWith("#")) { - break; - } - } - String l2; - while ((l2 = repCopy.readLine()) != null) { - if (!l2.startsWith("#")) { - break; - } - } - if (l1 == null || l2 == null) { - if (l1 != null || l2 != null) { - System.out.println("Warning: replay files are not equal"); - System.out.println("1: " + l1); - System.out.println("2: " + l2); - failure = true; - } - break; - } - if (!l1.equals(l2)) { - System.out.println("Warning: replay files are not equal"); - System.out.println("1: " + l1); - System.out.println("2: " + l2); - failure = true; - } - } - if (failure) { - throw new RuntimeException("Warning: replay files are not equal"); - } - } catch (IOException ioe) { - throw new Error("Can't read replay files: " + ioe, ioe); - } - commonTests(); - runVmTests(); - } - - public static void checkSetLimits() { - if (!Platform.isWindows()) { - OutputAnalyzer oa; - try { - // first check if setting limit is possible - oa = ProcessTools.executeProcess("sh", "-c", RUN_SHELL_NO_LIMIT + "ulimit -c"); - } catch (Throwable t) { - throw new Error("Can't set limits: " + t, t); - } - oa.shouldHaveExitValue(0); - - String out = oa.getOutput().trim(); // cut win/*nix newlines - if (!out.equals("unlimited") && !out.equals("-1")) { - throw new Error("Unable to set limits"); - } - } - } -} - diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestSAClient.java b/test/hotspot/jtreg/compiler/ciReplay/TestSAClient.java deleted file mode 100644 index a5a89d13c50..00000000000 --- a/test/hotspot/jtreg/compiler/ciReplay/TestSAClient.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2016, 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 - * 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 8011675 - * @library / /test/lib - * @summary testing of ciReplay with using generated by SA replay.txt - * @requires vm.hasSA & vm.flightRecorder != true & vm.compMode != "Xint" & vm.debug == true & vm.flavor == "client" - * @modules java.base/jdk.internal.misc - * @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 - * compiler.ciReplay.SABase client - */ diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestSAServer.java b/test/hotspot/jtreg/compiler/ciReplay/TestSAServer.java deleted file mode 100644 index 998f63e9ceb..00000000000 --- a/test/hotspot/jtreg/compiler/ciReplay/TestSAServer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2016, 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 - * 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 8011675 - * @library / /test/lib - * @summary testing of ciReplay with using generated by SA replay.txt - * @requires vm.hasSA & vm.flightRecorder != true & vm.compMode != "Xint" & vm.debug == true & vm.flavor == "server" - * @modules java.base/jdk.internal.misc - * @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 - * compiler.ciReplay.SABase server - */ From 30b0c6098028cce63e65bd9d563973f2774fa74d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 3 Mar 2025 12:31:33 +0000 Subject: [PATCH 188/587] 8350956: Fix repetitions of the word "the" in compiler component comments Reviewed-by: rcastanedalo --- src/hotspot/cpu/arm/frame_arm.inline.hpp | 2 +- src/hotspot/share/opto/escape.cpp | 2 +- src/hotspot/share/opto/vectorization.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 801b2f6177c..92a48f22f8c 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -62,7 +62,7 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add if (original_pc != nullptr) { _pc = original_pc; assert(_cb->as_nmethod()->insts_contains_inclusive(_pc), - "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); + "original PC must be in the main code section of the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 0ab911c18be..a90c27861c1 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4472,7 +4472,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, } } else if (n->is_AddP()) { if (has_reducible_merge_base(n->as_AddP(), reducible_merges)) { - // This AddP will go away when we reduce the the Phi + // This AddP will go away when we reduce the Phi continue; } Node* addp_base = get_addp_base(n); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 620eac25c9b..2a2186ab0aa 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -445,7 +445,7 @@ private: // types (byte, char, short). In the C2 IR, their operations are // done with full int type with 4 byte precision (e.g. AddI, MulI). // Example: char a,b,c; a = (char)(b + c); -// However, if we can prove the the upper bits are only truncated, +// However, if we can prove the upper bits are only truncated, // and the lower bits for the narrower type computed correctly, we // can compute the operations in the narrower type directly (e.g we // perform the AddI or MulI with 1 or 2 bytes). This allows us to From f47232ad7129e40bdc433525a66de2ca6657f211 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 3 Mar 2025 13:57:57 +0000 Subject: [PATCH 189/587] 8350954: Fix repetitions of the word "the" in gc component comments Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp | 2 +- src/hotspot/share/gc/z/zLiveMap.inline.hpp | 2 +- src/hotspot/share/gc/z/zRelocate.cpp | 6 +++--- src/hotspot/share/gc/z/zUncoloredRoot.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 2e48e438fc9..ce4738d784e 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -268,7 +268,7 @@ public: size_t sampled_code_root_rs_length() const { return _sampled_code_root_rs_length; } }; -// Adjust the target length (in regions) of the young gen, based on the the +// Adjust the target length (in regions) of the young gen, based on the // current length of the remembered sets. // // At the end of the GC G1 determines the length of the young gen based on diff --git a/src/hotspot/share/gc/z/zLiveMap.inline.hpp b/src/hotspot/share/gc/z/zLiveMap.inline.hpp index 54589e45c45..9a5529dac04 100644 --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp @@ -222,7 +222,7 @@ inline BitMap::idx_t ZLiveMap::find_base_bit_in_segment(BitMap::idx_t start, Bit } // The bitmaps contain pairs of bits to deal with strongly marked vs only - // finalizable marked. Align down to get the the first bit position. + // finalizable marked. Align down to get the first bit position. return bit & ~BitMap::idx_t(1); } diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 805044f9deb..213452e8d05 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -669,9 +669,9 @@ private: // moved them over to the current bitmap. // // If the young generation runs multiple cycles while the old generation is - // relocating, then the first cycle will have consume the the old remset, + // relocating, then the first cycle will have consumed the old remset, // bits and moved associated objects to a new old page. The old relocation - // could find either the the two bitmaps. So, either it will find the original + // could find either of the two bitmaps. So, either it will find the original // remset bits for the page, or it will find an empty bitmap for the page. It // doesn't matter for correctness, because the young generation marking has // already taken care of the bits. @@ -865,7 +865,7 @@ private: start_in_place_relocation_prepare_remset(from_page); if (promotion) { - // Register the the promotion + // Register the promotion ZGeneration::young()->in_place_relocate_promote(from_page, to_page); ZGeneration::young()->register_in_place_relocate_promoted(from_page); } diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.hpp index e980bd70eb2..c007176e5c2 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.hpp @@ -51,7 +51,7 @@ // The zaddress_unsafe type is used to hold uncolored oops that the GC needs // to process before it is safe to use. E.g. the original object might have // been relocated and the address needs to be updated. The zaddress type -// denotes that this pointer refers the the correct address of the object. +// denotes that this pointer refers to the correct address of the object. class ZUncoloredRoot : public AllStatic { private: From db69ec9e583791d359c5c0acb504c7f01e963e3b Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 3 Mar 2025 14:39:19 +0000 Subject: [PATCH 190/587] 8344009: Improve compiler memory statistics Reviewed-by: rcastanedalo, asmehra --- src/hotspot/share/c1/c1_Compilation.cpp | 2 + src/hotspot/share/ci/ciEnv.cpp | 4 +- src/hotspot/share/ci/ciObjectFactory.cpp | 2 +- .../compiler/compilationMemStatInternals.hpp | 287 ++++ .../compilationMemStatInternals.inline.hpp | 95 ++ .../compiler/compilationMemoryStatistic.cpp | 1199 ++++++++++++----- .../compiler/compilationMemoryStatistic.hpp | 121 +- src/hotspot/share/compiler/compilerOracle.cpp | 6 - src/hotspot/share/compiler/compilerOracle.hpp | 1 - src/hotspot/share/compiler/compilerThread.cpp | 6 +- src/hotspot/share/compiler/compilerThread.hpp | 3 +- src/hotspot/share/memory/arena.cpp | 47 +- src/hotspot/share/memory/arena.hpp | 30 +- src/hotspot/share/memory/resourceArea.hpp | 8 +- src/hotspot/share/opto/chaitin.cpp | 4 +- src/hotspot/share/opto/compile.cpp | 32 +- src/hotspot/share/opto/compile.hpp | 4 +- src/hotspot/share/opto/gcm.cpp | 2 +- src/hotspot/share/opto/matcher.cpp | 2 +- src/hotspot/share/opto/phase.hpp | 9 +- src/hotspot/share/opto/runtime.cpp | 2 + src/hotspot/share/opto/superword.cpp | 2 +- src/hotspot/share/opto/type.cpp | 2 +- src/hotspot/share/opto/vectorization.hpp | 4 +- src/hotspot/share/opto/vtransform.hpp | 2 +- src/hotspot/share/runtime/globals.hpp | 3 + src/hotspot/share/runtime/java.cpp | 4 +- .../share/services/diagnosticCommand.cpp | 11 +- .../share/services/diagnosticCommand.hpp | 7 +- src/hotspot/share/utilities/vmError.cpp | 14 +- .../print/CompileCommandMemLimit.java | 111 +- .../print/CompileCommandPrintMemStat.java | 97 +- 32 files changed, 1511 insertions(+), 612 deletions(-) create mode 100644 src/hotspot/share/compiler/compilationMemStatInternals.hpp create mode 100644 src/hotspot/share/compiler/compilationMemStatInternals.inline.hpp diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index 9b80c8a20a8..98ec1959cc2 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -410,6 +410,8 @@ int Compilation::compile_java_method() { env()->dump_replay_data(env()->compile_id()); } + DEBUG_ONLY(CompilationMemoryStatistic::do_test_allocations();) + { PhaseTraceTime timeit(_t_codeemit); return emit_code_body(); diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index e87c5ba08e9..2a88154faf6 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -106,7 +106,7 @@ static bool firstEnv = true; // ------------------------------------------------------------------ // ciEnv::ciEnv ciEnv::ciEnv(CompileTask* task) - : _ciEnv_arena(mtCompiler) { + : _ciEnv_arena(mtCompiler, Arena::Tag::tag_cienv) { VM_ENTRY_MARK; // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc. @@ -238,7 +238,7 @@ public: } }; -ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler) { +ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler, Arena::Tag::tag_cienv) { ASSERT_IN_VM; // Set up ciEnv::current immediately, for the sake of ciObjectFactory, etc. diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 35ec27b8aaa..1fa590e4ad3 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -108,7 +108,7 @@ void ciObjectFactory::initialize() { // This Arena is long lived and exists in the resource mark of the // compiler thread that initializes the initial ciObjectFactory which // creates the shared ciObjects that all later ciObjectFactories use. - Arena* arena = new (mtCompiler) Arena(mtCompiler); + Arena* arena = new (mtCompiler) Arena(mtCompiler, Arena::Tag::tag_cienv); ciEnv initial(arena); ciEnv* env = ciEnv::current(); env->_factory->init_shared_objects(); diff --git a/src/hotspot/share/compiler/compilationMemStatInternals.hpp b/src/hotspot/share/compiler/compilationMemStatInternals.hpp new file mode 100644 index 00000000000..a6050823771 --- /dev/null +++ b/src/hotspot/share/compiler/compilationMemStatInternals.hpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2024, 2025, Red Hat, Inc. and/or its affiliates. + * 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_COMPILER_COMPILATIONMEMSTATINTERNALS_HPP +#define SHARE_COMPILER_COMPILATIONMEMSTATINTERNALS_HPP + +#include "compiler/compilationMemoryStatistic.hpp" +#include "compiler/compilerDefinitions.hpp" +#include "memory/allocation.hpp" +#include "memory/arena.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef COMPILER2 +#include "opto/phase.hpp" +#endif + +class CompileTask; +class Method; +class Symbol; +class outputStream; + +#ifdef COMPILER2 +constexpr int phase_trc_id_max = (int)Phase::PhaseTraceId::max_phase_timers; +constexpr int phase_trc_id_none = (int)Phase::PhaseTraceId::_t_none; +#else +// In minimal builds, the ArenaCounterTable is just a single-dimension vector of arena tags (see below) +constexpr int phase_trc_id_max = 1; +constexpr int phase_trc_id_none = 0; +#endif +inline void check_phase_trace_id(int v) { assert(v >= 0 && v < phase_trc_id_max, "OOB (%d)", v); } + +constexpr int arena_tag_max = (int)Arena::Tag::tag_count; +inline void check_arena_tag(int v) { assert(v >= 0 && v < arena_tag_max, "OOB (%d)", v); } + +// A two-dimensional table, containing byte counters per arena type and +// per compilation phase. +class ArenaCounterTable { + size_t _v[phase_trc_id_max][arena_tag_max]; +public: + ArenaCounterTable(); + void copy_from(const ArenaCounterTable& other); + inline size_t at(int phase_trc_id, int arena_tag) const; + inline void add(size_t size, int phase_trc_id, int arena_tag); + inline void sub(size_t size, int phase_trc_id, int arena_tag); + void print_on(outputStream* ss) const; + void summarize(size_t out[arena_tag_max]) const; +}; + +struct PhaseInfo { + int id, num; + const char* text; +}; + +// A stack keeping track of the current compilation phase. Fixed-width for simplicity +// (we should never go beyond 5 or so in depth). +class PhaseInfoStack { + static constexpr int max_depth = 16; + int _depth; + PhaseInfo _stack[max_depth]; +public: + inline PhaseInfoStack(); + inline bool empty() const { return _depth == 0; } + inline void push(PhaseInfo info); + inline void pop(); + inline const PhaseInfo& top() const; + inline int depth() const { return _depth; } +}; + +// A very simple fixed-width FIFO buffer, used for the phase timeline +template +class SimpleFifo { + STATIC_ASSERT((size * 2) < INT_MAX); + T _v[size]; + int _pos; + int _oldest; + uint64_t _lost; + + int current_pos() const { return _pos; } + static int pos_to_index(int pos) { return pos % size; } + T& at(int pos) { return *(_v + pos_to_index(pos)); } + +public: + SimpleFifo() : _pos(0), _oldest(0), _lost(0UL) {} + T& current() { return at(current_pos()); } + T& last() { assert(!empty(), "sanity"); return at(current_pos() - 1); } + bool empty() const { return _pos == _oldest; } + uint64_t lost() const { return _lost; } + + void advance() { + _pos ++; + if (_pos >= size) { + _oldest ++; + _lost ++; + } + if (_pos == INT_MAX) { + _pos -= size; + _oldest -= size; + } + } + + void revert() { + assert(!empty(), "sanity"); + _pos--; + } + + template + void iterate_all(F f) const { + for (int i = _oldest; i < _pos; i++) { + const int index = pos_to_index(i); + f(_v[index]); + } + } + + void copy_from(const SimpleFifo& other) { + memcpy(_v, other._v, sizeof(_v)); + _pos = other._pos; + _lost = other._lost; + _oldest = other._oldest; + } +}; + +// Holds a table of n entries; each entry keeping start->end footprints when +// a phase started and ended; each entry also keeping the phase-local peak (if +// a phase caused a temporary spike in footprint that vanished before the phase +// ended). +// Handling nested phases: for this structure, there is always a phase active; +// if a phase ends, we "restart" the parent phase (which often is the +// "outside any phase" phase). +class FootprintTimeline { +public: + static constexpr unsigned max_num_phases = 256; // beyond that we wrap, keeping just the last n phases +private: + template + struct C { + T start, peak, cur; + void init(T v) { start = cur = peak = v; } + void update(T v) { cur = v; if (v > peak) peak = v; } + dT end_delta() const { return (dT)cur - (dT)start; } + // Returns the peak size during this phase: how high usage rose above either + // start or end of phase. The background is that we want to know the max. memory + // consumption during this phase, but that may not be reflected by the start or the + // end counters if an Arena was created during the phase and only lived temporarily. + size_t temporary_peak_size() const { return MIN2(peak - cur, peak - start); } + }; + struct Entry { + PhaseInfo info; + int level; + C _bytes; + C _live_nodes; + }; + SimpleFifo _fifo; + DEBUG_ONLY(bool _inbetween_phases;) +public: + FootprintTimeline(); + void copy_from(const FootprintTimeline& other); + inline void on_footprint_change(size_t cur_abs, unsigned cur_nodes); + void on_phase_end(size_t cur_abs, unsigned cur_nodes); + void on_phase_start(PhaseInfo info, size_t cur_abs, unsigned cur_nodes, int level); + void print_on(outputStream* st) const; +}; + +// We keep the name of the involved symbols in Symbol (made permanent) instead of resolving them to string and +// storing those. That significantly reduces footprint for the result store and delays resolving until printing +// time, which may be never. +class FullMethodName { + Symbol* _k; + Symbol* _m; + Symbol* _s; +public: + FullMethodName(); + FullMethodName(const Method* m); + FullMethodName(const FullMethodName& o); + FullMethodName& operator=(const FullMethodName& o); + void make_permanent(); + void print_on(outputStream* st) const; + char* as_C_string(char* buf, size_t len) const; + bool operator== (const FullMethodName& b) const; + DEBUG_ONLY(bool is_test_class() const;) +}; + +// ArenaState is the central data structure holding all statistics and temp data during +// a single compilation. It is created on demand (if memstat is active) and tied to the +// CompilerThread. +class ArenaStatCounter : public CHeapObj { + + FullMethodName _fmn; + + // from directives + const bool _should_print_memstat; + const bool _should_crash_on_memlimit; + + // Bytes total now + size_t _current; + // Bytes total at last global peak + size_t _peak; + // Bytes per arena/phase, now + ArenaCounterTable _counters_current; + // Bytes per arena/phase when we last reached the global peak + ArenaCounterTable _counters_at_global_peak; + + // Number of live nodes now (C2 only) + unsigned _live_nodes_current; + // Number of live nodes at global peak (C2 only) + unsigned _live_nodes_at_global_peak; + + // MemLimit handling + const size_t _limit; + bool _hit_limit; + bool _limit_in_process; + + // Keep track of current C2 phase + int _phase_counter; + PhaseInfoStack _phase_info_stack; + + // Keep track of C2 phase allocations over time + FootprintTimeline _timeline; + + const CompilerType _comp_type; + const int _comp_id; + + DEBUG_ONLY(bool _is_test_class;) + + int retrieve_live_node_count() const; + +public: + ArenaStatCounter(const CompileTask* task, size_t limit); + + void on_phase_start(PhaseInfo info); + void on_phase_end(); + + // Account an arena allocation. Returns true if new peak reached. + bool on_arena_chunk_allocation(size_t size, int arena_tag, uint64_t* stamp); + + // Account an arena deallocation. + void on_arena_chunk_deallocation(size_t size, uint64_t stamp); + + void print_peak_state_on(outputStream* st) const; + void print_error_state_on(outputStream* st) const; + + size_t limit() const { return _limit; } + bool hit_limit() const { return _hit_limit; } + bool limit_in_process() const { return _limit_in_process; } + void set_limit_in_process(bool v) { _limit_in_process = v; } + + const FullMethodName& fmn() const { return _fmn; } + bool should_print_memstat() { return _should_print_memstat; }; + bool should_crash_on_memlimit() const { return _should_crash_on_memlimit; }; + + CompilerType comp_type() const { return _comp_type; } + int comp_id() const { return _comp_id; } + DEBUG_ONLY(bool is_test_class() const { return _is_test_class; }) + + // Bytes total at last global peak + size_t peak() const { return _peak; } + + // Bytes per arena/phase when we last reached the global peak + const ArenaCounterTable& counters_at_global_peak() const { return _counters_at_global_peak; } + const FootprintTimeline& timeline() const { return _timeline; } + // Number of live nodes at global peak (C2 only) + unsigned live_nodes_at_global_peak() const { return _live_nodes_at_global_peak; } + + int advance_phase_counter() { return ++_phase_counter; } +}; + +#endif // SHARE_COMPILER_COMPILATIONMEMSTATINTERNALS_HPP diff --git a/src/hotspot/share/compiler/compilationMemStatInternals.inline.hpp b/src/hotspot/share/compiler/compilationMemStatInternals.inline.hpp new file mode 100644 index 00000000000..94be8606ac9 --- /dev/null +++ b/src/hotspot/share/compiler/compilationMemStatInternals.inline.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Red Hat, Inc. and/or its affiliates. + * 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_COMPILATIONMEMSTATINTERNALS_INLINE_HPP +#define SHARE_COMPILATIONMEMSTATINTERNALS_INLINE_HPP + +#include "compiler/compilationMemStatInternals.hpp" + +inline PhaseInfoStack::PhaseInfoStack() : _depth(0) {} + +inline void PhaseInfoStack::push(PhaseInfo info) { +#ifdef ASSERT + check_phase_trace_id(info.id); + if (_depth == 0) { + assert(info.id == phase_trc_id_none, "first entry must be none"); + } else { + assert(info.id != phase_trc_id_none, "subsequent entries must not be none"); + } + assert(_depth < max_depth, "Sanity"); +#endif // ASSERT + _stack[_depth] = info; + if (_depth < max_depth) { + _depth++; + } +} + +inline void PhaseInfoStack::pop() { +#ifdef ASSERT + assert(!empty(), "Sanity "); + const PhaseInfo to_be_popped = top(); + if (_depth == 1) { + assert(to_be_popped.id == phase_trc_id_none, "first entry must be none"); + } else { + assert(to_be_popped.id != phase_trc_id_none, "subsequent entries must not be none"); + } +#endif // ASSERT + if (_depth > 0) { + _depth--; + } +} + +inline const PhaseInfo& PhaseInfoStack::top() const { + assert(!empty(), "Sanity"); + return _stack[_depth - 1]; +} + +inline size_t ArenaCounterTable::at(int phase_trc_id, int arena_tag) const { + check_phase_trace_id(phase_trc_id); + check_arena_tag(arena_tag); + return _v[phase_trc_id][arena_tag]; +} + +inline void ArenaCounterTable::add(size_t size, int phase_trc_id, int arena_tag) { + check_arena_tag(arena_tag); + const size_t old = at(phase_trc_id, arena_tag); + _v[phase_trc_id][arena_tag] += size; + assert(at(phase_trc_id, arena_tag) >= old, "Overflow"); +} + +inline void ArenaCounterTable::sub(size_t size, int phase_trc_id, int arena_tag) { + check_arena_tag(arena_tag); + assert(at(phase_trc_id, arena_tag) >= size, "Underflow (%zu %zu)", at(phase_trc_id, arena_tag), size); + _v[phase_trc_id][arena_tag] -= size; +} + +inline void FootprintTimeline::on_footprint_change(size_t cur_abs, unsigned cur_nodes) { + assert(!_inbetween_phases, "no phase started?"); + Entry& e = _fifo.current(); + e._bytes.update(cur_abs); + e._live_nodes.update(cur_nodes); +} + +#endif // SHARE_COMPILATIONMEMSTATINTERNALS_INLINE_HPP diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 89d0b60212e..41991567c9a 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2025, Red Hat, Inc. and/or its affiliates. * 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,413 +23,778 @@ * */ +#include "code/nmethod.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compilationMemStatInternals.inline.hpp" +#include "compiler/compilerDefinitions.inline.hpp" +#include "compiler/compilerDirectives.hpp" +#include "compiler/compilerOracle.hpp" +#include "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" -#ifdef COMPILER1 -#include "c1/c1_Compilation.hpp" -#endif -#include "compiler/abstractCompiler.hpp" -#include "compiler/compilationMemoryStatistic.hpp" -#include "compiler/compilerDirectives.hpp" -#include "compiler/compileTask.hpp" -#include "compiler/compilerDefinitions.hpp" -#include "compiler/compilerThread.hpp" #include "memory/arena.hpp" -#include "memory/resourceArea.hpp" #include "nmt/nmtCommon.hpp" +#include "oops/method.inline.hpp" #include "oops/symbol.hpp" -#ifdef COMPILER2 -#include "opto/node.hpp" // compile.hpp is not self-contained -#include "opto/compile.hpp" -#endif +#include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" -#include "utilities/quickSort.hpp" -#include "utilities/resourceHash.hpp" -ArenaStatCounter::ArenaStatCounter() { - reset(); -} +#ifdef COMPILER1 +#include "c1/c1_Compilation.hpp" +#endif -void ArenaStatCounter::reset() { - _current = 0; - _peak = 0; - _current_by_tag.clear(); - _peak_by_tag.clear(); - _limit = 0; - _hit_limit = false; - _limit_in_process = false; - _live_nodes_at_peak = 0; - _active = false; -} - -void ArenaStatCounter::start(size_t limit) { - reset(); - _active = true; - _limit = limit; -} - -void ArenaStatCounter::end() { - _limit = 0; - _hit_limit = false; - _active = false; -} - -void ArenaStatCounter::update_c2_node_count() { - assert(_active, "compilaton has not yet started"); #ifdef COMPILER2 - CompilerThread* const th = Thread::current()->as_Compiler_thread(); - const CompileTask* const task = th->task(); - if (task != nullptr && - th->task()->compiler() != nullptr && - th->task()->compiler()->type() == compiler_c2) { - const Compile* const comp = Compile::current(); - if (comp != nullptr) { - _live_nodes_at_peak = comp->live_nodes(); +#include "opto/compile.hpp" +#include "opto/node.hpp" // compile.hpp is not self-contained +#endif + +static const char* phase_trc_id_to_string(int phase_trc_id) { + return COMPILER2_PRESENT(Phase::get_phase_trace_id_text((Phase::PhaseTraceId)phase_trc_id)) + NOT_COMPILER2(""); +} + +// If crash option on memlimit is enabled and an oom occurred, the stats for the +// first offending compilation. +static ArenaStatCounter* volatile _arenastat_oom_crash = nullptr; + +// Arena-chunk stamping +union chunkstamp_t { + uint64_t raw; + struct { + uint32_t tracked; + uint16_t arena_tag; + uint16_t phase_id; + }; +}; +STATIC_ASSERT(sizeof(chunkstamp_t) == sizeof(chunkstamp_t::raw)); + +ArenaCounterTable::ArenaCounterTable() { + memset(_v, 0, sizeof(_v)); +} + +void ArenaCounterTable::copy_from(const ArenaCounterTable& other) { + memcpy(_v, other._v, sizeof(_v)); +} + +void ArenaCounterTable::summarize(size_t out[arena_tag_max]) const { + memset(out, 0, arena_tag_max * sizeof(size_t)); + for (int i = 0; i < phase_trc_id_max; i++) { + for (int j = 0; j < arena_tag_max; j++) { + out[j] += _v[i][j]; } } -#endif } -// Account an arena allocation or de-allocation. -bool ArenaStatCounter::account(ssize_t delta, int tag) { - assert(_active, "compilaton has not yet started"); - bool rc = false; +void ArenaCounterTable::print_on(outputStream* st) const { + bool header_printed = false; + for (int phase_trc_id = 0; phase_trc_id < phase_trc_id_max; phase_trc_id++) { + size_t sum = 0; + for (int arena_tag = 0; arena_tag < arena_tag_max; arena_tag++) { + sum += at(phase_trc_id, arena_tag); + } + if (sum > 0) { // omit phases that did not contribute to allocation load + if (!header_printed) { + st->print("%-24s %10s", "Phase", "Total"); + for (int arena_tag = 0; arena_tag < arena_tag_max; arena_tag++) { + st->print("%10s", Arena::tag_name[arena_tag]); + } + st->cr(); + header_printed = true; + } + st->print("%-24s ", phase_trc_id_to_string(phase_trc_id)); + st->print("%10zu", sum); + for (int arena_tag = 0; arena_tag < arena_tag_max; arena_tag++) { + const size_t v = at(phase_trc_id, arena_tag); + st->print("%10zu", v); + } + st->cr(); + } + } +} + +// When reporting phase footprint movements, if phase-local peak over start as well over end +// was larger than this threshold, we report it. +static constexpr size_t significant_peak_threshold = M; + +FootprintTimeline::FootprintTimeline() { + DEBUG_ONLY(_inbetween_phases = true;) +} + +void FootprintTimeline::copy_from(const FootprintTimeline& other) { + _fifo.copy_from(other._fifo); + DEBUG_ONLY(_inbetween_phases = other._inbetween_phases;) +} + +void FootprintTimeline::print_on(outputStream* st) const { + const int start_indent = st->indentation(); + if (!_fifo.empty()) { + // .123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789 + st->print_cr("Phase seq. number Bytes Nodes"); + unsigned from = 0; + if (_fifo.lost() > 0) { + st->print_cr(" (" UINT64_FORMAT " older entries lost)", _fifo.lost()); + } + int last_level = 0; + int last_num = 0; // see if we are regressing + auto printer = [&](const Entry& e) { + int col = start_indent; + check_phase_trace_id(e.info.id); + st->print("%*s", e.level, + ((e.level < last_level) ? "<" : ((e.level > last_level) ? ">" : " ")) + ); + last_level = e.level; + st->print("%d ", e.info.num); + if (e.info.num < last_num) { + st->print("(cont.) "); + } + last_num = e.info.num; + col += 15; st->fill_to(col); + 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()); + 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()); + st->print("%s ", tmp); // end + if (e._bytes.temporary_peak_size() > significant_peak_threshold) { + col += 20; st->fill_to(col); + st->print(" significant temporary peak: %zu (%+zd)", e._bytes.peak, (ssize_t)e._bytes.peak - e._bytes.start); // peak + } + st->cr(); + }; + _fifo.iterate_all(printer); + } +} + +void FootprintTimeline::on_phase_end(size_t cur_abs, unsigned cur_nodes) { + const Entry& old = _fifo.current(); + + // One last counter update in old phase: + // We see all allocations, so cur_abs given should correspond to our topmost cur. + // But the same does not hold for nodes, since we only get updated when node allocation + // would cause a new arena chunk to be born. Node allocations that don't cause arena + // chunks (the vast majority) fly by us. + assert(old._bytes.cur == cur_abs, "miscount"); + on_footprint_change(cur_abs, cur_nodes); + + // Close old, open new entry + _fifo.advance(); + + DEBUG_ONLY(_inbetween_phases = true;) +} + +void FootprintTimeline::on_phase_start(PhaseInfo info, size_t cur_abs, unsigned cur_nodes, int level) { + if (!_fifo.empty() && _fifo.last().info.id == info.id && _fifo.last().level == level) { + // Two phases with the same id are collapsed if they were not interleaved by another phase + _fifo.revert(); + // We now just continue bookkeeping into the last entry + } else { + // seed current entry + Entry& e = _fifo.current(); + e._bytes.init(cur_abs); + e._live_nodes.init(cur_nodes); + e.info = info; + e.level = level; + } + DEBUG_ONLY(_inbetween_phases = false;) +} + +FullMethodName::FullMethodName() : _k(nullptr), _m(nullptr), _s(nullptr) {} + +FullMethodName::FullMethodName(const Method* m) : + _k(m->klass_name()), _m(m->name()), _s(m->signature()) {}; + +FullMethodName::FullMethodName(const FullMethodName& o) : _k(o._k), _m(o._m), _s(o._s) {} + +FullMethodName& FullMethodName::operator=(const FullMethodName& o) { + _k = o._k; _m = o._m; _s = o._s; + return *this; +} + +void FullMethodName::make_permanent() { + _k->make_permanent(); + _m->make_permanent(); + _s->make_permanent(); +} + +void FullMethodName::print_on(outputStream* st) const { + char tmp[1024]; + st->print_raw(_k->as_C_string(tmp, sizeof(tmp))); + st->print_raw("::"); + st->print_raw(_m->as_C_string(tmp, sizeof(tmp))); + st->put('('); + st->print_raw(_s->as_C_string(tmp, sizeof(tmp))); + st->put(')'); +} + +char* FullMethodName::as_C_string(char* buf, size_t len) const { + stringStream ss(buf, len); + print_on(&ss); + return buf; +} + +bool FullMethodName::operator== (const FullMethodName& b) const { + return _k == b._k && _m == b._m && _s == b._s; +} + #ifdef ASSERT - // Note: if this fires, we free more arena memory under the scope of the - // CompilationMemoryHistoryMark than we allocate. This cannot be since we - // assume arena allocations in CompilerThread to be stack bound and symmetric. - assert(delta >= 0 || ((ssize_t)_current + delta) >= 0, - "Negative overflow (d=%zd %zu %zu)", delta, _current, _peak); -#endif - // Update totals - _current += delta; - _current_by_tag.add(tag, delta); - // Did we reach a peak? +bool FullMethodName::is_test_class() const { + char tmp[1024]; + _k->as_C_string(tmp, sizeof(tmp)); + return strstr(tmp, "CompileCommandPrintMemStat") != nullptr || + strstr(tmp, "CompileCommandMemLimit") != nullptr; +} +#endif // ASSERT + +ArenaStatCounter::ArenaStatCounter(const CompileTask* task, size_t limit) : + _fmn(task->method()), + _should_print_memstat(task->directive()->should_print_memstat()), + _should_crash_on_memlimit(task->directive()->should_crash_at_mem_limit()), + _current(0), _peak(0), _live_nodes_current(0), _live_nodes_at_global_peak(0), + _limit(limit), _hit_limit(false), _limit_in_process(false), + _phase_counter(0), _comp_type(task->compiler()->type()), _comp_id(task->compile_id()) + DEBUG_ONLY(COMMA _is_test_class(false)) +{ + _fmn.make_permanent(); +#ifdef ASSERT + // If the class name matches the JTreg test class, we are in test mode and + // will do some test allocations to test the statistic + _is_test_class = _fmn.is_test_class(); +#endif // ASSERT +} + +void ArenaStatCounter::on_phase_start(PhaseInfo info) { + // Update node counter + _live_nodes_current = retrieve_live_node_count(); + + // For the timeline, when nesting TracePhase happens, we maintain the illusion of a flat succession of + // separate phases. Thus, { TracePhase p1; { TracePhase p2; }} will be seen as: + // P1 starts -> P1 ends -> P2 starts -> P2 ends -> P1 starts -> P1 ends + // In other words, when a child phase interrupts a parent phase, it "ends" the parent phase, which will + // be "restarted" when the child phase ends. + // This is the only way to get a per-phase timeline that makes any sort of sense. + if (!_phase_info_stack.empty()) { + _timeline.on_phase_end(_current, _live_nodes_current); + } + _phase_info_stack.push(info); + _timeline.on_phase_start(info, _current, _live_nodes_current, _phase_info_stack.depth()); +} + +void ArenaStatCounter::on_phase_end() { + PhaseInfo top = _phase_info_stack.top(); + _phase_info_stack.pop(); + _live_nodes_current = retrieve_live_node_count(); + _timeline.on_phase_end(_current, _live_nodes_current); + if (!_phase_info_stack.empty()) { + // "restart" parent phase in timeline + _timeline.on_phase_start(_phase_info_stack.top(), _current, _live_nodes_current, _phase_info_stack.depth()); + } +} + +int ArenaStatCounter::retrieve_live_node_count() const { + int result = 0; +#ifdef COMPILER2 + if (_comp_type == compiler_c2) { + // Update C2 node count + // Careful, Compile::current() may be null in a short time window when Compile itself + // is still being constructed. + if (Compile::current() != nullptr) { + result = Compile::current()->live_nodes(); + } + } +#endif // COMPILER2 + return result; +} + +// Account an arena allocation. Returns true if new peak reached. +bool ArenaStatCounter::on_arena_chunk_allocation(size_t size, int arena_tag, uint64_t* stamp) { + bool rc = false; + + const size_t old_current = _current; + _current += size; + assert(_current >= old_current, "Overflow"); + + const int phase_trc_id = _phase_info_stack.top().id; + _counters_current.add(size, phase_trc_id, arena_tag); + _live_nodes_current = retrieve_live_node_count(); + + _timeline.on_footprint_change(_current, _live_nodes_current); + + // Did we reach a global peak? if (_current > _peak) { _peak = _current; - assert(delta > 0, "Sanity (%zu %zu)", _current, _peak); - update_c2_node_count(); - _peak_by_tag = _current_by_tag; - rc = true; + // snapshot all current counters + _counters_at_global_peak.copy_from(_counters_current); + // snapshot live nodes + _live_nodes_at_global_peak = _live_nodes_current; // Did we hit the memory limit? if (!_hit_limit && _limit > 0 && _peak > _limit) { _hit_limit = true; } + // report peak back + rc = true; } + + // calculate arena chunk stamp + chunkstamp_t cs; + cs.tracked = 1; + cs.arena_tag = checked_cast(arena_tag); + cs.phase_id = checked_cast(_phase_info_stack.top().id); + *stamp = cs.raw; + return rc; } -void ArenaStatCounter::print_on(outputStream* st) const { - st->print("%zu [", _peak); - for (int tag = 0; tag < _peak_by_tag.element_count(); tag++) { - if (_peak_by_tag.counter(tag) > 0) { - st->print("%s %zu ", _peak_by_tag.tag_name(tag), _peak_by_tag.counter(tag)); - } - } - st->print("]"); -#ifdef ASSERT - st->print(" (%zu->%zu)", _peak, _current); -#endif +void ArenaStatCounter::on_arena_chunk_deallocation(size_t size, uint64_t stamp) { + assert(_current >= size, "Underflow (%zu %zu)", size, _current); + + // Extract tag and phase id from stamp + chunkstamp_t cs; + cs.raw = stamp; + assert(cs.tracked == 1, "Sanity"); + const int arena_tag = cs.arena_tag; + assert(arena_tag >= 0 && arena_tag < arena_tag_max, "Arena Tag OOB (%d)", arena_tag_max); + const int phase_trc_id(cs.phase_id); + assert(phase_trc_id >= 0 && phase_trc_id < phase_trc_id_max, "Phase trace id OOB (%d)", phase_trc_id); + + _current -= size; + _counters_current.sub(size, phase_trc_id, arena_tag); + _live_nodes_current = retrieve_live_node_count(); + _timeline.on_footprint_change(_current, _live_nodes_current); } -////////////////////////// -// Backend - -class FullMethodName { - Symbol* const _k; - Symbol* const _m; - Symbol* const _s; - -public: - - FullMethodName(const Method* m) : - _k(m->klass_name()), _m(m->name()), _s(m->signature()) {}; - FullMethodName(const FullMethodName& o) : _k(o._k), _m(o._m), _s(o._s) {} - - void make_permanent() { - _k->make_permanent(); - _m->make_permanent(); - _s->make_permanent(); +// Used for logging, not for the report table generated with jcmd Compiler.memory +void ArenaStatCounter::print_peak_state_on(outputStream* st) const { + st->print("Total Usage: %zu ", _peak); + if (_peak > 0) { +#ifdef COMPILER2 + // C1: print allocations broken down by arena types + if (_comp_type == CompilerType::compiler_c1) { + st->print("["); + size_t sums[arena_tag_max]; + _counters_at_global_peak.summarize(sums); + bool print_comma = false; + for (int i = 0; i < arena_tag_max; i++) { + if (sums[i] > 0) { + if (print_comma) { + st->print_raw(", "); + } + st->print("%s %zu", Arena::tag_name[i], sums[i]); + print_comma = true; + } + } + st->print_cr("]"); + } +#endif // COMPILER1 +#ifdef COMPILER2 + // C2: print counters and timeline on multiple lines, indented + if (_comp_type == CompilerType::compiler_c2) { + streamIndentor si(st, 4); + st->cr(); + st->print_cr("--- Arena Usage by Arena Type and compilation phase, at arena usage peak of %zu ---", _peak); + { + streamIndentor si(st, 4); + _counters_at_global_peak.print_on(st); + } + st->print_cr("--- Allocation timelime by phase ---"); + { + streamIndentor si(st, 4); + _timeline.print_on(st); + } + st->print_cr("---"); + } +#endif + } else { + st->cr(); } +} - static unsigned compute_hash(const FullMethodName& n) { - return Symbol::compute_hash(n._k) ^ - Symbol::compute_hash(n._m) ^ - Symbol::compute_hash(n._s); - } +class MemStatEntry : public CHeapObj { - char* as_C_string(char* buf, size_t len) const { - stringStream ss(buf, len); - ResourceMark rm; - ss.print_raw(_k->as_C_string()); - ss.print_raw("::"); - ss.print_raw(_m->as_C_string()); - ss.put('('); - ss.print_raw(_s->as_C_string()); - ss.put(')'); - return buf; - } - bool operator== (const FullMethodName& b) const { - return _k == b._k && _m == b._m && _s == b._s; - } -}; - -// Note: not mtCompiler since we don't want to change what we measure -class MemStatEntry : public CHeapObj { - const FullMethodName _method; - CompilerType _comptype; + FullMethodName _fmn; + CompilerType _comp_type; + int _comp_id; double _time; - // How often this has been recompiled. - int _num_recomp; // Compiling thread. Only for diagnostic purposes. Thread may not be alive anymore. const Thread* _thread; // active limit for this compilation, if any size_t _limit; - - // peak usage, bytes, over all arenas - size_t _total; - // usage per arena tag when total peaked - ArenaCountersByTag _peak_by_tag; - // number of nodes (c2 only) when total peaked - unsigned _live_nodes_at_peak; + // true if the compilation hit the limit + bool _hit_limit; + // result as reported by compiler const char* _result; + // Bytes total at global peak + size_t _peak; + // Bytes per arena tag. + size_t _peak_composition_per_arena_tag[arena_tag_max]; + // Number of live nodes at global peak (C2 only) + unsigned _live_nodes_at_global_peak; + + struct Details { + ArenaCounterTable counters_at_global_peak; + FootprintTimeline timeline; + }; + + Details* _detail_stats; + + MemStatEntry(const MemStatEntry& e); // deny + public: - MemStatEntry(FullMethodName method) - : _method(method), _comptype(compiler_c1), - _time(0), _num_recomp(0), _thread(nullptr), _limit(0), - _total(0), _live_nodes_at_peak(0), - _result(nullptr) { - _peak_by_tag.clear(); + MemStatEntry() + : _comp_type(compiler_none), _comp_id(-1), + _time(0), _thread(nullptr), _limit(0), _hit_limit(false), + _result(nullptr), _peak(0), _live_nodes_at_global_peak(0), + _detail_stats(nullptr) { } - void set_comptype(CompilerType comptype) { _comptype = comptype; } + ~MemStatEntry() { + clean_details(); + } + + void set_comp_id(int comp_id) { _comp_id = comp_id; } + void set_comptype(CompilerType comptype) { _comp_type = comptype; } void set_current_time() { _time = os::elapsedTime(); } void set_current_thread() { _thread = Thread::current(); } void set_limit(size_t limit) { _limit = limit; } - void inc_recompilation() { _num_recomp++; } - void set_total(size_t n) { _total = n; } - void set_peak_by_tag(ArenaCountersByTag peak_by_tag) { _peak_by_tag = peak_by_tag; } - void set_live_nodes_at_peak(unsigned n) { _live_nodes_at_peak = n; } + void set_from_state(const ArenaStatCounter* state, bool store_details) { + _fmn = state->fmn(); + _comp_type = state->comp_type(); + _comp_id = state->comp_id(); + _limit = state->limit(); + _hit_limit = state->hit_limit(); + _peak = state->peak(); + _live_nodes_at_global_peak = state->live_nodes_at_global_peak(); + state->counters_at_global_peak().summarize(_peak_composition_per_arena_tag); +#ifdef COMPILER2 + assert(_detail_stats == nullptr, "should have been cleaned"); + if (store_details) { + _detail_stats = NEW_C_HEAP_OBJ(Details, mtCompiler); + _detail_stats->counters_at_global_peak.copy_from(state->counters_at_global_peak()); + _detail_stats->timeline.copy_from(state->timeline()); + } +#endif // COMPILER2 + } - void set_result(const char* s) { _result = s; } + void clean_details() { + if (_detail_stats != nullptr) { + FREE_C_HEAP_ARRAY(Details, _detail_stats); + _detail_stats = nullptr; + } + } - size_t total() const { return _total; } + void reset() { + clean_details(); + _comp_type = CompilerType::compiler_none; + _comp_id = -1; + _limit = _peak = 0; + _live_nodes_at_global_peak = 0; + memset(_peak_composition_per_arena_tag, 0, sizeof(_peak_composition_per_arena_tag)); + } + + void set_result(const char* s) { _result = s; } + + size_t peak() const { return _peak; } + bool is_c1() const { return _comp_type == CompilerType::compiler_c1; } + bool is_c2() const { return _comp_type == CompilerType::compiler_c2; } static void print_legend(outputStream* st) { #define LEGEND_KEY_FMT "%11s" st->print_cr("Legend:"); - st->print_cr(" " LEGEND_KEY_FMT ": %s", "total", "memory allocated via arenas while compiling"); - for (int tag = 0; tag < Arena::tag_count(); tag++) { + st->print_cr(" " LEGEND_KEY_FMT ": %s", "ctype", "compiler type"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "total", "peak memory allocated via arenas while compiling"); + for (int tag = 0; tag < arena_tag_max; tag++) { st->print_cr(" " LEGEND_KEY_FMT ": %s", Arena::tag_name[tag], Arena::tag_desc[tag]); } - st->print_cr(" " LEGEND_KEY_FMT ": %s", "result", "Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed"); st->print_cr(" " LEGEND_KEY_FMT ": %s", "#nodes", "...how many nodes (c2 only)"); - st->print_cr(" " LEGEND_KEY_FMT ": %s", "limit", "memory limit, if set"); - st->print_cr(" " LEGEND_KEY_FMT ": %s", "time", "time taken for last compilation (sec)"); - st->print_cr(" " LEGEND_KEY_FMT ": %s", "type", "compiler type"); - st->print_cr(" " LEGEND_KEY_FMT ": %s", "#rc", "how often recompiled"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "result", "Result reported by compiler"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "limit", "memory limit; followed by \"*\" if the limit was hit"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "time", "timestamp"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "id", "compile id"); st->print_cr(" " LEGEND_KEY_FMT ": %s", "thread", "compiler thread"); #undef LEGEND_KEY_FMT } static void print_header(outputStream* st) { + st->print("%-6s", "ctyp"); + #define SIZE_FMT "%-10s" st->print(SIZE_FMT, "total"); - for (int tag = 0; tag < Arena::tag_count(); tag++) { + for (int tag = 0; tag < arena_tag_max; tag++) { st->print(SIZE_FMT, Arena::tag_name[tag]); } -#define HDR_FMT1 "%-8s%-8s%-8s%-8s" -#define HDR_FMT2 "%-6s%-4s%-19s%s" +#define HDR_FMT1 "%-8s%-8s%-10s%-8s" +#define HDR_FMT2 "%-6s%-19s%s" - st->print(HDR_FMT1, "result", "#nodes", "limit", "time"); - st->print(HDR_FMT2, "type", "#rc", "thread", "method"); - st->print_cr(""); + st->print(HDR_FMT1, "#nodes", "result", "limit", "time"); + st->print(HDR_FMT2, "id", "thread", "method"); } - void print_on(outputStream* st, bool human_readable) const { - int col = 0; + void print_brief_oneline(outputStream* st) const { + int col = st->indentation(); + + // Type + st->print("%2s ", compilertype2name(_comp_type)); + col += 6; st->fill_to(col); // Total - if (human_readable) { - st->print(PROPERFMT " ", PROPERFMTARGS(_total)); - } else { - st->print("%zu ", _total); - } + size_t v = _peak; + st->print("%zu ", v); col += 10; st->fill_to(col); - for (int tag = 0; tag < Arena::tag_count(); tag++) { - if (human_readable) { - st->print(PROPERFMT " ", PROPERFMTARGS(_peak_by_tag.counter(tag))); - } else { - st->print("%zu ", _peak_by_tag.counter(tag)); - } + for (int tag = 0; tag < arena_tag_max; tag++) { + v = _peak_composition_per_arena_tag[tag]; + st->print("%zu ", v); col += 10; st->fill_to(col); } + // Number of Nodes when memory peaked + if (_live_nodes_at_global_peak > 0) { + st->print("%u ", _live_nodes_at_global_peak); + } else { + st->print("-"); + } + col += 8; st->fill_to(col); + // result? st->print("%s ", _result ? _result : ""); col += 8; st->fill_to(col); - // Number of Nodes when memory peaked - if (_live_nodes_at_peak > 0) { - st->print("%u ", _live_nodes_at_peak); - } else { - st->print("-"); - } - col += 8; st->fill_to(col); - // Limit if (_limit > 0) { - st->print(PROPERFMT " ", PROPERFMTARGS(_limit)); + st->print("%zu%s ", _limit, _hit_limit ? "*" : ""); } else { st->print("-"); } - col += 8; st->fill_to(col); + col += 10; st->fill_to(col); // TimeStamp st->print("%.3f ", _time); col += 8; st->fill_to(col); - // Type - st->print("%s ", compilertype2name(_comptype)); + // Compile ID + st->print("%d ", _comp_id); col += 6; st->fill_to(col); - // Recomp - st->print("%u ", _num_recomp); - col += 4; st->fill_to(col); - // Thread st->print(PTR_FORMAT " ", p2i(_thread)); // MethodName char buf[1024]; - st->print("%s ", _method.as_C_string(buf, sizeof(buf))); + st->print("%s ", _fmn.as_C_string(buf, sizeof(buf))); + st->cr(); } - int compare_by_size(const MemStatEntry* b) const { - const size_t x1 = b->_total; - const size_t x2 = _total; - return x1 < x2 ? -1 : x1 == x2 ? 0 : 1; - } -}; + void print_detailed(outputStream* st) const { + int col = 0; -// The MemStatTable contains records of memory usage of all compilations. It is printed, -// as memory summary, either with jcmd Compiler.memory, or - if the "print" suboption has -// been given with the MemStat compile command - as summary printout at VM exit. -// For any given compiled method, we only keep the memory statistics of the most recent -// compilation, but on a per-compiler basis. If one needs statistics of prior compilations, -// one needs to look into the log produced by the "print" suboption. + constexpr int indent1 = 40; + constexpr int indent2 = 50; -class MemStatTableKey { - const FullMethodName _fmn; - const CompilerType _comptype; -public: - MemStatTableKey(FullMethodName fmn, CompilerType comptype) : - _fmn(fmn), _comptype(comptype) {} - MemStatTableKey(const MemStatTableKey& o) : - _fmn(o._fmn), _comptype(o._comptype) {} - bool operator== (const MemStatTableKey& other) const { - return _fmn == other._fmn && _comptype == other._comptype; - } - static unsigned compute_hash(const MemStatTableKey& n) { - return FullMethodName::compute_hash(n._fmn) + (unsigned)n._comptype; - } -}; - -class MemStatTable : - public ResourceHashtable -{ -public: - - void add(const FullMethodName& fmn, CompilerType comptype, - size_t total, ArenaCountersByTag peak_by_tag, - unsigned live_nodes_at_peak, size_t limit, const char* result) { - assert_lock_strong(NMTCompilationCostHistory_lock); - MemStatTableKey key(fmn, comptype); - MemStatEntry** pe = get(key); - MemStatEntry* e = nullptr; - if (pe == nullptr) { - e = new MemStatEntry(fmn); - put(key, e); - } else { - // Update existing entry - e = *pe; - assert(e != nullptr, "Sanity"); + char buf[1024]; + st->print_cr("Method : %s", _fmn.as_C_string(buf, sizeof(buf))); + st->print_cr("Compiler : %2s", compilertype2name(_comp_type)); + st->print( "Arena Usage at peak : %zu", _peak); + if (_peak > M) { + st->print(" (%.2fM)", ((double)_peak/(double)M)); } + st->cr(); + if (_comp_type == CompilerType::compiler_c2) { + st->print_cr("Nodes at peak : %u", _live_nodes_at_global_peak); + } + st->print_cr("Compile ID : %d", _comp_id); + st->print( "Result : %s", _result); + if (strcmp(_result, "oom") == 0) { + st->print(" (memory limit was: %zu)", _limit); + } + st->cr(); + st->print_cr("Thread : " PTR_FORMAT, p2i(_thread)); + st->print_cr("Timestamp : %.3f", _time); + + if (_detail_stats != nullptr) { + st->cr(); + st->print_cr("Arena Usage by Arena Type and compilation phase, at arena usage peak of %zu:", _peak); + _detail_stats->counters_at_global_peak.print_on(st); + st->cr(); + st->print_cr("Allocation timelime by phase:"); + _detail_stats->timeline.print_on(st); + } else { + st->cr(); + st->print_cr("Arena Usage by Arena Type, at arena usage peak of %zu:", _peak); + for (int tag = 0; tag < arena_tag_max; tag++) { + const size_t v = _peak_composition_per_arena_tag[tag]; + if (v > 0) { + st->print_cr("%-36s: %zu ", Arena::tag_desc[tag], v); + } + } + } + } +}; + +class MemStatStore : public CHeapObj { + + // Total number of entries. Reaching this limit, we discard the least interesting (smallest allocation size) first. + static constexpr int max_entries = 64; + + struct { + size_t s; MemStatEntry* e; + } _entries[max_entries]; + + struct iteration_result { unsigned num, num_c1, num_c2, num_filtered_out; }; + template + void iterate_sorted_filtered(F f, size_t minsize, int max_num_printed, iteration_result& result) const { + assert_lock_strong(NMTCompilationCostHistory_lock); + const unsigned stop_after = max_num_printed == -1 ? UINT_MAX : (unsigned)max_num_printed; + result.num = result.num_c1 = result.num_c2 = result.num_filtered_out = 0; + for (int i = 0; _entries[i].e != nullptr && i < max_entries && result.num < stop_after; i++) { + if (_entries[i].s >= minsize) { + f(_entries[i].e); + result.num++; + result.num_c1 += _entries[i].e->is_c1() ? 1 : 0; + result.num_c2 += _entries[i].e->is_c2() ? 1 : 0; + } else { + result.num_filtered_out++; + } + } + } + + void print_footer(outputStream* st, size_t minsize, const iteration_result& result) const { + if (result.num > 0) { + st->print_cr("Total: %u (C1: %u, C2: %u)", result.num, result.num_c1, result.num_c2); + } else { + st->print_cr("No entries."); + } + if (result.num_filtered_out > 0) { + st->print_cr(" (%d compilations smaller than %zu omitted)", result.num_filtered_out, minsize); + } + } + +public: + + MemStatStore() { + memset(_entries, 0, sizeof(_entries)); + } + + void add(const ArenaStatCounter* state, const char* result) { + + const size_t size = state->peak(); + + // search insert point + int i = 0; + while (i < max_entries && _entries[i].s > size) { + i++; + } + if (i == max_entries) { + return; + } + MemStatEntry* e = _entries[max_entries - 1].e; // recycle last one + if (e == nullptr) { + e = new MemStatEntry(); + } + memmove(_entries + i + 1, _entries + i, sizeof(_entries[0]) * (max_entries - i - 1)); + + e->reset(); e->set_current_time(); e->set_current_thread(); - e->set_comptype(comptype); - e->inc_recompilation(); - e->set_total(total); - e->set_peak_by_tag(peak_by_tag); - e->set_live_nodes_at_peak(live_nodes_at_peak); - e->set_limit(limit); e->set_result(result); + + // Since we don't have phases in C1, for now we just avoid saving details for C1. + const bool save_details = state->comp_type() == CompilerType::compiler_c2; + e->set_from_state(state, save_details); + + _entries[i].s = e->peak(); + _entries[i].e = e; } - // Returns a C-heap-allocated SortMe array containing all entries from the table, - // optionally filtered by entry size - MemStatEntry** calc_flat_array(int& num, size_t min_size) { + void print_table(outputStream* st, bool legend, size_t minsize, int max_num_printed) const { assert_lock_strong(NMTCompilationCostHistory_lock); - const int num_all = number_of_entries(); - MemStatEntry** flat = NEW_C_HEAP_ARRAY(MemStatEntry*, num_all, mtInternal); - int i = 0; - auto do_f = [&] (const MemStatTableKey& ignored, MemStatEntry* e) { - if (e->total() >= min_size) { - flat[i] = e; - assert(i < num_all, "Sanity"); - i ++; - } - }; - iterate_all(do_f); - if (min_size == 0) { - assert(i == num_all, "Sanity"); - } else { - assert(i <= num_all, "Sanity"); + if (legend) { + MemStatEntry::print_legend(st); + st->cr(); } - num = i; - return flat; + + MemStatEntry::print_header(st); + st->cr(); + + iteration_result itres; + auto printer = [&](const MemStatEntry* e) { + e->print_brief_oneline(st); + }; + iterate_sorted_filtered(printer, minsize, max_num_printed, itres); + print_footer(st, minsize, itres); + } + + void print_details(outputStream* st, size_t minsize, int max_num_printed) const { + assert_lock_strong(NMTCompilationCostHistory_lock); + iteration_result itres; + auto printer = [&](const MemStatEntry* e) { + e->print_detailed(st); + st->cr(); + st->print_cr("------------------------"); + st->cr(); + }; + iterate_sorted_filtered(printer, minsize, max_num_printed, itres); } }; bool CompilationMemoryStatistic::_enabled = false; - -static MemStatTable* _the_table = nullptr; +static MemStatStore* _the_store = nullptr; void CompilationMemoryStatistic::initialize() { - assert(_enabled == false && _the_table == nullptr, "Only once"); - _the_table = new (mtCompiler) MemStatTable; + assert(_enabled == false && _the_store == nullptr, "Only once"); + _the_store = new MemStatStore; _enabled = true; log_info(compilation, alloc)("Compilation memory statistic enabled"); } void CompilationMemoryStatistic::on_start_compilation(const DirectiveSet* directive) { assert(enabled(), "Not enabled?"); + assert(directive->should_collect_memstat(), "Don't call if not needed"); + CompilerThread* const th = Thread::current()->as_Compiler_thread(); + CompileTask* const task = th->task(); const size_t limit = directive->mem_limit(); - Thread::current()->as_Compiler_thread()->arena_stat()->start(limit); + // Create new ArenaStat object and hook it into the thread + assert(th->arena_stat() == nullptr, "Sanity"); + ArenaStatCounter* const arena_stat = new ArenaStatCounter(task, limit); + th->set_arenastat(arena_stat); + // Start a "root" phase + PhaseInfo info; + info.id = phase_trc_id_none; + info.num = 0; + info.text = "(outside)"; + arena_stat->on_phase_start(info); } void CompilationMemoryStatistic::on_end_compilation() { assert(enabled(), "Not enabled?"); - ResourceMark rm; CompilerThread* const th = Thread::current()->as_Compiler_thread(); ArenaStatCounter* const arena_stat = th->arena_stat(); + if (arena_stat == nullptr) { // not started + return; + } + + // Mark end of compilation by clearing out the arena state object in the CompilerThread. + // Do this before the final "phase end". + th->set_arenastat(nullptr); + + // End final outer phase. + arena_stat->on_phase_end(); + CompileTask* const task = th->task(); - const CompilerType ct = task->compiler()->type(); + assert(task->compile_id() == arena_stat->comp_id(), "Different compilation?"); const Method* const m = th->task()->method(); - FullMethodName fmn(m); - fmn.make_permanent(); const DirectiveSet* directive = th->task()->directive(); assert(directive->should_collect_memstat(), "Should only be called if memstat is enabled for this method"); @@ -438,7 +803,7 @@ void CompilationMemoryStatistic::on_end_compilation() { // Store memory used in task, for later processing by JFR task->set_arena_bytes(arena_stat->peak()); - // Store result + // Store result (ok, failed, oom...) // For this to work, we must call on_end_compilation() at a point where // Compile|Compilation already handed over the failure string to ciEnv, // but ciEnv must still be alive. @@ -453,24 +818,22 @@ void CompilationMemoryStatistic::on_end_compilation() { { MutexLocker ml(NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag); - assert(_the_table != nullptr, "not initialized"); - - _the_table->add(fmn, ct, - arena_stat->peak(), // total - arena_stat->peak_by_tag(), - arena_stat->live_nodes_at_peak(), - arena_stat->limit(), - result); + assert(_the_store != nullptr, "not initialized"); + _the_store->add(arena_stat, result); } + if (print) { - char buf[1024]; - fmn.as_C_string(buf, sizeof(buf)); - tty->print("%s Arena usage %s: ", compilertype2name(ct), buf); - arena_stat->print_on(tty); - tty->cr(); + // Pre-assemble string to prevent tearing + stringStream ss; + StreamAutoIndentor sai(&ss); + ss.print("%s (%d) (%s) Arena usage ", compilertype2name(arena_stat->comp_type()), arena_stat->comp_id(), result); + arena_stat->fmn().print_on(&ss); + ss.print_raw(": "); + arena_stat->print_peak_state_on(&ss); + tty->print_raw(ss.base()); } - arena_stat->end(); // reset things + delete arena_stat; } static void inform_compilation_about_oom(CompilerType ct) { @@ -508,124 +871,178 @@ static void inform_compilation_about_oom(CompilerType ct) { } } -void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* arena) { - assert(enabled(), "Not enabled?"); - CompilerThread* const th = Thread::current()->as_Compiler_thread(); +void CompilationMemoryStatistic::on_arena_chunk_allocation(size_t size, int arena_tag, uint64_t* stamp) { + assert(enabled(), "Not enabled?"); + assert(arena_tag >= 0 && arena_tag < arena_tag_max, "Arena Tag OOB (%d)", arena_tag_max); + + CompilerThread* const th = Thread::current()->as_Compiler_thread(); ArenaStatCounter* const arena_stat = th->arena_stat(); - if (arena_stat->limit_in_process()) { - return; // avoid recursion on limit hit + if (arena_stat == nullptr || // not started + arena_stat->limit_in_process()) { // limit handling in process, prevent recursion + return; } - bool hit_limit_before = arena_stat->hit_limit(); + // Compiler can be slow to bailout, so we may hit memlimit more than once + const bool hit_limit_before = arena_stat->hit_limit(); - if (arena_stat->is_active() && arena_stat->account(diff, (int)arena->get_tag())) { // new peak? + if (arena_stat->on_arena_chunk_allocation(size, arena_tag, stamp)) { // new peak? // Limit handling if (arena_stat->hit_limit()) { char name[1024] = ""; - bool print = false; - bool crash = false; - CompilerType ct = compiler_none; - + const CompilerType ct = arena_stat->comp_type(); + const bool print = arena_stat->should_print_memstat(); + const bool crash = arena_stat->should_crash_on_memlimit(); arena_stat->set_limit_in_process(true); // prevent recursive limit hits + arena_stat->fmn().as_C_string(name, sizeof(name)); - // get some more info - const CompileTask* const task = th->task(); - if (task != nullptr) { - ct = task->compiler()->type(); - const DirectiveSet* directive = task->directive(); - print = directive->should_print_memstat(); - crash = directive->should_crash_at_mem_limit(); - const Method* m = th->task()->method(); - if (m != nullptr) { - FullMethodName(m).as_C_string(name, sizeof(name)); + inform_compilation_about_oom(ct); + + if (crash) { + // Store this ArenaStat. If other threads also run into OOMs, let them sleep. + // We will never return, so the global store will not contain this info. We will + // print the stored ArenaStat in hs-err (see print_error_report) + if (Atomic::cmpxchg(&_arenastat_oom_crash, (ArenaStatCounter*) nullptr, arena_stat) != nullptr) { + os::infinite_sleep(); } } - char message[1024] = ""; + stringStream short_msg; - // build up message if we need it later + // We print to tty if either print is enabled or if we are to crash on MemLimit hit. + // If printing/crashing are not enabled, we just quietly abort the compilation. The + // compilation is marked as "oom" in the compilation memory result store. if (print || crash) { - stringStream ss(message, sizeof(message)); - if (ct != compiler_none && name[0] != '\0') { - ss.print("%s %s: ", compilertype2name(ct), name); - } - ss.print("Hit MemLimit %s(limit: %zu now: %zu)", + short_msg.print("%s (%d) %s: ", compilertype2name(ct), arena_stat->comp_id(), name); + short_msg.print("Hit MemLimit %s- limit: %zu now: %zu", (hit_limit_before ? "again " : ""), arena_stat->limit(), arena_stat->peak()); - } - - // log if needed - if (print) { - tty->print_raw(message); + tty->print_raw(short_msg.base()); tty->cr(); } - // Crash out if needed if (crash) { - report_fatal(OOM_HOTSPOT_ARENA, __FILE__, __LINE__, "%s", message); - } else { - inform_compilation_about_oom(ct); + // Before crashing, if C2, end current phase. That causes its info (which is the most important) to + // be added to the phase timeline. + if (arena_stat->comp_type() == CompilerType::compiler_c2) { + arena_stat->on_phase_end(); + } + // print extended message to tty (mirrors the one that should show up in the hs-err file, just for good measure) + tty->print_cr("Details:"); + arena_stat->print_peak_state_on(tty); + tty->cr(); + // abort VM + report_fatal(OOM_HOTSPOT_ARENA, __FILE__, __LINE__, "%s", short_msg.base()); } arena_stat->set_limit_in_process(false); - } + } // end Limit handling } } -static inline ssize_t diff_entries_by_size(const MemStatEntry* e1, const MemStatEntry* e2) { - return e1->compare_by_size(e2); -} - -void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_readable, size_t min_size) { - - MutexLocker ml(NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag); - - st->cr(); - st->print_cr("Compilation memory statistics"); - - if (!enabled()) { - st->print_cr("(unavailable)"); +void CompilationMemoryStatistic::on_arena_chunk_deallocation(size_t size, uint64_t stamp) { + assert(enabled(), "Not enabled?"); + CompilerThread* const th = Thread::current()->as_Compiler_thread(); + ArenaStatCounter* const arena_stat = th->arena_stat(); + if (arena_stat == nullptr) { // not started return; } - - st->cr(); - - MemStatEntry::print_legend(st); - st->cr(); - - if (min_size > 0) { - st->print_cr(" (cutoff: %zu bytes)", min_size); + if (arena_stat->limit_in_process()) { + return; // avoid recursion on limit hit } - st->cr(); - MemStatEntry::print_header(st); + arena_stat->on_arena_chunk_deallocation(size, stamp); +} - MemStatEntry** filtered = nullptr; +void CompilationMemoryStatistic::on_phase_start(int phase_trc_id, const char* text) { + assert(enabled(), "Not enabled?"); + assert(phase_trc_id >= 0 && phase_trc_id < phase_trc_id_max, "Phase trace id OOB (%d)", phase_trc_id); + CompilerThread* const th = Thread::current()->as_Compiler_thread(); + ArenaStatCounter* const arena_stat = th->arena_stat(); + if (arena_stat == nullptr) { // not started + return; + } + PhaseInfo info; + info.id = phase_trc_id; + info.num = arena_stat->advance_phase_counter(); + info.text = text; + arena_stat->on_phase_start(info); +} - if (_the_table != nullptr) { - // We sort with quicksort - int num = 0; - filtered = _the_table->calc_flat_array(num, min_size); - if (min_size > 0) { - st->print_cr("(%d/%d)", num, _the_table->number_of_entries()); - } - if (num > 0) { - QuickSort::sort(filtered, num, diff_entries_by_size); - // Now print. Has to happen under lock protection too, since entries may be changed. - for (int i = 0; i < num; i ++) { - filtered[i]->print_on(st, human_readable); - } - } else { - st->print_cr("No entries."); - } +void CompilationMemoryStatistic::on_phase_end() { + assert(enabled(), "Not enabled?"); + CompilerThread* const th = Thread::current()->as_Compiler_thread(); + ArenaStatCounter* const arena_stat = th->arena_stat(); + if (arena_stat == nullptr) { // not started + return; + } + arena_stat->on_phase_end(); +} + +static bool check_before_reporting(outputStream* st) { + if (!CompilationMemoryStatistic::enabled()) { + st->print_cr("Compilation memory statistics disabled."); + return false; + } + if (_the_store == nullptr) { + st->print_cr("Compilation memory statistics not yet initialized. "); + return false; + } + return true; +} + +bool CompilationMemoryStatistic::in_oom_crash() { + return Atomic::load(&_arenastat_oom_crash) != nullptr; +} + +void CompilationMemoryStatistic::print_error_report(outputStream* st) { + if (!check_before_reporting(st)) { + return; + } + StreamAutoIndentor sai(tty); + streamIndentor si(tty, 4); + const ArenaStatCounter* const oom_stats = Atomic::load(&_arenastat_oom_crash); + if (oom_stats != nullptr) { + // we crashed due to a compiler limit hit. Lead with a printout of the offending stats + // in detail. + st->print_cr("Compiler Memory Statistic, hit OOM limit; offending compilation:"); + oom_stats->fmn().print_on(st); + st->cr(); + oom_stats->print_peak_state_on(st); + st->cr(); + } + st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); + print_all_by_size(st, false, false, 0, 10); +} + +void CompilationMemoryStatistic::print_final_report(outputStream* st) { + if (!check_before_reporting(st)) { + return; + } + st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); + StreamAutoIndentor sai(st); + streamIndentor si(st, 4); + print_all_by_size(st, false, false, 0, 10); +} + +void CompilationMemoryStatistic::print_jcmd_report(outputStream* st, bool verbose, bool legend, size_t minsize) { + if (!check_before_reporting(st)) { + return; + } + st->print_cr("Compiler Memory Statistic"); + StreamAutoIndentor sai(st); + streamIndentor si(st, 4); + print_all_by_size(st, verbose, legend, minsize, -1); +} + +void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool verbose, bool legend, size_t minsize, int max_num_printed) { + MutexLocker ml(NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag); + if (verbose) { + _the_store->print_details(st, minsize, max_num_printed); } else { - st->print_cr("Not initialized."); + _the_store->print_table(st, legend, minsize, max_num_printed); } - st->cr(); - - FREE_C_HEAP_ARRAY(Entry, filtered); } const char* CompilationMemoryStatistic::failure_reason_memlimit() { @@ -633,12 +1050,50 @@ const char* CompilationMemoryStatistic::failure_reason_memlimit() { return s; } +#ifdef ASSERT +void CompilationMemoryStatistic::do_test_allocations() { + + CompilerThread* const th = Thread::current()->as_Compiler_thread(); + ArenaStatCounter* const arena_stat = th->arena_stat(); + if (arena_stat == nullptr || !arena_stat->is_test_class()) { // not started or not the JTREG test + return; + } + const CompilerType ctyp = th->task()->compiler()->type(); + + // Note: all allocations in here need to be tagged as mtCompiler to be recognized + // by the compilation memstat. ResourceArea in a CompilerThread is already tagged + // mtCompiler (special handling for compiler threads). + +#ifdef COMPILER2 + if (ctyp == CompilerType::compiler_c2) { + { + Compile::TracePhase tp(Phase::_t_testPhase1); + Arena ar(MemTag::mtCompiler, Arena::Tag::tag_reglive); + ar.Amalloc(2 * M); // phase-local peak + } + { + Compile::TracePhase tp(Phase::_t_testPhase2); + NEW_RESOURCE_ARRAY(char, 32 * M); // leaked (until compilation end) + } + } // C2 +#endif // COMPILER2 + +#ifdef COMPILER1 + if (ctyp == CompilerType::compiler_c1) { + NEW_RESOURCE_ARRAY(char, 32 * M); // leaked (until compilation end) + } +#endif // COMPILER2 + +} +#endif // ASSERT + CompilationMemoryStatisticMark::CompilationMemoryStatisticMark(const DirectiveSet* directive) : _active(directive->should_collect_memstat()) { if (_active) { CompilationMemoryStatistic::on_start_compilation(directive); } } + CompilationMemoryStatisticMark::~CompilationMemoryStatisticMark() { if (_active) { CompilationMemoryStatistic::on_end_compilation(); diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.hpp b/src/hotspot/share/compiler/compilationMemoryStatistic.hpp index d9cbfabde1b..2de5b0e9abb 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.hpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Red Hat, Inc. and/or its affiliates. * 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,114 +26,49 @@ #ifndef SHARE_COMPILER_COMPILATIONMEMORYSTATISTIC_HPP #define SHARE_COMPILER_COMPILATIONMEMORYSTATISTIC_HPP -#include "compiler/compilerDefinitions.hpp" #include "memory/allocation.hpp" #include "memory/allStatic.hpp" -#include "memory/arena.hpp" #include "utilities/globalDefinitions.hpp" -class outputStream; -class Symbol; class DirectiveSet; - -// Helper class to wrap the array of arena tags for easier processing -class ArenaCountersByTag { -private: - size_t _counter[Arena::tag_count()]; - -public: - int element_count() const { return Arena::tag_count(); } - const char* tag_name(int tag) const { return Arena::tag_name[tag]; } - - size_t counter(int tag) const { - assert(tag < element_count(), "invalid tag %d", tag); - return _counter[tag]; - } - - void add(int tag, size_t value) { - assert(tag < element_count(), "invalid tag %d", tag); - _counter[tag] += value; - } - - void clear() { - memset(_counter, 0, sizeof(size_t) * element_count()); - } -}; - -// Counters for allocations from arenas during compilation -class ArenaStatCounter : public CHeapObj { - // Current bytes, total - size_t _current; - // bytes at last peak, total - size_t _peak; - // Current bytes used by arenas per tag - ArenaCountersByTag _current_by_tag; - // Peak composition: - ArenaCountersByTag _peak_by_tag; - // MemLimit handling - size_t _limit; - bool _hit_limit; - bool _limit_in_process; - - // When to start accounting - bool _active; - - // Number of live nodes when total peaked (c2 only) - unsigned _live_nodes_at_peak; - - void update_c2_node_count(); - - void reset(); - -public: - ArenaStatCounter(); - - // Size of peak since last compilation - size_t peak() const { return _peak; } - - // Peak details - ArenaCountersByTag peak_by_tag() const { return _peak_by_tag; } - unsigned live_nodes_at_peak() const { return _live_nodes_at_peak; } - - // Mark the start and end of a compilation. - void start(size_t limit); - void end(); - - // Account an arena allocation or de-allocation. - // Returns true if new peak reached - bool account(ssize_t delta, int tag); - - void set_live_nodes_at_peak(unsigned i) { _live_nodes_at_peak = i; } - - void print_on(outputStream* st) const; - - size_t limit() const { return _limit; } - bool hit_limit() const { return _hit_limit; } - bool limit_in_process() const { return _limit_in_process; } - void set_limit_in_process(bool v) { _limit_in_process = v; } - bool is_active() const { return _active; } -}; +class outputStream; class CompilationMemoryStatistic : public AllStatic { - static bool _enabled; + friend class CompilationMemoryStatisticMark; + static bool _enabled; // set to true if memstat is active for any method. + + // Private, should only be called via CompilationMemoryStatisticMark + static void on_start_compilation(const DirectiveSet* directive); + + // Private, should only be called via CompilationMemoryStatisticMark + static void on_end_compilation(); + + static void print_all_by_size(outputStream* st, bool verbose, bool legend, size_t minsize, int max_num_printed); + public: static void initialize(); // true if CollectMemStat or PrintMemStat has been enabled for any method static bool enabled() { return _enabled; } - static void on_start_compilation(const DirectiveSet* directive); + // true if we are in a fatal error inited by hitting the MemLimit + static bool in_oom_crash(); + + static void on_phase_start(int phase_trc_id, const char* text); + static void on_phase_end(); + static void on_arena_chunk_allocation(size_t size, int arenatag, uint64_t* stamp); + static void on_arena_chunk_deallocation(size_t size, uint64_t stamp); + + static void print_final_report(outputStream* st); + static void print_error_report(outputStream* st); + static void print_jcmd_report(outputStream* st, bool verbose, bool legend, size_t minsize); - // Called at end of compilation. Records the arena usage peak. Also takes over - // status information from ciEnv (compilation failed, oom'ed or went okay). ciEnv::_failure_reason - // must be set at this point (so place CompilationMemoryStatisticMark correctly). - static void on_end_compilation(); - static void on_arena_change(ssize_t diff, const Arena* arena); - static void print_all_by_size(outputStream* st, bool human_readable, size_t minsize); // For compilers static const char* failure_reason_memlimit(); + + DEBUG_ONLY(static void do_test_allocations();) }; // RAII object to wrap one compilation -class CompilationMemoryStatisticMark { +class CompilationMemoryStatisticMark : public StackObj { const bool _active; public: CompilationMemoryStatisticMark(const DirectiveSet* directive); diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index 8e296226fee..e7ef9703191 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -121,7 +121,6 @@ class TypedMethodOptionMatcher; static TypedMethodOptionMatcher* option_list = nullptr; static bool any_set = false; -static bool print_final_memstat_report = false; // A filter for quick lookup if an option is set static bool option_filter[static_cast(CompileCommandEnum::Unknown) + 1] = { 0 }; @@ -482,10 +481,6 @@ bool CompilerOracle::should_collect_memstat() { return has_command(CompileCommandEnum::MemStat) || has_command(CompileCommandEnum::MemLimit); } -bool CompilerOracle::should_print_final_memstat_report() { - return print_final_memstat_report; -} - bool CompilerOracle::should_log(const methodHandle& method) { if (!LogCompilation) return false; if (!has_command(CompileCommandEnum::Log)) { @@ -711,7 +706,6 @@ static bool parseMemStat(const char* line, uintx& value, int& bytes_read, char* }); IF_ENUM_STRING("print", { value = (uintx)MemStatAction::print; - print_final_memstat_report = true; }); #undef IF_ENUM_STRING diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index 0e55ca416e0..943cd2c9734 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -166,7 +166,6 @@ class CompilerOracle : AllStatic { // Tells whether there are any methods to (collect|collect+print) memory statistics for static bool should_collect_memstat(); - static bool should_print_final_memstat_report(); // Tags the method as blackhole candidate, if possible. static void tag_blackhole_if_possible(const methodHandle& method); diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index a72fc48b9a1..55dd8383ac4 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -22,7 +22,6 @@ * */ -#include "compiler/compilationMemoryStatistic.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileTask.hpp" #include "compiler/compilerThread.hpp" @@ -40,7 +39,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, _buffer_blob = nullptr; _can_call_java = false; _compiler = nullptr; - _arena_stat = CompilationMemoryStatistic::enabled() ? new ArenaStatCounter : nullptr; + _arena_stat = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -50,7 +49,8 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; - delete _arena_stat; + // arenastat should have been deleted at the end of the compilation + assert(_arena_stat == nullptr, "Should be null"); } void CompilerThread::set_compiler(AbstractCompiler* c) { diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index 3531fb6d72d..e20e3017d1f 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.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 @@ -85,6 +85,7 @@ class CompilerThread : public JavaThread { CompileQueue* queue() const { return _queue; } CompilerCounters* counters() const { return _counters; } ArenaStatCounter* arena_stat() const { return _arena_stat; } + void set_arenastat(ArenaStatCounter* v) { _arena_stat = v; } // Get/set the thread's compilation environment. ciEnv* env() { return _env; } diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index 055c6405590..d03c0776f61 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -45,13 +45,13 @@ STATIC_ASSERT(is_aligned((int)Chunk::size, ARENA_AMALLOC_ALIGNMENT)); const char* Arena::tag_name[] = { -#define ARENA_TAG_STRING(name, str, desc) XSTR(name), +#define ARENA_TAG_STRING(name, desc) XSTR(name), DO_ARENA_TAG(ARENA_TAG_STRING) #undef ARENA_TAG_STRING }; const char* Arena::tag_desc[] = { -#define ARENA_TAG_DESC(name, str, desc) XSTR(desc), +#define ARENA_TAG_DESC(name, desc) XSTR(desc), DO_ARENA_TAG(ARENA_TAG_DESC) #undef ARENA_TAG_DESC }; @@ -118,11 +118,19 @@ public: } // Returns an initialized and null-terminated Chunk of requested size - static Chunk* allocate_chunk(size_t length, AllocFailType alloc_failmode); + static Chunk* allocate_chunk(Arena* arena, size_t length, AllocFailType alloc_failmode); static void deallocate_chunk(Chunk* p); }; -Chunk* ChunkPool::allocate_chunk(size_t length, AllocFailType alloc_failmode) { +static bool on_compiler_thread() { +#if defined(COMPILER1) || defined(COMPILER2) + return Thread::current_or_null() != nullptr && + Thread::current()->is_Compiler_thread(); +#endif // COMPILER1 || COMPILER2 + return false; +} + +Chunk* ChunkPool::allocate_chunk(Arena* arena, size_t length, AllocFailType alloc_failmode) { // - requested_size = sizeof(Chunk) // - length = payload size // We must ensure that the boundaries of the payload (C and D) are aligned to 64-bit: @@ -164,10 +172,27 @@ Chunk* ChunkPool::allocate_chunk(size_t length, AllocFailType alloc_failmode) { ::new(chunk) Chunk(length); // We rely on arena alignment <= malloc alignment. assert(is_aligned(chunk, ARENA_AMALLOC_ALIGNMENT), "Chunk start address misaligned."); + + if (CompilationMemoryStatistic::enabled() && on_compiler_thread()) { + uint64_t stamp = 0; + CompilationMemoryStatistic::on_arena_chunk_allocation(chunk->length(), (int)arena->get_tag(), &stamp); + chunk->set_stamp(stamp); + } else { + chunk->set_stamp(0); + } + return chunk; } void ChunkPool::deallocate_chunk(Chunk* c) { + + // Inform compilation memstat + if (CompilationMemoryStatistic::enabled() && c->stamp() != 0) { + assert(on_compiler_thread(), "we stamped this chunk"); + CompilationMemoryStatistic::on_arena_chunk_deallocation(c->length(), c->stamp()); + c->set_stamp(0); + } + // If this is a standard-sized chunk, return it to its pool; otherwise free it. ChunkPool* pool = ChunkPool::get_pool_for_size(c->length()); if (pool != nullptr) { @@ -200,8 +225,8 @@ void Arena::start_chunk_pool_cleaner_task() { cleaner->enroll(); } -Chunk::Chunk(size_t length) : _len(length) { - _next = nullptr; // Chain on the linked list +Chunk::Chunk(size_t length) : + _next(nullptr), _len(length), _stamp(0) { } void Chunk::chop(Chunk* k) { @@ -227,7 +252,7 @@ Arena::Arena(MemTag mem_tag, Tag tag, size_t init_size) : _hwm(nullptr), _max(nullptr) { init_size = ARENA_ALIGN(init_size); - _chunk = ChunkPool::allocate_chunk(init_size, AllocFailStrategy::EXIT_OOM); + _chunk = ChunkPool::allocate_chunk(this, init_size, AllocFailStrategy::EXIT_OOM); _first = _chunk; _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); @@ -258,12 +283,6 @@ void Arena::set_size_in_bytes(size_t size) { ssize_t delta = size - size_in_bytes(); _size_in_bytes = size; MemTracker::record_arena_size_change(delta, _mem_tag); - if (CompilationMemoryStatistic::enabled() && _mem_tag == mtCompiler) { - Thread* const t = Thread::current(); - if (t != nullptr && t->is_Compiler_thread()) { - CompilationMemoryStatistic::on_arena_change(delta, this); - } - } } } @@ -289,7 +308,7 @@ void* Arena::grow(size_t x, AllocFailType alloc_failmode) { } Chunk* k = _chunk; // Get filled-up chunk address - _chunk = ChunkPool::allocate_chunk(len, alloc_failmode); + _chunk = ChunkPool::allocate_chunk(this, len, alloc_failmode); if (_chunk == nullptr) { _chunk = k; // restore the previous value of _chunk diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index 5f0def2a655..dfa12209f40 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -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 @@ -44,6 +44,9 @@ class Chunk { private: Chunk* _next; // Next Chunk in list const size_t _len; // Size of this Chunk + // Used for Compilation Memory Statistic + uint64_t _stamp; + public: NONCOPYABLE(Chunk); @@ -66,7 +69,8 @@ public: tiny_size = 256 - slack, // Size of first chunk (tiny) init_size = 1*K - slack, // Size of first chunk (normal aka small) medium_size= 10*K - slack, // Size of medium-sized chunk - size = 32*K - slack // Default size of an Arena chunk (following the first) + size = 32*K - slack, // Default size of an Arena chunk (following the first) + max_default_size = size // Largest default size }; static void chop(Chunk* chunk); // Chop this chunk @@ -81,19 +85,30 @@ public: char* bottom() const { return ((char*) this) + aligned_overhead_size(); } char* top() const { return bottom() + _len; } bool contains(char* p) const { return bottom() <= p && p <= top(); } + + void set_stamp(uint64_t v) { _stamp = v; } + uint64_t stamp() const { return _stamp; } }; +// Arena types (for Compilation Memory Statistic) #define DO_ARENA_TAG(FN) \ - FN(other, Others, Other arenas) \ - FN(ra, RA, Resource areas) \ - FN(ha, HA, Handle area) \ - FN(node, NA, Node arena) \ + FN(ra, Resource areas) \ + FN(node, C2 Node arena) \ + FN(comp, C2 Compile arena) \ + FN(type, C2 Type arena) \ + FN(states, C2 Matcher States Arena) \ + FN(reglive, C2 Register Allocation Live Arenas) \ + FN(regsplit, C2 Register Allocation Split Arena) \ + FN(superword, C2 SuperWord Arenas) \ + FN(cienv, CI Env Arena) \ + FN(ha, Handle area) \ + FN(other, Other arenas) \ // Fast allocation of memory class Arena : public CHeapObjBase { public: enum class Tag: uint8_t { -#define ARENA_TAG_ENUM(name, str, desc) tag_##name, +#define ARENA_TAG_ENUM(name, desc) tag_##name, DO_ARENA_TAG(ARENA_TAG_ENUM) #undef ARENA_TAG_ENUM tag_count @@ -192,6 +207,7 @@ protected: size_t size_in_bytes() const { return _size_in_bytes; }; void set_size_in_bytes(size_t size); + MemTag get_mem_tag() const { return _mem_tag; } Tag get_tag() const { return _tag; } private: diff --git a/src/hotspot/share/memory/resourceArea.hpp b/src/hotspot/share/memory/resourceArea.hpp index 29dea9ad2f4..85ad6590d69 100644 --- a/src/hotspot/share/memory/resourceArea.hpp +++ b/src/hotspot/share/memory/resourceArea.hpp @@ -54,8 +54,12 @@ public: ResourceArea(MemTag mem_tag = mtThread) : Arena(mem_tag, Arena::Tag::tag_ra) DEBUG_ONLY(COMMA _nesting(0)) {} - ResourceArea(size_t init_size, MemTag mem_tag = mtThread) : - Arena(mem_tag, Arena::Tag::tag_ra, init_size) DEBUG_ONLY(COMMA _nesting(0)) { + ResourceArea(size_t init_size, MemTag mem_tag = mtThread, Arena::Tag arena_tag = Arena::Tag::tag_ra) : + Arena(mem_tag, arena_tag, init_size) DEBUG_ONLY(COMMA _nesting(0)) { + } + + ResourceArea(MemTag mem_tag, Arena::Tag arena_tag) : + Arena(mem_tag, arena_tag) DEBUG_ONLY(COMMA _nesting(0)) { } char* allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 30d8e1ac287..11e1797d034 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -366,8 +366,8 @@ void PhaseChaitin::Register_Allocate() { _alternate = 0; _matcher._allocation_started = true; - ResourceArea split_arena(mtCompiler); // Arena for Split local resources - ResourceArea live_arena(mtCompiler); // Arena for liveness & IFG info + ResourceArea split_arena(mtCompiler, Arena::Tag::tag_regsplit); // Arena for Split local resources + ResourceArea live_arena(mtCompiler, Arena::Tag::tag_reglive); // Arena for liveness & IFG info ResourceMark rm(&live_arena); // Need live-ness for the IFG; need the IFG for coalescing. If the diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7c9d8250e5c..014463ccc21 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -41,6 +41,7 @@ #include "jfr/jfrEvents.hpp" #include "jvm_io.h" #include "memory/allocation.hpp" +#include "memory/arena.hpp" #include "memory/resourceArea.hpp" #include "opto/addnode.hpp" #include "opto/block.hpp" @@ -638,7 +639,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), - _comp_arena(mtCompiler), + _comp_arena(mtCompiler, Arena::Tag::tag_comp), _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), _env(ci_env), _directive(directive), @@ -661,7 +662,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _node_arena_two(mtCompiler, Arena::Tag::tag_node), _node_arena(&_node_arena_one), _mach_constant_base_node(nullptr), - _Compile_types(mtCompiler), + _Compile_types(mtCompiler, Arena::Tag::tag_type), _initial_gvn(nullptr), _igvn_worklist(nullptr), _types(nullptr), @@ -915,7 +916,7 @@ Compile::Compile(ciEnv* ci_env, _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), - _comp_arena(mtCompiler), + _comp_arena(mtCompiler, Arena::Tag::tag_comp), _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), _env(ci_env), _directive(directive), @@ -927,11 +928,11 @@ Compile::Compile(ciEnv* ci_env, _unique(0), _dead_node_count(0), _dead_node_list(comp_arena()), - _node_arena_one(mtCompiler), - _node_arena_two(mtCompiler), + _node_arena_one(mtCompiler, Arena::Tag::tag_node), + _node_arena_two(mtCompiler, Arena::Tag::tag_node), _node_arena(&_node_arena_one), _mach_constant_base_node(nullptr), - _Compile_types(mtCompiler), + _Compile_types(mtCompiler, Arena::Tag::tag_type), _initial_gvn(nullptr), _igvn_worklist(nullptr), _types(nullptr), @@ -3013,6 +3014,13 @@ void Compile::Code_Gen() { print_method(PHASE_POSTALLOC_EXPAND, 3); } +#ifdef ASSERT + { + CompilationMemoryStatistic::do_test_allocations(); + if (failing()) return; + } +#endif + // Convert Nodes to instruction bits in a buffer { TracePhase tp(_t_output); @@ -4313,6 +4321,7 @@ Compile::TracePhase::TracePhase(const char* name, PhaseTraceId id) _dolog(CITimeVerbose) { assert(_compile != nullptr, "sanity check"); + assert(id != PhaseTraceId::_t_none, "Don't use none"); if (_dolog) { _log = _compile->log(); } @@ -4321,12 +4330,23 @@ Compile::TracePhase::TracePhase(const char* name, PhaseTraceId id) _log->stamp(); _log->end_head(); } + + // Inform memory statistic, if enabled + if (CompilationMemoryStatistic::enabled()) { + CompilationMemoryStatistic::on_phase_start((int)id, name); + } } Compile::TracePhase::TracePhase(PhaseTraceId id) : TracePhase(Phase::get_phase_trace_id_text(id), id) {} Compile::TracePhase::~TracePhase() { + + // Inform memory statistic, if enabled + if (CompilationMemoryStatistic::enabled()) { + CompilationMemoryStatistic::on_phase_end(); + } + if (_compile->failing_internal()) { if (_log != nullptr) { _log->done("phase"); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 2ae3cca218d..1fe6180c54f 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -236,9 +236,9 @@ class Compile : public Phase { // (The time collection itself is always conditionalized on CITime.) class TracePhase : public TraceTime { private: - Compile* _compile; + Compile* const _compile; CompileLog* _log; - bool _dolog; + const bool _dolog; public: TracePhase(PhaseTraceId phaseTraceId); TracePhase(const char* name, PhaseTraceId phaseTraceId); diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index c9cdd235f03..eeab96de3fa 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1695,7 +1695,7 @@ void PhaseCFG::global_code_motion() { // Enabling the scheduler for register pressure plus finding blocks of size to schedule for it // is key to enabling this feature. PhaseChaitin regalloc(C->unique(), *this, _matcher, true); - ResourceArea live_arena(mtCompiler); // Arena for liveness + ResourceArea live_arena(mtCompiler, Arena::Tag::tag_reglive); // Arena for liveness ResourceMark rm_live(&live_arena); PhaseLive live(*this, regalloc._lrg_map.names(), &live_arena, true); PhaseIFG ifg(&live_arena); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 1c9afae6510..fd89a6e5431 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -60,7 +60,7 @@ const uint Matcher::_end_rematerialize = _END_REMATERIALIZE; //---------------------------Matcher------------------------------------------- Matcher::Matcher() : PhaseTransform( Phase::Ins_Select ), - _states_arena(Chunk::medium_size, mtCompiler), + _states_arena(Chunk::medium_size, mtCompiler, Arena::Tag::tag_states), _new_nodes(C->comp_arena()), _visited(&_states_arena), _shared(&_states_arena), diff --git a/src/hotspot/share/opto/phase.hpp b/src/hotspot/share/opto/phase.hpp index ff166c8de8e..6700df6ec17 100644 --- a/src/hotspot/share/opto/phase.hpp +++ b/src/hotspot/share/opto/phase.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 @@ -31,6 +31,8 @@ class IfNode; class MergeMemNode; class Node; class PhaseGVN; +class Compile; +class ciMethod; //------------------------------Phase------------------------------------------ // Most optimizations are done in Phases. Creating a phase does any long @@ -65,6 +67,7 @@ public: }; #define ALL_PHASE_TRACE_IDS(f) \ + f( _t_none, "none") \ f( _t_parser, "parse") \ f( _t_optimizer, "optimizer") \ f( _t_escapeAnalysis, "escapeAnalysis") \ @@ -118,7 +121,9 @@ public: f( _t_fillBuffer, "fill buffer") \ f( _t_registerMethod, "install_code") \ f( _t_temporaryTimer1, "tempTimer1") \ - f( _t_temporaryTimer2, "tempTimer2") + f( _t_temporaryTimer2, "tempTimer2") \ + f( _t_testPhase1, "testPhase1") \ + f( _t_testPhase2, "testPhase2") enum PhaseTraceId { #define DEFID(name, text) name, diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 30cfbddc196..b288f21f99e 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -30,6 +30,7 @@ #include "code/pcDesc.hpp" #include "code/scopeDesc.hpp" #include "code/vtableStubs.hpp" +#include "compiler/compilationMemoryStatistic.hpp" #include "compiler/compileBroker.hpp" #include "compiler/oopMap.hpp" #include "gc/g1/g1HeapRegion.hpp" @@ -267,6 +268,7 @@ address OptoRuntime::generate_stub(ciEnv* env, // Matching the default directive, we currently have no method to match. DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_full_optimization)); + CompilationMemoryStatisticMark cmsm(directive); ResourceMark rm; Compile C(env, gen, C_function, name, is_fancy_jump, pass_tls, return_pc, directive); DirectivesStack::release(directive); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 697e4d842d5..092fa07e184 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -33,7 +33,7 @@ SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) : _vloop_analyzer(vloop_analyzer), _vloop(vloop_analyzer.vloop()), - _arena(mtCompiler), + _arena(mtCompiler, Arena::Tag::tag_superword), _clone_map(phase()->C->clone_map()), // map of nodes created in cloning _pairset(&_arena, _vloop_analyzer), _packset(&_arena, _vloop_analyzer diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index b56e3739a9d..fabcec48719 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -440,7 +440,7 @@ void Type::Initialize_shared(Compile* current) { // locking. Arena* save = current->type_arena(); - Arena* shared_type_arena = new (mtCompiler)Arena(mtCompiler); + Arena* shared_type_arena = new (mtCompiler)Arena(mtCompiler, Arena::Tag::tag_type); current->set_type_arena(shared_type_arena); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 2a2186ab0aa..d4b78515312 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -256,7 +256,7 @@ private: public: VSharedData() : - _arena(mtCompiler), + _arena(mtCompiler, Arena::Tag::tag_superword), _node_idx_to_loop_body_idx(&_arena, estimated_node_count(), 0, 0) { } @@ -696,7 +696,7 @@ private: public: VLoopAnalyzer(const VLoop& vloop, VSharedData& vshared) : _vloop(vloop), - _arena(mtCompiler), + _arena(mtCompiler, Arena::Tag::tag_superword), _success(false), _reductions (&_arena, vloop), _memory_slices (&_arena, vloop), diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 308578ecb57..588da3cd56e 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -217,7 +217,7 @@ public: _vloop_analyzer(vloop_analyzer), _vloop(vloop_analyzer.vloop()), NOT_PRODUCT(_trace(trace) COMMA) - _arena(mtCompiler), + _arena(mtCompiler, Arena::Tag::tag_superword), _graph(_vloop_analyzer, _arena NOT_PRODUCT(COMMA _trace)), _mem_ref_for_main_loop_alignment(mem_ref_for_main_loop_alignment), _aw_for_main_loop_alignment(aw_for_main_loop_alignment) {} diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index a1ebe226e85..e7aa034612b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1403,6 +1403,9 @@ const int ObjectAlignmentInBytes = 8; product(bool, PrintMetaspaceStatisticsAtExit, false, DIAGNOSTIC, \ "Print metaspace statistics upon VM exit.") \ \ + product(bool, PrintCompilerMemoryStatisticsAtExit, false, DIAGNOSTIC, \ + "Print compiler memory statistics upon VM exit.") \ + \ product(uintx, MinHeapFreeRatio, 40, MANAGEABLE, \ "The minimum percentage of heap free after GC to avoid expansion."\ " For most GCs this applies to the old generation. In G1 and" \ diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index b2c24169505..45e63e90ffb 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -353,8 +353,8 @@ void print_statistics() { MetaspaceUtils::print_basic_report(tty, 0); } - if (CompilerOracle::should_print_final_memstat_report()) { - CompilationMemoryStatistic::print_all_by_size(tty, false, 0); + if (PrintCompilerMemoryStatisticsAtExit) { + CompilationMemoryStatistic::print_final_report(tty); } ThreadsSMRSupport::log_statistics(); diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 13d996e7ab7..d257ef61be6 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -1145,16 +1145,17 @@ void VThreadPollersDCmd::execute(DCmdSource source, TRAPS) { CompilationMemoryStatisticDCmd::CompilationMemoryStatisticDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), - _human_readable("-H", "Human readable format", "BOOLEAN", false, "false"), - _minsize("-s", "Minimum memory size", "MEMORY SIZE", false, "0") { - _dcmdparser.add_dcmd_option(&_human_readable); + _verbose("verbose", "Print detailed information", "BOOLEAN", false, "false"), + _legend("legend", "Table mode: print legend", "BOOLEAN", false, "false"), + _minsize("minsize", "Minimum memory size", "MEMORY SIZE", false, "0") { + _dcmdparser.add_dcmd_option(&_verbose); _dcmdparser.add_dcmd_option(&_minsize); + _dcmdparser.add_dcmd_option(&_legend); } void CompilationMemoryStatisticDCmd::execute(DCmdSource source, TRAPS) { - const bool human_readable = _human_readable.value(); const size_t minsize = _minsize.has_value() ? _minsize.value()._size : 0; - CompilationMemoryStatistic::print_all_by_size(output(), human_readable, minsize); + CompilationMemoryStatistic::print_jcmd_report(output(), _verbose.value(), _legend.value(), minsize); } #if defined(LINUX) || defined(_WIN64) || defined(__APPLE__) diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index 212a8996d0a..18d06f45a6a 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -805,10 +805,11 @@ public: class CompilationMemoryStatisticDCmd: public DCmdWithParser { protected: - DCmdArgument _human_readable; + DCmdArgument _verbose; + DCmdArgument _legend; DCmdArgument _minsize; public: - static int num_arguments() { return 2; } + static int num_arguments() { return 3; } CompilationMemoryStatisticDCmd(outputStream* output, bool heap); static const char* name() { return "Compiler.memory"; diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 9e06614bc7e..bbf1fcf9d6f 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -27,6 +27,7 @@ #include "cds/metaspaceShared.hpp" #include "code/codeCache.hpp" #include "compiler/compilationFailureInfo.hpp" +#include "compiler/compilationMemoryStatistic.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/gcConfig.hpp" @@ -1000,6 +1001,11 @@ void VMError::report(outputStream* st, bool _verbose) { STEP_IF("printing pending compilation failure", _verbose && _thread != nullptr && _thread->is_Compiler_thread()) CompilationFailureInfo::print_pending_compilation_failure(st); + if (CompilationMemoryStatistic::enabled() && CompilationMemoryStatistic::in_oom_crash()) { + st->cr(); + st->print_cr(">> Please see below for a detailed breakdown of compiler memory usage."); + st->cr(); + } #endif STEP_IF("printing registers", _verbose && _context != nullptr) @@ -1260,6 +1266,10 @@ void VMError::report(outputStream* st, bool _verbose) { MemTracker::error_report(st); st->cr(); + STEP_IF("printing compiler memory info, if any", _verbose) + CompilationMemoryStatistic::print_error_report(st); + st->cr(); + STEP_IF("printing periodic trim state", _verbose) NativeHeapTrimmer::print_state(st); st->cr(); @@ -1436,10 +1446,12 @@ void VMError::print_vm_info(outputStream* st) { st->cr(); // STEP("Native Memory Tracking") - MemTracker::error_report(st); st->cr(); + // STEP("Compiler Memory Statistic") + CompilationMemoryStatistic::print_final_report(st); + // STEP("printing periodic trim state") NativeHeapTrimmer::print_state(st); st->cr(); diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java b/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java index f1565db47d9..aef477f4402 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandMemLimit.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, 2024, Red Hat, Inc. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Red Hat, Inc. 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,33 +25,33 @@ /* * @test id=c1_crash * @requires vm.compiler1.enabled - * @summary Checks that -XX:CompileCommand=MemLimit,...,crash causes C1 to crash + * @summary Checks that -XX:CompileCommand=MemLimit,...,xx~crash causes C1 to crash * @library /test/lib - * @run driver compiler.print.CompileCommandMemLimit crash false + * @run driver compiler.print.CompileCommandMemLimit c1 crash */ /* * @test id=c2_crash * @requires vm.compiler2.enabled - * @summary Checks that -XX:CompileCommand=MemLimit,...,crash causes C2 to crash + * @summary Checks that -XX:CompileCommand=MemLimit,...,xx~crash causes C2 to crash * @library /test/lib - * @run driver compiler.print.CompileCommandMemLimit crash true + * @run driver compiler.print.CompileCommandMemLimit c2 crash */ /* * @test id=c1_stop * @requires vm.compiler1.enabled - * @summary Checks that -XX:CompileCommand=MemLimit,...,stop causes C1 to stop + * @summary Checks that -XX:CompileCommand=MemLimit,...,xx causes C1 to bail out from the compilation * @library /test/lib - * @run driver compiler.print.CompileCommandMemLimit stop false + * @run driver compiler.print.CompileCommandMemLimit c1 stop */ /* * @test id=c2_stop * @requires vm.compiler2.enabled - * @summary Checks that -XX:CompileCommand=MemLimit,...,stop causes C2 to stop + * @summary Checks that -XX:CompileCommand=MemLimit,...,xx causes C2 to bail out from the compilation * @library /test/lib - * @run driver compiler.print.CompileCommandMemLimit stop true + * @run driver compiler.print.CompileCommandMemLimit c2 stop */ package compiler.print; @@ -73,16 +73,12 @@ public class CompileCommandMemLimit { // Method for which we explicitly disable a limit on the command line. final static String METHOD3 = "method3"; - static boolean c2; - static boolean test_crash; + enum TestMode { crash, stop }; + enum CompilerType { c1, c2 }; public static void main(String[] args) throws Exception { - switch (args[0]) { - case "crash" : test_crash = true; break; - case "stop" : test_crash = false; break; - default: throw new RuntimeException("invalid argument"); - } - c2 = Boolean.parseBoolean(args[1]); + CompilerType ctyp = CompilerType.valueOf(args[0]); + TestMode mode = TestMode.valueOf(args[1]); List options = new ArrayList(); options.add("-Xcomp"); @@ -92,19 +88,40 @@ public class CompileCommandMemLimit { options.add("-XX:CompileCommand=compileonly," + getTestClass() + "::*"); // We want a final report - options.add("-XX:CompileCommand=MemStat,*.*,print"); + options.add("-XX:CompileCommand=MemStat," + getTestMethod(METHOD2) + ",print"); - // We limit method 2 to a very small limit that is guaranteed to trigger - options.add("-XX:CompileCommand=MemLimit," + getTestMethod(METHOD2) + ",4k" + (test_crash ? "~crash" : "")); + String suffix = mode == TestMode.crash ? "~crash" : ""; - // We disable any limit set on method 3 - options.add("-XX:CompileCommand=MemLimit," + getTestMethod(METHOD3) + ",0"); + // About the limit: + // + // In the debug JVM, for this test class, compilers will allocate (near the very end of the compilation) + // 32MB of arena memory. + // + // C1 will allocate them in a single step from RA, leaked until end of compilation. + // + // C2 will allocate them in two steps: first 2MB inside phase "testPhase1" in a temporary arena + // that will be gone by phase end. So, in the phase timeline these 2MB must show up as + // "significant temporary peak". + // In a second phase "testPhase2", we allocate 32MB from resource area, which is leaked until + // the end of the compilation. This means that these 32MB will show up as permanent memory + // increase in the per-phase-timeline. + // + // We then set the limit to 31MB (just shy of the 32MB we allocate), which should reliably trigger the mem limit. + // The 32MB are deliberately chosen to be large, because this will harden the test against normal allocation fluctuations + // (the methods are tiny, so compiling them should accrue normally only a few dozen KB). + // + // In the release JVM, we just use a very tiny memlimit that we are sure to hit every time. - if (c2) { + long limit = Platform.isDebugBuild() ? (1024 * 1024 * 31) : 4096; + + options.add("-XX:CompileCommand=MemLimit," + getTestMethod(METHOD2) + "," + limit + suffix); + + if (ctyp == CompilerType.c2) { options.add("-XX:-TieredCompilation"); } else { options.add("-XX:TieredStopAtLevel=1"); } + options.add(getTestClass()); OutputAnalyzer oa = ProcessTools.executeTestJava(options); @@ -114,14 +131,14 @@ public class CompileCommandMemLimit { String method1regex = testMethodNameForRegex(getTestMethod(METHOD1)); String method2regex = testMethodNameForRegex(getTestMethod(METHOD2)); String method3regex = testMethodNameForRegex(getTestMethod(METHOD3)); - String ct = c2 ? "c2" : "c1"; + String limitHitRegex = ctyp + " \\(\\d+\\) compiler/print/CompileCommandMemLimit\\$TestMain::method2.*: Hit MemLimit - limit: " + limit + " now: \\d+"; - if (test_crash) { + if (mode == TestMode.crash) { oa.shouldNotHaveExitValue(0); oa.shouldMatch("# *Internal Error.*"); // method 2 should have hit its tiny limit - oa.shouldMatch("# *fatal error: " + ct + " *" + method2regex + ".*: Hit MemLimit .*limit: 4096.*"); + oa.shouldMatch("# *fatal error: " + limitHitRegex); // none of the other ones should have hit a limit oa.shouldNotMatch(method1regex + ".*Hit MemLimit"); @@ -143,36 +160,28 @@ public class CompileCommandMemLimit { } else { oa.shouldHaveExitValue(0); - // In debug builds we have an inbuilt MemLimit. It is very high, so we don't expect it to fire in this test. - // But it will still show up in the final report. - String implicitMemoryLimit = Platform.isDebugBuild() ? "1024M" : "-"; - - // With C2, we print number of nodes, with C1 we don't - String numberNodesRegex = c2 ? "\\d+" : "-"; - // method 2 should have hit its tiny limit - oa.shouldMatch(ct + " " + method2regex + ".*: Hit MemLimit \\(limit: 4096 now: \\d+\\)"); + oa.shouldMatch(limitHitRegex); + + // Compilation should have been aborted and marked as oom + oa.shouldMatch(ctyp + " \\(\\d+\\) \\(oom\\) Arena usage " + method2regex + ".*\\d+.*"); // neither of the other ones should have hit a limit oa.shouldNotMatch(method1regex + ".*Hit MemLimit"); oa.shouldNotMatch(method3regex + ".*Hit MemLimit"); - - // Final report: - // Method 1 should show up as "ok" and with the default limit, e.g. - // total NA RA result #nodes limit time type #rc thread method - // 32728 0 32728 ok - 1024M 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J) - oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +" + numberNodesRegex + " +" + implicitMemoryLimit + " +.* +" + method1regex); - - // Method 2 should show up as "oom" and with its tiny limit, e.g. - // total NA RA result #nodes limit time type #rc thread method - // 32728 0 32728 oom - 4096B 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J) - oa.shouldMatch("\\d+ +\\d+ +\\d+ +oom +" + numberNodesRegex + " +4096B +.* +" + method2regex); - - // Method 3 should show up as "ok", and with no limit, even in debug builds, e.g. - // total NA RA result #nodes limit time type #rc thread method - // 32728 0 32728 ok - - 0.045 c1 1 0x000000011b019c10 compiler/print/CompileCommandMemLimit$TestMain::method1(()J) - oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +" + numberNodesRegex + " +- +.* +" + method3regex); } + + // In C2, analyze phase timeline and per-phase accumulation + if (ctyp == CompilerType.c2) { + oa.shouldMatch("--- Arena Usage by Arena Type and compilation phase, at arena usage peak of \\d+ ---"); + oa.shouldContain("--- Allocation timelime by phase ---"); + if (Platform.isDebugBuild()) { + oa.shouldMatch(".*testPhase2 +33554432 +33554432 +0 +0 +0 +0 +0.*"); + oa.shouldMatch(" +>\\d+ +testPhase1.*significant temporary peak: \\d+ \\(\\+2098136\\)"); + oa.shouldMatch(" +>\\d+ +testPhase2 +\\d+ +\\(\\+33554432\\).*"); + } + } + } // Test class that is invoked by the sub process diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java index 2dbf46fd040..733cb3d8513 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, 2024, Red Hat, Inc. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Red Hat, Inc. 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,11 +23,19 @@ */ /* - * @test - * @summary Checks that -XX:CompileCommand=PrintMemStat,... works - * @requires vm.compiler1.enabled | vm.compiler2.enabled + * @test id=c2 + * @summary Checks that -XX:CompileCommand=MemStat,...,print works with C2 + * @requires vm.compiler1.enabled & vm.compiler2.enabled * @library /test/lib - * @run driver compiler.print.CompileCommandPrintMemStat + * @run driver compiler.print.CompileCommandPrintMemStat c2 + */ + +/* + * @test id=c1 + * @summary Checks that -XX:CompileCommand=MemStat,...,print works with C1 + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @library /test/lib + * @run driver compiler.print.CompileCommandPrintMemStat c1 */ package compiler.print; @@ -44,22 +52,41 @@ public class CompileCommandPrintMemStat { final static String METHOD1 = "method1"; final static String METHOD2 = "method2"; - public static void main(String[] args) throws Exception { - test(METHOD1, METHOD2); - test(METHOD2, METHOD1); + enum CompType { + c1, c2 } - private static void test(String include, String exclude) throws Exception { + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Missing Args"); + } + CompType ctyp = CompType.valueOf(args[0]); + test(METHOD1, METHOD2, ctyp); + test(METHOD2, METHOD1, ctyp); + test(METHOD1, METHOD2, ctyp); + test(METHOD2, METHOD1, ctyp); + } + + private static void test(String include, String exclude, CompType ctyp) throws Exception { List options = new ArrayList(); options.add("-Xcomp"); - options.add("-XX:-Inline"); options.add("-XX:CompileCommand=compileonly," + getTestClass() + "::*"); + options.add("-XX:-Inline"); + if (ctyp.equals(CompType.c2)) { + options.add("-XX:-TieredCompilation"); + } else { + options.add("-XX:TieredStopAtLevel=1"); + } options.add("-XX:CompileCommand=MemStat," + getTestMethod(include) + ",print"); + options.add("-XX:+UnlockDiagnosticVMOptions"); + options.add("-XX:+PrintCompilerMemoryStatisticsAtExit"); + options.add(getTestClass()); OutputAnalyzer oa = ProcessTools.executeTestJava(options); + oa.reportDiagnosticSummary(); - // We expect two printouts for "PrintMemStat". A line at compilation time, and a line in a summary report + // We expect two printouts for "MemStat". A line at compilation time, and a line in a summary report // that is printed when we exit. Both use the typical ::name format but use / as separator and also // print the signature. String expectedNameIncl = getTestMethod(include) @@ -69,27 +96,39 @@ public class CompileCommandPrintMemStat { .replace('.', '/') .replace("$", "\\$"); - // Should see trace output when methods are compiled - oa.shouldHaveExitValue(0). - shouldMatch("Arena usage.*" + expectedNameIncl + ".*"). - shouldNotMatch("Arena usage.*" + expectedNameExcl + ".*"); + oa.shouldHaveExitValue(0); + if (ctyp == CompType.c1) { + // Example output for a C1 compilation output: + // c1 (885) (ok) Arena usage java/util/zip/ZipFile$Source::get((Ljava/io/File;ZLjava/util/zip/ZipCoder;)Ljava/util/zip/ZipFile$Source;): 752744 [ra 687288, cienv 65456] + oa.shouldMatch("c1.*Arena usage " + expectedNameIncl + ".*: \\d+.*"); + } - // Should see final report - // Looks like this: - // total Others RA HA NA result #nodes limit time type #rc thread method - // 523648 32728 490920 0 0 ok - - 0.250 c1 1 0x00007f4ec00d4ac0 java/lang/Class::descriptorString(()Ljava/lang/String;) - // or - // 1898600 853176 750872 0 294552 ok 934 - 1.501 c2 1 0x00007f4ec00d3330 java/lang/String::replace((CC)Ljava/lang/String;) - oa.shouldMatch("total.*method"); - oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameIncl + ".*"); + // In C2, analyze phase timeline and per-phase accumulation + if (ctyp == CompType.c2) { + oa.shouldMatch("c2.*Arena usage " + expectedNameIncl + ".*: \\d+.*"); + oa.shouldMatch("--- Arena Usage by Arena Type and compilation phase, at arena usage peak of \\d+ ---"); + oa.shouldContain("--- Allocation timelime by phase ---"); + if (Platform.isDebugBuild()) { + oa.shouldMatch(".*testPhase2 +33554432 +33554432 +0 +0 +0 +0 +0.*"); + oa.shouldMatch(" +>\\d+ +testPhase1.*significant temporary peak: \\d+ \\(\\+2098136\\)"); + oa.shouldMatch(" +>\\d+ +testPhase2 +\\d+ +\\(\\+33554432\\).*"); + } + } + + // We also print a final report to tty if print is enabled. Looks like this: + // + // Compilation Memory usage: + // ctyp total ra node comp type index reglive regsplit cienv other #nodes codesz result limit time id thread method + // c1 14104176 13776896 0 0 0 0 0 0 327280 0 - 0 oom 10240K 0,547 412 0x00007fb14c1fb640 jdk/internal/classfile/impl/StackMapGenerator::processBlock((Ljdk/internal/classfile/impl/RawBytecodeHelper;)Z) + // c2 5058384 4499056 262808 197352 0 0 0 0 32728 66440 293 1464 ok 10240K 0,200 191 0x00007fb14c1f9bb0 java/lang/StringLatin1::lastIndexOf(([BII)I) + oa.shouldMatch("\\s+ctyp\\s+total.*method.*"); + oa.shouldMatch("\\s+c(1|2)\\s+\\d+.*" + expectedNameIncl + ".*"); // In debug builds, we have a default memory limit enabled. That implies MemStat. Therefore we - // expect to see all methods, not just the one we specified on the command line. - if (Platform.isDebugBuild()) { - oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameExcl + ".*"); - } else { - oa.shouldNotMatch(".*" + expectedNameExcl + ".*"); + // may see the other method also. + if (!Platform.isDebugBuild()) { + oa.shouldNotContain(expectedNameExcl); } } From 4a51c61b2cfa396dace2ca21d819b5f363c9b6b5 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Mon, 3 Mar 2025 15:39:35 +0000 Subject: [PATCH 191/587] 8350567: NMT: update VMATree::register_mapping to copy the existing tag of the region Reviewed-by: jsjolen, stuefe --- src/hotspot/share/nmt/vmatree.cpp | 2 +- test/hotspot/gtest/nmt/test_vmatree.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 21aee26ca87..3352a6e5cd4 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -206,7 +206,7 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType } // Finally, we can register the new region [A, B)'s summary data. - SingleDiff& rescom = diff.tag[NMTUtil::tag_to_index(metadata.mem_tag)]; + SingleDiff& rescom = diff.tag[NMTUtil::tag_to_index(stA.out.mem_tag())]; if (state == StateType::Reserved) { rescom.reserve += B - A; } else if (state == StateType::Committed) { diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index 1a618604de6..80b5df50062 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -724,3 +724,19 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { } } } + +TEST_VM_F(NMTVMATreeTest, SummaryAccountingWhenUseFlagInplace) { + Tree tree; + VMATree::RegionData rd1(si[0], mtTest); + VMATree::RegionData rd2(si[1], mtNone); + tree.reserve_mapping(0, 100, rd1); + VMATree::SummaryDiff diff = tree.commit_mapping(0, 50, rd2, true); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + diff = tree.commit_mapping(60, 10, rd2, true); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(10, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + diff = tree.uncommit_mapping(0, 50, rd2); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(-50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); +} \ No newline at end of file From 67dfdfa6ea829fcd1ecac0df8211b591ad15f859 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 3 Mar 2025 15:53:47 +0000 Subject: [PATCH 192/587] 8350623: Fix -Wzero-as-null-pointer-constant warnings in nsk native test utilities Reviewed-by: coleenp --- .../jtreg/vmTestbase/nsk/share/native/native_thread.cpp | 6 +++++- test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.cpp | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.cpp index 089aab78bb5..1929864e0d0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.cpp @@ -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 @@ -98,7 +98,11 @@ void* procedure(void* t) { thread->started = 1; thread->status = thread->procedure(thread->context); thread->finished = 1; +#ifdef windows return 0; +#else // !windows + return nullptr; +#endif } /** diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.cpp index 736ddafdfaf..3da3858445b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.cpp @@ -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 @@ -109,7 +109,7 @@ int nsk_list_remove(const void *plist, int ind) { list_info->arr[i - 1] = list_info->arr[i]; } } - list_info->arr[--list_info->elements_count] = 0; + list_info->arr[--list_info->elements_count] = nullptr; return NSK_TRUE; } From c988d7d6476807bf71a977dc771017915b708ca3 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 3 Mar 2025 15:55:07 +0000 Subject: [PATCH 193/587] 8350767: Fix -Wzero-as-null-pointer-constant warnings in nsk jni stress tests Reviewed-by: coleenp --- .../nsk/stress/jni/libjnistress001.cpp | 6 +++--- .../nsk/stress/jni/libjnistress003.cpp | 18 +++++++++--------- .../nsk/stress/jni/libjnistress004.cpp | 10 +++++----- .../nsk/stress/jni/libjnistress006.cpp | 4 ++-- .../nsk/stress/jni/libjnistress007.cpp | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress001.cpp index 2a5c78488c3..0702f9e5c09 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress001.cpp @@ -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 @@ -77,7 +77,7 @@ Java_nsk_stress_jni_JNIter001_jnistress (JNIEnv *env, jobject jobj, jstring jstr for (j = 0; j < DIGESTLENGTH; j++) { digest[j] = 0; } - element->str[allocs] = env->GetStringUTFChars(jstr, 0); CE + element->str[allocs] = env->GetStringUTFChars(jstr, nullptr); CE if (strlen(element->str[allocs]) != (size_t) env->GetStringUTFLength(jstr)) { printf("Length is wrong in string No. %d\n", allocs); } else { @@ -177,7 +177,7 @@ Java_nsk_stress_jni_JNIter001_jnistress1(JNIEnv *env, jobject jobj, jstring jstr for (j = 0; j < DIGESTLENGTH; j++) { digest[j] = 0; } - javachars->str[index] = env->GetStringChars(jstr, 0); CE + javachars->str[index] = env->GetStringChars(jstr, nullptr); CE javachars->size[index] = env->GetStringUTFLength(jstr); CE elem_len = javachars->size[index]; len += elem_len; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress003.cpp index 4a261ff6aad..66e8e67d2e0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress003.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress003.cpp @@ -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 @@ -171,14 +171,14 @@ Java_nsk_stress_jni_JNIter003_jniBodyChangeArray (JNIEnv *env, jobject jobj, /* Take the elements from Java arrays into native buffers */ /* Use GetArrayElements */ - boolOrig = env->GetBooleanArrayElements((jbooleanArray) arrayOrig[BOOL], 0); CE - byteOrig = env->GetByteArrayElements((jbyteArray) arrayOrig[BYTE], 0); CE - charOrig = env->GetCharArrayElements((jcharArray) arrayOrig[CHAR], 0); CE - shortOrig = env->GetShortArrayElements((jshortArray) arrayOrig[SHORT], 0); CE - intOrig = env->GetIntArrayElements((jintArray) arrayOrig[INT], 0); CE - longOrig = env->GetLongArrayElements((jlongArray) arrayOrig[LONG], 0); CE - floatOrig = env->GetFloatArrayElements((jfloatArray) arrayOrig[FLOAT], 0); CE - doubleOrig = env->GetDoubleArrayElements((jdoubleArray) arrayOrig[DOUBLE], 0); CE + boolOrig = env->GetBooleanArrayElements((jbooleanArray) arrayOrig[BOOL], nullptr); CE + byteOrig = env->GetByteArrayElements((jbyteArray) arrayOrig[BYTE], nullptr); CE + charOrig = env->GetCharArrayElements((jcharArray) arrayOrig[CHAR], nullptr); CE + shortOrig = env->GetShortArrayElements((jshortArray) arrayOrig[SHORT], nullptr); CE + intOrig = env->GetIntArrayElements((jintArray) arrayOrig[INT], nullptr); CE + longOrig = env->GetLongArrayElements((jlongArray) arrayOrig[LONG], nullptr); CE + floatOrig = env->GetFloatArrayElements((jfloatArray) arrayOrig[FLOAT], nullptr); CE + doubleOrig = env->GetDoubleArrayElements((jdoubleArray) arrayOrig[DOUBLE], nullptr); CE /* Alloc some memory for cloned arrays buffers */ boolClone = (jboolean *)c_malloc(env, SIZE(BOOL) * sizeof(jboolean)); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress004.cpp b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress004.cpp index 8347d00da80..3e3b0ea1cdf 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress004.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress004.cpp @@ -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 @@ -47,13 +47,13 @@ Java_nsk_stress_jni_JNIter004_CheckSum (JNIEnv *env, jobject jobj, jstring jstr) digest[i] = 0; } str = (char *)c_malloc(env, len * sizeof(char)); - /* const char *threadName = env->GetStringUTFChars(jstr, 0); */ + /* const char *threadName = env->GetStringUTFChars(jstr, nullptr); */ CHECK(env->MonitorEnter(jobj)); if (upper == 0) { tmp = (jchar *) c_malloc(env, DIGESTLENGTH * sizeof(char)); } - critstr = env->GetStringCritical(jstr, 0); CE + critstr = env->GetStringCritical(jstr, nullptr); CE for (i = 0; i < len; i++) { str[i] = (char) critstr[i]; } @@ -101,7 +101,7 @@ Java_nsk_stress_jni_JNIter004_CheckCompare (JNIEnv *env, jobject jobj, jstring j return JNI_FALSE; } tmp = (jchar *)c_malloc(env, DIGESTLENGTH * sizeof(char)); - critstr = env->GetStringCritical(jstr, 0); CE + critstr = env->GetStringCritical(jstr, nullptr); CE for (i = 0; i < strlen; i++) { str[i] = (char) critstr[i]; } @@ -121,7 +121,7 @@ Java_nsk_stress_jni_JNIter004_CheckCompare (JNIEnv *env, jobject jobj, jstring j /* Compare */ /* env->MonitorEnter(jobj); */ - ch = (jchar *)env->GetPrimitiveArrayCritical(cArr, 0); CE + ch = (jchar *)env->GetPrimitiveArrayCritical(cArr, nullptr); CE printf("Comparing: "); for (i = 0; i < len; i++) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress006.cpp b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress006.cpp index c84685a50fe..5cb9b9385f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress006.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress006.cpp @@ -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 @@ extern "C" { JNIEXPORT jboolean JNICALL Java_nsk_stress_jni_JNIter006_refs (JNIEnv *env, jobject jobj, jobject tobj, jint LIMIT) { - static jobject *globRefsArray = 0; + static jobject *globRefsArray = nullptr; static int upper = 0; jclass clazz; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress007.cpp index 44c195cfd6b..8b3a0d41b1d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/libjnistress007.cpp @@ -32,7 +32,7 @@ Java_nsk_stress_jni_JNIter007_incCount (JNIEnv *env, jobject jobj, jstring name) jclass clazz; jfieldID fld; jint value; - const char *str = env->GetStringUTFChars(name, 0); CE + const char *str = env->GetStringUTFChars(name, nullptr); CE CHECK(env->MonitorEnter(jobj)); clazz = env->GetObjectClass(jobj); CE From 3602c8cfd805d2e5ae07685145b91bf2c20e255a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 3 Mar 2025 16:51:56 +0000 Subject: [PATCH 194/587] 8350955: Fix repetitions of the word "the" in runtime component comments Reviewed-by: coleenp --- src/hotspot/share/cds/metaspaceShared.cpp | 2 +- src/hotspot/share/runtime/objectMonitor.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 2e5ebff456e..9e9f9fd1d9e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -151,7 +151,7 @@ static bool shared_base_valid(char* shared_base) { // We check user input for SharedBaseAddress at dump time. // At CDS runtime, "shared_base" will be the (attempted) mapping start. It will also - // be the encoding base, since the the headers of archived base objects (and with Lilliput, + // be the encoding base, since the headers of archived base objects (and with Lilliput, // the prototype mark words) carry pre-computed narrow Klass IDs that refer to the mapping // start as base. // diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 94c4c242f82..29971d7b4f8 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -144,7 +144,7 @@ class ObjectMonitor : public CHeapObj { // ParkEvent of unblocker thread. static ParkEvent* _vthread_unparker_ParkEvent; - // Because of frequent access, the the metadata field is at offset zero (0). + // 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. From 7c187b5d81a653b87fc498101ad9e2d99b72efc6 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Mon, 3 Mar 2025 17:20:54 +0000 Subject: [PATCH 195/587] 8338737: Shenandoah: Reset marking bitmaps after the cycle Reviewed-by: wkemper --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 64 +++++++++++--- .../gc/shenandoah/shenandoahConcurrentGC.hpp | 5 ++ .../share/gc/shenandoah/shenandoahFullGC.cpp | 30 ++----- .../gc/shenandoah/shenandoahGeneration.cpp | 85 +++++++++---------- .../gc/shenandoah/shenandoahGeneration.hpp | 1 + .../gc/shenandoah/shenandoahHeapRegion.cpp | 5 +- .../gc/shenandoah/shenandoahHeapRegion.hpp | 14 +++ .../gc/shenandoah/shenandoahPhaseTimings.hpp | 1 + 8 files changed, 119 insertions(+), 86 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 5327c9d230e..316904f8bd0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -241,6 +241,12 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { if (heap->mode()->is_generational()) { ShenandoahGenerationalHeap::heap()->complete_concurrent_cycle(); } + + // Instead of always resetting immediately before the start of a new GC, we can often reset at the end of the + // previous GC. This allows us to start the next GC cycle more quickly after a trigger condition is detected, + // reducing the likelihood that GC will degenerate. + entry_reset_after_collect(); + return true; } @@ -363,17 +369,6 @@ void ShenandoahConcurrentGC::entry_reset() { msg); op_reset(); } - - if (_do_old_gc_bootstrap) { - static const char* msg = "Concurrent reset (Old)"; - ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_old); - ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(), - ShenandoahWorkerPolicy::calc_workers_for_conc_reset(), - msg); - EventMark em("%s", msg); - - heap->old_generation()->prepare_gc(); - } } void ShenandoahConcurrentGC::entry_scan_remembered_set() { @@ -583,12 +578,29 @@ void ShenandoahConcurrentGC::entry_cleanup_complete() { op_cleanup_complete(); } +void ShenandoahConcurrentGC::entry_reset_after_collect() { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + const char* msg = conc_reset_after_collect_event_message(); + ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_reset_after_collect); + EventMark em("%s", msg); + + op_reset_after_collect(); +} + void ShenandoahConcurrentGC::op_reset() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); if (ShenandoahPacing) { heap->pacer()->setup_for_reset(); } - _generation->prepare_gc(); + // If it is old GC bootstrap cycle, always clear bitmap for global gen + // to ensure bitmap for old gen is clear for old GC cycle after this. + if (_do_old_gc_bootstrap) { + assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot reset old without making it parsable"); + heap->global_generation()->prepare_gc(); + } else { + _generation->prepare_gc(); + } } class ShenandoahInitMarkUpdateRegionStateClosure : public ShenandoahHeapRegionClosure { @@ -1211,6 +1223,26 @@ void ShenandoahConcurrentGC::op_cleanup_complete() { ShenandoahHeap::heap()->recycle_trash(); } +void ShenandoahConcurrentGC::op_reset_after_collect() { + ShenandoahWorkerScope scope(ShenandoahHeap::heap()->workers(), + ShenandoahWorkerPolicy::calc_workers_for_conc_reset(), + "reset after collection."); + + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + if (heap->mode()->is_generational()) { + // Resetting bitmaps of young gen when bootstrap old GC or there is preempted old GC + // causes crash due to remembered set violation, hence condition is added to fix the crash. + // Assuming bitmaps of young gen are not used at all after the cycle, the crash should not + // have happend, it seems to tickle a bug in remembered set scan. Root causing and fixing of the bug + // will be tracked via ticket https://bugs.openjdk.org/browse/JDK-8347371 + if (!_do_old_gc_bootstrap && !heap->is_concurrent_old_mark_in_progress()) { + heap->young_generation()->reset_mark_bitmap(); + } + } else { + _generation->reset_mark_bitmap(); + } +} + bool ShenandoahConcurrentGC::check_cancellation_and_abort(ShenandoahDegenPoint point) { if (ShenandoahHeap::heap()->cancelled_gc()) { _degen_point = point; @@ -1260,6 +1292,14 @@ const char* ShenandoahConcurrentGC::conc_reset_event_message() const { } } +const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() const { + if (ShenandoahHeap::heap()->unload_classes()) { + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", " (unload classes)"); + } else { + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Concurrent reset after collect", ""); + } +} + const char* ShenandoahConcurrentGC::final_roots_event_message() const { if (ShenandoahHeap::heap()->unload_classes()) { SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Final Roots", " (unload classes)"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index b4c858bb245..81e7e943af3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -118,10 +118,14 @@ protected: void op_final_update_refs(); void op_final_roots(); void op_cleanup_complete(); + void op_reset_after_collect(); // Check GC cancellation and abort concurrent GC bool check_cancellation_and_abort(ShenandoahDegenPoint point); + // Called when concurrent GC succeeds. + void entry_reset_after_collect(); + private: void start_mark(); @@ -134,6 +138,7 @@ private: const char* final_roots_event_message() const; const char* conc_mark_event_message() const; const char* conc_reset_event_message() const; + const char* conc_reset_after_collect_event_message() const; const char* conc_weak_refs_event_message() const; const char* conc_weak_roots_event_message() const; const char* conc_cleanup_event_message() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 474838c3bb3..91a71adbe1c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -197,16 +197,11 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { update_roots(true /*full_gc*/); } - // d. Reset the bitmaps for new marking - heap->global_generation()->reset_mark_bitmap(); - assert(heap->marking_context()->is_bitmap_clear(), "sanity"); - assert(!heap->global_generation()->is_mark_complete(), "sanity"); - - // e. Abandon reference discovery and clear all discovered references. + // d. Abandon reference discovery and clear all discovered references. ShenandoahReferenceProcessor* rp = heap->global_generation()->ref_processor(); rp->abandon_partial_discovery(); - // f. Sync pinned region status from the CP marks + // e. Sync pinned region status from the CP marks heap->sync_pinned_region_status(); if (heap->mode()->is_generational()) { @@ -287,30 +282,15 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { } } -class ShenandoahPrepareForMarkClosure: public ShenandoahHeapRegionClosure { -private: - ShenandoahMarkingContext* const _ctx; - -public: - ShenandoahPrepareForMarkClosure() : _ctx(ShenandoahHeap::heap()->marking_context()) {} - - void heap_region_do(ShenandoahHeapRegion *r) override { - _ctx->capture_top_at_mark_start(r); - r->clear_live_data(); - } - - bool is_thread_safe() override { return true; } -}; - void ShenandoahFullGC::phase1_mark_heap() { GCTraceTime(Info, gc, phases) time("Phase 1: Mark live objects", _gc_timer); ShenandoahGCPhase mark_phase(ShenandoahPhaseTimings::full_gc_mark); ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahPrepareForMarkClosure prepare_for_mark; - ShenandoahExcludeRegionClosure cl(&prepare_for_mark); - heap->parallel_heap_region_iterate(&cl); + heap->global_generation()->reset_mark_bitmap(); + assert(heap->marking_context()->is_bitmap_clear(), "sanity"); + assert(!heap->global_generation()->is_mark_complete(), "sanity"); heap->set_unload_classes(heap->global_generation()->heuristics()->can_unload_classes()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index d00d5168ee7..a6f67b809d7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -41,53 +41,44 @@ #include "utilities/quickSort.hpp" - -class ShenandoahResetUpdateRegionStateClosure : public ShenandoahHeapRegionClosure { +template +class ShenandoahResetBitmapClosure final : public ShenandoahHeapRegionClosure { private: - ShenandoahHeap* _heap; - ShenandoahMarkingContext* const _ctx; -public: - ShenandoahResetUpdateRegionStateClosure() : - _heap(ShenandoahHeap::heap()), - _ctx(_heap->marking_context()) {} + ShenandoahHeap* _heap; + ShenandoahMarkingContext* _ctx; - void heap_region_do(ShenandoahHeapRegion* r) override { - if (r->is_active()) { - // Reset live data and set TAMS optimistically. We would recheck these under the pause - // anyway to capture any updates that happened since now. - _ctx->capture_top_at_mark_start(r); - r->clear_live_data(); +public: + explicit ShenandoahResetBitmapClosure() : + ShenandoahHeapRegionClosure(), _heap(ShenandoahHeap::heap()), _ctx(_heap->marking_context()) {} + + void heap_region_do(ShenandoahHeapRegion* region) override { + assert(!_heap->is_uncommit_in_progress(), "Cannot uncommit bitmaps while resetting them."); + if (PREPARE_FOR_CURRENT_CYCLE) { + if (region->need_bitmap_reset() && _heap->is_bitmap_slice_committed(region)) { + _ctx->clear_bitmap(region); + } else { + region->set_needs_bitmap_reset(); + } + // Capture Top At Mark Start for this generation. + if (FULL_GC || region->is_active()) { + // Reset live data and set TAMS optimistically. We would recheck these under the pause + // anyway to capture any updates that happened since now. + _ctx->capture_top_at_mark_start(region); + region->clear_live_data(); + } + } else { + if (_heap->is_bitmap_slice_committed(region)) { + _ctx->clear_bitmap(region); + region->unset_needs_bitmap_reset(); + } else { + region->set_needs_bitmap_reset(); + } } } bool is_thread_safe() override { return true; } }; -class ShenandoahResetBitmapTask : public WorkerTask { -private: - ShenandoahRegionIterator _regions; - ShenandoahGeneration* _generation; - -public: - ShenandoahResetBitmapTask(ShenandoahGeneration* generation) : - WorkerTask("Shenandoah Reset Bitmap"), _generation(generation) {} - - void work(uint worker_id) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - assert(!heap->is_uncommit_in_progress(), "Cannot uncommit bitmaps while resetting them."); - ShenandoahHeapRegion* region = _regions.next(); - ShenandoahMarkingContext* const ctx = heap->marking_context(); - while (region != nullptr) { - auto const affiliation = region->affiliation(); - bool needs_reset = affiliation == FREE || _generation->contains(affiliation); - if (needs_reset && heap->is_bitmap_slice_committed(region)) { - ctx->clear_bitmap(region); - } - region = _regions.next(); - } - } -}; - // Copy the write-version of the card-table into the read-version, clearing the // write-copy. class ShenandoahMergeWriteTable: public ShenandoahHeapRegionClosure { @@ -225,15 +216,20 @@ void ShenandoahGeneration::log_status(const char *msg) const { PROPERFMTARGS(v_soft_max_capacity), PROPERFMTARGS(v_max_capacity), PROPERFMTARGS(v_available)); } +template void ShenandoahGeneration::reset_mark_bitmap() { ShenandoahHeap* heap = ShenandoahHeap::heap(); heap->assert_gc_workers(heap->workers()->active_workers()); set_mark_incomplete(); - ShenandoahResetBitmapTask task(this); - heap->workers()->run_task(&task); + ShenandoahResetBitmapClosure closure; + parallel_heap_region_iterate_free(&closure); } +// Explicit specializations +template void ShenandoahGeneration::reset_mark_bitmap(); +template void ShenandoahGeneration::reset_mark_bitmap(); +template void ShenandoahGeneration::reset_mark_bitmap(); // The ideal is to swap the remembered set so the safepoint effort is no more than a few pointer manipulations. // However, limitations in the implementation of the mutator write-barrier make it difficult to simply change the @@ -265,12 +261,7 @@ void ShenandoahGeneration::merge_write_table() { } void ShenandoahGeneration::prepare_gc() { - - reset_mark_bitmap(); - - // Capture Top At Mark Start for this generation (typically young) and reset mark bitmap. - ShenandoahResetUpdateRegionStateClosure cl; - parallel_heap_region_iterate_free(&cl); + reset_mark_bitmap(); } void ShenandoahGeneration::parallel_heap_region_iterate_free(ShenandoahHeapRegionClosure* cl) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 2f1102edbd7..1dc777777aa 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -159,6 +159,7 @@ private: void log_status(const char* msg) const; // Used directly by FullGC + template void reset_mark_bitmap(); // Used by concurrent and degenerated GC to reset remembered set. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 42237a0ab06..2c70cecf705 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -76,10 +76,11 @@ ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool c _live_data(0), _critical_pins(0), _update_watermark(start), - _age(0) + _age(0), #ifdef SHENANDOAH_CENSUS_NOISE - , _youth(0) + _youth(0), #endif // SHENANDOAH_CENSUS_NOISE + _needs_bitmap_reset(false) { assert(Universe::on_page_boundary(_bottom) && Universe::on_page_boundary(_end), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 3dc8febbad4..4c99364bc6e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -266,6 +266,8 @@ private: ShenandoahSharedFlag _recycling; // Used to indicate that the region is being recycled; see try_recycle*(). + bool _needs_bitmap_reset; + public: ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed); @@ -477,6 +479,18 @@ public: CENSUS_NOISE(void clear_youth() { _youth = 0; }) + inline bool need_bitmap_reset() const { + return _needs_bitmap_reset; + } + + inline void set_needs_bitmap_reset() { + _needs_bitmap_reset = true; + } + + inline void unset_needs_bitmap_reset() { + _needs_bitmap_reset = false; + } + private: void decrement_humongous_waste() const; void do_commit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index eab1e279b0f..20c59cce69b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -50,6 +50,7 @@ class outputStream; #define SHENANDOAH_PHASE_DO(f) \ f(conc_reset, "Concurrent Reset") \ + f(conc_reset_after_collect, "Concurrent Reset After Collect") \ f(conc_reset_old, "Concurrent Reset (OLD)") \ f(init_mark_gross, "Pause Init Mark (G)") \ f(init_mark, "Pause Init Mark (N)") \ From bb70896e356536477cfb770096fb769485edc55b Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 3 Mar 2025 17:36:31 +0000 Subject: [PATCH 196/587] 8350903: Remove explicit libjvm.so dependency for libVThreadEventTest Reviewed-by: dholmes, alanb --- make/test/JtregNativeHotspot.gmk | 2 -- .../vthread/VThreadEventTest/libVThreadEventTest.cpp | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk index 2ee26b422e0..31d2c522387 100644 --- a/make/test/JtregNativeHotspot.gmk +++ b/make/test/JtregNativeHotspot.gmk @@ -882,7 +882,6 @@ ifeq ($(call isTargetOs, windows), true) BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libMonitorWithDeadObjectTest.c libTestPsig.c exeGetCreatedJavaVMs.c libTestUnloadedClass.cpp BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libnativeStack := java.base:libjvm - BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libVThreadEventTest := java.base:libjvm else BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libbootclssearch_agent += -lpthread BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libsystemclssearch_agent += -lpthread @@ -1522,7 +1521,6 @@ else BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMonitorWithDeadObjectTest += -lpthread BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libTestUnloadedClass += -lpthread - BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libVThreadEventTest := java.base:libjvm BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -lpthread BUILD_HOTSPOT_JTREG_EXECUTABLES_JDK_LIBS_exeGetCreatedJavaVMs := java.base:libjvm diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/libVThreadEventTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/libVThreadEventTest.cpp index 7d898bcab25..b9db8b9cc93 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/libVThreadEventTest.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/libVThreadEventTest.cpp @@ -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 @@ -127,7 +127,6 @@ Agent_OnAttach(JavaVM *vm, char *options, void *reserved) { jvmtiCapabilities caps; jvmtiError err; JNIEnv *env; - jsize nVMs; jint res; jclass clazz; jmethodID mid; @@ -166,12 +165,6 @@ Agent_OnAttach(JavaVM *vm, char *options, void *reserved) { // call VThreadEventTest.agentStarted to notify test that agent has started - res = JNI_GetCreatedJavaVMs(&vm, 1, &nVMs); - if (res != JNI_OK) { - LOG("JNI_GetCreatedJavaVMs failed: %d\n", res); - return JNI_ERR; - } - res = vm->GetEnv((void **) &env, JNI_VERSION_21); if (res != JNI_OK) { LOG("GetEnv failed: %d\n", res); From 79880e56375a1c17ec6ad29bb0ab01868bc956ff Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 3 Mar 2025 18:28:28 +0000 Subject: [PATCH 197/587] 8351033: RISC-V: TestFloat16ScalarOperations asserts with offset (4210) is too large to be patched in one beq/bge/bgeu/blt/bltu/bne instruction! Reviewed-by: fyang --- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index e52cf7565be..f145eb879df 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2287,7 +2287,7 @@ void C2_MacroAssembler::float16_to_float(FloatRegister dst, Register src, Regist mv(t0, 0x7c00); andr(tmp, src, t0); // jump to stub processing NaN and Inf cases. - beq(t0, tmp, stub->entry()); + beq(t0, tmp, stub->entry(), true); // non-NaN or non-Inf cases, just use built-in instructions. fmv_h_x(dst, src); @@ -2330,7 +2330,7 @@ void C2_MacroAssembler::float_to_float16(Register dst, FloatRegister src, FloatR // replace fclass with feq as performance optimization. feq_s(t0, src, src); // jump to stub processing NaN cases. - beqz(t0, stub->entry()); + beqz(t0, stub->entry(), true); // non-NaN cases, just use built-in instructions. fcvt_h_s(ftmp, src); @@ -2391,7 +2391,7 @@ void C2_MacroAssembler::float16_to_float_v(VectorRegister dst, VectorRegister sr vfwcvt_f_f_v(dst, src); // jump to stub processing NaN and Inf cases if there is any of them in the vector-wide. - bnez(t0, stub->entry()); + bnez(t0, stub->entry(), true); bind(stub->continuation()); } @@ -2445,7 +2445,7 @@ void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister sr vfncvt_f_f_w(dst, src); // jump to stub processing NaN cases. - bnez(t0, stub->entry()); + bnez(t0, stub->entry(), true); bind(stub->continuation()); } From e1fc14fa17e78fef712b5635ee53d10d6d2bb50e Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 3 Mar 2025 18:29:36 +0000 Subject: [PATCH 198/587] 8350940: RISC-V: remove unnecessary assert_different_registers in minmax_fp Reviewed-by: fyang --- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 3 --- src/hotspot/cpu/riscv/riscv.ad | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index f145eb879df..e6bb7c46624 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2135,9 +2135,6 @@ void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Regis // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, bool is_double, bool is_min) { - assert_different_registers(dst, src1); - assert_different_registers(dst, src2); - Label Done, Compare; is_double ? fclass_d(t0, src1) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index b8660afb5fd..a4da786f02e 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -7287,7 +7287,7 @@ instruct nmaddD_reg_reg(fRegD dst, fRegD src1, fRegD src2, fRegD src3) %{ // Math.max(FF)F instruct maxF_reg_reg(fRegF dst, fRegF src1, fRegF src2, rFlagsReg cr) %{ match(Set dst (MaxF src1 src2)); - effect(TEMP_DEF dst, KILL cr); + effect(KILL cr); format %{ "maxF $dst, $src1, $src2" %} @@ -7303,7 +7303,7 @@ instruct maxF_reg_reg(fRegF dst, fRegF src1, fRegF src2, rFlagsReg cr) %{ // Math.min(FF)F instruct minF_reg_reg(fRegF dst, fRegF src1, fRegF src2, rFlagsReg cr) %{ match(Set dst (MinF src1 src2)); - effect(TEMP_DEF dst, KILL cr); + effect(KILL cr); format %{ "minF $dst, $src1, $src2" %} @@ -7319,7 +7319,7 @@ instruct minF_reg_reg(fRegF dst, fRegF src1, fRegF src2, rFlagsReg cr) %{ // Math.max(DD)D instruct maxD_reg_reg(fRegD dst, fRegD src1, fRegD src2, rFlagsReg cr) %{ match(Set dst (MaxD src1 src2)); - effect(TEMP_DEF dst, KILL cr); + effect(KILL cr); format %{ "maxD $dst, $src1, $src2" %} @@ -7335,7 +7335,7 @@ instruct maxD_reg_reg(fRegD dst, fRegD src1, fRegD src2, rFlagsReg cr) %{ // Math.min(DD)D instruct minD_reg_reg(fRegD dst, fRegD src1, fRegD src2, rFlagsReg cr) %{ match(Set dst (MinD src1 src2)); - effect(TEMP_DEF dst, KILL cr); + effect(KILL cr); format %{ "minD $dst, $src1, $src2" %} From f53de9208cf5f841ddf80ef9c6073fa61f68fa59 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 3 Mar 2025 18:30:43 +0000 Subject: [PATCH 199/587] 8350931: RISC-V: remove unnecessary src register for fp_sqrt_d/f Reviewed-by: fyang --- src/hotspot/cpu/riscv/riscv.ad | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index a4da786f02e..00ebeabe3e2 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -4097,21 +4097,19 @@ pipe_class fp_div_d(fRegD dst, fRegD src1, fRegD src2) FPU : S5; %} -pipe_class fp_sqrt_s(fRegF dst, fRegF src1, fRegF src2) +pipe_class fp_sqrt_s(fRegF dst, fRegF src) %{ single_instruction; - src1 : S1(read); - src2 : S2(read); + src : S1(read); dst : S5(write); DECODE : ID; FPU : S5; %} -pipe_class fp_sqrt_d(fRegD dst, fRegD src1, fRegD src2) +pipe_class fp_sqrt_d(fRegD dst, fRegD src) %{ single_instruction; - src1 : S1(read); - src2 : S2(read); + src : S1(read); dst : S5(write); DECODE : ID; FPU : S5; From e470f474ee2176eecc211ec8e99cccc941104c68 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 3 Mar 2025 18:31:56 +0000 Subject: [PATCH 200/587] 8350095: RISC-V: Refactor string_compare Reviewed-by: fyang --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 335 ++++++++++-------- .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 9 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 32 +- .../string/TestStringIntrinsics.java | 1 + 4 files changed, 207 insertions(+), 170 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index e6bb7c46624..dc33691586b 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1382,15 +1382,183 @@ void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register ne bind(DONE); } +// Compare longwords +void C2_MacroAssembler::string_compare_long_same_encoding(Register result, Register str1, Register str2, + const bool isLL, Register cnt1, Register cnt2, + Register tmp1, Register tmp2, Register tmp3, + const int STUB_THRESHOLD, Label *STUB, Label *SHORT_STRING, Label *DONE) { + Label TAIL_CHECK, TAIL, NEXT_WORD, DIFFERENCE; + + const int base_offset = isLL ? arrayOopDesc::base_offset_in_bytes(T_BYTE) + : arrayOopDesc::base_offset_in_bytes(T_CHAR); + assert((base_offset % (UseCompactObjectHeaders ? 4 : + (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + + const int minCharsInWord = isLL ? wordSize : wordSize / 2; + + // load first parts of strings and finish initialization while loading + beq(str1, str2, *DONE); + // Alignment + if (AvoidUnalignedAccesses && (base_offset % 8) != 0) { + lwu(tmp1, Address(str1)); + lwu(tmp2, Address(str2)); + bne(tmp1, tmp2, DIFFERENCE); + addi(str1, str1, 4); + addi(str2, str2, 4); + subi(cnt2, cnt2, minCharsInWord / 2); + + // A very short string + mv(t0, minCharsInWord); + ble(cnt2, t0, *SHORT_STRING); + } +#ifdef ASSERT + if (AvoidUnalignedAccesses) { + Label align_ok; + orr(t0, str1, str2); + andi(t0, t0, 0x7); + beqz(t0, align_ok); + stop("bad alignment"); + bind(align_ok); + } +#endif + // load 8 bytes once to compare + ld(tmp1, Address(str1)); + ld(tmp2, Address(str2)); + mv(t0, STUB_THRESHOLD); + bge(cnt2, t0, *STUB); + subi(cnt2, cnt2, minCharsInWord); + beqz(cnt2, TAIL_CHECK); + // convert cnt2 from characters to bytes + if (!isLL) { + slli(cnt2, cnt2, 1); + } + add(str2, str2, cnt2); + add(str1, str1, cnt2); + sub(cnt2, zr, cnt2); + addi(cnt2, cnt2, 8); + bne(tmp1, tmp2, DIFFERENCE); + bgez(cnt2, TAIL); + + // main loop + bind(NEXT_WORD); + // 8-byte aligned loads when AvoidUnalignedAccesses is enabled + add(t0, str1, cnt2); + ld(tmp1, Address(t0)); + add(t0, str2, cnt2); + ld(tmp2, Address(t0)); + addi(cnt2, cnt2, 8); + bne(tmp1, tmp2, DIFFERENCE); + bltz(cnt2, NEXT_WORD); + + bind(TAIL); + load_long_misaligned(tmp1, Address(str1), tmp3, isLL ? 1 : 2); + load_long_misaligned(tmp2, Address(str2), tmp3, isLL ? 1 : 2); + + bind(TAIL_CHECK); + beq(tmp1, tmp2, *DONE); + + // Find the first different characters in the longwords and + // compute their difference. + bind(DIFFERENCE); + xorr(tmp3, tmp1, tmp2); + // count bits of trailing zero chars + ctzc_bits(result, tmp3, isLL); + srl(tmp1, tmp1, result); + srl(tmp2, tmp2, result); + if (isLL) { + zext(tmp1, tmp1, 8); + zext(tmp2, tmp2, 8); + } else { + zext(tmp1, tmp1, 16); + zext(tmp2, tmp2, 16); + } + sub(result, tmp1, tmp2); + + j(*DONE); +} + +// Compare longwords +void C2_MacroAssembler::string_compare_long_different_encoding(Register result, Register str1, Register str2, + bool isLU, Register cnt1, Register cnt2, + Register tmp1, Register tmp2, Register tmp3, + const int STUB_THRESHOLD, Label *STUB, Label *DONE) { + Label TAIL, NEXT_WORD, DIFFERENCE; + + const int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + assert((base_offset % (UseCompactObjectHeaders ? 4 : + (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + + Register strL = isLU ? str1 : str2; + Register strU = isLU ? str2 : str1; + Register tmpL = tmp1, tmpU = tmp2; + + // load first parts of strings and finish initialization while loading + mv(t0, STUB_THRESHOLD); + bge(cnt2, t0, *STUB); + lwu(tmpL, Address(strL)); + load_long_misaligned(tmpU, Address(strU), tmp3, (base_offset % 8) != 0 ? 4 : 8); + subi(cnt2, cnt2, 4); + add(strL, strL, cnt2); + sub(cnt1, zr, cnt2); + slli(cnt2, cnt2, 1); + add(strU, strU, cnt2); + inflate_lo32(tmp3, tmpL); + mv(tmpL, tmp3); + sub(cnt2, zr, cnt2); + addi(cnt1, cnt1, 4); + addi(cnt2, cnt2, 8); + bne(tmpL, tmpU, DIFFERENCE); + bgez(cnt2, TAIL); + + // main loop + bind(NEXT_WORD); + add(t0, strL, cnt1); + lwu(tmpL, Address(t0)); + add(t0, strU, cnt2); + load_long_misaligned(tmpU, Address(t0), tmp3, (base_offset % 8) != 0 ? 4 : 8); + addi(cnt1, cnt1, 4); + inflate_lo32(tmp3, tmpL); + mv(tmpL, tmp3); + addi(cnt2, cnt2, 8); + bne(tmpL, tmpU, DIFFERENCE); + bltz(cnt2, NEXT_WORD); + + bind(TAIL); + load_int_misaligned(tmpL, Address(strL), tmp3, false); + load_long_misaligned(tmpU, Address(strU), tmp3, 2); + inflate_lo32(tmp3, tmpL); + mv(tmpL, tmp3); + + beq(tmpL, tmpU, *DONE); + + // Find the first different characters in the longwords and + // compute their difference. + bind(DIFFERENCE); + xorr(tmp3, tmpL, tmpU); + // count bits of trailing zero chars + ctzc_bits(result, tmp3); + srl(tmpL, tmpL, result); + srl(tmpU, tmpU, result); + zext(tmpL, tmpL, 16); + zext(tmpU, tmpU, 16); + if (isLU) { + sub(result, tmpL, tmpU); + } else { + sub(result, tmpU, tmpL); + } + + j(*DONE); +} + // Compare strings. void C2_MacroAssembler::string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2, Register tmp3, int ae) { - Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, TAIL, STUB, - DIFFERENCE, NEXT_WORD, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT, - SHORT_LOOP_START, TAIL_CHECK, L; + Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, STUB, + SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT, + SHORT_LOOP_START, L; const int STUB_THRESHOLD = 64 + 8; bool isLL = ae == StrIntrinsicNode::LL; @@ -1409,14 +1577,6 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, load_chr_insn str1_load_chr = str1_isL ? (load_chr_insn)&MacroAssembler::lbu : (load_chr_insn)&MacroAssembler::lhu; load_chr_insn str2_load_chr = str2_isL ? (load_chr_insn)&MacroAssembler::lbu : (load_chr_insn)&MacroAssembler::lhu; - int base_offset1 = arrayOopDesc::base_offset_in_bytes(T_BYTE); - int base_offset2 = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - assert((base_offset1 % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); - assert((base_offset2 % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); - BLOCK_COMMENT("string_compare {"); // Bizarrely, the counts are passed in bytes, regardless of whether they @@ -1434,154 +1594,23 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, mv(cnt2, cnt1); bind(L); - // Load 4 bytes once to compare for alignment before main loop. Note that this - // is only possible for LL/UU case. We need to resort to load_long_misaligned - // for both LU and UL cases. - if (str1_isL == str2_isL) { // LL or UU - beq(str1, str2, DONE); - int base_offset = isLL ? base_offset1 : base_offset2; - if (AvoidUnalignedAccesses && (base_offset % 8) != 0) { - mv(t0, minCharsInWord / 2); - ble(cnt2, t0, SHORT_STRING); - lwu(tmp1, Address(str1)); - lwu(tmp2, Address(str2)); - bne(tmp1, tmp2, DIFFERENCE); - addi(str1, str1, 4); - addi(str2, str2, 4); - subi(cnt2, cnt2, minCharsInWord / 2); - } - } - // A very short string mv(t0, minCharsInWord); ble(cnt2, t0, SHORT_STRING); // Compare longwords - // load first parts of strings and finish initialization while loading { if (str1_isL == str2_isL) { // LL or UU -#ifdef ASSERT - if (AvoidUnalignedAccesses) { - Label align_ok; - orr(t0, str1, str2); - andi(t0, t0, 0x7); - beqz(t0, align_ok); - stop("bad alignment"); - bind(align_ok); - } -#endif - // load 8 bytes once to compare - ld(tmp1, Address(str1)); - ld(tmp2, Address(str2)); - mv(t0, STUB_THRESHOLD); - bge(cnt2, t0, STUB); - subi(cnt2, cnt2, minCharsInWord); - beqz(cnt2, TAIL_CHECK); - // convert cnt2 from characters to bytes - if (!str1_isL) { - slli(cnt2, cnt2, 1); - } - add(str2, str2, cnt2); - add(str1, str1, cnt2); - sub(cnt2, zr, cnt2); - } else if (isLU) { // LU case - mv(t0, STUB_THRESHOLD); - bge(cnt2, t0, STUB); - lwu(tmp1, Address(str1)); - load_long_misaligned(tmp2, Address(str2), tmp3, (base_offset2 % 8) != 0 ? 4 : 8); - subi(cnt2, cnt2, 4); - add(str1, str1, cnt2); - sub(cnt1, zr, cnt2); - slli(cnt2, cnt2, 1); - add(str2, str2, cnt2); - inflate_lo32(tmp3, tmp1); - mv(tmp1, tmp3); - sub(cnt2, zr, cnt2); - addi(cnt1, cnt1, 4); - } else { // UL case - mv(t0, STUB_THRESHOLD); - bge(cnt2, t0, STUB); - load_long_misaligned(tmp1, Address(str1), tmp3, (base_offset2 % 8) != 0 ? 4 : 8); - lwu(tmp2, Address(str2)); - subi(cnt2, cnt2, 4); - slli(t0, cnt2, 1); - sub(cnt1, zr, t0); - add(str1, str1, t0); - add(str2, str2, cnt2); - inflate_lo32(tmp3, tmp2); - mv(tmp2, tmp3); - sub(cnt2, zr, cnt2); - addi(cnt1, cnt1, 8); + string_compare_long_same_encoding(result, + str1, str2, isLL, + cnt1, cnt2, tmp1, tmp2, tmp3, + STUB_THRESHOLD, &STUB, &SHORT_STRING, &DONE); + } else { // LU or UL + string_compare_long_different_encoding(result, + str1, str2, isLU, + cnt1, cnt2, tmp1, tmp2, tmp3, + STUB_THRESHOLD, &STUB, &DONE); } - addi(cnt2, cnt2, isUL ? 4 : 8); - bne(tmp1, tmp2, DIFFERENCE); - bgez(cnt2, TAIL); - - // main loop - bind(NEXT_WORD); - if (str1_isL == str2_isL) { // LL or UU - // 8-byte aligned loads when AvoidUnalignedAccesses is enabled - add(t0, str1, cnt2); - ld(tmp1, Address(t0)); - add(t0, str2, cnt2); - ld(tmp2, Address(t0)); - addi(cnt2, cnt2, 8); - } else if (isLU) { // LU case - add(t0, str1, cnt1); - lwu(tmp1, Address(t0)); - add(t0, str2, cnt2); - load_long_misaligned(tmp2, Address(t0), tmp3, (base_offset2 % 8) != 0 ? 4 : 8); - addi(cnt1, cnt1, 4); - inflate_lo32(tmp3, tmp1); - mv(tmp1, tmp3); - addi(cnt2, cnt2, 8); - } else { // UL case - add(t0, str2, cnt2); - lwu(tmp2, Address(t0)); - add(t0, str1, cnt1); - load_long_misaligned(tmp1, Address(t0), tmp3, (base_offset2 % 8) != 0 ? 4 : 8); - inflate_lo32(tmp3, tmp2); - mv(tmp2, tmp3); - addi(cnt1, cnt1, 8); - addi(cnt2, cnt2, 4); - } - bne(tmp1, tmp2, DIFFERENCE); - bltz(cnt2, NEXT_WORD); - bind(TAIL); - if (str1_isL == str2_isL) { // LL or UU - load_long_misaligned(tmp1, Address(str1), tmp3, isLL ? 1 : 2); - load_long_misaligned(tmp2, Address(str2), tmp3, isLL ? 1 : 2); - } else if (isLU) { // LU case - load_int_misaligned(tmp1, Address(str1), tmp3, false); - load_long_misaligned(tmp2, Address(str2), tmp3, 2); - inflate_lo32(tmp3, tmp1); - mv(tmp1, tmp3); - } else { // UL case - load_int_misaligned(tmp2, Address(str2), tmp3, false); - load_long_misaligned(tmp1, Address(str1), tmp3, 2); - inflate_lo32(tmp3, tmp2); - mv(tmp2, tmp3); - } - bind(TAIL_CHECK); - beq(tmp1, tmp2, DONE); - - // Find the first different characters in the longwords and - // compute their difference. - bind(DIFFERENCE); - xorr(tmp3, tmp1, tmp2); - // count bits of trailing zero chars - ctzc_bits(result, tmp3, isLL); - srl(tmp1, tmp1, result); - srl(tmp2, tmp2, result); - if (isLL) { - zext(tmp1, tmp1, 8); - zext(tmp2, tmp2, 8); - } else { - zext(tmp1, tmp1, 16); - zext(tmp2, tmp2, 16); - } - sub(result, tmp1, tmp2); - j(DONE); } bind(STUB); @@ -2636,7 +2665,7 @@ void C2_MacroAssembler::string_compare_v(Register str1, Register str2, Register int minCharsInWord = encLL ? wordSize : wordSize / 2; - BLOCK_COMMENT("string_compare {"); + BLOCK_COMMENT("string_compare_v {"); // for Latin strings, 1 byte for 1 character // for UTF16 strings, 2 bytes for 1 character @@ -2696,6 +2725,8 @@ void C2_MacroAssembler::string_compare_v(Register str1, Register str2, Register sub(result, tmp1, tmp2); bind(DONE); + + BLOCK_COMMENT("} string_compare_v"); } void C2_MacroAssembler::byte_array_inflate_v(Register src, Register dst, Register len, Register tmp) { diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index c79c360d2eb..72f3c1460f3 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -39,6 +39,15 @@ VectorRegister vrs, bool is_latin, Label& DONE, Assembler::LMUL lmul); + void string_compare_long_same_encoding(Register result, Register str1, Register str2, + const bool isLL, Register cnt1, Register cnt2, + Register tmp1, Register tmp2, Register tmp3, + const int STUB_THRESHOLD, Label *STUB, Label *SHORT_STRING, Label *DONE); + void string_compare_long_different_encoding(Register result, Register str1, Register str2, + bool isLU, Register cnt1, Register cnt2, + Register tmp1, Register tmp2, Register tmp3, + 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, diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 01ed7fcac9f..249b871bd00 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2431,23 +2431,6 @@ class StubGenerator: public StubCodeGenerator { return start; } - // code for comparing 16 bytes of strings with same encoding - void compare_string_16_bytes_same(Label &DIFF1, Label &DIFF2) { - const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, tmp1 = x28, tmp2 = x29, tmp4 = x7, tmp5 = x31; - __ ld(tmp5, Address(str1)); - __ addi(str1, str1, 8); - __ xorr(tmp4, tmp1, tmp2); - __ ld(cnt1, Address(str2)); - __ addi(str2, str2, 8); - __ bnez(tmp4, DIFF1); - __ ld(tmp1, Address(str1)); - __ addi(str1, str1, 8); - __ xorr(tmp4, tmp5, cnt1); - __ ld(tmp2, Address(str2)); - __ addi(str2, str2, 8); - __ bnez(tmp4, DIFF2); - } - // code for comparing 8 characters of strings with Latin1 and Utf16 encoding void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { @@ -2702,7 +2685,20 @@ class StubGenerator: public StubCodeGenerator { __ push_reg(spilled_regs, sp); __ bltz(cnt2, TAIL); __ bind(SMALL_LOOP); - compare_string_16_bytes_same(DIFF, DIFF2); + // compare 16 bytes of strings with same encoding + __ ld(tmp5, Address(str1)); + __ addi(str1, str1, 8); + __ xorr(tmp4, tmp1, tmp2); + __ ld(cnt1, Address(str2)); + __ addi(str2, str2, 8); + __ bnez(tmp4, DIFF); + __ ld(tmp1, Address(str1)); + __ addi(str1, str1, 8); + __ xorr(tmp4, tmp5, cnt1); + __ ld(tmp2, Address(str2)); + __ addi(str2, str2, 8); + __ bnez(tmp4, DIFF2); + __ subi(cnt2, cnt2, isLL ? 16 : 8); __ bgez(cnt2, SMALL_LOOP); __ bind(TAIL); diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java index 062866d657f..f82a4899d97 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java @@ -160,6 +160,7 @@ public class TestStringIntrinsics { // Different lengths invokeAndCheck(m, 1, "ABCD", "ABC"); + invokeAndCheck(m, '\uff21' - 'A', "ABCEFGHIJKLMNOPQRSTUVWXY\uff21Z", "ABCEFGHIJKLMNOPQRSTUVWXYAZ"); invokeAndCheck(m, -1, "\uff21\uff22\uff23", "\uff21\uff22\uff23\uff24"); invokeAndCheck(m, 1, "ABC\uff24", "ABC"); invokeAndCheck(m, 3, "ABC\uff24\uff25\uff26", "ABC"); From c4b516dfe7c5a5fddd4d9c97a21f5f36bf845646 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 3 Mar 2025 18:49:11 +0000 Subject: [PATCH 201/587] 8348322: AOT cache creation crashes with "All cached hidden classes must be aot-linkable" when AOTInvokeDynamicLinking is disabled Co-authored-by: Ioi Lam Reviewed-by: iklam, matsaave --- src/hotspot/share/cds/aotClassInitializer.cpp | 4 ++-- src/hotspot/share/cds/aotClassLinker.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 11 ++++++++--- src/hotspot/share/cds/cdsConfig.cpp | 10 +++++++--- src/hotspot/share/cds/cdsConfig.hpp | 4 +--- src/hotspot/share/cds/cdsHeapVerifier.cpp | 4 +++- src/hotspot/share/cds/classListParser.cpp | 2 +- src/hotspot/share/cds/filemap.cpp | 6 ------ src/hotspot/share/cds/filemap.hpp | 1 - src/hotspot/share/cds/heapShared.cpp | 8 ++++---- src/hotspot/share/cds/lambdaFormInvokers.cpp | 2 +- src/hotspot/share/cds/metaspaceShared.cpp | 7 +++++-- src/hotspot/share/classfile/javaClasses.cpp | 2 +- .../share/classfile/systemDictionaryShared.cpp | 4 ++-- src/hotspot/share/oops/constantPool.cpp | 2 +- src/hotspot/share/oops/cpCache.cpp | 2 +- .../aotClassLinking/AOTClassLinkingVMOptions.java | 11 ++++++++++- 17 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp index 5b022cae244..c5ad36ac315 100644 --- a/src/hotspot/share/cds/aotClassInitializer.cpp +++ b/src/hotspot/share/cds/aotClassInitializer.cpp @@ -107,7 +107,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { // Automatic selection for aot-inited classes // ========================================== // - // When CDSConfig::is_initing_classes_at_dump_time() is enabled, + // When CDSConfig::is_initing_classes_at_dump_time is enabled, // AOTArtifactFinder::find_artifacts() finds the classes of all // heap objects that are reachable from HeapShared::_run_time_special_subgraph, // and mark these classes as aot-inited. This preserves the initialized @@ -266,7 +266,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { } } - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { // This table was created with the help of CDSHeapVerifier. // Also, some $Holder classes are needed. E.g., Invokers. explicitly // initializes Invokers$Holder. Since Invokers. won't be executed diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index a1cacd735dd..dc539eb3d55 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -142,7 +142,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) { if (ik->is_hidden()) { assert(ik->shared_class_loader_type() != ClassLoader::OTHER, "must have been set"); - if (!CDSConfig::is_dumping_invokedynamic()) { + if (!CDSConfig::is_dumping_method_handles()) { return false; } if (HeapShared::is_lambda_proxy_klass(ik)) { diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 21e97457a87..48e843e473f 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -786,6 +786,7 @@ void ArchiveBuilder::make_klasses_shareable() { const char* aotlinked_msg = ""; const char* inited_msg = ""; Klass* k = get_buffered_addr(klasses()->at(i)); + bool inited = false; k->remove_java_mirror(); #ifdef _LP64 if (UseCompactObjectHeaders) { @@ -810,7 +811,7 @@ void ArchiveBuilder::make_klasses_shareable() { InstanceKlass* ik = InstanceKlass::cast(k); InstanceKlass* src_ik = get_source_addr(ik); bool aotlinked = AOTClassLinker::is_candidate(src_ik); - bool inited = ik->has_aot_initialized_mirror(); + inited = ik->has_aot_initialized_mirror(); ADD_COUNT(num_instance_klasses); if (CDSConfig::is_dumping_dynamic_archive()) { // For static dump, class loader type are already set. @@ -833,7 +834,7 @@ void ArchiveBuilder::make_klasses_shareable() { type = "bad"; assert(0, "shouldn't happen"); } - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { assert(HeapShared::is_archivable_hidden_klass(ik), "sanity"); } else { // Legacy CDS support for lambda proxies @@ -891,7 +892,11 @@ void ArchiveBuilder::make_klasses_shareable() { aotlinked_msg = " aot-linked"; } if (inited) { - inited_msg = " inited"; + if (InstanceKlass::cast(k)->static_field_size() == 0) { + inited_msg = " inited (no static fields)"; + } else { + inited_msg = " inited"; + } } MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index ff11b807910..f50ae446363 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -47,7 +47,6 @@ bool CDSConfig::_is_using_optimized_module_handling = true; bool CDSConfig::_is_dumping_full_module_graph = true; bool CDSConfig::_is_using_full_module_graph = true; bool CDSConfig::_has_aot_linked_classes = false; -bool CDSConfig::_has_archived_invokedynamic = false; bool CDSConfig::_old_cds_flags_used = false; bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; @@ -738,8 +737,13 @@ bool CDSConfig::is_dumping_invokedynamic() { return AOTInvokeDynamicLinking && is_dumping_aot_linked_classes() && is_dumping_heap(); } -bool CDSConfig::is_loading_invokedynamic() { - return UseSharedSpaces && is_using_full_module_graph() && _has_archived_invokedynamic; +// When we are dumping aot-linked classes and we are able to write archived heap objects, we automatically +// enable the archiving of MethodHandles. This will in turn enable the archiving of MethodTypes and hidden +// classes that are used in the implementation of MethodHandles. +// Archived MethodHandles are required for higher-level optimizations such as AOT resolution of invokedynamic +// and dynamic proxies. +bool CDSConfig::is_dumping_method_handles() { + return is_initing_classes_at_dump_time(); } #endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index d9f5a593098..753ed6b746a 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -41,7 +41,6 @@ class CDSConfig : public AllStatic { static bool _is_dumping_full_module_graph; static bool _is_using_full_module_graph; static bool _has_aot_linked_classes; - static bool _has_archived_invokedynamic; static char* _default_archive_path; static char* _static_archive_path; @@ -160,8 +159,7 @@ public: static bool is_initing_classes_at_dump_time() NOT_CDS_JAVA_HEAP_RETURN_(false); static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false); - static bool is_loading_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false); - static void set_has_archived_invokedynamic() { CDS_JAVA_HEAP_ONLY(_has_archived_invokedynamic = true); } + static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false); // full_module_graph (requires optimized_module_handling) static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); } diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index f9e613a74ce..729637f47c2 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -106,6 +106,8 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) ADD_EXCL("java/lang/System", "bootLayer"); // A + ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E + // A dummy object used by HashSet. The value doesn't matter and it's never // tested for equality. ADD_EXCL("java/util/HashSet", "PRESENT"); // E @@ -127,7 +129,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) ADD_EXCL("sun/invoke/util/ValueConversions", "ONE_INT", // E "ZERO_INT"); // E - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator", "MEMBERNAME_FACTORY", // D "CD_Object_array", // E same as <...>ConstantUtils.CD_Object_array::CD_Object "INVOKER_SUPER_DESC"); // E same as java.lang.constant.ConstantDescs::CD_Object diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index e0c008678ca..133cfcc8738 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -627,7 +627,7 @@ void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbo } void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { // The CP entry for the invokedynamic instruction will be resolved. // No need to do the following. return; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 8a7e66c19e4..ebcd33f8bd5 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -234,7 +234,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, _use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling(); _has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes(); _has_full_module_graph = CDSConfig::is_dumping_full_module_graph(); - _has_archived_invokedynamic = CDSConfig::is_dumping_invokedynamic(); // The following fields are for sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's @@ -309,7 +308,6 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling); st->print_cr("- has_full_module_graph %d", _has_full_module_graph); st->print_cr("- has_aot_linked_classes %d", _has_aot_linked_classes); - st->print_cr("- has_archived_invokedynamic %d", _has_archived_invokedynamic); } bool FileMapInfo::validate_class_location() { @@ -1950,10 +1948,6 @@ bool FileMapHeader::validate() { if (!_has_full_module_graph) { CDSConfig::stop_using_full_module_graph("archive was created without full module graph"); } - - if (_has_archived_invokedynamic) { - CDSConfig::set_has_archived_invokedynamic(); - } } return true; diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 25550d76d2a..095faba69f3 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -140,7 +140,6 @@ private: // some expensive operations. bool _has_aot_linked_classes; // Was the CDS archive created with -XX:+AOTClassLinking bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph? - bool _has_archived_invokedynamic; // Does the archive have aot-linked invokedynamic CP entries? HeapRootSegments _heap_root_segments; // Heap root segments info size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap. size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap. diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index c95a358de5f..7bd5d5a6267 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -492,7 +492,7 @@ bool HeapShared::is_string_concat_klass(InstanceKlass* ik) { } bool HeapShared::is_archivable_hidden_klass(InstanceKlass* ik) { - return CDSConfig::is_dumping_invokedynamic() && + return CDSConfig::is_dumping_method_handles() && (is_lambda_form_klass(ik) || is_lambda_proxy_klass(ik) || is_string_concat_klass(ik)); } @@ -782,7 +782,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) { if (orig_k->is_instance_klass()) { #ifdef ASSERT InstanceKlass* ik = InstanceKlass::cast(orig_k); - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { assert(ik->class_loader() == nullptr || HeapShared::is_lambda_proxy_klass(ik), "we can archive only instances of boot classes or lambda proxy classes"); @@ -835,7 +835,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) { } const char* lambda_msg = ""; - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { lambda_msg = ", or a lambda proxy class"; if (HeapShared::is_lambda_proxy_klass(ik) && (ik->class_loader() == nullptr || @@ -1108,7 +1108,7 @@ void HeapShared::resolve_classes_for_subgraph_of(JavaThread* current, Klass* k) } void HeapShared::initialize_java_lang_invoke(TRAPS) { - if (CDSConfig::is_loading_invokedynamic() || CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_using_aot_linked_classes() || CDSConfig::is_dumping_method_handles()) { resolve_or_init("java/lang/invoke/Invokers$Holder", true, CHECK); resolve_or_init("java/lang/invoke/MethodHandle", true, CHECK); resolve_or_init("java/lang/invoke/MethodHandleNatives", true, CHECK); diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index fc1917086f3..ab22b4775b7 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -95,7 +95,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { return; } - if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_method_handles()) { // Work around JDK-8310831, as some methods in lambda form holder classes may not get generated. log_info(cds)("Archived MethodHandles may refer to lambda form holder classes. Cannot regenerate."); return; diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 9e9f9fd1d9e..ee877c474b9 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -636,7 +636,7 @@ void VM_PopulateDumpSharedSpace::doit() { DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); _pending_method_handle_intrinsics = new (mtClassShared) GrowableArray(256, mtClassShared); - if (CDSConfig::is_dumping_aot_linked_classes()) { + if (CDSConfig::is_dumping_method_handles()) { // When dumping AOT-linked classes, some classes may have direct references to a method handle // intrinsic. The easiest thing is to save all of them into the AOT cache. SystemDictionary::get_all_method_handle_intrinsics(_pending_method_handle_intrinsics); @@ -985,7 +985,7 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS HeapShared::reset_archived_object_states(CHECK); } - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { // This assert means that the MethodType and MethodTypeForm tables won't be // updated concurrently when we are saving their contents into a side table. assert(CDSConfig::allow_only_single_java_thread(), "Required"); @@ -995,12 +995,15 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS vmSymbols::createArchivedObjects(), vmSymbols::void_method_signature(), CHECK); + } + if (CDSConfig::is_initing_classes_at_dump_time()) { // java.lang.Class::reflectionFactory cannot be archived yet. We set this field // to null, and it will be initialized again at runtime. log_debug(cds)("Resetting Class::reflectionFactory"); TempNewSymbol method_name = SymbolTable::new_symbol("resetArchivedStates"); Symbol* method_sig = vmSymbols::void_method_signature(); + JavaValue result(T_VOID); JavaCalls::call_static(&result, vmClasses::Class_klass(), method_name, method_sig, CHECK); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a224ef481b0..fa97888360a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -5452,7 +5452,7 @@ void JavaClasses::serialize_offsets(SerializeClosure* soc) { bool JavaClasses::is_supported_for_archiving(oop obj) { Klass* klass = obj->klass(); - if (!CDSConfig::is_dumping_invokedynamic()) { + if (!CDSConfig::is_dumping_method_handles()) { // These are supported by CDS only when CDSConfig::is_dumping_invokedynamic() is enabled. if (klass == vmClasses::ResolvedMethodName_klass() || klass == vmClasses::MemberName_klass()) { diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 2f7887c2d46..6bd573ea465 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -295,7 +295,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) { if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) { // This class is dynamically generated by the JDK - if (CDSConfig::is_dumping_aot_linked_classes()) { + if (CDSConfig::is_dumping_method_handles()) { k->set_shared_classpath_index(0); } else { ResourceMark rm; @@ -587,7 +587,7 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) { guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name); if (is_builtin(k)) { if (k->is_hidden()) { - if (!CDSConfig::is_dumping_invokedynamic()) { + if (!CDSConfig::is_dumping_method_handles()) { assert(is_registered_lambda_proxy_class(k), "unexpected hidden class %s", name); } } diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index ee53e43c327..23e1bc14d38 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -288,7 +288,7 @@ void ConstantPool::klass_at_put(int class_index, Klass* k) { template void ConstantPool::iterate_archivable_resolved_references(Function function) { objArrayOop rr = resolved_references(); - if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_invokedynamic()) { + if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_method_handles()) { Array* indy_entries = cache()->resolved_indy_entries(); if (indy_entries != nullptr) { for (int i = 0; i < indy_entries->length(); i++) { diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index f4c53c0089e..a354e0b07a6 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -572,7 +572,7 @@ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, Resolv method_entry->is_resolved(Bytecodes::_invokespecial)) { return true; } else if (method_entry->is_resolved(Bytecodes::_invokehandle)) { - if (CDSConfig::is_dumping_invokedynamic()) { + if (CDSConfig::is_dumping_method_handles()) { // invokehandle depends on archived MethodType and LambdaForms. return true; } else { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java index 0d75d16d2b0..af5c619d767 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.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 @@ -80,6 +80,15 @@ public class AOTClassLinkingVMOptions { .assertAbnormalExit("CDS archive has aot-linked classes." + " It cannot be used with -Djava.security.manager=default."); + // Dumping with AOTInvokeDynamicLinking disabled + TestCommon.testDump(appJar, TestCommon.list("Hello"), + "-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking"); + + testCase("Archived full module graph must be enabled at runtime (with -XX:-AOTInvokeDynamicLinking)"); + TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello") + .assertAbnormalExit("CDS archive has aot-linked classes." + + " It cannot be used when archived full module graph is not used"); + // NOTE: tests for ClassFileLoadHook + AOTClassLinking is in // ../jvmti/ClassFileLoadHookTest.java From 768b02410f1b53ac95d6014f152be84c89eb33ab Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 3 Mar 2025 21:05:19 +0000 Subject: [PATCH 202/587] 8350682: [JMH] vector.IndexInRangeBenchmark failed with IndexOutOfBoundsException for size=1024 Reviewed-by: xgong, drwhite, sviswanathan --- .../bench/jdk/incubator/vector/IndexInRangeBenchmark.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java index 1875ea00feb..6a068bc4346 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/IndexInRangeBenchmark.java @@ -48,7 +48,7 @@ public class IndexInRangeBenchmark { @Setup(Level.Trial) public void Setup() { - mask = new boolean[512]; + mask = new boolean[size + 64]; } @Benchmark From 99fb350bf65f9469c8097ddebcc6742255435a88 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 3 Mar 2025 21:25:11 +0000 Subject: [PATCH 203/587] 8350654: (fs) Files.createTempDirectory should say something about the default file permissions when no file attributes specified Reviewed-by: alanb --- src/java.base/share/classes/java/nio/file/Files.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 17d6eebbcb8..44a0a8e164c 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.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 @@ -860,7 +860,10 @@ public final class Files { * file-attributes} to set atomically when creating the directory. Each * attribute is identified by its {@link FileAttribute#name name}. If more * than one attribute of the same name is included in the array then all but - * the last occurrence is ignored. + * the last occurrence is ignored. When no file attributes are specified, + * then the resulting directory may have more restrictive access + * permissions to directories created by the + * {@linkplain Files#createDirectory(Path, FileAttribute...)} method. * * @param dir * the path to directory in which to create the directory From 3a8a432c05999fe478b94de75b416404b5a515d2 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 4 Mar 2025 00:41:39 +0000 Subject: [PATCH 204/587] 8349094: GenShen: Race between control and regulator threads may violate assertions Reviewed-by: ysr, kdnilsen --- src/hotspot/share/gc/shared/gcCause.hpp | 1 + .../heuristics/shenandoahOldHeuristics.cpp | 42 +- .../heuristics/shenandoahOldHeuristics.hpp | 4 +- .../gc/shenandoah/shenandoahBarrierSet.cpp | 2 +- .../shenandoah/shenandoahCollectorPolicy.cpp | 29 +- .../shenandoah/shenandoahCollectorPolicy.hpp | 11 +- .../gc/shenandoah/shenandoahControlThread.cpp | 35 +- .../gc/shenandoah/shenandoahController.cpp | 59 +- .../gc/shenandoah/shenandoahController.hpp | 33 +- .../shenandoahGenerationalControlThread.cpp | 910 +++++++++--------- .../shenandoahGenerationalControlThread.hpp | 107 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 38 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 34 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 8 +- .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 +- .../shenandoah/shenandoahRegulatorThread.cpp | 31 +- .../shenandoah/shenandoahRegulatorThread.hpp | 15 +- .../shenandoah/shenandoahScanRemembered.cpp | 4 +- 18 files changed, 699 insertions(+), 666 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index bd819e8f5c9..ef96bf21567 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -74,6 +74,7 @@ class GCCause : public AllStatic { _shenandoah_stop_vm, _shenandoah_allocation_failure_evac, + _shenandoah_humongous_allocation_failure, _shenandoah_concurrent_gc, _shenandoah_upgrade_to_full_gc, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 0393a2bb366..cf1a76ff4ff 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -60,7 +60,6 @@ int ShenandoahOldHeuristics::compare_by_index(RegionData a, RegionData b) { ShenandoahOldHeuristics::ShenandoahOldHeuristics(ShenandoahOldGeneration* generation, ShenandoahGenerationalHeap* gen_heap) : ShenandoahHeuristics(generation), _heap(gen_heap), - _old_gen(generation), _first_pinned_candidate(NOT_FOUND), _last_old_collection_candidate(0), _next_old_collection_candidate(0), @@ -567,9 +566,9 @@ void ShenandoahOldHeuristics::set_trigger_if_old_is_fragmented(size_t first_old_ // allocation request will require a STW full GC. size_t allowed_old_gen_span = num_regions - (ShenandoahGenerationalHumongousReserve * num_regions) / 100; - size_t old_available = _old_gen->available() / HeapWordSize; + size_t old_available = _old_generation->available() / HeapWordSize; size_t region_size_words = ShenandoahHeapRegion::region_size_words(); - size_t old_unaffiliated_available = _old_gen->free_unaffiliated_regions() * region_size_words; + size_t old_unaffiliated_available = _old_generation->free_unaffiliated_regions() * region_size_words; assert(old_available >= old_unaffiliated_available, "sanity"); size_t old_fragmented_available = old_available - old_unaffiliated_available; @@ -603,12 +602,12 @@ void ShenandoahOldHeuristics::set_trigger_if_old_is_fragmented(size_t first_old_ } void ShenandoahOldHeuristics::set_trigger_if_old_is_overgrown() { - size_t old_used = _old_gen->used() + _old_gen->get_humongous_waste(); - size_t trigger_threshold = _old_gen->usage_trigger_threshold(); + size_t old_used = _old_generation->used() + _old_generation->get_humongous_waste(); + size_t trigger_threshold = _old_generation->usage_trigger_threshold(); // Detects unsigned arithmetic underflow assert(old_used <= _heap->capacity(), "Old used (%zu, %zu) must not be more than heap capacity (%zu)", - _old_gen->used(), _old_gen->get_humongous_waste(), _heap->capacity()); + _old_generation->used(), _old_generation->get_humongous_waste(), _heap->capacity()); if (old_used > trigger_threshold) { _growth_trigger = true; } @@ -620,13 +619,32 @@ void ShenandoahOldHeuristics::evaluate_triggers(size_t first_old_region, size_t set_trigger_if_old_is_overgrown(); } +bool ShenandoahOldHeuristics::should_resume_old_cycle() { + // If we are preparing to mark old, or if we are already marking old, then try to continue that work. + if (_old_generation->is_concurrent_mark_in_progress()) { + assert(_old_generation->state() == ShenandoahOldGeneration::MARKING, "Unexpected old gen state: %s", _old_generation->state_name()); + log_trigger("Resume marking old"); + return true; + } + + if (_old_generation->is_preparing_for_mark()) { + assert(_old_generation->state() == ShenandoahOldGeneration::FILLING, "Unexpected old gen state: %s", _old_generation->state_name()); + log_trigger("Resume preparing to mark old"); + return true; + } + + return false; +} + bool ShenandoahOldHeuristics::should_start_gc() { - // Cannot start a new old-gen GC until previous one has finished. - // - // Future refinement: under certain circumstances, we might be more sophisticated about this choice. - // For example, we could choose to abandon the previous old collection before it has completed evacuations. - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!_old_generation->can_start_gc() || heap->collection_set()->has_old_regions()) { + + const ShenandoahHeap* heap = ShenandoahHeap::heap(); + if (_old_generation->is_doing_mixed_evacuations()) { + // Do not try to start an old cycle if we are waiting for old regions to be evacuated (we need + // a young cycle for this). Note that the young heuristic has a feature to expedite old evacuations. + // Future refinement: under certain circumstances, we might be more sophisticated about this choice. + // For example, we could choose to abandon the previous old collection before it has completed evacuations. + log_debug(gc)("Not starting an old cycle because we are waiting for mixed evacuations"); return false; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp index d77380926b6..8d3fec746ba 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.hpp @@ -53,7 +53,6 @@ private: static uint NOT_FOUND; ShenandoahGenerationalHeap* _heap; - ShenandoahOldGeneration* _old_gen; // After final marking of the old generation, this heuristic will select // a set of candidate regions to be included in subsequent mixed collections. @@ -186,6 +185,9 @@ public: bool should_start_gc() override; + // Returns true if the old generation needs to prepare for marking, or continue marking. + bool should_resume_old_cycle(); + void record_success_concurrent() override; void record_success_degenerated() override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index 37470067ed9..17a89f631c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -90,7 +90,7 @@ bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators, Basi void ShenandoahBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { #if COMPILER2_OR_JVMCI assert(!ReduceInitialCardMarks || !ShenandoahCardBarrier || ShenandoahGenerationalHeap::heap()->is_in_young(new_obj), - "Error: losing card mark on initialzing store to old gen"); + "Allocating new object outside of young generation: " INTPTR_FORMAT, p2i(new_obj)); #endif // COMPILER2_OR_JVMCI assert(thread->deferred_card_mark().is_empty(), "We don't use this"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp index 782db285c2a..0169795d6f6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp @@ -123,25 +123,28 @@ void ShenandoahCollectorPolicy::record_shutdown() { _in_shutdown.set(); } -bool ShenandoahCollectorPolicy::is_at_shutdown() { +bool ShenandoahCollectorPolicy::is_at_shutdown() const { return _in_shutdown.is_set(); } -bool is_explicit_gc(GCCause::Cause cause) { +bool ShenandoahCollectorPolicy::is_explicit_gc(GCCause::Cause cause) { return GCCause::is_user_requested_gc(cause) - || GCCause::is_serviceability_requested_gc(cause); + || GCCause::is_serviceability_requested_gc(cause) + || cause == GCCause::_wb_full_gc + || cause == GCCause::_wb_young_gc; } bool is_implicit_gc(GCCause::Cause cause) { return cause != GCCause::_no_gc && cause != GCCause::_shenandoah_concurrent_gc && cause != GCCause::_allocation_failure - && !is_explicit_gc(cause); + && !ShenandoahCollectorPolicy::is_explicit_gc(cause); } #ifdef ASSERT bool is_valid_request(GCCause::Cause cause) { - return is_explicit_gc(cause) + return ShenandoahCollectorPolicy::is_explicit_gc(cause) + || ShenandoahCollectorPolicy::is_shenandoah_gc(cause) || cause == GCCause::_metadata_GC_clear_soft_refs || cause == GCCause::_codecache_GC_aggressive || cause == GCCause::_codecache_GC_threshold @@ -153,6 +156,22 @@ bool is_valid_request(GCCause::Cause cause) { } #endif +bool ShenandoahCollectorPolicy::is_shenandoah_gc(GCCause::Cause cause) { + return cause == GCCause::_allocation_failure + || cause == GCCause::_shenandoah_stop_vm + || cause == GCCause::_shenandoah_allocation_failure_evac + || cause == GCCause::_shenandoah_humongous_allocation_failure + || cause == GCCause::_shenandoah_concurrent_gc + || cause == GCCause::_shenandoah_upgrade_to_full_gc; +} + + +bool ShenandoahCollectorPolicy::is_allocation_failure(GCCause::Cause cause) { + return cause == GCCause::_allocation_failure + || cause == GCCause::_shenandoah_allocation_failure_evac + || cause == GCCause::_shenandoah_humongous_allocation_failure; +} + bool ShenandoahCollectorPolicy::is_requested_gc(GCCause::Cause cause) { return is_explicit_gc(cause) || is_implicit_gc(cause); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp index 2c92d91ac99..68579508de5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.hpp @@ -77,9 +77,9 @@ public: void record_collection_cause(GCCause::Cause cause); void record_shutdown(); - bool is_at_shutdown(); + bool is_at_shutdown() const; - ShenandoahTracer* tracer() {return _tracer;} + ShenandoahTracer* tracer() const {return _tracer;} void print_gc_stats(outputStream* out) const; @@ -90,15 +90,18 @@ public: // If the heuristics find that the number of consecutive degenerated cycles is above // ShenandoahFullGCThreshold, then they will initiate a Full GC upon an allocation // failure. - inline size_t consecutive_degenerated_gc_count() const { + size_t consecutive_degenerated_gc_count() const { return _consecutive_degenerated_gcs; } + static bool is_allocation_failure(GCCause::Cause cause); + static bool is_shenandoah_gc(GCCause::Cause cause); static bool is_requested_gc(GCCause::Cause cause); + static bool is_explicit_gc(GCCause::Cause cause); static bool should_run_full_gc(GCCause::Cause cause); static bool should_handle_requested_gc(GCCause::Cause cause); - inline size_t consecutive_young_gc_count() const { + size_t consecutive_young_gc_count() const { return _consecutive_young_gcs; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 1ddfb6b7054..4848a69a6f3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -50,7 +50,6 @@ ShenandoahControlThread::ShenandoahControlThread() : void ShenandoahControlThread::run_service() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); - const GCMode default_mode = concurrent_normal; const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc; int sleep = ShenandoahControlIntervalMin; @@ -59,9 +58,14 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); - while (!in_graceful_shutdown() && !should_terminate()) { + while (!should_terminate()) { + const GCCause::Cause cancelled_cause = heap->cancelled_cause(); + if (cancelled_cause == GCCause::_shenandoah_stop_vm) { + break; + } + // Figure out if we have pending requests. - const bool alloc_failure_pending = _alloc_failure_gc.is_set(); + const bool alloc_failure_pending = ShenandoahCollectorPolicy::is_allocation_failure(cancelled_cause); const bool is_gc_requested = _gc_requested.is_set(); const GCCause::Cause requested_gc_cause = _requested_gc_cause; @@ -254,11 +258,6 @@ void ShenandoahControlThread::run_service() { } os::naked_short_sleep(sleep); } - - // Wait for the actual stop(), can't leave run_service() earlier. - while (!should_terminate()) { - os::naked_short_sleep(ShenandoahControlIntervalMin); - } } void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) { @@ -322,19 +321,24 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { ShenandoahHeap* heap = ShenandoahHeap::heap(); if (heap->cancelled_gc()) { - assert (is_alloc_failure_gc() || in_graceful_shutdown(), "Cancel GC either for alloc failure GC, or gracefully exiting"); - if (!in_graceful_shutdown()) { + if (heap->cancelled_cause() == GCCause::_shenandoah_stop_vm) { + return true; + } + + if (ShenandoahCollectorPolicy::is_allocation_failure(heap->cancelled_cause())) { assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle, "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); _degen_point = point; + return true; } - return true; + + fatal("Unexpected reason for cancellation: %s", GCCause::to_string(heap->cancelled_cause())); } return false; } void ShenandoahControlThread::stop_service() { - // Nothing to do here. + ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_stop_vm); } void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) { @@ -363,6 +367,11 @@ void ShenandoahControlThread::request_gc(GCCause::Cause cause) { } void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { + if (should_terminate()) { + log_info(gc)("Control thread is terminating, no more GCs"); + return; + } + // For normal requested GCs (System.gc) we want to block the caller. However, // for whitebox requested GC, we want to initiate the GC and return immediately. // The whitebox caller thread will arrange for itself to wait until the GC notifies @@ -385,7 +394,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { MonitorLocker ml(&_gc_waiters_lock); size_t current_gc_id = get_gc_id(); size_t required_gc_id = current_gc_id + 1; - while (current_gc_id < required_gc_id) { + while (current_gc_id < required_gc_id && !should_terminate()) { // Although setting gc request is under _gc_waiters_lock, but read side (run_service()) // does not take the lock. We need to enforce following order, so that read side sees // latest requested gc cause when the flag is set. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp index a4d5a572349..c430981bfe6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -25,6 +25,8 @@ #include "gc/shared/gc_globals.hpp" #include "gc/shenandoah/shenandoahController.hpp" + +#include "shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" @@ -37,14 +39,6 @@ size_t ShenandoahController::reset_allocs_seen() { return Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed); } -void ShenandoahController::prepare_for_graceful_shutdown() { - _graceful_shutdown.set(); -} - -bool ShenandoahController::in_graceful_shutdown() { - return _graceful_shutdown.is_set(); -} - void ShenandoahController::update_gc_id() { Atomic::inc(&_gc_id); } @@ -53,59 +47,38 @@ size_t ShenandoahController::get_gc_id() { return Atomic::load(&_gc_id); } -void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - +void ShenandoahController::handle_alloc_failure(const ShenandoahAllocRequest& req, bool block) { assert(current()->is_Java_thread(), "expect Java thread here"); - bool is_humongous = ShenandoahHeapRegion::requires_humongous(req.size()); - if (try_set_alloc_failure_gc(is_humongous)) { - // Only report the first allocation failure - log_info(gc)("Failed to allocate %s, %zu%s", - req.type_string(), - byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize)); + const bool is_humongous = ShenandoahHeapRegion::requires_humongous(req.size()); + const GCCause::Cause cause = is_humongous ? GCCause::_shenandoah_humongous_allocation_failure : GCCause::_allocation_failure; - // Now that alloc failure GC is scheduled, we can abort everything else - heap->cancel_gc(GCCause::_allocation_failure); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + if (heap->cancel_gc(cause)) { + log_info(gc)("Failed to allocate %s, " PROPERFMT, req.type_string(), PROPERFMTARGS(req.size() * HeapWordSize)); + request_gc(cause); } - if (block) { MonitorLocker ml(&_alloc_failure_waiters_lock); - while (is_alloc_failure_gc()) { + while (!should_terminate() && ShenandoahCollectorPolicy::is_allocation_failure(heap->cancelled_cause())) { ml.wait(); } } } void ShenandoahController::handle_alloc_failure_evac(size_t words) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - bool is_humongous = ShenandoahHeapRegion::requires_humongous(words); - if (try_set_alloc_failure_gc(is_humongous)) { - // Only report the first allocation failure - log_info(gc)("Failed to allocate %zu%s for evacuation", - byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize)); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + const bool is_humongous = ShenandoahHeapRegion::requires_humongous(words); + const GCCause::Cause cause = is_humongous ? GCCause::_shenandoah_humongous_allocation_failure : GCCause::_shenandoah_allocation_failure_evac; + + if (heap->cancel_gc(cause)) { + log_info(gc)("Failed to allocate " PROPERFMT " for evacuation", PROPERFMTARGS(words * HeapWordSize)); } - - // Forcefully report allocation failure - heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac); } void ShenandoahController::notify_alloc_failure_waiters() { - _alloc_failure_gc.unset(); - _humongous_alloc_failure_gc.unset(); MonitorLocker ml(&_alloc_failure_waiters_lock); ml.notify_all(); } - -bool ShenandoahController::try_set_alloc_failure_gc(bool is_humongous) { - if (is_humongous) { - _humongous_alloc_failure_gc.try_set(); - } - return _alloc_failure_gc.try_set(); -} - -bool ShenandoahController::is_alloc_failure_gc() { - return _alloc_failure_gc.is_set(); -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp index 6c28ff4e969..83cde94f509 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp @@ -36,27 +36,25 @@ */ class ShenandoahController: public ConcurrentGCThread { private: - ShenandoahSharedFlag _graceful_shutdown; - shenandoah_padding(0); volatile size_t _allocs_seen; shenandoah_padding(1); + // A monotonically increasing GC count. volatile size_t _gc_id; shenandoah_padding(2); protected: - ShenandoahSharedFlag _alloc_failure_gc; - ShenandoahSharedFlag _humongous_alloc_failure_gc; - // While we could have a single lock for these, it may risk unblocking // GC waiters when alloc failure GC cycle finishes. We want instead // to make complete explicit cycle for demanding customers. Monitor _alloc_failure_waiters_lock; Monitor _gc_waiters_lock; + // Increments the internal GC count. + void update_gc_id(); + public: ShenandoahController(): - ConcurrentGCThread(), _allocs_seen(0), _gc_id(0), _alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true), @@ -68,38 +66,25 @@ public: virtual void request_gc(GCCause::Cause cause) = 0; // This cancels the collection cycle and has an option to block - // until another cycle runs and clears the alloc failure gc flag. - void handle_alloc_failure(ShenandoahAllocRequest& req, bool block); + // until another cycle completes successfully. + void handle_alloc_failure(const ShenandoahAllocRequest& req, bool block); // Invoked for allocation failures during evacuation. This cancels // the collection cycle without blocking. void handle_alloc_failure_evac(size_t words); - // Return true if setting the flag which indicates allocation failure succeeds. - bool try_set_alloc_failure_gc(bool is_humongous); - // Notify threads waiting for GC to complete. void notify_alloc_failure_waiters(); - // True if allocation failure flag has been set. - bool is_alloc_failure_gc(); - // This is called for every allocation. The control thread accumulates // this value when idle. During the gc cycle, the control resets it // and reports it to the pacer. void pacing_notify_alloc(size_t words); + + // Zeros out the number of allocations seen since the last GC cycle. size_t reset_allocs_seen(); - // These essentially allows to cancel a collection cycle for the - // purpose of shutting down the JVM, without trying to start a degenerated - // cycle. - void prepare_for_graceful_shutdown(); - bool in_graceful_shutdown(); - - - // Returns the internal gc count used by the control thread. Probably - // doesn't need to be exposed. + // Return the value of a monotonic increasing GC count, maintained by the control thread. size_t get_gc_id(); - void update_gc_id(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index db4b517a1f5..cabe51edc51 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -24,7 +24,6 @@ * */ -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" @@ -45,294 +44,301 @@ #include "memory/metaspaceUtils.hpp" #include "memory/metaspaceStats.hpp" #include "runtime/atomic.hpp" +#include "utilities/events.hpp" ShenandoahGenerationalControlThread::ShenandoahGenerationalControlThread() : - ShenandoahController(), - _control_lock(Mutex::nosafepoint - 2, "ShenandoahControlGC_lock", true), - _regulator_lock(Mutex::nosafepoint - 2, "ShenandoahRegulatorGC_lock", true), + _control_lock(Mutex::nosafepoint - 2, "ShenandoahGCRequest_lock", true), _requested_gc_cause(GCCause::_no_gc), - _requested_generation(GLOBAL), - _degen_point(ShenandoahGC::_degenerated_outside_cycle), - _degen_generation(nullptr), - _mode(none) { + _requested_generation(nullptr), + _gc_mode(none), + _degen_point(ShenandoahGC::_degenerated_unset), + _heap(ShenandoahGenerationalHeap::heap()), + _age_period(0) { shenandoah_assert_generational(); set_name("Shenandoah Control Thread"); create_and_start(); } void ShenandoahGenerationalControlThread::run_service() { - ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap(); - const GCMode default_mode = concurrent_normal; - ShenandoahGenerationType generation = GLOBAL; - - uint age_period = 0; - - ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); - - // Heuristics are notified of allocation failures here and other outcomes - // of the cycle. They're also used here to control whether the Nth consecutive - // degenerated cycle should be 'promoted' to a full cycle. The decision to - // trigger a cycle or not is evaluated on the regulator thread. - ShenandoahHeuristics* global_heuristics = heap->global_generation()->heuristics(); - while (!in_graceful_shutdown() && !should_terminate()) { - // Figure out if we have pending requests. - const bool alloc_failure_pending = _alloc_failure_gc.is_set(); - const bool humongous_alloc_failure_pending = _humongous_alloc_failure_gc.is_set(); - - GCCause::Cause cause = Atomic::xchg(&_requested_gc_cause, GCCause::_no_gc); - - const bool is_gc_requested = ShenandoahCollectorPolicy::is_requested_gc(cause); + const int64_t wait_ms = ShenandoahPacing ? ShenandoahControlIntervalMin : 0; + ShenandoahGCRequest request; + while (!should_terminate()) { // This control loop iteration has seen this much allocation. const size_t allocs_seen = reset_allocs_seen(); - // Check if we have seen a new target for soft max heap size. - const bool soft_max_changed = heap->check_soft_max_changed(); + // Figure out if we have pending requests. + check_for_request(request); - // Choose which GC mode to run in. The block below should select a single mode. - set_gc_mode(none); - ShenandoahGC::ShenandoahDegenPoint degen_point = ShenandoahGC::_degenerated_unset; - - if (alloc_failure_pending) { - // Allocation failure takes precedence: we have to deal with it first thing - cause = GCCause::_allocation_failure; - - // Consume the degen point, and seed it with default value - degen_point = _degen_point; - _degen_point = ShenandoahGC::_degenerated_outside_cycle; - - if (degen_point == ShenandoahGC::_degenerated_outside_cycle) { - _degen_generation = heap->young_generation(); - } else { - assert(_degen_generation != nullptr, "Need to know which generation to resume"); - } - - ShenandoahHeuristics* heuristics = _degen_generation->heuristics(); - generation = _degen_generation->type(); - bool old_gen_evacuation_failed = heap->old_generation()->clear_failed_evacuation(); - - heuristics->log_trigger("Handle Allocation Failure"); - - // Do not bother with degenerated cycle if old generation evacuation failed or if humongous allocation failed - if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle() && - !old_gen_evacuation_failed && !humongous_alloc_failure_pending) { - heuristics->record_allocation_failure_gc(); - policy->record_alloc_failure_to_degenerated(degen_point); - set_gc_mode(stw_degenerated); - } else { - heuristics->record_allocation_failure_gc(); - policy->record_alloc_failure_to_full(); - generation = GLOBAL; - set_gc_mode(stw_full); - } - } else if (is_gc_requested) { - generation = GLOBAL; - global_heuristics->log_trigger("GC request (%s)", GCCause::to_string(cause)); - global_heuristics->record_requested_gc(); - - if (ShenandoahCollectorPolicy::should_run_full_gc(cause)) { - set_gc_mode(stw_full); - } else { - set_gc_mode(default_mode); - // Unload and clean up everything - heap->set_unload_classes(global_heuristics->can_unload_classes()); - } - } else { - // We should only be here if the regulator requested a cycle or if - // there is an old generation mark in progress. - if (cause == GCCause::_shenandoah_concurrent_gc) { - if (_requested_generation == OLD && heap->old_generation()->is_doing_mixed_evacuations()) { - // If a request to start an old cycle arrived while an old cycle was running, but _before_ - // it chose any regions for evacuation we don't want to start a new old cycle. Rather, we want - // the heuristic to run a young collection so that we can evacuate some old regions. - assert(!heap->is_concurrent_old_mark_in_progress(), "Should not be running mixed collections and concurrent marking"); - generation = YOUNG; - } else { - generation = _requested_generation; - } - - // preemption was requested or this is a regular cycle - set_gc_mode(default_mode); - - // Don't start a new old marking if there is one already in progress - if (generation == OLD && heap->is_concurrent_old_mark_in_progress()) { - set_gc_mode(servicing_old); - } - - if (generation == GLOBAL) { - heap->set_unload_classes(global_heuristics->should_unload_classes()); - } else { - heap->set_unload_classes(false); - } - } else if (heap->is_concurrent_old_mark_in_progress() || heap->is_prepare_for_old_mark_in_progress()) { - // Nobody asked us to do anything, but we have an old-generation mark or old-generation preparation for - // mixed evacuation in progress, so resume working on that. - log_info(gc)("Resume old GC: marking is%s in progress, preparing is%s in progress", - heap->is_concurrent_old_mark_in_progress() ? "" : " NOT", - heap->is_prepare_for_old_mark_in_progress() ? "" : " NOT"); - - cause = GCCause::_shenandoah_concurrent_gc; - generation = OLD; - set_gc_mode(servicing_old); - heap->set_unload_classes(false); - } + if (request.cause == GCCause::_shenandoah_stop_vm) { + break; } - const bool gc_requested = (gc_mode() != none); - assert (!gc_requested || cause != GCCause::_no_gc, "GC cause should be set"); - - if (gc_requested) { - // Cannot uncommit bitmap slices during concurrent reset - ShenandoahNoUncommitMark forbid_region_uncommit(heap); - - // Blow away all soft references on this cycle, if handling allocation failure, - // either implicit or explicit GC request, or we are requested to do so unconditionally. - if (generation == GLOBAL && (alloc_failure_pending || is_gc_requested || ShenandoahAlwaysClearSoftRefs)) { - heap->soft_ref_policy()->set_should_clear_all_soft_refs(true); - } - - // GC is starting, bump the internal ID - update_gc_id(); - - heap->reset_bytes_allocated_since_gc_start(); - - MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics(); - - // If GC was requested, we are sampling the counters even without actual triggers - // from allocation machinery. This captures GC phases more accurately. - heap->set_forced_counters_update(true); - - // If GC was requested, we better dump freeset data for performance debugging - heap->free_set()->log_status_under_lock(); - - // In case this is a degenerated cycle, remember whether original cycle was aging. - const bool was_aging_cycle = heap->is_aging_cycle(); - heap->set_aging_cycle(false); - - switch (gc_mode()) { - case concurrent_normal: { - // At this point: - // if (generation == YOUNG), this is a normal YOUNG cycle - // if (generation == OLD), this is a bootstrap OLD cycle - // if (generation == GLOBAL), this is a GLOBAL cycle triggered by System.gc() - // In all three cases, we want to age old objects if this is an aging cycle - if (age_period-- == 0) { - heap->set_aging_cycle(true); - age_period = ShenandoahAgingCyclePeriod - 1; - } - service_concurrent_normal_cycle(heap, generation, cause); - break; - } - case stw_degenerated: { - heap->set_aging_cycle(was_aging_cycle); - service_stw_degenerated_cycle(cause, degen_point); - break; - } - case stw_full: { - if (age_period-- == 0) { - heap->set_aging_cycle(true); - age_period = ShenandoahAgingCyclePeriod - 1; - } - service_stw_full_cycle(cause); - break; - } - case servicing_old: { - assert(generation == OLD, "Expected old generation here"); - GCIdMark gc_id_mark; - service_concurrent_old_cycle(heap, cause); - break; - } - default: - ShouldNotReachHere(); - } - - // If this was the requested GC cycle, notify waiters about it - if (is_gc_requested) { - notify_gc_waiters(); - } - - // If this was the allocation failure GC cycle, notify waiters about it - if (alloc_failure_pending) { - notify_alloc_failure_waiters(); - } - - // Report current free set state at the end of cycle, whether - // it is a normal completion, or the abort. - heap->free_set()->log_status_under_lock(); - - // Notify Universe about new heap usage. This has implications for - // global soft refs policy, and we better report it every time heap - // usage goes down. - heap->update_capacity_and_used_at_gc(); - - // Signal that we have completed a visit to all live objects. - heap->record_whole_heap_examined_timestamp(); - - // Disable forced counters update, and update counters one more time - // to capture the state at the end of GC session. - heap->handle_force_counters_update(); - heap->set_forced_counters_update(false); - - // Retract forceful part of soft refs policy - heap->soft_ref_policy()->set_should_clear_all_soft_refs(false); - - // Clear metaspace oom flag, if current cycle unloaded classes - if (heap->unload_classes()) { - global_heuristics->clear_metaspace_oom(); - } - - process_phase_timings(heap); - - // Print Metaspace change following GC (if logging is enabled). - MetaspaceUtils::print_metaspace_change(meta_sizes); - - // GC is over, we are at idle now - if (ShenandoahPacing) { - heap->pacer()->setup_for_idle(); - } + if (request.cause != GCCause::_no_gc) { + run_gc_cycle(request); } else { // Report to pacer that we have seen this many words allocated if (ShenandoahPacing && (allocs_seen > 0)) { - heap->pacer()->report_alloc(allocs_seen); + _heap->pacer()->report_alloc(allocs_seen); } } - // Check if we have seen a new target for soft max heap size or if a gc was requested. - // Either of these conditions will attempt to uncommit regions. - if (ShenandoahUncommit) { - if (heap->check_soft_max_changed()) { - heap->notify_soft_max_changed(); - } else if (is_gc_requested) { - heap->notify_explicit_gc_requested(); + // If the cycle was cancelled, continue the next iteration to deal with it. Otherwise, + // if there was no other cycle requested, cleanup and wait for the next request. + if (!_heap->cancelled_gc()) { + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + if (_requested_gc_cause == GCCause::_no_gc) { + set_gc_mode(ml, none); + ml.wait(wait_ms); } } - - // Wait for ShenandoahControlIntervalMax unless there was an allocation failure or another request was made mid-cycle. - if (!is_alloc_failure_gc() && _requested_gc_cause == GCCause::_no_gc) { - // The timed wait is necessary because this thread has a responsibility to send - // 'alloc_words' to the pacer when it does not perform a GC. - MonitorLocker lock(&_control_lock, Mutex::_no_safepoint_check_flag); - lock.wait(ShenandoahControlIntervalMax); - } } + // In case any threads are waiting for a cycle to happen, notify them so they observe the shutdown. + notify_gc_waiters(); + notify_alloc_failure_waiters(); set_gc_mode(stopped); +} - // Wait for the actual stop(), can't leave run_service() earlier. - while (!should_terminate()) { - os::naked_short_sleep(ShenandoahControlIntervalMin); +void ShenandoahGenerationalControlThread::stop_service() { + log_debug(gc, thread)("Stopping control thread"); + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + _heap->cancel_gc(GCCause::_shenandoah_stop_vm); + _requested_gc_cause = GCCause::_shenandoah_stop_vm; + notify_cancellation(ml, GCCause::_shenandoah_stop_vm); + // We can't wait here because it may interfere with the active cycle's ability + // to reach a safepoint (this runs on a java thread). +} + +void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest& request) { + // Hold the lock while we read request cause and generation + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + if (_heap->cancelled_gc()) { + // The previous request was cancelled. Either it was cancelled for an allocation + // failure (degenerated cycle), or old marking was cancelled to run a young collection. + // In either case, the correct generation for the next cycle can be determined by + // the cancellation cause. + request.cause = _heap->cancelled_cause(); + if (request.cause == GCCause::_shenandoah_concurrent_gc) { + request.generation = _heap->young_generation(); + _heap->clear_cancelled_gc(false); + } + } else { + request.cause = _requested_gc_cause; + request.generation = _requested_generation; + + // Only clear these if we made a request from them. In the case of a cancelled gc, + // we do not want to inadvertently lose this pending request. + _requested_gc_cause = GCCause::_no_gc; + _requested_generation = nullptr; + } + + if (request.cause == GCCause::_no_gc || request.cause == GCCause::_shenandoah_stop_vm) { + return; + } + + GCMode mode; + if (ShenandoahCollectorPolicy::is_allocation_failure(request.cause)) { + mode = prepare_for_allocation_failure_gc(request); + } else if (ShenandoahCollectorPolicy::is_explicit_gc(request.cause)) { + mode = prepare_for_explicit_gc(request); + } else { + mode = prepare_for_concurrent_gc(request); + } + set_gc_mode(ml, mode); +} + +ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_allocation_failure_gc(ShenandoahGCRequest &request) { + + if (_degen_point == ShenandoahGC::_degenerated_unset) { + _degen_point = ShenandoahGC::_degenerated_outside_cycle; + request.generation = _heap->young_generation(); + } else if (request.generation->is_old()) { + // This means we degenerated during the young bootstrap for the old generation + // cycle. The following degenerated cycle should therefore also be young. + request.generation = _heap->young_generation(); + } + + ShenandoahHeuristics* heuristics = request.generation->heuristics(); + bool old_gen_evacuation_failed = _heap->old_generation()->clear_failed_evacuation(); + + heuristics->log_trigger("Handle Allocation Failure"); + + // Do not bother with degenerated cycle if old generation evacuation failed or if humongous allocation failed + if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle() && + !old_gen_evacuation_failed && request.cause != GCCause::_shenandoah_humongous_allocation_failure) { + heuristics->record_allocation_failure_gc(); + _heap->shenandoah_policy()->record_alloc_failure_to_degenerated(_degen_point); + return stw_degenerated; + } else { + heuristics->record_allocation_failure_gc(); + _heap->shenandoah_policy()->record_alloc_failure_to_full(); + request.generation = _heap->global_generation(); + return stw_full; } } -void ShenandoahGenerationalControlThread::process_phase_timings(const ShenandoahGenerationalHeap* heap) { - // Commit worker statistics to cycle data - heap->phase_timings()->flush_par_workers_to_cycle(); - if (ShenandoahPacing) { - heap->pacer()->flush_stats_to_cycle(); +ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_explicit_gc(ShenandoahGCRequest &request) const { + ShenandoahHeuristics* global_heuristics = _heap->global_generation()->heuristics(); + request.generation = _heap->global_generation(); + global_heuristics->log_trigger("GC request (%s)", GCCause::to_string(request.cause)); + global_heuristics->record_requested_gc(); + + if (ShenandoahCollectorPolicy::should_run_full_gc(request.cause)) { + return stw_full;; + } else { + // Unload and clean up everything. Note that this is an _explicit_ request and so does not use + // the same `should_unload_classes` call as the regulator's concurrent gc request. + _heap->set_unload_classes(global_heuristics->can_unload_classes()); + return concurrent_normal; + } +} + +ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread::prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const { + assert(!(request.generation->is_old() && _heap->old_generation()->is_doing_mixed_evacuations()), + "Old heuristic should not request cycles while it waits for mixed evacuations"); + + if (request.generation->is_global()) { + ShenandoahHeuristics* global_heuristics = _heap->global_generation()->heuristics(); + _heap->set_unload_classes(global_heuristics->should_unload_classes()); + } else { + _heap->set_unload_classes(false); } - ShenandoahEvacuationTracker* evac_tracker = heap->evac_tracker(); + // preemption was requested or this is a regular cycle + return request.generation->is_old() ? servicing_old : concurrent_normal; +} + +void ShenandoahGenerationalControlThread::maybe_set_aging_cycle() { + if (_age_period-- == 0) { + _heap->set_aging_cycle(true); + _age_period = ShenandoahAgingCyclePeriod - 1; + } else { + _heap->set_aging_cycle(false); + } +} + +void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest& request) { + + log_debug(gc, thread)("Starting GC (%s): %s, %s", gc_mode_name(gc_mode()), GCCause::to_string(request.cause), request.generation->name()); + assert(gc_mode() != none, "GC mode cannot be none here"); + + // Blow away all soft references on this cycle, if handling allocation failure, + // either implicit or explicit GC request, or we are requested to do so unconditionally. + if (request.generation->is_global() && (ShenandoahCollectorPolicy::is_allocation_failure(request.cause) || ShenandoahCollectorPolicy::is_explicit_gc(request.cause) || ShenandoahAlwaysClearSoftRefs)) { + _heap->soft_ref_policy()->set_should_clear_all_soft_refs(true); + } + + // GC is starting, bump the internal ID + update_gc_id(); + + _heap->reset_bytes_allocated_since_gc_start(); + + MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics(); + + // If GC was requested, we are sampling the counters even without actual triggers + // from allocation machinery. This captures GC phases more accurately. + _heap->set_forced_counters_update(true); + + // If GC was requested, we better dump freeset data for performance debugging + _heap->free_set()->log_status_under_lock(); + + { + // Cannot uncommit bitmap slices during concurrent reset + ShenandoahNoUncommitMark forbid_region_uncommit(_heap); + + switch (gc_mode()) { + case concurrent_normal: { + service_concurrent_normal_cycle(request); + break; + } + case stw_degenerated: { + service_stw_degenerated_cycle(request); + break; + } + case stw_full: { + service_stw_full_cycle(request.cause); + break; + } + case servicing_old: { + assert(request.generation->is_old(), "Expected old generation here"); + GCIdMark gc_id_mark; + service_concurrent_old_cycle(request); + break; + } + default: + ShouldNotReachHere(); + } + } + + // If this was the requested GC cycle, notify waiters about it + if (ShenandoahCollectorPolicy::is_explicit_gc(request.cause)) { + notify_gc_waiters(); + } + + // If this was an allocation failure GC cycle, notify waiters about it + if (ShenandoahCollectorPolicy::is_allocation_failure(request.cause)) { + notify_alloc_failure_waiters(); + } + + // Report current free set state at the end of cycle, whether + // it is a normal completion, or the abort. + _heap->free_set()->log_status_under_lock(); + + // Notify Universe about new heap usage. This has implications for + // global soft refs policy, and we better report it every time heap + // usage goes down. + _heap->update_capacity_and_used_at_gc(); + + // Signal that we have completed a visit to all live objects. + _heap->record_whole_heap_examined_timestamp(); + + // Disable forced counters update, and update counters one more time + // to capture the state at the end of GC session. + _heap->handle_force_counters_update(); + _heap->set_forced_counters_update(false); + + // Retract forceful part of soft refs policy + _heap->soft_ref_policy()->set_should_clear_all_soft_refs(false); + + // Clear metaspace oom flag, if current cycle unloaded classes + if (_heap->unload_classes()) { + _heap->global_generation()->heuristics()->clear_metaspace_oom(); + } + + process_phase_timings(); + + // Print Metaspace change following GC (if logging is enabled). + MetaspaceUtils::print_metaspace_change(meta_sizes); + + // GC is over, we are at idle now + if (ShenandoahPacing) { + _heap->pacer()->setup_for_idle(); + } + + // Check if we have seen a new target for soft max heap size or if a gc was requested. + // Either of these conditions will attempt to uncommit regions. + if (ShenandoahUncommit) { + if (_heap->check_soft_max_changed()) { + _heap->notify_soft_max_changed(); + } else if (ShenandoahCollectorPolicy::is_explicit_gc(request.cause)) { + _heap->notify_explicit_gc_requested(); + } + } + + log_debug(gc, thread)("Completed GC (%s): %s, %s, cancelled: %s", + gc_mode_name(gc_mode()), GCCause::to_string(request.cause), request.generation->name(), GCCause::to_string(_heap->cancelled_cause())); +} + +void ShenandoahGenerationalControlThread::process_phase_timings() const { + // Commit worker statistics to cycle data + _heap->phase_timings()->flush_par_workers_to_cycle(); + if (ShenandoahPacing) { + _heap->pacer()->flush_stats_to_cycle(); + } + + ShenandoahEvacuationTracker* evac_tracker = _heap->evac_tracker(); ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global(); // Print GC stats for current cycle @@ -341,17 +347,17 @@ void ShenandoahGenerationalControlThread::process_phase_timings(const Shenandoah if (lt.is_enabled()) { ResourceMark rm; LogStream ls(lt); - heap->phase_timings()->print_cycle_on(&ls); + _heap->phase_timings()->print_cycle_on(&ls); evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, &evac_stats.mutators); if (ShenandoahPacing) { - heap->pacer()->print_cycle_on(&ls); + _heap->pacer()->print_cycle_on(&ls); } } } // Commit statistics to globals - heap->phase_timings()->flush_cycle_to_global(); + _heap->phase_timings()->flush_cycle_to_global(); } // Young and old concurrent cycles are initiated by the regulator. Implicit @@ -379,46 +385,27 @@ void ShenandoahGenerationalControlThread::process_phase_timings(const Shenandoah // | v v | // +---> Global Degen +--------------------> Full <----+ // -void ShenandoahGenerationalControlThread::service_concurrent_normal_cycle(ShenandoahGenerationalHeap* heap, - const ShenandoahGenerationType generation, - GCCause::Cause cause) { +void ShenandoahGenerationalControlThread::service_concurrent_normal_cycle(const ShenandoahGCRequest& request) { GCIdMark gc_id_mark; - switch (generation) { - case YOUNG: { - // Run a young cycle. This might or might not, have interrupted an ongoing - // concurrent mark in the old generation. We need to think about promotions - // in this case. Promoted objects should be above the TAMS in the old regions - // they end up in, but we have to be sure we don't promote into any regions - // that are in the cset. - log_info(gc, ergo)("Start GC cycle (Young)"); - service_concurrent_cycle(heap->young_generation(), cause, false); - break; - } - case OLD: { - log_info(gc, ergo)("Start GC cycle (Old)"); - service_concurrent_old_cycle(heap, cause); - break; - } - case GLOBAL: { - log_info(gc, ergo)("Start GC cycle (Global)"); - service_concurrent_cycle(heap->global_generation(), cause, false); - break; - } - default: - ShouldNotReachHere(); + log_info(gc, ergo)("Start GC cycle (%s)", request.generation->name()); + if (request.generation->is_old()) { + service_concurrent_old_cycle(request); + } else { + service_concurrent_cycle(request.generation, request.cause, false); } } -void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(ShenandoahGenerationalHeap* heap, GCCause::Cause &cause) { - ShenandoahOldGeneration* old_generation = heap->old_generation(); - ShenandoahYoungGeneration* young_generation = heap->young_generation(); +void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const ShenandoahGCRequest& request) { + ShenandoahOldGeneration* old_generation = _heap->old_generation(); + ShenandoahYoungGeneration* young_generation = _heap->young_generation(); ShenandoahOldGeneration::State original_state = old_generation->state(); - TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + TraceCollectorStats tcs(_heap->monitoring_support()->concurrent_collection_counters()); switch (original_state) { case ShenandoahOldGeneration::FILLING: { - ShenandoahGCSession session(cause, old_generation); + ShenandoahGCSession session(request.cause, old_generation); + assert(gc_mode() == servicing_old, "Filling should be servicing old"); _allow_old_preemption.set(); old_generation->entry_coalesce_and_fill(); _allow_old_preemption.unset(); @@ -430,7 +417,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(Shenandoa // acknowledge the cancellation request, the subsequent young cycle will observe // the request and essentially cancel itself. if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) { - log_info(gc)("Preparation for old generation cycle was cancelled"); + log_info(gc, thread)("Preparation for old generation cycle was cancelled"); return; } @@ -448,20 +435,16 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(Shenandoa // task queues but it will not traverse them. set_gc_mode(bootstrapping_old); young_generation->set_old_gen_task_queues(old_generation->task_queues()); - ShenandoahGCSession session(cause, young_generation); - service_concurrent_cycle(heap, young_generation, cause, true); - process_phase_timings(heap); - if (heap->cancelled_gc()) { + service_concurrent_cycle(young_generation, request.cause, true); + process_phase_timings(); + if (_heap->cancelled_gc()) { // Young generation bootstrap cycle has failed. Concurrent mark for old generation // is going to resume after degenerated bootstrap cycle completes. log_info(gc)("Bootstrap cycle for old generation was cancelled"); return; } - // Reset the degenerated point. Normally this would happen at the top - // of the control loop, but here we have just completed a young cycle - // which has bootstrapped the old concurrent marking. - _degen_point = ShenandoahGC::_degenerated_outside_cycle; + assert(_degen_point == ShenandoahGC::_degenerated_unset, "Degen point should not be set if gc wasn't cancelled"); // From here we will 'resume' the old concurrent mark. This will skip reset // and init mark for the concurrent mark. All of that work will have been @@ -470,17 +453,17 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(Shenandoa old_generation->transition_to(ShenandoahOldGeneration::MARKING); } case ShenandoahOldGeneration::MARKING: { - ShenandoahGCSession session(cause, old_generation); - bool marking_complete = resume_concurrent_old_cycle(old_generation, cause); + ShenandoahGCSession session(request.cause, old_generation); + bool marking_complete = resume_concurrent_old_cycle(old_generation, request.cause); if (marking_complete) { assert(old_generation->state() != ShenandoahOldGeneration::MARKING, "Should not still be marking"); if (original_state == ShenandoahOldGeneration::MARKING) { - heap->mmu_tracker()->record_old_marking_increment(true); - heap->log_heap_status("At end of Concurrent Old Marking finishing increment"); + _heap->mmu_tracker()->record_old_marking_increment(true); + _heap->log_heap_status("At end of Concurrent Old Marking finishing increment"); } } else if (original_state == ShenandoahOldGeneration::MARKING) { - heap->mmu_tracker()->record_old_marking_increment(false); - heap->log_heap_status("At end of Concurrent Old Marking increment"); + _heap->mmu_tracker()->record_old_marking_increment(false); + _heap->log_heap_status("At end of Concurrent Old Marking increment"); } break; } @@ -490,21 +473,19 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(Shenandoa } bool ShenandoahGenerationalControlThread::resume_concurrent_old_cycle(ShenandoahOldGeneration* generation, GCCause::Cause cause) { - assert(ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress(), "Old mark should be in progress"); + assert(_heap->is_concurrent_old_mark_in_progress(), "Old mark should be in progress"); log_debug(gc)("Resuming old generation with " UINT32_FORMAT " marking tasks queued", generation->task_queues()->tasks()); - ShenandoahHeap* heap = ShenandoahHeap::heap(); - // We can only tolerate being cancelled during concurrent marking or during preparation for mixed // evacuation. This flag here (passed by reference) is used to control precisely where the regulator // is allowed to cancel a GC. ShenandoahOldGC gc(generation, _allow_old_preemption); if (gc.collect(cause)) { - heap->notify_gc_progress(); + _heap->notify_gc_progress(); generation->record_success_concurrent(false); } - if (heap->cancelled_gc()) { + if (_heap->cancelled_gc()) { // It's possible the gc cycle was cancelled after the last time // the collection checked for cancellation. In which case, the // old gc cycle is still completed, and we have to deal with this @@ -515,89 +496,84 @@ bool ShenandoahGenerationalControlThread::resume_concurrent_old_cycle(Shenandoah // cycle, then we are not actually going to a degenerated cycle, // so the degenerated point doesn't matter here. check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle); - if (_requested_gc_cause == GCCause::_shenandoah_concurrent_gc) { - heap->shenandoah_policy()->record_interrupted_old(); + if (cause == GCCause::_shenandoah_concurrent_gc) { + _heap->shenandoah_policy()->record_interrupted_old(); } return false; } return true; } -void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool do_old_gc_bootstrap) { - // Normal cycle goes via all concurrent phases. If allocation failure (af) happens during - // any of the concurrent phases, it first degrades to Degenerated GC and completes GC there. - // If second allocation failure happens during Degenerated GC cycle (for example, when GC - // tries to evac something and no memory is available), cycle degrades to Full GC. - // - // There are also a shortcut through the normal cycle: immediate garbage shortcut, when - // heuristics says there are no regions to compact, and all the collection comes from immediately - // reclaimable regions. - // - // ................................................................................................ - // - // (immediate garbage shortcut) Concurrent GC - // /-------------------------------------------\ - // | | - // | | - // | | - // | v - // [START] ----> Conc Mark ----o----> Conc Evac --o--> Conc Update-Refs ---o----> [END] - // | | | ^ - // | (af) | (af) | (af) | - // ..................|....................|.................|..............|....................... - // | | | | - // | | | | Degenerated GC - // v v v | - // STW Mark ----------> STW Evac ----> STW Update-Refs ----->o - // | | | ^ - // | (af) | (af) | (af) | - // ..................|....................|.................|..............|....................... - // | | | | - // | v | | Full GC - // \------------------->o<----------------/ | - // | | - // v | - // Full GC --------------------------/ - // - if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return; +// Normal cycle goes via all concurrent phases. If allocation failure (af) happens during +// any of the concurrent phases, it first degrades to Degenerated GC and completes GC there. +// If second allocation failure happens during Degenerated GC cycle (for example, when GC +// tries to evac something and no memory is available), cycle degrades to Full GC. +// +// There are also a shortcut through the normal cycle: immediate garbage shortcut, when +// heuristics says there are no regions to compact, and all the collection comes from immediately +// reclaimable regions. +// +// ................................................................................................ +// +// (immediate garbage shortcut) Concurrent GC +// /-------------------------------------------\ +// | | +// | | +// | | +// | v +// [START] ----> Conc Mark ----o----> Conc Evac --o--> Conc Update-Refs ---o----> [END] +// | | | ^ +// | (af) | (af) | (af) | +// ..................|....................|.................|..............|....................... +// | | | | +// | | | | Degenerated GC +// v v v | +// STW Mark ----------> STW Evac ----> STW Update-Refs ----->o +// | | | ^ +// | (af) | (af) | (af) | +// ..................|....................|.................|..............|....................... +// | | | | +// | v | | Full GC +// \------------------->o<----------------/ | +// | | +// v | +// Full GC --------------------------/ +// +void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahGeneration* generation, + GCCause::Cause cause, + bool do_old_gc_bootstrap) { + // At this point: + // if (generation == YOUNG), this is a normal young cycle or a bootstrap cycle + // if (generation == GLOBAL), this is a GLOBAL cycle + // In either case, we want to age old objects if this is an aging cycle + maybe_set_aging_cycle(); - ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahGCSession session(cause, generation); - TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + TraceCollectorStats tcs(_heap->monitoring_support()->concurrent_collection_counters()); - service_concurrent_cycle(heap, generation, cause, do_old_gc_bootstrap); -} - -void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahHeap* heap, - ShenandoahGeneration* generation, - GCCause::Cause& cause, - bool do_old_gc_bootstrap) { assert(!generation->is_old(), "Old GC takes a different control path"); ShenandoahConcurrentGC gc(generation, do_old_gc_bootstrap); if (gc.collect(cause)) { // Cycle is complete - heap->notify_gc_progress(); + _heap->notify_gc_progress(); generation->record_success_concurrent(gc.abbreviated()); } else { - assert(heap->cancelled_gc(), "Must have been cancelled"); + assert(_heap->cancelled_gc(), "Must have been cancelled"); check_cancellation_or_degen(gc.degen_point()); - - // Concurrent young-gen collection degenerates to young - // collection. Same for global collections. - _degen_generation = generation; } + const char* msg; - ShenandoahMmuTracker* mmu_tracker = heap->mmu_tracker(); + ShenandoahMmuTracker* mmu_tracker = _heap->mmu_tracker(); if (generation->is_young()) { - if (heap->cancelled_gc()) { + if (_heap->cancelled_gc()) { msg = (do_old_gc_bootstrap) ? "At end of Interrupted Concurrent Bootstrap GC" : "At end of Interrupted Concurrent Young GC"; } else { // We only record GC results if GC was successful msg = (do_old_gc_bootstrap) ? "At end of Concurrent Bootstrap GC" : "At end of Concurrent Young GC"; - if (heap->collection_set()->has_old_regions()) { + if (_heap->collection_set()->has_old_regions()) { mmu_tracker->record_mixed(get_gc_id()); } else if (do_old_gc_bootstrap) { mmu_tracker->record_bootstrap(get_gc_id()); @@ -608,7 +584,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahHea } else { assert(generation->is_global(), "If not young, must be GLOBAL"); assert(!do_old_gc_bootstrap, "Do not bootstrap with GLOBAL GC"); - if (heap->cancelled_gc()) { + if (_heap->cancelled_gc()) { msg = "At end of Interrupted Concurrent GLOBAL GC"; } else { // We only record GC results if GC was successful @@ -616,39 +592,27 @@ void ShenandoahGenerationalControlThread::service_concurrent_cycle(ShenandoahHea mmu_tracker->record_global(get_gc_id()); } } - heap->log_heap_status(msg); + _heap->log_heap_status(msg); } bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!heap->cancelled_gc()) { + if (!_heap->cancelled_gc()) { return false; } - if (in_graceful_shutdown()) { + if (_heap->cancelled_cause() == GCCause::_shenandoah_stop_vm + || _heap->cancelled_cause() == GCCause::_shenandoah_concurrent_gc) { + log_debug(gc, thread)("Cancellation detected, reason: %s", GCCause::to_string(_heap->cancelled_cause())); return true; } - assert(_degen_point == ShenandoahGC::_degenerated_outside_cycle, - "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); - - if (is_alloc_failure_gc()) { + if (ShenandoahCollectorPolicy::is_allocation_failure(_heap->cancelled_cause())) { + assert(_degen_point == ShenandoahGC::_degenerated_unset, + "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point)); _degen_point = point; - _preemption_requested.unset(); - return true; - } - - if (_preemption_requested.is_set()) { - assert(_requested_generation == YOUNG, "Only young GCs may preempt old."); - _preemption_requested.unset(); - - // Old generation marking is only cancellable during concurrent marking. - // Once final mark is complete, the code does not check again for cancellation. - // If old generation was cancelled for an allocation failure, we wouldn't - // make it to this case. The calling code is responsible for forcing a - // cancellation due to allocation failure into a degenerated cycle. - _degen_point = point; - heap->clear_cancelled_gc(false /* clear oom handler */); + log_debug(gc, thread)("Cancellation detected:, reason: %s, degen point: %s", + GCCause::to_string(_heap->cancelled_cause()), + ShenandoahGC::degen_point_to_string(_degen_point)); return true; } @@ -656,38 +620,32 @@ bool ShenandoahGenerationalControlThread::check_cancellation_or_degen(Shenandoah return false; } -void ShenandoahGenerationalControlThread::stop_service() { - // Nothing to do here. -} - void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause cause) { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - GCIdMark gc_id_mark; - ShenandoahGCSession session(cause, heap->global_generation()); - + ShenandoahGCSession session(cause, _heap->global_generation()); + maybe_set_aging_cycle(); ShenandoahFullGC gc; gc.collect(cause); + _degen_point = ShenandoahGC::_degenerated_unset; } -void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, - ShenandoahGC::ShenandoahDegenPoint point) { - assert(point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set"); - ShenandoahHeap* const heap = ShenandoahHeap::heap(); +void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const ShenandoahGCRequest& request) { + assert(_degen_point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set"); GCIdMark gc_id_mark; - ShenandoahGCSession session(cause, _degen_generation); + ShenandoahGCSession session(request.cause, request.generation); - ShenandoahDegenGC gc(point, _degen_generation); - gc.collect(cause); + ShenandoahDegenGC gc(_degen_point, request.generation); + gc.collect(request.cause); + _degen_point = ShenandoahGC::_degenerated_unset; - assert(heap->young_generation()->task_queues()->is_empty(), "Unexpected young generation marking tasks"); - if (_degen_generation->is_global()) { - assert(heap->old_generation()->task_queues()->is_empty(), "Unexpected old generation marking tasks"); - assert(heap->global_generation()->task_queues()->is_empty(), "Unexpected global generation marking tasks"); + assert(_heap->young_generation()->task_queues()->is_empty(), "Unexpected young generation marking tasks"); + if (request.generation->is_global()) { + assert(_heap->old_generation()->task_queues()->is_empty(), "Unexpected old generation marking tasks"); + assert(_heap->global_generation()->task_queues()->is_empty(), "Unexpected global generation marking tasks"); } else { - assert(_degen_generation->is_young(), "Expected degenerated young cycle, if not global."); - ShenandoahOldGeneration* old = heap->old_generation(); + assert(request.generation->is_young(), "Expected degenerated young cycle, if not global."); + ShenandoahOldGeneration* old = _heap->old_generation(); if (old->is_bootstrapping()) { old->transition_to(ShenandoahOldGeneration::MARKING); } @@ -695,72 +653,87 @@ void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(GCCause: } void ShenandoahGenerationalControlThread::request_gc(GCCause::Cause cause) { - if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) { + if (ShenandoahCollectorPolicy::is_allocation_failure(cause)) { + // GC should already be cancelled. Here we are just notifying the control thread to + // wake up and handle the cancellation request, so we don't need to set _requested_gc_cause. + notify_cancellation(cause); + } else if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) { handle_requested_gc(cause); } } -bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenerationType generation) { - if (_preemption_requested.is_set() || _requested_gc_cause != GCCause::_no_gc || ShenandoahHeap::heap()->cancelled_gc()) { +bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGeneration* generation) { + if (_heap->cancelled_gc()) { // Ignore subsequent requests from the heuristics - log_debug(gc, thread)("Reject request for concurrent gc: preemption_requested: %s, gc_requested: %s, gc_cancelled: %s", - BOOL_TO_STR(_preemption_requested.is_set()), + log_debug(gc, thread)("Reject request for concurrent gc: gc_requested: %s, gc_cancelled: %s", GCCause::to_string(_requested_gc_cause), - BOOL_TO_STR(ShenandoahHeap::heap()->cancelled_gc())); + BOOL_TO_STR(_heap->cancelled_gc())); return false; } - if (gc_mode() == none) { - GCCause::Cause existing = Atomic::cmpxchg(&_requested_gc_cause, GCCause::_no_gc, GCCause::_shenandoah_concurrent_gc); - if (existing != GCCause::_no_gc) { - log_debug(gc, thread)("Reject request for concurrent gc because another gc is pending: %s", GCCause::to_string(existing)); + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + if (gc_mode() == servicing_old) { + if (!preempt_old_marking(generation)) { + log_debug(gc, thread)("Cannot start young, old collection is not preemptible"); return false; } - _requested_generation = generation; - notify_control_thread(); - - MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag); - while (gc_mode() == none) { - ml.wait(); - } - return true; - } - - if (preempt_old_marking(generation)) { - assert(gc_mode() == servicing_old, "Expected to be servicing old, but was: %s.", gc_mode_name(gc_mode())); - GCCause::Cause existing = Atomic::cmpxchg(&_requested_gc_cause, GCCause::_no_gc, GCCause::_shenandoah_concurrent_gc); - if (existing != GCCause::_no_gc) { - log_debug(gc, thread)("Reject request to interrupt old gc because another gc is pending: %s", GCCause::to_string(existing)); - return false; - } - - log_info(gc)("Preempting old generation mark to allow %s GC", shenandoah_generation_name(generation)); - _requested_generation = generation; - _preemption_requested.set(); - ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc); - notify_control_thread(); - - MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag); + // Cancel the old GC and wait for the control thread to start servicing the new request. + log_info(gc)("Preempting old generation mark to allow %s GC", generation->name()); while (gc_mode() == servicing_old) { + ShenandoahHeap::heap()->cancel_gc(GCCause::_shenandoah_concurrent_gc); + notify_cancellation(ml, GCCause::_shenandoah_concurrent_gc); ml.wait(); } return true; } + if (gc_mode() == none) { + while (gc_mode() == none) { + if (_requested_gc_cause != GCCause::_no_gc) { + log_debug(gc, thread)("Reject request for concurrent gc because another gc is pending: %s", GCCause::to_string(_requested_gc_cause)); + return false; + } + + notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc, generation); + ml.wait(); + } + return true; + } + + log_debug(gc, thread)("Reject request for concurrent gc: mode: %s, allow_old_preemption: %s", gc_mode_name(gc_mode()), BOOL_TO_STR(_allow_old_preemption.is_set())); return false; } -void ShenandoahGenerationalControlThread::notify_control_thread() { - MonitorLocker locker(&_control_lock, Mutex::_no_safepoint_check_flag); - _control_lock.notify(); +void ShenandoahGenerationalControlThread::notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation) { + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + notify_control_thread(ml, cause, generation); } -bool ShenandoahGenerationalControlThread::preempt_old_marking(ShenandoahGenerationType generation) { - return (generation == YOUNG) && _allow_old_preemption.try_unset(); +void ShenandoahGenerationalControlThread::notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation) { + assert(_control_lock.is_locked(), "Request lock must be held here"); + log_debug(gc, thread)("Notify control (%s): %s, %s", gc_mode_name(gc_mode()), GCCause::to_string(cause), generation->name()); + _requested_gc_cause = cause; + _requested_generation = generation; + ml.notify(); +} + +void ShenandoahGenerationalControlThread::notify_cancellation(GCCause::Cause cause) { + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + notify_cancellation(ml, cause); +} + +void ShenandoahGenerationalControlThread::notify_cancellation(MonitorLocker& ml, GCCause::Cause cause) { + assert(_heap->cancelled_gc(), "GC should already be cancelled"); + log_debug(gc,thread)("Notify control (%s): %s", gc_mode_name(gc_mode()), GCCause::to_string(cause)); + ml.notify(); +} + +bool ShenandoahGenerationalControlThread::preempt_old_marking(ShenandoahGeneration* generation) { + return generation->is_young() && _allow_old_preemption.try_unset(); } void ShenandoahGenerationalControlThread::handle_requested_gc(GCCause::Cause cause) { @@ -769,8 +742,7 @@ void ShenandoahGenerationalControlThread::handle_requested_gc(GCCause::Cause cau // The whitebox caller thread will arrange for itself to wait until the GC notifies // it that has reached the requested breakpoint (phase in the GC). if (cause == GCCause::_wb_breakpoint) { - Atomic::xchg(&_requested_gc_cause, cause); - notify_control_thread(); + notify_control_thread(cause, ShenandoahHeap::heap()->global_generation()); return; } @@ -785,17 +757,10 @@ void ShenandoahGenerationalControlThread::handle_requested_gc(GCCause::Cause cau MonitorLocker ml(&_gc_waiters_lock); size_t current_gc_id = get_gc_id(); - size_t required_gc_id = current_gc_id + 1; - while (current_gc_id < required_gc_id) { - // This races with the regulator thread to start a concurrent gc and the - // control thread to clear it at the start of a cycle. Threads here are - // allowed to escalate a heuristic's request for concurrent gc. - GCCause::Cause existing = Atomic::xchg(&_requested_gc_cause, cause); - if (existing != GCCause::_no_gc) { - log_debug(gc, thread)("GC request supersedes existing request: %s", GCCause::to_string(existing)); - } - - notify_control_thread(); + const size_t required_gc_id = current_gc_id + 1; + while (current_gc_id < required_gc_id && !should_terminate()) { + // Make requests to run a global cycle until at least one is completed + notify_control_thread(cause, ShenandoahHeap::heap()->global_generation()); ml.wait(); current_gc_id = get_gc_id(); } @@ -806,7 +771,7 @@ void ShenandoahGenerationalControlThread::notify_gc_waiters() { ml.notify_all(); } -const char* ShenandoahGenerationalControlThread::gc_mode_name(ShenandoahGenerationalControlThread::GCMode mode) { +const char* ShenandoahGenerationalControlThread::gc_mode_name(GCMode mode) { switch (mode) { case none: return "idle"; case concurrent_normal: return "normal"; @@ -819,11 +784,16 @@ const char* ShenandoahGenerationalControlThread::gc_mode_name(ShenandoahGenerati } } -void ShenandoahGenerationalControlThread::set_gc_mode(ShenandoahGenerationalControlThread::GCMode new_mode) { - if (_mode != new_mode) { - log_debug(gc)("Transition from: %s to: %s", gc_mode_name(_mode), gc_mode_name(new_mode)); - MonitorLocker ml(&_regulator_lock, Mutex::_no_safepoint_check_flag); - _mode = new_mode; +void ShenandoahGenerationalControlThread::set_gc_mode(GCMode new_mode) { + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + set_gc_mode(ml, new_mode); +} + +void ShenandoahGenerationalControlThread::set_gc_mode(MonitorLocker& ml, GCMode new_mode) { + if (_gc_mode != new_mode) { + log_debug(gc, thread)("Transition from: %s to: %s", gc_mode_name(_gc_mode), gc_mode_name(new_mode)); + EventMark event("Control thread transition from: %s, to %s", gc_mode_name(_gc_mode), gc_mode_name(new_mode)); + _gc_mode = new_mode; ml.notify_all(); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp index 46072b98255..1586205742a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp @@ -28,10 +28,9 @@ #include "gc/shared/gcCause.hpp" #include "gc/shenandoah/shenandoahController.hpp" -#include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahGC.hpp" -#include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" +#include "runtime/mutexLocker.hpp" class ShenandoahOldGeneration; class ShenandoahGeneration; @@ -52,21 +51,43 @@ public: stopped } GCMode; + class ShenandoahGCRequest { + public: + ShenandoahGCRequest() : generation(nullptr), cause(GCCause::_no_gc) {} + ShenandoahGeneration* generation; + GCCause::Cause cause; + }; + private: + // This lock is used to coordinate setting the _requested_gc_cause, _requested generation + // and _gc_mode. It is important that these be changed together and have a consistent view. Monitor _control_lock; - Monitor _regulator_lock; - - ShenandoahSharedFlag _allow_old_preemption; - ShenandoahSharedFlag _preemption_requested; + // Represents a normal (non cancellation) gc request. This can be set by mutators (System.gc, + // whitebox gc, etc.) or by the regulator thread when the heuristics want to start a cycle. GCCause::Cause _requested_gc_cause; - volatile ShenandoahGenerationType _requested_generation; - ShenandoahGC::ShenandoahDegenPoint _degen_point; - ShenandoahGeneration* _degen_generation; - shenandoah_padding(0); - volatile GCMode _mode; - shenandoah_padding(1); + // This is the generation the request should operate on. + ShenandoahGeneration* _requested_generation; + + // The mode is read frequently by requesting threads and only ever written by the control thread. + // This may be read without taking the _control_lock, but should be read again under the lock + // before making any state changes (double-checked locking idiom). + volatile GCMode _gc_mode; + + // Only the control thread knows the correct degeneration point. This is used to have the + // control thread resume a STW cycle from the point where the concurrent cycle was cancelled. + ShenandoahGC::ShenandoahDegenPoint _degen_point; + + // A reference to the heap + ShenandoahGenerationalHeap* _heap; + + // This is used to keep track of whether to age objects during the current cycle. + uint _age_period; + + // This is true when the old generation cycle is in an interruptible phase (i.e., marking or + // preparing for mark). + ShenandoahSharedFlag _allow_old_preemption; public: ShenandoahGenerationalControlThread(); @@ -77,54 +98,68 @@ public: void request_gc(GCCause::Cause cause) override; // Return true if the request to start a concurrent GC for the given generation succeeded. - bool request_concurrent_gc(ShenandoahGenerationType generation); + bool request_concurrent_gc(ShenandoahGeneration* generation); - GCMode gc_mode() { - return _mode; + // Returns the current state of the control thread + GCMode gc_mode() const { + return _gc_mode; } private: - // Returns true if the cycle has been cancelled or degenerated. bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point); + // Executes one GC cycle + void run_gc_cycle(const ShenandoahGCRequest& request); + // Returns true if the old generation marking completed (i.e., final mark executed for old generation). bool resume_concurrent_old_cycle(ShenandoahOldGeneration* generation, GCCause::Cause cause); + + // Various service methods handle different gc cycle types void service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool reset_old_bitmap_specially); void service_stw_full_cycle(GCCause::Cause cause); - void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point); + void service_stw_degenerated_cycle(const ShenandoahGCRequest& request); + void service_concurrent_normal_cycle(const ShenandoahGCRequest& request); + void service_concurrent_old_cycle(const ShenandoahGCRequest& request); void notify_gc_waiters(); - // Handle GC request. - // Blocks until GC is over. + // Blocks until at least one global GC cycle is complete. void handle_requested_gc(GCCause::Cause cause); - bool is_explicit_gc(GCCause::Cause cause) const; - bool is_implicit_gc(GCCause::Cause cause) const; - // Returns true if the old generation marking was interrupted to allow a young cycle. - bool preempt_old_marking(ShenandoahGenerationType generation); + bool preempt_old_marking(ShenandoahGeneration* generation); - void process_phase_timings(const ShenandoahGenerationalHeap* heap); - - void service_concurrent_normal_cycle(ShenandoahGenerationalHeap* heap, - ShenandoahGenerationType generation, - GCCause::Cause cause); - - void service_concurrent_old_cycle(ShenandoahGenerationalHeap* heap, - GCCause::Cause &cause); + // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle. + void process_phase_timings() const; + // Set the gc mode and post a notification if it has changed. The overloaded variant should be used + // when the _control_lock is already held. void set_gc_mode(GCMode new_mode); + void set_gc_mode(MonitorLocker& ml, GCMode new_mode); + // Return printable name for the given gc mode. static const char* gc_mode_name(GCMode mode); - void notify_control_thread(); + // Takes the request lock and updates the requested cause and generation, then notifies the control thread. + // The overloaded variant should be used when the _control_lock is already held. + void notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation); + void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation); - void service_concurrent_cycle(ShenandoahHeap* heap, - ShenandoahGeneration* generation, - GCCause::Cause &cause, - bool do_old_gc_bootstrap); + // Notifies the control thread, but does not update the requested cause or generation. + // The overloaded variant should be used when the _control_lock is already held. + void notify_cancellation(GCCause::Cause cause); + void notify_cancellation(MonitorLocker& ml, GCCause::Cause cause); + // Configure the heap to age objects and regions if the aging period has elapsed. + void maybe_set_aging_cycle(); + + // Take the _control_lock and check for a request to run a gc cycle. If a request is found, + // the `prepare` methods are used to configure the heap and update heuristics accordingly. + void check_for_request(ShenandoahGCRequest& request); + + GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request); + GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const; + GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 68b83cbf75a..fc1ff230688 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -583,6 +583,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : { // Initialize GC mode early, many subsequent initialization procedures depend on it initialize_mode(); + _cancelled_gc.set(GCCause::_no_gc); } #ifdef _MSC_VER @@ -993,13 +994,13 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { // a) We experienced a GC that had good progress, or // b) We experienced at least one Full GC (whether or not it had good progress) - size_t original_count = shenandoah_policy()->full_gc_count(); - while ((result == nullptr) && (original_count == shenandoah_policy()->full_gc_count())) { + const size_t original_count = shenandoah_policy()->full_gc_count(); + while (result == nullptr && should_retry_allocation(original_count)) { control_thread()->handle_alloc_failure(req, true); result = allocate_memory_under_lock(req, in_new_region); } if (result != nullptr) { - // If our allocation request has been satisifed after it initially failed, we count this as good gc progress + // If our allocation request has been satisfied after it initially failed, we count this as good gc progress notify_gc_progress(); } if (log_develop_is_enabled(Debug, gc, alloc)) { @@ -1050,6 +1051,11 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { return result; } +inline bool ShenandoahHeap::should_retry_allocation(size_t original_full_gc_count) const { + return shenandoah_policy()->full_gc_count() == original_full_gc_count + && !shenandoah_policy()->is_at_shutdown(); +} + HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req, bool& in_new_region) { // If we are dealing with mutator allocation, then we may need to block for safepoint. // We cannot block for safepoint for GC allocations, because there is a high chance @@ -2120,9 +2126,9 @@ size_t ShenandoahHeap::tlab_used(Thread* thread) const { return _free_set->used(); } -bool ShenandoahHeap::try_cancel_gc() { - jbyte prev = _cancelled_gc.cmpxchg(CANCELLED, CANCELLABLE); - return prev == CANCELLABLE; +bool ShenandoahHeap::try_cancel_gc(GCCause::Cause cause) { + jbyte prev = _cancelled_gc.cmpxchg(cause, GCCause::_no_gc); + return prev == GCCause::_no_gc; } void ShenandoahHeap::cancel_concurrent_mark() { @@ -2136,13 +2142,15 @@ void ShenandoahHeap::cancel_concurrent_mark() { ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking(); } -void ShenandoahHeap::cancel_gc(GCCause::Cause cause) { - if (try_cancel_gc()) { +bool ShenandoahHeap::cancel_gc(GCCause::Cause cause) { + if (try_cancel_gc(cause)) { FormatBuffer<> msg("Cancelling GC: %s", GCCause::to_string(cause)); - log_info(gc)("%s", msg.buffer()); + log_info(gc,thread)("%s", msg.buffer()); Events::log(Thread::current(), "%s", msg.buffer()); _cancel_requested_time = os::elapsedTime(); + return true; } + return false; } uint ShenandoahHeap::max_workers() { @@ -2155,18 +2163,10 @@ void ShenandoahHeap::stop() { // Step 0. Notify policy to disable event recording and prevent visiting gc threads during shutdown _shenandoah_policy->record_shutdown(); - // Step 0a. Stop reporting on gc thread cpu utilization + // Step 1. Stop reporting on gc thread cpu utilization mmu_tracker()->stop(); - // Step 1. Notify control thread that we are in shutdown. - // Note that we cannot do that with stop(), because stop() is blocking and waits for the actual shutdown. - // Doing stop() here would wait for the normal GC cycle to complete, never falling through to cancel below. - control_thread()->prepare_for_graceful_shutdown(); - - // Step 2. Notify GC workers that we are cancelling GC. - cancel_gc(GCCause::_shenandoah_stop_vm); - - // Step 3. Wait until GC worker exits normally. + // Step 2. Wait until GC worker exits normally (this will cancel any ongoing GC). control_thread()->stop(); // Stop 4. Shutdown uncommit thread. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 785e1742b0c..33d2db0b2f1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -430,35 +430,38 @@ public: private: void manage_satb_barrier(bool active); - enum CancelState { - // Normal state. GC has not been cancelled and is open for cancellation. - // Worker threads can suspend for safepoint. - CANCELLABLE, - - // GC has been cancelled. Worker threads can not suspend for - // safepoint but must finish their work as soon as possible. - CANCELLED - }; - + // Records the time of the first successful cancellation request. This is used to measure + // the responsiveness of the heuristic when starting a cycle. double _cancel_requested_time; - ShenandoahSharedEnumFlag _cancelled_gc; + + // Indicates the reason the current GC has been cancelled (GCCause::_no_gc means the gc is not cancelled). + ShenandoahSharedEnumFlag _cancelled_gc; // Returns true if cancel request was successfully communicated. // Returns false if some other thread already communicated cancel // request. A true return value does not mean GC has been // cancelled, only that the process of cancelling GC has begun. - bool try_cancel_gc(); + bool try_cancel_gc(GCCause::Cause cause); public: + // True if gc has been cancelled inline bool cancelled_gc() const; + + // Used by workers in the GC cycle to detect cancellation and honor STS requirements inline bool check_cancelled_gc_and_yield(bool sts_active = true); + // This indicates the reason the last GC cycle was cancelled. + inline GCCause::Cause cancelled_cause() const; + + // Clears the cancellation cause and optionally resets the oom handler (cancelling an + // old mark does _not_ touch the oom handler). inline void clear_cancelled_gc(bool clear_oom_handler = true); void cancel_concurrent_mark(); - void cancel_gc(GCCause::Cause cause); -public: + // Returns true if and only if this call caused a gc to be cancelled. + bool cancel_gc(GCCause::Cause cause); + // Returns true if the soft maximum heap has been changed using management APIs. bool check_soft_max_changed(); @@ -690,6 +693,9 @@ private: HeapWord* allocate_from_gclab_slow(Thread* thread, size_t size); HeapWord* allocate_new_gclab(size_t min_size, size_t word_size, size_t* actual_size); + // We want to retry an unsuccessful attempt at allocation until at least a full gc. + bool should_retry_allocation(size_t original_full_gc_count) const; + public: HeapWord* allocate_memory(ShenandoahAllocRequest& request); HeapWord* mem_allocate(size_t size, bool* what) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 461447cf9ba..13c203d423c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -252,7 +252,7 @@ inline void ShenandoahHeap::atomic_clear_oop(narrowOop* addr, narrowOop compare) } inline bool ShenandoahHeap::cancelled_gc() const { - return _cancelled_gc.get() == CANCELLED; + return _cancelled_gc.get() != GCCause::_no_gc; } inline bool ShenandoahHeap::check_cancelled_gc_and_yield(bool sts_active) { @@ -264,8 +264,12 @@ inline bool ShenandoahHeap::check_cancelled_gc_and_yield(bool sts_active) { return cancelled_gc(); } +inline GCCause::Cause ShenandoahHeap::cancelled_cause() const { + return _cancelled_gc.get(); +} + inline void ShenandoahHeap::clear_cancelled_gc(bool clear_oom_handler) { - _cancelled_gc.set(CANCELLABLE); + _cancelled_gc.set(GCCause::_no_gc); if (_cancel_requested_time > 0) { log_debug(gc)("GC cancellation took %.3fs", (os::elapsedTime() - _cancel_requested_time)); _cancel_requested_time = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 38887217255..9b030905b6d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -495,7 +495,7 @@ const char* ShenandoahOldGeneration::state_name(State state) { void ShenandoahOldGeneration::transition_to(State new_state) { if (_state != new_state) { - log_debug(gc)("Old generation transition from %s to %s", state_name(_state), state_name(new_state)); + log_debug(gc, thread)("Old generation transition from %s to %s", state_name(_state), state_name(new_state)); EventMark event("Old was %s, now is %s", state_name(_state), state_name(new_state)); validate_transition(new_state); _state = new_state; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index 752ad743520..f9e6f714c7f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -33,15 +33,14 @@ #include "logging/log.hpp" ShenandoahRegulatorThread::ShenandoahRegulatorThread(ShenandoahGenerationalControlThread* control_thread) : - ConcurrentGCThread(), + _heap(ShenandoahHeap::heap()), _control_thread(control_thread), _sleep(ShenandoahControlIntervalMin), _last_sleep_adjust_time(os::elapsedTime()) { shenandoah_assert_generational(); - ShenandoahHeap* heap = ShenandoahHeap::heap(); - _old_heuristics = heap->old_generation()->heuristics(); - _young_heuristics = heap->young_generation()->heuristics(); - _global_heuristics = heap->global_generation()->heuristics(); + _old_heuristics = _heap->old_generation()->heuristics(); + _young_heuristics = _heap->young_generation()->heuristics(); + _global_heuristics = _heap->global_generation()->heuristics(); set_name("Shenandoah Regulator Thread"); create_and_start(); @@ -62,7 +61,7 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { ShenandoahGenerationalControlThread::GCMode mode = _control_thread->gc_mode(); if (mode == ShenandoahGenerationalControlThread::none) { if (should_start_metaspace_gc()) { - if (request_concurrent_gc(GLOBAL)) { + if (request_concurrent_gc(_heap->global_generation())) { // Some of vmTestbase/metaspace tests depend on following line to count GC cycles _global_heuristics->log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold)); _global_heuristics->cancel_trigger_request(); @@ -75,10 +74,14 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { log_debug(gc)("Heuristics request for old collection accepted"); _young_heuristics->cancel_trigger_request(); _old_heuristics->cancel_trigger_request(); - } else if (request_concurrent_gc(YOUNG)) { + } else if (request_concurrent_gc(_heap->young_generation())) { log_debug(gc)("Heuristics request for young collection accepted"); _young_heuristics->cancel_trigger_request(); } + } else if (_old_heuristics->should_resume_old_cycle() || _old_heuristics->should_start_gc()) { + if (request_concurrent_gc(_heap->old_generation())) { + log_debug(gc)("Heuristics request to resume old collection accepted"); + } } } } else if (mode == ShenandoahGenerationalControlThread::servicing_old) { @@ -132,19 +135,19 @@ void ShenandoahRegulatorThread::regulator_sleep() { } } -bool ShenandoahRegulatorThread::start_old_cycle() { - return _old_heuristics->should_start_gc() && request_concurrent_gc(OLD); +bool ShenandoahRegulatorThread::start_old_cycle() const { + return _old_heuristics->should_start_gc() && request_concurrent_gc(_heap->old_generation()); } -bool ShenandoahRegulatorThread::start_young_cycle() { - return _young_heuristics->should_start_gc() && request_concurrent_gc(YOUNG); +bool ShenandoahRegulatorThread::start_young_cycle() const { + return _young_heuristics->should_start_gc() && request_concurrent_gc(_heap->young_generation()); } -bool ShenandoahRegulatorThread::start_global_cycle() { - return _global_heuristics->should_start_gc() && request_concurrent_gc(GLOBAL); +bool ShenandoahRegulatorThread::start_global_cycle() const { + return _global_heuristics->should_start_gc() && request_concurrent_gc(_heap->global_generation()); } -bool ShenandoahRegulatorThread::request_concurrent_gc(ShenandoahGenerationType generation) { +bool ShenandoahRegulatorThread::request_concurrent_gc(ShenandoahGeneration* generation) const { double now = os::elapsedTime(); bool accepted = _control_thread->request_concurrent_gc(generation); if (LogTarget(Debug, gc, thread)::is_enabled() && accepted) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index f9f7e25f97c..a72d6004beb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -26,8 +26,11 @@ #include "gc/shared/concurrentGCThread.hpp" +class ShenandoahHeap; class ShenandoahHeuristics; +class ShenandoahGeneration; class ShenandoahGenerationalControlThread; +class ShenandoahOldHeuristics; /* * The purpose of this class (and thread) is to allow us to continue @@ -58,9 +61,10 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { void regulate_young_and_global_cycles(); // These return true if a cycle was started. - bool start_old_cycle(); - bool start_young_cycle(); - bool start_global_cycle(); + bool start_old_cycle() const; + bool start_young_cycle() const; + bool start_global_cycle() const; + bool resume_old_cycle(); // The generational mode can only unload classes in a global cycle. The regulator // thread itself will trigger a global cycle if metaspace is out of memory. @@ -70,11 +74,12 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { void regulator_sleep(); // Provides instrumentation to track how long it takes to acknowledge a request. - bool request_concurrent_gc(ShenandoahGenerationType generation); + bool request_concurrent_gc(ShenandoahGeneration* generation) const; + ShenandoahHeap* _heap; ShenandoahGenerationalControlThread* _control_thread; ShenandoahHeuristics* _young_heuristics; - ShenandoahHeuristics* _old_heuristics; + ShenandoahOldHeuristics* _old_heuristics; ShenandoahHeuristics* _global_heuristics; uint _sleep; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 9bbb76b3e48..109e940e2bd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -475,7 +475,7 @@ HeapWord* ShenandoahScanRemembered::addr_for_cluster(size_t cluster_no) { void ShenandoahScanRemembered::roots_do(OopIterateClosure* cl) { ShenandoahHeap* heap = ShenandoahHeap::heap(); bool old_bitmap_stable = heap->old_generation()->is_mark_complete(); - log_info(gc, remset)("Scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); + log_debug(gc, remset)("Scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); for (size_t i = 0, n = heap->num_regions(); i < n; ++i) { ShenandoahHeapRegion* region = heap->get_region(i); if (region->is_old() && region->is_active() && !region->is_cset()) { @@ -653,7 +653,7 @@ ShenandoahScanRememberedTask::ShenandoahScanRememberedTask(ShenandoahObjToScanQu WorkerTask("Scan Remembered Set"), _queue_set(queue_set), _old_queue_set(old_queue_set), _rp(rp), _work_list(work_list), _is_concurrent(is_concurrent) { bool old_bitmap_stable = ShenandoahHeap::heap()->old_generation()->is_mark_complete(); - log_info(gc, remset)("Scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); + log_debug(gc, remset)("Scan remembered set using bitmap: %s", BOOL_TO_STR(old_bitmap_stable)); } void ShenandoahScanRememberedTask::work(uint worker_id) { From 96613cc53842bc744e220e5bf7d91e92d0769a8e Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Tue, 4 Mar 2025 03:49:17 +0000 Subject: [PATCH 205/587] 8349516: StAXStream2SAX.handleCharacters() fails on empty CDATA Reviewed-by: naoto --- .../internal/xsltc/trax/StAXStream2SAX.java | 22 ++------ .../unittest/validation/ValidationTest.java | 54 ++++++++++++++++++- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/StAXStream2SAX.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/StAXStream2SAX.java index 4667226f1bc..6746ede9d9b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/StAXStream2SAX.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/StAXStream2SAX.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 @@ -275,32 +275,18 @@ public class StAXStream2SAX implements XMLReader, Locator { } private void handleCharacters() throws XMLStreamException { - - // workaround for bugid 5046319 - switch over to commented section - // below when it is fixed. int textLength = staxStreamReader.getTextLength(); char[] chars = new char[textLength]; - staxStreamReader.getTextCharacters(0, chars, 0, textLength); + if (textLength > 0) { + staxStreamReader.getTextCharacters(0, chars, 0, textLength); + } try { _sax.characters(chars, 0, chars.length); } catch (SAXException e) { throw new XMLStreamException(e); } - - -// int start = 0; -// int len; -// do { -// len = staxStreamReader.getTextCharacters(start, buf, 0, buf.length); -// start += len; -// try { -// _sax.characters(buf, 0, len); -// } catch (SAXException e) { -// throw new XMLStreamException(e); -// } -// } while (len == buf.length); } private void handleEndElement() throws XMLStreamException { diff --git a/test/jaxp/javax/xml/jaxp/unittest/validation/ValidationTest.java b/test/jaxp/javax/xml/jaxp/unittest/validation/ValidationTest.java index a4538bcf5b5..198196a6d13 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/validation/ValidationTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/validation/ValidationTest.java @@ -26,6 +26,8 @@ package validation; import java.io.File; import java.io.FileInputStream; +import java.io.Reader; +import java.io.StringReader; import javax.xml.XMLConstants; import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.XMLInputFactory; @@ -33,6 +35,7 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; @@ -48,7 +51,7 @@ import org.xml.sax.helpers.XMLFilterImpl; /* * @test - * @bug 8220818 8176447 + * @bug 8220818 8176447 8349516 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm validation.ValidationTest * @summary Runs validations with schemas and sources @@ -139,6 +142,55 @@ public class ValidationTest { } + /** + * Verifies the bug fix for 8349516, which adds a guard against empty text. + * Prior to the fix, calling {@link XMLStreamReader#getTextCharacters() XMLStreamReader#getTextCharacters()} + * with {@code length = 0} resulted in an {@code IndexOutOfBoundsException}. + * + * This test ensures that the fix prevents such an exception. + * + * @throws Exception if the test fails due to unexpected issues, such as errors + * in creating the schema or reader, or validation errors other than the + * {@code IndexOutOfBoundsException}. + */ + @Test + public void testValidationWithStAX() throws Exception { + String schema = """ + + + + + + + + + + + + """; + + String xml = """ + + + + """; + + Reader schemaReader = new StringReader(schema); + Reader xmlReader = new StringReader(xml); + + Source source = new StreamSource(schemaReader); + + Validator validator = + SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(source).newValidator(); + + XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(xmlReader); + validator.validate(new StAXSource(xmlStreamReader)); + } + private static String getTargetNamespace(String xsdFile) throws Exception { XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(xsdFile)); while (reader.hasNext()) { From 7c173fde4274a798f299876492a2cd833eee9fdd Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Tue, 4 Mar 2025 03:56:16 +0000 Subject: [PATCH 206/587] 8351077: Shenandoah: Update comments in ShenandoahConcurrentGC::op_reset_after_collect Reviewed-by: wkemper, ysr --- .../share/gc/shenandoah/shenandoahConcurrentGC.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 316904f8bd0..49aa4b3610d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -1230,11 +1230,9 @@ void ShenandoahConcurrentGC::op_reset_after_collect() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); if (heap->mode()->is_generational()) { - // Resetting bitmaps of young gen when bootstrap old GC or there is preempted old GC - // causes crash due to remembered set violation, hence condition is added to fix the crash. - // Assuming bitmaps of young gen are not used at all after the cycle, the crash should not - // have happend, it seems to tickle a bug in remembered set scan. Root causing and fixing of the bug - // will be tracked via ticket https://bugs.openjdk.org/browse/JDK-8347371 + // If we are in the midst of an old gc bootstrap or an old marking, we want to leave the mark bit map of + // the young generation intact. In particular, reference processing in the old generation may potentially + // need the reachability of a young generation referent of a Reference object in the old generation. if (!_do_old_gc_bootstrap && !heap->is_concurrent_old_mark_in_progress()) { heap->young_generation()->reset_mark_bitmap(); } From d9b98f72c29f9cf8828fbd33799378bc6b9bfc08 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 4 Mar 2025 04:27:24 +0000 Subject: [PATCH 207/587] 8350771: Fix -Wzero-as-null-pointer-constant warning in nsk/monitoring ThreadController utility Reviewed-by: dholmes --- .../vmTestbase/nsk/monitoring/share/ThreadController.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.cpp b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.cpp index 90fd4df97e6..247705d9b9a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.cpp @@ -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 @@ -465,8 +465,8 @@ extern "C" { return env->NewStringUTF("TIMED_WAITING"); } // should never reach - assert(0); - return 0; + assert(false); + return nullptr; } /* From b6e2d66cc4c100d6604ce3edd25e04d459ed1ef1 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 4 Mar 2025 05:23:16 +0000 Subject: [PATCH 208/587] 8351087: Combine scratch object tables in heapShared.cpp Reviewed-by: ccheung --- src/hotspot/share/cds/heapShared.cpp | 22 ++++++++++------------ src/hotspot/share/cds/heapShared.hpp | 5 ++--- src/hotspot/share/memory/universe.cpp | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 7bd5d5a6267..0dc1d255da7 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -141,8 +141,7 @@ GrowableArrayCHeap* HeapShared::_pending_roots = nullptr; GrowableArrayCHeap* HeapShared::_root_segments; int HeapShared::_root_segment_max_size_elems; OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1]; -MetaspaceObjToOopHandleTable* HeapShared::_scratch_java_mirror_table = nullptr; -MetaspaceObjToOopHandleTable* HeapShared::_scratch_references_table = nullptr; +MetaspaceObjToOopHandleTable* HeapShared::_scratch_objects_table = nullptr; static bool is_subgraph_root_class_of(ArchivableStaticFieldInfo fields[], InstanceKlass* ik) { for (int i = 0; fields[i].valid(); i++) { @@ -393,20 +392,19 @@ public: void HeapShared::add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) { if (SystemDictionaryShared::is_builtin_loader(src->pool_holder()->class_loader_data())) { - _scratch_references_table->set_oop(src, dest); + _scratch_objects_table->set_oop(src, dest); } } objArrayOop HeapShared::scratch_resolved_references(ConstantPool* src) { - return (objArrayOop)_scratch_references_table->get_oop(src); + return (objArrayOop)_scratch_objects_table->get_oop(src); } void HeapShared::init_dumping() { - _scratch_java_mirror_table = new (mtClass)MetaspaceObjToOopHandleTable(); - _scratch_references_table = new (mtClass)MetaspaceObjToOopHandleTable(); + _scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable(); } -void HeapShared::init_scratch_objects(TRAPS) { +void HeapShared::init_scratch_objects_for_basic_type_mirrors(TRAPS) { for (int i = T_BOOLEAN; i < T_VOID+1; i++) { BasicType bt = (BasicType)i; if (!is_reference_type(bt)) { @@ -448,24 +446,24 @@ oop HeapShared::scratch_java_mirror(BasicType t) { } oop HeapShared::scratch_java_mirror(Klass* k) { - return _scratch_java_mirror_table->get_oop(k); + return _scratch_objects_table->get_oop(k); } void HeapShared::set_scratch_java_mirror(Klass* k, oop mirror) { - _scratch_java_mirror_table->set_oop(k, mirror); + _scratch_objects_table->set_oop(k, mirror); } void HeapShared::remove_scratch_objects(Klass* k) { // Klass is being deallocated. Java mirror can still be alive, and it should not // point to dead klass. We need to break the link from mirror to the Klass. // See how InstanceKlass::deallocate_contents does it for normal mirrors. - oop mirror = _scratch_java_mirror_table->get_oop(k); + oop mirror = _scratch_objects_table->get_oop(k); if (mirror != nullptr) { java_lang_Class::set_klass(mirror, nullptr); } - _scratch_java_mirror_table->remove_oop(k); + _scratch_objects_table->remove_oop(k); if (k->is_instance_klass()) { - _scratch_references_table->remove(InstanceKlass::cast(k)->constants()); + _scratch_objects_table->remove(InstanceKlass::cast(k)->constants()); } } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index ba2fe5be775..9ad09882410 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -284,8 +284,7 @@ private: static GrowableArrayCHeap* _root_segments; static int _root_segment_max_size_elems; static OopHandle _scratch_basic_type_mirrors[T_VOID+1]; - static MetaspaceObjToOopHandleTable* _scratch_java_mirror_table; - static MetaspaceObjToOopHandleTable* _scratch_references_table; + static MetaspaceObjToOopHandleTable* _scratch_objects_table; static void init_seen_objects_table() { assert(_seen_objects_table == nullptr, "must be"); @@ -406,7 +405,7 @@ private: static objArrayOop scratch_resolved_references(ConstantPool* src); static void add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) NOT_CDS_JAVA_HEAP_RETURN; static void init_dumping() NOT_CDS_JAVA_HEAP_RETURN; - static void init_scratch_objects(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; + 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);) diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 3097ad1be10..fe9c960b7f2 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -572,7 +572,7 @@ void Universe::initialize_basic_type_mirrors(TRAPS) { } } if (CDSConfig::is_dumping_heap()) { - HeapShared::init_scratch_objects(CHECK); + HeapShared::init_scratch_objects_for_basic_type_mirrors(CHECK); } } From 4fc72b8e4b22db2aa3217afb5b8c30d496589eb8 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 4 Mar 2025 05:23:30 +0000 Subject: [PATCH 209/587] 8351082: Remove dead code for estimating CDS archive size Reviewed-by: ccheung --- .../share/classfile/compactHashtable.cpp | 13 ------- .../share/classfile/compactHashtable.hpp | 2 - src/hotspot/share/classfile/moduleEntry.hpp | 3 +- src/hotspot/share/classfile/symbolTable.cpp | 7 ---- src/hotspot/share/classfile/symbolTable.hpp | 1 - .../classfile/systemDictionaryShared.cpp | 39 ------------------- .../classfile/systemDictionaryShared.hpp | 1 - 7 files changed, 1 insertion(+), 65 deletions(-) diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 5a3c6998904..8d50e8136a3 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -72,19 +72,6 @@ CompactHashtableWriter::~CompactHashtableWriter() { FREE_C_HEAP_ARRAY(GrowableArray*, _buckets); } -size_t CompactHashtableWriter::estimate_size(int num_entries) { - int num_buckets = calculate_num_buckets(num_entries); - size_t bucket_bytes = ArchiveBuilder::ro_array_bytesize(num_buckets + 1); - - // In worst case, we have no VALUE_ONLY_BUCKET_TYPE, so each entry takes 2 slots - int entries_space = 2 * num_entries; - size_t entry_bytes = ArchiveBuilder::ro_array_bytesize(entries_space); - - return bucket_bytes - + entry_bytes - + SimpleCompactHashtable::calculate_header_size(); -} - // Add a symbol entry to the temporary hash table void CompactHashtableWriter::add(unsigned int hash, u4 value) { int index = hash % _num_buckets; diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 73e9f7fc092..161f21eac99 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -134,8 +134,6 @@ private: public: void dump(SimpleCompactHashtable *cht, const char* table_name); - - static size_t estimate_size(int num_entries); }; #endif // INCLUDE_CDS diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 9ad7bde8954..c2d07a78512 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.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 @@ -207,7 +207,6 @@ public: void load_from_archive(ClassLoaderData* loader_data); void restore_archived_oops(ClassLoaderData* loader_data); void clear_archived_oops(); - void update_oops_in_archived_module(int root_oop_index); static void verify_archived_module_entries() PRODUCT_RETURN; #endif }; diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 3cb453aaecb..04640b672f6 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -705,13 +705,6 @@ void SymbolTable::copy_shared_symbol_table(GrowableArray* symbols, } } -size_t SymbolTable::estimate_size_for_archive() { - if (_items_count > (size_t)max_jint) { - fatal("Too many symbols to be archived: %zu", _items_count); - } - return CompactHashtableWriter::estimate_size(int(_items_count)); -} - void SymbolTable::write_to_archive(GrowableArray* symbols) { CompactHashtableWriter writer(int(_items_count), ArchiveBuilder::symbol_stats()); copy_shared_symbol_table(symbols, &writer); diff --git a/src/hotspot/share/classfile/symbolTable.hpp b/src/hotspot/share/classfile/symbolTable.hpp index a1e585e97de..ee2cfe19d8e 100644 --- a/src/hotspot/share/classfile/symbolTable.hpp +++ b/src/hotspot/share/classfile/symbolTable.hpp @@ -161,7 +161,6 @@ private: static void copy_shared_symbol_table(GrowableArray* symbols, CompactHashtableWriter* ch_table); public: - static size_t estimate_size_for_archive() NOT_CDS_RETURN_(0); static void write_to_archive(GrowableArray* symbols) NOT_CDS_RETURN; static void serialize_shared_table_header(SerializeClosure* soc, bool is_static_archive = true) NOT_CDS_RETURN; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 6bd573ea465..8b815cf9cb7 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1223,45 +1223,6 @@ bool SystemDictionaryShared::is_supported_invokedynamic(BootstrapInfo* bsi) { return false; } -class EstimateSizeForArchive : StackObj { - size_t _shared_class_info_size; - int _num_builtin_klasses; - int _num_unregistered_klasses; - -public: - EstimateSizeForArchive() { - _shared_class_info_size = 0; - _num_builtin_klasses = 0; - _num_unregistered_klasses = 0; - } - - void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) { - if (!info.is_excluded()) { - size_t byte_size = info.runtime_info_bytesize(); - _shared_class_info_size += align_up(byte_size, SharedSpaceObjectAlignment); - } - } - - size_t total() { - return _shared_class_info_size; - } -}; - -size_t SystemDictionaryShared::estimate_size_for_archive() { - EstimateSizeForArchive est; - _dumptime_table->iterate_all_live_classes(&est); - size_t total_size = est.total() + - CompactHashtableWriter::estimate_size(_dumptime_table->count_of(true)) + - CompactHashtableWriter::estimate_size(_dumptime_table->count_of(false)); - - size_t bytesize = align_up(sizeof(RunTimeLambdaProxyClassInfo), SharedSpaceObjectAlignment); - total_size += - (bytesize * _dumptime_lambda_proxy_class_dictionary->_count) + - CompactHashtableWriter::estimate_size(_dumptime_lambda_proxy_class_dictionary->_count); - - return total_size; -} - unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { if (ArchiveBuilder::is_active()) { uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 7286bdad3fd..c7f38880837 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -294,7 +294,6 @@ public: static void set_excluded_locked(InstanceKlass* k); static bool warn_excluded(InstanceKlass* k, const char* reason); static void dumptime_classes_do(class MetaspaceClosure* it); - static size_t estimate_size_for_archive(); static void write_to_archive(bool is_static_archive = true); static void adjust_lambda_proxy_class_dictionary(); static void serialize_dictionary_headers(class SerializeClosure* soc, From 1f10ffba88119caab169b1fc43ccfd143e3b85a6 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 4 Mar 2025 07:30:10 +0000 Subject: [PATCH 210/587] 8350851: ZGC: Reduce size of ZAddressOffsetMax scaling data structures Reviewed-by: eosterlund, jsikstro --- src/hotspot/share/gc/z/zIndexDistributor.hpp | 6 +++ .../share/gc/z/zIndexDistributor.inline.hpp | 39 +++++++++++++++---- src/hotspot/share/gc/z/zMemory.cpp | 12 ++++++ src/hotspot/share/gc/z/zMemory.hpp | 1 + src/hotspot/share/gc/z/zPageTable.cpp | 11 +++++- src/hotspot/share/gc/z/zPageTable.hpp | 2 + src/hotspot/share/gc/z/zPageTable.inline.hpp | 11 +++++- src/hotspot/share/gc/z/zVirtualMemory.cpp | 3 ++ src/hotspot/share/gc/z/zVirtualMemory.hpp | 1 + .../share/gc/z/zVirtualMemory.inline.hpp | 4 ++ 10 files changed, 81 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/z/zIndexDistributor.hpp b/src/hotspot/share/gc/z/zIndexDistributor.hpp index 94f146176d6..d4b9edcb5b4 100644 --- a/src/hotspot/share/gc/z/zIndexDistributor.hpp +++ b/src/hotspot/share/gc/z/zIndexDistributor.hpp @@ -24,6 +24,8 @@ #ifndef SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP #define SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP +#include + class ZIndexDistributor { private: void* _strategy; @@ -39,6 +41,10 @@ public: template void do_indices(Function function); + + // Returns a count that is max_count or larger and upholds the requirements + // for using the ZIndexDistributor strategy specfied by ZIndexDistributorStrategy + static size_t get_count(size_t max_count); }; #endif // SHARE_GC_Z_ZINDEXDISTRIBUTOR_HPP diff --git a/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp b/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp index c582be8fcee..163dd2ad685 100644 --- a/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp +++ b/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp @@ -32,11 +32,13 @@ #include "runtime/os.hpp" #include "runtime/thread.hpp" #include "utilities/align.hpp" +#include "utilities/powerOfTwo.hpp" class ZIndexDistributorStriped : public CHeapObj { static const int MemSize = 4096; + static const int StripeCount = MemSize / ZCacheLineSize; - const int _max_index; + const int _count; // For claiming a stripe volatile int _claim_stripe; // For claiming inside a stripe @@ -51,8 +53,8 @@ class ZIndexDistributorStriped : public CHeapObj { } public: - ZIndexDistributorStriped(int max_index) - : _max_index(max_index), + ZIndexDistributorStriped(int count) + : _count(count), _claim_stripe(0), _mem() { memset(_mem, 0, MemSize + ZCacheLineSize); @@ -60,11 +62,10 @@ public: template void do_indices(Function function) { - const int count = MemSize / ZCacheLineSize; - const int stripe_max = _max_index / count; + const int stripe_max = _count / StripeCount; // Use claiming - for (int i; (i = claim_stripe()) < count;) { + for (int i; (i = claim_stripe()) < StripeCount;) { for (int index; (index = Atomic::fetch_then_add(claim_addr(i), 1, memory_order_relaxed)) < stripe_max;) { if (!function(i * stripe_max + index)) { return; @@ -73,7 +74,7 @@ public: } // Use stealing - for (int i = 0; i < count; i++) { + for (int i = 0; i < StripeCount; i++) { for (int index; (index = Atomic::fetch_then_add(claim_addr(i), 1, memory_order_relaxed)) < stripe_max;) { if (!function(i * stripe_max + index)) { return; @@ -81,6 +82,11 @@ public: } } } + + static size_t get_count(size_t max_count) { + // Must be multiple of the StripeCount + return align_up(max_count, StripeCount); + } }; class ZIndexDistributorClaimTree : public CHeapObj { @@ -290,6 +296,12 @@ public: claim_and_do(function, indices, 0 /* level */); steal_and_do(function, indices, 0 /* level */); } + + static size_t get_count(size_t max_count) { + // Must be at least claim_level_size(ClaimLevels) and a power of two + const size_t min_count = claim_level_size(ClaimLevels); + return round_up_power_of_2(MAX2(max_count, min_count)); + } }; // Using dynamically allocated objects just to be able to evaluate @@ -328,4 +340,17 @@ inline void ZIndexDistributor::do_indices(Function function) { }; } +inline size_t ZIndexDistributor::get_count(size_t max_count) { + size_t required_count; + switch (ZIndexDistributorStrategy) { + case 0: required_count = ZIndexDistributorClaimTree::get_count(max_count); break; + case 1: required_count = ZIndexDistributorStriped::get_count(max_count); break; + default: fatal("Unknown ZIndexDistributorStrategy"); + }; + + assert(max_count <= required_count, "unsupported max_count: %zu", max_count); + + return required_count; +} + #endif // SHARE_GC_Z_ZINDEXDISTRIBUTOR_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zMemory.cpp b/src/hotspot/share/gc/z/zMemory.cpp index 14578c2db8a..8ccde9f45a2 100644 --- a/src/hotspot/share/gc/z/zMemory.cpp +++ b/src/hotspot/share/gc/z/zMemory.cpp @@ -100,6 +100,18 @@ zoffset ZMemoryManager::peek_low_address() const { return zoffset(UINTPTR_MAX); } +zoffset_end ZMemoryManager::peak_high_address_end() const { + ZLocker locker(&_lock); + + const ZMemory* const area = _freelist.last(); + if (area != nullptr) { + return area->end(); + } + + // Out of memory + return zoffset_end(UINTPTR_MAX); +} + zoffset ZMemoryManager::alloc_low_address(size_t size) { ZLocker locker(&_lock); diff --git a/src/hotspot/share/gc/z/zMemory.hpp b/src/hotspot/share/gc/z/zMemory.hpp index ce9100f8026..229d5a7c50c 100644 --- a/src/hotspot/share/gc/z/zMemory.hpp +++ b/src/hotspot/share/gc/z/zMemory.hpp @@ -86,6 +86,7 @@ public: void register_callbacks(const Callbacks& callbacks); zoffset peek_low_address() const; + zoffset_end peak_high_address_end() const; zoffset alloc_low_address(size_t size); zoffset alloc_low_address_at_most(size_t size, size_t* allocated); zoffset alloc_high_address(size_t size); diff --git a/src/hotspot/share/gc/z/zPageTable.cpp b/src/hotspot/share/gc/z/zPageTable.cpp index 9a4bbc85d04..d960270c451 100644 --- a/src/hotspot/share/gc/z/zPageTable.cpp +++ b/src/hotspot/share/gc/z/zPageTable.cpp @@ -23,13 +23,22 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zGranuleMap.inline.hpp" +#include "gc/z/zIndexDistributor.inline.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageTable.inline.hpp" #include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" +static size_t get_max_offset_for_map() { + // The page table has (ZAddressOffsetMax >> ZGranuleSizeShift) slots + const size_t max_count = ZAddressOffsetMax >> ZGranuleSizeShift; + const size_t required_count = ZIndexDistributor::get_count(max_count); + + return required_count << ZGranuleSizeShift; +} + ZPageTable::ZPageTable() - : _map(ZAddressOffsetMax) {} + : _map(get_max_offset_for_map()) {} void ZPageTable::insert(ZPage* page) { const zoffset offset = page->start(); diff --git a/src/hotspot/share/gc/z/zPageTable.hpp b/src/hotspot/share/gc/z/zPageTable.hpp index e809a0ac0ca..fadf550d996 100644 --- a/src/hotspot/share/gc/z/zPageTable.hpp +++ b/src/hotspot/share/gc/z/zPageTable.hpp @@ -45,6 +45,8 @@ private: public: ZPageTable(); + int count() const; + ZPage* get(zaddress addr) const; ZPage* get(volatile zpointer* p) const; diff --git a/src/hotspot/share/gc/z/zPageTable.inline.hpp b/src/hotspot/share/gc/z/zPageTable.inline.hpp index 79a2d297df8..583017d5c9c 100644 --- a/src/hotspot/share/gc/z/zPageTable.inline.hpp +++ b/src/hotspot/share/gc/z/zPageTable.inline.hpp @@ -32,6 +32,15 @@ #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageAllocator.inline.hpp" +#include + +inline int ZPageTable::count() const { + const size_t size = _map._size; + assert(size <= std::numeric_limits::max(), "Invalid page table size"); + + return static_cast(size); +} + inline ZPage* ZPageTable::get(zaddress addr) const { assert(!is_null(addr), "Invalid address"); return _map.get(ZAddress::offset(addr)); @@ -64,7 +73,7 @@ inline bool ZPageTableIterator::next(ZPage** page) { inline ZPageTableParallelIterator::ZPageTableParallelIterator(const ZPageTable* table) : _table(table), - _index_distributor(int(ZAddressOffsetMax >> ZGranuleSizeShift)) {} + _index_distributor(table->count()) {} template inline void ZPageTableParallelIterator::do_pages(Function function) { diff --git a/src/hotspot/share/gc/z/zVirtualMemory.cpp b/src/hotspot/share/gc/z/zVirtualMemory.cpp index ccc30626a3f..21152cf4db6 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.cpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.cpp @@ -48,6 +48,9 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) return; } + // Set ZAddressOffsetMax to the highest address end available after reservation + ZAddressOffsetMax = untype(highest_available_address_end()); + // Initialize platform specific parts after reserving address space pd_initialize_after_reserve(); diff --git a/src/hotspot/share/gc/z/zVirtualMemory.hpp b/src/hotspot/share/gc/z/zVirtualMemory.hpp index a2df86262ea..57a377ab61b 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.hpp @@ -77,6 +77,7 @@ public: size_t reserved() const; zoffset lowest_available_address() const; + zoffset_end highest_available_address_end() const; ZVirtualMemory alloc(size_t size, bool force_low_address); void free(const ZVirtualMemory& vmem); diff --git a/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp b/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp index 972e51a143b..9d5fe7dd57a 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.inline.hpp @@ -65,4 +65,8 @@ inline zoffset ZVirtualMemoryManager::lowest_available_address() const { return _manager.peek_low_address(); } +inline zoffset_end ZVirtualMemoryManager::highest_available_address_end() const { + return _manager.peak_high_address_end(); +} + #endif // SHARE_GC_Z_ZVIRTUALMEMORY_INLINE_HPP From fae37aaae8b36fd74309b84fa1fdf017c7d932ed Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 4 Mar 2025 10:27:52 +0000 Subject: [PATCH 211/587] 8345627: [REDO] Use gcc12 -ftrivial-auto-var-init=pattern in debug builds Reviewed-by: erikj, kbarrett --- make/autoconf/flags-cflags.m4 | 10 ++++++++++ make/hotspot/lib/CompileGtest.gmk | 1 + make/modules/jdk.incubator.vector/Lib.gmk | 2 ++ test/lib/jdk/test/lib/jvmti/jvmti_common.hpp | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 857e2b65e57..238c9752fd1 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -482,6 +482,16 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], else DEBUG_CFLAGS_JDK="-DDEBUG" + if test "x$TOOLCHAIN_TYPE" = xgcc; then + INIT_PATTERN_FLAG="-ftrivial-auto-var-init=pattern" + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_PATTERN_FLAG], + IF_TRUE: [ + DEBUG_CFLAGS_JDK="$DEBUG_CFLAGS_JDK $INIT_PATTERN_FLAG" + DEBUG_CFLAGS_JVM="$INIT_PATTERN_FLAG" + ] + ) + fi + if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then DEBUG_CFLAGS_JVM="-fpic -mcmodel=large" fi diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 5c576cbbf0d..d2cdc7685c9 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -104,6 +104,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ undef stringop-overflow, \ DISABLED_WARNINGS_gcc_test_metaspace_misc.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_test_threadCpuLoad.cpp := address, \ + DISABLED_WARNINGS_gcc_test_tribool.cpp := uninitialized, \ DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \ undef switch format-nonliteral tautological-undefined-compare \ self-assign-overloaded, \ diff --git a/make/modules/jdk.incubator.vector/Lib.gmk b/make/modules/jdk.incubator.vector/Lib.gmk index 6d1259cfe60..5c979ae8191 100644 --- a/make/modules/jdk.incubator.vector/Lib.gmk +++ b/make/modules/jdk.incubator.vector/Lib.gmk @@ -53,6 +53,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, riscv64)+$(INCLUDE_COMPILER2 DISABLED_WARNINGS_gcc := unused-function sign-compare tautological-compare ignored-qualifiers, \ DISABLED_WARNINGS_clang := unused-function sign-compare tautological-compare ignored-qualifiers, \ CFLAGS := -march=rv64gcv, \ + CFLAGS_FILTER_OUT := -ftrivial-auto-var-init=pattern, \ )) TARGETS += $(BUILD_LIBSLEEF) @@ -67,6 +68,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, aarch64)+$(INCLUDE_COMPILER2 DISABLED_WARNINGS_gcc := unused-function sign-compare tautological-compare ignored-qualifiers, \ DISABLED_WARNINGS_clang := unused-function sign-compare tautological-compare ignored-qualifiers, \ vector_math_sve.c_CFLAGS := $(SVE_CFLAGS), \ + CFLAGS_FILTER_OUT := -ftrivial-auto-var-init=pattern, \ )) TARGETS += $(BUILD_LIBSLEEF) diff --git a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp index f16b9fefb99..5efd58e7773 100644 --- a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp +++ b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp @@ -283,7 +283,7 @@ get_thread_info(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { static jint get_thread_state(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { - jint thread_state; + jint thread_state = 0; jvmtiError err = jvmti->GetThreadState(thread, &thread_state); check_jvmti_status(jni, err, "get_thread_state: error in JVMTI GetThreadState call"); return thread_state; From 7ee89a53014bc3509271a81c62c91646f891e546 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 4 Mar 2025 12:18:56 +0000 Subject: [PATCH 212/587] 8350893: Use generated names for hand generated opto runtime blobs Reviewed-by: kvn --- src/hotspot/cpu/aarch64/runtime_aarch64.cpp | 6 ++++-- src/hotspot/cpu/arm/runtime_arm.cpp | 8 +++++--- src/hotspot/cpu/ppc/runtime_ppc.cpp | 3 ++- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 3 ++- src/hotspot/cpu/riscv/runtime_riscv.cpp | 6 ++++-- src/hotspot/cpu/s390/runtime_s390.cpp | 3 ++- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 3 ++- src/hotspot/cpu/x86/runtime_x86_32.cpp | 6 ++++-- src/hotspot/cpu/x86/runtime_x86_64.cpp | 6 ++++-- 9 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index 635c074eadc..ba676573f39 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -63,7 +63,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -282,7 +283,8 @@ void OptoRuntime::generate_exception_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); // TODO check various assumptions made here diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index cf4b398cf1f..ac6e1be0395 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -47,11 +47,12 @@ void OptoRuntime::generate_uncommon_trap_blob() { ResourceMark rm; // setup code generation tools + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); #ifdef _LP64 - CodeBuffer buffer("uncommon_trap_blob", 2700, 512); + CodeBuffer buffer(name, 2700, 512); #else // Measured 8/7/03 at 660 in 32bit debug build - CodeBuffer buffer("uncommon_trap_blob", 2000, 512); + CodeBuffer buffer(name, 2000, 512); #endif // bypassed when code generation useless MacroAssembler* masm = new MacroAssembler(&buffer); @@ -206,7 +207,8 @@ void OptoRuntime::generate_exception_blob() { // setup code generation tools // Measured 8/7/03 at 256 in 32bit debug build - CodeBuffer buffer("exception_blob", 600, 512); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 600, 512); MacroAssembler* masm = new MacroAssembler(&buffer); int framesize_in_words = 2; // FP + LR diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index c5990e01e0d..6ab29ac98b2 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -71,7 +71,8 @@ void OptoRuntime::generate_exception_blob() { // Allocate space for the code. ResourceMark rm; // Setup code generation tools. - CodeBuffer buffer("exception_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 2048, 1024); InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index f7e1410d10f..4bdd8667c62 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -3104,7 +3104,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code. ResourceMark rm; // Setup code generation tools. - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 2048, 1024); InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp index a0879b68053..0a838896a02 100644 --- a/src/hotspot/cpu/riscv/runtime_riscv.cpp +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -61,7 +61,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); @@ -279,7 +280,8 @@ void OptoRuntime::generate_exception_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); diff --git a/src/hotspot/cpu/s390/runtime_s390.cpp b/src/hotspot/cpu/s390/runtime_s390.cpp index dfaf73b9a7c..a0714619d87 100644 --- a/src/hotspot/cpu/s390/runtime_s390.cpp +++ b/src/hotspot/cpu/s390/runtime_s390.cpp @@ -70,7 +70,8 @@ void OptoRuntime::generate_exception_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); Register handle_exception = Z_ARG5; diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 9716a5d71b3..69a9b22778d 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2766,7 +2766,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 2048, 1024); InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); Register unroll_block_reg = Z_tmp_1; diff --git a/src/hotspot/cpu/x86/runtime_x86_32.cpp b/src/hotspot/cpu/x86/runtime_x86_32.cpp index bcba6093871..4148f98f81c 100644 --- a/src/hotspot/cpu/x86/runtime_x86_32.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_32.cpp @@ -45,7 +45,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // allocate space for the code ResourceMark rm; // setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 512, 512); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 512, 512); MacroAssembler* masm = new MacroAssembler(&buffer); enum frame_layout { @@ -255,7 +256,8 @@ void OptoRuntime::generate_exception_blob() { // allocate space for the code ResourceMark rm; // setup code generation tools - CodeBuffer buffer("exception_blob", 512, 512); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 512, 512); MacroAssembler* masm = new MacroAssembler(&buffer); OopMapSet *oop_maps = new OopMapSet(); diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp index d7d8fc1895b..464b0eeac6c 100644 --- a/src/hotspot/cpu/x86/runtime_x86_64.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp @@ -59,7 +59,8 @@ void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -264,7 +265,8 @@ void OptoRuntime::generate_exception_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); From 8073914af7d4ddd7bbd93d75104c7637e38a7ad9 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 4 Mar 2025 12:32:23 +0000 Subject: [PATCH 213/587] 8350974: The os_cpu VM_STRUCTS, VM_TYPES, etc have no declarations and should be removed Reviewed-by: kvn, dholmes --- .../os_cpu/aix_ppc/vmStructs_aix_ppc.hpp | 41 ------------------ .../bsd_aarch64/vmStructs_bsd_aarch64.hpp | 42 ------------------- .../os_cpu/bsd_x86/vmStructs_bsd_x86.hpp | 40 ------------------ .../os_cpu/bsd_zero/vmStructs_bsd_zero.hpp | 41 ------------------ .../linux_aarch64/vmStructs_linux_aarch64.hpp | 41 ------------------ .../os_cpu/linux_arm/vmStructs_linux_arm.hpp | 40 ------------------ .../os_cpu/linux_ppc/vmStructs_linux_ppc.hpp | 41 ------------------ .../linux_riscv/vmStructs_linux_riscv.hpp | 41 ------------------ .../linux_s390/vmStructs_linux_s390.hpp | 41 ------------------ .../os_cpu/linux_x86/vmStructs_linux_x86.hpp | 40 ------------------ .../linux_zero/vmStructs_linux_zero.hpp | 41 ------------------ .../vmStructs_windows_aarch64.hpp | 40 ------------------ .../windows_x86/vmStructs_windows_x86.hpp | 40 ------------------ src/hotspot/share/runtime/vmStructs.cpp | 35 ---------------- 14 files changed, 564 deletions(-) delete mode 100644 src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp delete mode 100644 src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp delete mode 100644 src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp delete mode 100644 src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp delete mode 100644 src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp delete mode 100644 src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp delete mode 100644 src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp delete mode 100644 src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp delete mode 100644 src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp delete mode 100644 src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp delete mode 100644 src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp delete mode 100644 src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp delete mode 100644 src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp diff --git a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp deleted file mode 100644 index df8857a5b84..00000000000 --- a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 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. - * - */ - -#ifndef OS_CPU_AIX_PPC_VMSTRUCTS_AIX_PPC_HPP -#define OS_CPU_AIX_PPC_VMSTRUCTS_AIX_PPC_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_AIX_PPC_VMSTRUCTS_AIX_PPC_HPP diff --git a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp deleted file mode 100644 index fc98519eb82..00000000000 --- a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. - * Copyright (c) 2021, Azul Systems, 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. - * - */ - -#ifndef OS_CPU_BSD_AARCH64_VMSTRUCTS_BSD_AARCH64_HPP -#define OS_CPU_BSD_AARCH64_VMSTRUCTS_BSD_AARCH64_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_BSD_AARCH64_VMSTRUCTS_BSD_AARCH64_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp deleted file mode 100644 index d26921e25ba..00000000000 --- a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_BSD_X86_VMSTRUCTS_BSD_X86_HPP -#define OS_CPU_BSD_X86_VMSTRUCTS_BSD_X86_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_BSD_X86_VMSTRUCTS_BSD_X86_HPP diff --git a/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp deleted file mode 100644 index b5b523cd0ac..00000000000 --- a/src/hotspot/os_cpu/bsd_zero/vmStructs_bsd_zero.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. - * 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 OS_CPU_BSD_ZERO_VMSTRUCTS_BSD_ZERO_HPP -#define OS_CPU_BSD_ZERO_VMSTRUCTS_BSD_ZERO_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_BSD_ZERO_VMSTRUCTS_BSD_ZERO_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp deleted file mode 100644 index cf44ce0ca74..00000000000 --- a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat 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. - * - */ - -#ifndef OS_CPU_LINUX_AARCH64_VMSTRUCTS_LINUX_AARCH64_HPP -#define OS_CPU_LINUX_AARCH64_VMSTRUCTS_LINUX_AARCH64_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_AARCH64_VMSTRUCTS_LINUX_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp deleted file mode 100644 index 9d4c610b45a..00000000000 --- a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_LINUX_ARM_VMSTRUCTS_LINUX_ARM_HPP -#define OS_CPU_LINUX_ARM_VMSTRUCTS_LINUX_ARM_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_ARM_VMSTRUCTS_LINUX_ARM_HPP diff --git a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp deleted file mode 100644 index e52dc525e64..00000000000 --- a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 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. - * - */ - -#ifndef OS_CPU_LINUX_PPC_VMSTRUCTS_LINUX_PPC_HPP -#define OS_CPU_LINUX_PPC_VMSTRUCTS_LINUX_PPC_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_PPC_VMSTRUCTS_LINUX_PPC_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp deleted file mode 100644 index 02bcf429d42..00000000000 --- a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. - * 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 OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP -#define OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp deleted file mode 100644 index 0a75e6d4b92..00000000000 --- a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 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. - * - */ - -#ifndef OS_CPU_LINUX_S390_VMSTRUCTS_LINUX_S390_HPP -#define OS_CPU_LINUX_S390_VMSTRUCTS_LINUX_S390_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_S390_VMSTRUCTS_LINUX_S390_HPP diff --git a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp deleted file mode 100644 index 290e30dff68..00000000000 --- a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_LINUX_X86_VMSTRUCTS_LINUX_X86_HPP -#define OS_CPU_LINUX_X86_VMSTRUCTS_LINUX_X86_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_X86_VMSTRUCTS_LINUX_X86_HPP diff --git a/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp deleted file mode 100644 index 651846c4b36..00000000000 --- a/src/hotspot/os_cpu/linux_zero/vmStructs_linux_zero.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. - * 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 OS_CPU_LINUX_ZERO_VMSTRUCTS_LINUX_ZERO_HPP -#define OS_CPU_LINUX_ZERO_VMSTRUCTS_LINUX_ZERO_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_LINUX_ZERO_VMSTRUCTS_LINUX_ZERO_HPP diff --git a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp deleted file mode 100644 index 2462a20568d..00000000000 --- a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, Microsoft 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 - * 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 OS_CPU_WINDOWS_AARCH64_VMSTRUCTS_WINDOWS_AARCH64_HPP -#define OS_CPU_WINDOWS_AARCH64_VMSTRUCTS_WINDOWS_AARCH64_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_WINDOWS_AARCH64_VMSTRUCTS_WINDOWS_AARCH64_HPP diff --git a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp deleted file mode 100644 index 0ac47bdbd80..00000000000 --- a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - * 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 OS_CPU_WINDOWS_X86_VMSTRUCTS_WINDOWS_X86_HPP -#define OS_CPU_WINDOWS_X86_VMSTRUCTS_WINDOWS_X86_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant) - -#endif // OS_CPU_WINDOWS_X86_VMSTRUCTS_WINDOWS_X86_HPP diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 5184440499a..53bdfe522d0 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -120,7 +120,6 @@ #include CPU_HEADER(vmStructs) #include OS_HEADER(vmStructs) -#include OS_CPU_HEADER(vmStructs) // Note: the cross-product of (c1, c2, product, nonproduct, ...), // (nonstatic, static), and (unchecked, checked) has not been taken. @@ -1913,12 +1912,6 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) - VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_STATIC_VM_STRUCT_ENTRY, - GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) - GENERATE_VM_STRUCT_LAST_ENTRY() }; @@ -1946,12 +1939,6 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_INTEGER_VM_TYPE_ENTRY, GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) - VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY, - GENERATE_TOPLEVEL_VM_TYPE_ENTRY, - GENERATE_OOP_VM_TYPE_ENTRY, - GENERATE_INTEGER_VM_TYPE_ENTRY, - GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) - GENERATE_VM_TYPE_LAST_ENTRY() }; @@ -1971,8 +1958,6 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) - VM_INT_CONSTANTS_OS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #ifdef VM_INT_CPU_FEATURE_CONSTANTS VM_INT_CPU_FEATURE_CONSTANTS #endif @@ -1995,8 +1980,6 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) - VM_LONG_CONSTANTS_OS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) #ifdef VM_LONG_CPU_FEATURE_CONSTANTS VM_LONG_CPU_FEATURE_CONSTANTS #endif @@ -2058,12 +2041,6 @@ void VMStructs::init() { CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) - VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_STATIC_VM_STRUCT_ENTRY, - CHECK_NO_OP, - CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, - CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY) - VM_TYPES(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -2077,12 +2054,6 @@ void VMStructs::init() { CHECK_SINGLE_ARG_VM_TYPE_NO_OP, CHECK_SINGLE_ARG_VM_TYPE_NO_OP) - VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP, - CHECK_SINGLE_ARG_VM_TYPE_NO_OP) - // // Split VM_STRUCTS() invocation into two parts to allow MS VC++ 6.0 // to build with the source mounted over SNC3.2. Symptom was that @@ -2119,12 +2090,6 @@ void VMStructs::init() { CHECK_NO_OP, ENSURE_FIELD_TYPE_PRESENT, ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT) - - VM_STRUCTS_OS_CPU(ENSURE_FIELD_TYPE_PRESENT, - ENSURE_FIELD_TYPE_PRESENT, - CHECK_NO_OP, - ENSURE_FIELD_TYPE_PRESENT, - ENSURE_NONPRODUCT_FIELD_TYPE_PRESENT) #endif // !_WINDOWS } From 3230894bdd8ab4183b83ad4c942eb6acad4acce6 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Tue, 4 Mar 2025 14:41:35 +0000 Subject: [PATCH 214/587] 8348561: Add aarch64 intrinsics for ML-DSA Reviewed-by: adinn --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 10 +- .../cpu/aarch64/stubDeclarations_aarch64.hpp | 2 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 1223 +++++++++++++++-- .../cpu/aarch64/stubRoutines_aarch64.cpp | 9 + .../cpu/aarch64/stubRoutines_aarch64.hpp | 3 +- .../cpu/aarch64/vm_version_aarch64.cpp | 11 + src/hotspot/share/classfile/vmIntrinsics.cpp | 8 + src/hotspot/share/classfile/vmIntrinsics.hpp | 26 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 6 + src/hotspot/share/opto/c2compiler.cpp | 6 + src/hotspot/share/opto/escape.cpp | 6 + src/hotspot/share/opto/library_call.cpp | 214 +++ src/hotspot/share/opto/library_call.hpp | 6 + src/hotspot/share/opto/runtime.cpp | 137 ++ src/hotspot/share/opto/runtime.hpp | 36 + src/hotspot/share/runtime/globals.hpp | 3 + .../share/runtime/stubDeclarations.hpp | 21 +- src/hotspot/share/runtime/stubRoutines.cpp | 1 + .../classes/sun/security/provider/ML_DSA.java | 512 +++++-- .../sun/security/provider/SHA3Parallel.java | 16 +- test/hotspot/gtest/aarch64/aarch64-asmtest.py | 5 + test/hotspot/gtest/aarch64/asmtest.out.h | 837 +++++------ 22 files changed, 2518 insertions(+), 580 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index a5e0e2665af..c91a136e7d5 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.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) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2552,6 +2552,11 @@ template ldst_sstr(T, index, a, op1, op2, Vt, Vt2, Vt3, Vt4); \ } + INSN1(ld1, 0b001101010, 0b0000); + INSN2(ld2, 0b001101011, 0b0000); + INSN3(ld3, 0b001101010, 0b0010); + INSN4(ld4, 0b001101011, 0b0010); + INSN1(st1, 0b001101000, 0b0000); INSN2(st2, 0b001101001, 0b0000); INSN3(st3, 0b001101000, 0b0010); @@ -2586,6 +2591,7 @@ template void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \ guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \ if (!acceptT2D) guarantee(T != T2D, "incorrect arrangement"); \ + if (opc2 == 0b101101) guarantee(T != T8B && T != T16B, "incorrect arrangement"); \ starti; \ f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \ f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \ @@ -2609,6 +2615,8 @@ template INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(smaxp, 0, 0b101001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(sminp, 0, 0b101011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S + INSN(sqdmulh,0, 0b101101, false); // accepted arrangements: T4H, T8H, T2S, T4S + INSN(shsubv, 0, 0b001001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S #undef INSN diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index 3b5d0640ea4..a893aacaaf2 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -44,7 +44,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 35000 ZGC_ONLY(+5000)) \ + do_arch_blob(compiler, 55000 ZGC_ONLY(+5000)) \ do_stub(compiler, vector_iota_indices) \ do_arch_entry(aarch64, compiler, vector_iota_indices, \ vector_iota_indices, vector_iota_indices) \ diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 5f901a5e9ea..d5b23dc6843 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4063,6 +4063,95 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Execute one round of keccak of two computations in parallel. + // One of the states should be loaded into the lower halves of + // the vector registers v0-v24, the other should be loaded into + // the upper halves of those registers. The ld1r instruction loads + // the round constant into both halves of register v31. + // Intermediate results c0...c5 and d0...d5 are computed + // in registers v25...v30. + // All vector instructions that are used operate on both register + // halves in parallel. + // If only a single computation is needed, one can only load the lower halves. + void keccak_round(Register rscratch1) { + __ eor3(v29, __ T16B, v4, v9, v14); // c4 = a4 ^ a9 ^ a14 + __ eor3(v26, __ T16B, v1, v6, v11); // c1 = a1 ^ a16 ^ a11 + __ eor3(v28, __ T16B, v3, v8, v13); // c3 = a3 ^ a8 ^a13 + __ eor3(v25, __ T16B, v0, v5, v10); // c0 = a0 ^ a5 ^ a10 + __ eor3(v27, __ T16B, v2, v7, v12); // c2 = a2 ^ a7 ^ a12 + __ eor3(v29, __ T16B, v29, v19, v24); // c4 ^= a19 ^ a24 + __ eor3(v26, __ T16B, v26, v16, v21); // c1 ^= a16 ^ a21 + __ eor3(v28, __ T16B, v28, v18, v23); // c3 ^= a18 ^ a23 + __ eor3(v25, __ T16B, v25, v15, v20); // c0 ^= a15 ^ a20 + __ eor3(v27, __ T16B, v27, v17, v22); // c2 ^= a17 ^ a22 + + __ rax1(v30, __ T2D, v29, v26); // d0 = c4 ^ rol(c1, 1) + __ rax1(v26, __ T2D, v26, v28); // d2 = c1 ^ rol(c3, 1) + __ rax1(v28, __ T2D, v28, v25); // d4 = c3 ^ rol(c0, 1) + __ rax1(v25, __ T2D, v25, v27); // d1 = c0 ^ rol(c2, 1) + __ rax1(v27, __ T2D, v27, v29); // d3 = c2 ^ rol(c4, 1) + + __ eor(v0, __ T16B, v0, v30); // a0 = a0 ^ d0 + __ xar(v29, __ T2D, v1, v25, (64 - 1)); // a10' = rol((a1^d1), 1) + __ xar(v1, __ T2D, v6, v25, (64 - 44)); // a1 = rol(a6^d1), 44) + __ xar(v6, __ T2D, v9, v28, (64 - 20)); // a6 = rol((a9^d4), 20) + __ xar(v9, __ T2D, v22, v26, (64 - 61)); // a9 = rol((a22^d2), 61) + __ xar(v22, __ T2D, v14, v28, (64 - 39)); // a22 = rol((a14^d4), 39) + __ xar(v14, __ T2D, v20, v30, (64 - 18)); // a14 = rol((a20^d0), 18) + __ xar(v31, __ T2D, v2, v26, (64 - 62)); // a20' = rol((a2^d2), 62) + __ xar(v2, __ T2D, v12, v26, (64 - 43)); // a2 = rol((a12^d2), 43) + __ xar(v12, __ T2D, v13, v27, (64 - 25)); // a12 = rol((a13^d3), 25) + __ xar(v13, __ T2D, v19, v28, (64 - 8)); // a13 = rol((a19^d4), 8) + __ xar(v19, __ T2D, v23, v27, (64 - 56)); // a19 = rol((a23^d3), 56) + __ xar(v23, __ T2D, v15, v30, (64 - 41)); // a23 = rol((a15^d0), 41) + __ xar(v15, __ T2D, v4, v28, (64 - 27)); // a15 = rol((a4^d4), 27) + __ xar(v28, __ T2D, v24, v28, (64 - 14)); // a4' = rol((a24^d4), 14) + __ xar(v24, __ T2D, v21, v25, (64 - 2)); // a24 = rol((a21^d1), 2) + __ xar(v8, __ T2D, v8, v27, (64 - 55)); // a21' = rol((a8^d3), 55) + __ xar(v4, __ T2D, v16, v25, (64 - 45)); // a8' = rol((a16^d1), 45) + __ xar(v16, __ T2D, v5, v30, (64 - 36)); // a16 = rol((a5^d0), 36) + __ xar(v5, __ T2D, v3, v27, (64 - 28)); // a5 = rol((a3^d3), 28) + __ xar(v27, __ T2D, v18, v27, (64 - 21)); // a3' = rol((a18^d3), 21) + __ xar(v3, __ T2D, v17, v26, (64 - 15)); // a18' = rol((a17^d2), 15) + __ xar(v25, __ T2D, v11, v25, (64 - 10)); // a17' = rol((a11^d1), 10) + __ xar(v26, __ T2D, v7, v26, (64 - 6)); // a11' = rol((a7^d2), 6) + __ xar(v30, __ T2D, v10, v30, (64 - 3)); // a7' = rol((a10^d0), 3) + + __ bcax(v20, __ T16B, v31, v22, v8); // a20 = a20' ^ (~a21 & a22') + __ bcax(v21, __ T16B, v8, v23, v22); // a21 = a21' ^ (~a22 & a23) + __ bcax(v22, __ T16B, v22, v24, v23); // a22 = a22 ^ (~a23 & a24) + __ bcax(v23, __ T16B, v23, v31, v24); // a23 = a23 ^ (~a24 & a20') + __ bcax(v24, __ T16B, v24, v8, v31); // a24 = a24 ^ (~a20' & a21') + + __ ld1r(v31, __ T2D, __ post(rscratch1, 8)); // rc = round_constants[i] + + __ bcax(v17, __ T16B, v25, v19, v3); // a17 = a17' ^ (~a18' & a19) + __ bcax(v18, __ T16B, v3, v15, v19); // a18 = a18' ^ (~a19 & a15') + __ bcax(v19, __ T16B, v19, v16, v15); // a19 = a19 ^ (~a15 & a16) + __ bcax(v15, __ T16B, v15, v25, v16); // a15 = a15 ^ (~a16 & a17') + __ bcax(v16, __ T16B, v16, v3, v25); // a16 = a16 ^ (~a17' & a18') + + __ bcax(v10, __ T16B, v29, v12, v26); // a10 = a10' ^ (~a11' & a12) + __ bcax(v11, __ T16B, v26, v13, v12); // a11 = a11' ^ (~a12 & a13) + __ bcax(v12, __ T16B, v12, v14, v13); // a12 = a12 ^ (~a13 & a14) + __ bcax(v13, __ T16B, v13, v29, v14); // a13 = a13 ^ (~a14 & a10') + __ bcax(v14, __ T16B, v14, v26, v29); // a14 = a14 ^ (~a10' & a11') + + __ bcax(v7, __ T16B, v30, v9, v4); // a7 = a7' ^ (~a8' & a9) + __ bcax(v8, __ T16B, v4, v5, v9); // a8 = a8' ^ (~a9 & a5) + __ bcax(v9, __ T16B, v9, v6, v5); // a9 = a9 ^ (~a5 & a6) + __ bcax(v5, __ T16B, v5, v30, v6); // a5 = a5 ^ (~a6 & a7) + __ bcax(v6, __ T16B, v6, v4, v30); // a6 = a6 ^ (~a7 & a8') + + __ bcax(v3, __ T16B, v27, v0, v28); // a3 = a3' ^ (~a4' & a0) + __ bcax(v4, __ T16B, v28, v1, v0); // a4 = a4' ^ (~a0 & a1) + __ bcax(v0, __ T16B, v0, v2, v1); // a0 = a0 ^ (~a1 & a2) + __ bcax(v1, __ T16B, v1, v27, v2); // a1 = a1 ^ (~a2 & a3) + __ bcax(v2, __ T16B, v2, v28, v27); // a2 = a2 ^ (~a3 & a4') + + __ eor(v0, __ T16B, v0, v31); // a0 = a0 ^ rc + } + // Arguments: // // Inputs: @@ -4167,7 +4256,7 @@ class StubGenerator: public StubCodeGenerator { __ cbzw(c_rarg5, rounds24_loop); __ tbnz(block_size, 5, shake128); - // block_size == 144, bit5 == 0, SHA3-244 + // block_size == 144, bit5 == 0, SHA3-224 __ ldrd(v28, __ post(buf, 8)); __ eor(v17, __ T8B, v17, v28); __ b(rounds24_loop); @@ -4196,82 +4285,7 @@ class StubGenerator: public StubCodeGenerator { __ BIND(rounds24_loop); __ subw(rscratch2, rscratch2, 1); - __ eor3(v29, __ T16B, v4, v9, v14); - __ eor3(v26, __ T16B, v1, v6, v11); - __ eor3(v28, __ T16B, v3, v8, v13); - __ eor3(v25, __ T16B, v0, v5, v10); - __ eor3(v27, __ T16B, v2, v7, v12); - __ eor3(v29, __ T16B, v29, v19, v24); - __ eor3(v26, __ T16B, v26, v16, v21); - __ eor3(v28, __ T16B, v28, v18, v23); - __ eor3(v25, __ T16B, v25, v15, v20); - __ eor3(v27, __ T16B, v27, v17, v22); - - __ rax1(v30, __ T2D, v29, v26); - __ rax1(v26, __ T2D, v26, v28); - __ rax1(v28, __ T2D, v28, v25); - __ rax1(v25, __ T2D, v25, v27); - __ rax1(v27, __ T2D, v27, v29); - - __ eor(v0, __ T16B, v0, v30); - __ xar(v29, __ T2D, v1, v25, (64 - 1)); - __ xar(v1, __ T2D, v6, v25, (64 - 44)); - __ xar(v6, __ T2D, v9, v28, (64 - 20)); - __ xar(v9, __ T2D, v22, v26, (64 - 61)); - __ xar(v22, __ T2D, v14, v28, (64 - 39)); - __ xar(v14, __ T2D, v20, v30, (64 - 18)); - __ xar(v31, __ T2D, v2, v26, (64 - 62)); - __ xar(v2, __ T2D, v12, v26, (64 - 43)); - __ xar(v12, __ T2D, v13, v27, (64 - 25)); - __ xar(v13, __ T2D, v19, v28, (64 - 8)); - __ xar(v19, __ T2D, v23, v27, (64 - 56)); - __ xar(v23, __ T2D, v15, v30, (64 - 41)); - __ xar(v15, __ T2D, v4, v28, (64 - 27)); - __ xar(v28, __ T2D, v24, v28, (64 - 14)); - __ xar(v24, __ T2D, v21, v25, (64 - 2)); - __ xar(v8, __ T2D, v8, v27, (64 - 55)); - __ xar(v4, __ T2D, v16, v25, (64 - 45)); - __ xar(v16, __ T2D, v5, v30, (64 - 36)); - __ xar(v5, __ T2D, v3, v27, (64 - 28)); - __ xar(v27, __ T2D, v18, v27, (64 - 21)); - __ xar(v3, __ T2D, v17, v26, (64 - 15)); - __ xar(v25, __ T2D, v11, v25, (64 - 10)); - __ xar(v26, __ T2D, v7, v26, (64 - 6)); - __ xar(v30, __ T2D, v10, v30, (64 - 3)); - - __ bcax(v20, __ T16B, v31, v22, v8); - __ bcax(v21, __ T16B, v8, v23, v22); - __ bcax(v22, __ T16B, v22, v24, v23); - __ bcax(v23, __ T16B, v23, v31, v24); - __ bcax(v24, __ T16B, v24, v8, v31); - - __ ld1r(v31, __ T2D, __ post(rscratch1, 8)); - - __ bcax(v17, __ T16B, v25, v19, v3); - __ bcax(v18, __ T16B, v3, v15, v19); - __ bcax(v19, __ T16B, v19, v16, v15); - __ bcax(v15, __ T16B, v15, v25, v16); - __ bcax(v16, __ T16B, v16, v3, v25); - - __ bcax(v10, __ T16B, v29, v12, v26); - __ bcax(v11, __ T16B, v26, v13, v12); - __ bcax(v12, __ T16B, v12, v14, v13); - __ bcax(v13, __ T16B, v13, v29, v14); - __ bcax(v14, __ T16B, v14, v26, v29); - - __ bcax(v7, __ T16B, v30, v9, v4); - __ bcax(v8, __ T16B, v4, v5, v9); - __ bcax(v9, __ T16B, v9, v6, v5); - __ bcax(v5, __ T16B, v5, v30, v6); - __ bcax(v6, __ T16B, v6, v4, v30); - - __ bcax(v3, __ T16B, v27, v0, v28); - __ bcax(v4, __ T16B, v28, v1, v0); - __ bcax(v0, __ T16B, v0, v2, v1); - __ bcax(v1, __ T16B, v1, v27, v2); - __ bcax(v2, __ T16B, v2, v28, v27); - - __ eor(v0, __ T16B, v0, v31); + keccak_round(rscratch1); __ cbnzw(rscratch2, rounds24_loop); @@ -4290,6 +4304,7 @@ class StubGenerator: public StubCodeGenerator { __ st1(v20, v21, v22, v23, __ T1D, __ post(state, 32)); __ st1(v24, __ T1D, state); + // restore callee-saved registers __ ldpd(v14, v15, Address(sp, 48)); __ ldpd(v12, v13, Address(sp, 32)); __ ldpd(v10, v11, Address(sp, 16)); @@ -4300,6 +4315,96 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Inputs: + // c_rarg0 - long[] state0 + // c_rarg1 - long[] state1 + address generate_double_keccak() { + static const uint64_t round_consts[24] = { + 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, + 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, + 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, + 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L + }; + + // Implements the double_keccak() method of the + // sun.secyrity.provider.SHA3Parallel class + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "double_keccak"); + address start = __ pc(); + __ enter(); + + Register state0 = c_rarg0; + Register state1 = c_rarg1; + + Label rounds24_loop; + + // save callee-saved registers + __ stpd(v8, v9, __ pre(sp, -64)); + __ stpd(v10, v11, Address(sp, 16)); + __ stpd(v12, v13, Address(sp, 32)); + __ stpd(v14, v15, Address(sp, 48)); + + // load states + __ add(rscratch1, state0, 32); + __ ld4(v0, v1, v2, v3, __ D, 0, state0); + __ ld4(v4, v5, v6, v7, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v8, v9, v10, v11, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v12, v13, v14, v15, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v16, v17, v18, v19, __ D, 0, __ post(rscratch1, 32)); + __ ld4(v20, v21, v22, v23, __ D, 0, __ post(rscratch1, 32)); + __ ld1(v24, __ D, 0, rscratch1); + __ add(rscratch1, state1, 32); + __ ld4(v0, v1, v2, v3, __ D, 1, state1); + __ ld4(v4, v5, v6, v7, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v8, v9, v10, v11, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v12, v13, v14, v15, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v16, v17, v18, v19, __ D, 1, __ post(rscratch1, 32)); + __ ld4(v20, v21, v22, v23, __ D, 1, __ post(rscratch1, 32)); + __ ld1(v24, __ D, 1, rscratch1); + + // 24 keccak rounds + __ movw(rscratch2, 24); + + // load round_constants base + __ lea(rscratch1, ExternalAddress((address) round_consts)); + + __ BIND(rounds24_loop); + __ subw(rscratch2, rscratch2, 1); + keccak_round(rscratch1); + __ cbnzw(rscratch2, rounds24_loop); + + __ st4(v0, v1, v2, v3, __ D, 0, __ post(state0, 32)); + __ st4(v4, v5, v6, v7, __ D, 0, __ post(state0, 32)); + __ st4(v8, v9, v10, v11, __ D, 0, __ post(state0, 32)); + __ st4(v12, v13, v14, v15, __ D, 0, __ post(state0, 32)); + __ st4(v16, v17, v18, v19, __ D, 0, __ post(state0, 32)); + __ st4(v20, v21, v22, v23, __ D, 0, __ post(state0, 32)); + __ st1(v24, __ D, 0, state0); + __ st4(v0, v1, v2, v3, __ D, 1, __ post(state1, 32)); + __ st4(v4, v5, v6, v7, __ D, 1, __ post(state1, 32)); + __ st4(v8, v9, v10, v11, __ D, 1, __ post(state1, 32)); + __ st4(v12, v13, v14, v15, __ D, 1, __ post(state1, 32)); + __ st4(v16, v17, v18, v19, __ D, 1, __ post(state1, 32)); + __ st4(v20, v21, v22, v23, __ D, 1, __ post(state1, 32)); + __ st1(v24, __ D, 1, state1); + + // restore callee-saved vector registers + __ ldpd(v14, v15, Address(sp, 48)); + __ ldpd(v12, v13, Address(sp, 32)); + __ ldpd(v10, v11, Address(sp, 16)); + __ ldpd(v8, v9, __ post(sp, 64)); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -4538,6 +4643,961 @@ class StubGenerator: public StubCodeGenerator { return start; } + void dilithium_load16zetas(int o0, Register zetas) { + __ ldpq(as_FloatRegister(o0), as_FloatRegister(o0 + 1), __ post (zetas, 32)); + __ ldpq(as_FloatRegister(o0 + 2), as_FloatRegister(o0 + 3), __ post (zetas, 32)); + + } + + void dilithium_load32zetas(Register zetas) { + dilithium_load16zetas(16, zetas); + dilithium_load16zetas(20, zetas); + } + + // 2x16 32-bit Montgomery multiplications in parallel + // See the montMul() method of the sun.security.provider.ML_DSA class. + // Here MONT_R_BITS is 32, so the right shift by it is implicit. + // The constants qInv = MONT_Q_INV_MOD_R and q = MONT_Q are loaded in + // (all 32-bit chunks of) vector registers v30 and v31, resp. + // The inputs are b[i]s in v0-v7 and c[i]s v16-v23 and + // the results are a[i]s in v16-v23, four 32-bit values in each register + // and we do a_i = b_i * c_i * 2^-32 mod MONT_Q for all + void dilithium_montmul32(bool by_constant) { + FloatRegister vr0 = by_constant ? v29 : v0; + FloatRegister vr1 = by_constant ? v29 : v1; + FloatRegister vr2 = by_constant ? v29 : v2; + FloatRegister vr3 = by_constant ? v29 : v3; + FloatRegister vr4 = by_constant ? v29 : v4; + FloatRegister vr5 = by_constant ? v29 : v5; + FloatRegister vr6 = by_constant ? v29 : v6; + FloatRegister vr7 = by_constant ? v29 : v7; + + __ sqdmulh(v24, __ T4S, vr0, v16); // aHigh = hi32(2 * b * c) + __ mulv(v16, __ T4S, vr0, v16); // aLow = lo32(b * c) + __ sqdmulh(v25, __ T4S, vr1, v17); + __ mulv(v17, __ T4S, vr1, v17); + __ sqdmulh(v26, __ T4S, vr2, v18); + __ mulv(v18, __ T4S, vr2, v18); + __ sqdmulh(v27, __ T4S, vr3, v19); + __ mulv(v19, __ T4S, vr3, v19); + + __ mulv(v16, __ T4S, v16, v30); // m = aLow * qinv + __ mulv(v17, __ T4S, v17, v30); + __ mulv(v18, __ T4S, v18, v30); + __ mulv(v19, __ T4S, v19, v30); + + __ sqdmulh(v16, __ T4S, v16, v31); // n = hi32(2 * m * q) + __ sqdmulh(v17, __ T4S, v17, v31); + __ sqdmulh(v18, __ T4S, v18, v31); + __ sqdmulh(v19, __ T4S, v19, v31); + + __ shsubv(v16, __ T4S, v24, v16); // a = (aHigh - n) / 2 + __ shsubv(v17, __ T4S, v25, v17); + __ shsubv(v18, __ T4S, v26, v18); + __ shsubv(v19, __ T4S, v27, v19); + + __ sqdmulh(v24, __ T4S, vr4, v20); + __ mulv(v20, __ T4S, vr4, v20); + __ sqdmulh(v25, __ T4S, vr5, v21); + __ mulv(v21, __ T4S, vr5, v21); + __ sqdmulh(v26, __ T4S, vr6, v22); + __ mulv(v22, __ T4S, vr6, v22); + __ sqdmulh(v27, __ T4S, vr7, v23); + __ mulv(v23, __ T4S, vr7, v23); + + __ mulv(v20, __ T4S, v20, v30); + __ mulv(v21, __ T4S, v21, v30); + __ mulv(v22, __ T4S, v22, v30); + __ mulv(v23, __ T4S, v23, v30); + + __ sqdmulh(v20, __ T4S, v20, v31); + __ sqdmulh(v21, __ T4S, v21, v31); + __ sqdmulh(v22, __ T4S, v22, v31); + __ sqdmulh(v23, __ T4S, v23, v31); + + __ shsubv(v20, __ T4S, v24, v20); + __ shsubv(v21, __ T4S, v25, v21); + __ shsubv(v22, __ T4S, v26, v22); + __ shsubv(v23, __ T4S, v27, v23); + } + + // Do the addition and subtraction done in the ntt algorithm. + // See sun.security.provider.ML_DSA.implDilithiumAlmostNttJava() + void dilithium_add_sub32() { + __ addv(v24, __ T4S, v0, v16); // coeffs[j] = coeffs[j] + tmp; + __ addv(v25, __ T4S, v1, v17); + __ addv(v26, __ T4S, v2, v18); + __ addv(v27, __ T4S, v3, v19); + __ addv(v28, __ T4S, v4, v20); + __ addv(v29, __ T4S, v5, v21); + __ addv(v30, __ T4S, v6, v22); + __ addv(v31, __ T4S, v7, v23); + + __ subv(v0, __ T4S, v0, v16); // coeffs[j + l] = coeffs[j] - tmp; + __ subv(v1, __ T4S, v1, v17); + __ subv(v2, __ T4S, v2, v18); + __ subv(v3, __ T4S, v3, v19); + __ subv(v4, __ T4S, v4, v20); + __ subv(v5, __ T4S, v5, v21); + __ subv(v6, __ T4S, v6, v22); + __ subv(v7, __ T4S, v7, v23); + } + + // Do the same computation that + // dilithium_montmul32() and dilithium_add_sub32() does, + // except for only 4x4 32-bit vector elements and with + // different register usage. + void dilithium_montmul_sub_add16() { + __ sqdmulh(v24, __ T4S, v1, v16); + __ mulv(v16, __ T4S, v1, v16); + __ sqdmulh(v25, __ T4S, v3, v17); + __ mulv(v17, __ T4S, v3, v17); + __ sqdmulh(v26, __ T4S, v5, v18); + __ mulv(v18, __ T4S, v5, v18); + __ sqdmulh(v27, __ T4S, v7, v19); + __ mulv(v19, __ T4S, v7, v19); + + __ mulv(v16, __ T4S, v16, v30); + __ mulv(v17, __ T4S, v17, v30); + __ mulv(v18, __ T4S, v18, v30); + __ mulv(v19, __ T4S, v19, v30); + + __ sqdmulh(v16, __ T4S, v16, v31); + __ sqdmulh(v17, __ T4S, v17, v31); + __ sqdmulh(v18, __ T4S, v18, v31); + __ sqdmulh(v19, __ T4S, v19, v31); + + __ shsubv(v16, __ T4S, v24, v16); + __ shsubv(v17, __ T4S, v25, v17); + __ shsubv(v18, __ T4S, v26, v18); + __ shsubv(v19, __ T4S, v27, v19); + + __ subv(v1, __ T4S, v0, v16); + __ subv(v3, __ T4S, v2, v17); + __ subv(v5, __ T4S, v4, v18); + __ subv(v7, __ T4S, v6, v19); + + __ addv(v0, __ T4S, v0, v16); + __ addv(v2, __ T4S, v2, v17); + __ addv(v4, __ T4S, v4, v18); + __ addv(v6, __ T4S, v6, v19); + } + + // At these levels, the indices that correspond to the 'j's (and 'j+l's) + // in the Java implementation come in sequences of at least 8, so we + // can use ldpq to collect the corresponding data into pairs of vector + // registers. + // We collect the coefficients corresponding to the 'j+l' indexes into + // the vector registers v0-v7, the zetas into the vector registers v16-v23 + // then we do the (Montgomery) multiplications by the zetas in parallel + // into v16-v23, load the coeffs corresponding to the 'j' indexes into + // v0-v7, then do the additions into v24-v31 and the subtractions into + // v0-v7 and finally save the results back to the coeffs array. + void dilithiumNttLevel0_4(const Register dilithiumConsts, + const Register coeffs, const Register zetas) { + int c1 = 0; + int c2 = 512; + int startIncr; + int incr1 = 32; + int incr2 = 64; + int incr3 = 96; + + for (int level = 0; level < 5; level++) { + int c1Start = c1; + int c2Start = c2; + if (level == 3) { + incr1 = 32; + incr2 = 128; + incr3 = 160; + } else if (level == 4) { + incr1 = 64; + incr2 = 128; + incr3 = 192; + } + + for (int i = 0; i < 4; i++) { + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ ldpq(v0, v1, Address(coeffs, c2Start)); + __ ldpq(v2, v3, Address(coeffs, c2Start + incr1)); + __ ldpq(v4, v5, Address(coeffs, c2Start + incr2)); + __ ldpq(v6, v7, Address(coeffs, c2Start + incr3)); + dilithium_load32zetas(zetas); + dilithium_montmul32(false); + __ ldpq(v0, v1, Address(coeffs, c1Start)); + __ ldpq(v2, v3, Address(coeffs, c1Start + incr1)); + __ ldpq(v4, v5, Address(coeffs, c1Start + incr2)); + __ ldpq(v6, v7, Address(coeffs, c1Start + incr3)); + dilithium_add_sub32(); + __ stpq(v24, v25, Address(coeffs, c1Start)); + __ stpq(v26, v27, Address(coeffs, c1Start + incr1)); + __ stpq(v28, v29, Address(coeffs, c1Start + incr2)); + __ stpq(v30, v31, Address(coeffs, c1Start + incr3)); + __ stpq(v0, v1, Address(coeffs, c2Start)); + __ stpq(v2, v3, Address(coeffs, c2Start + incr1)); + __ stpq(v4, v5, Address(coeffs, c2Start + incr2)); + __ stpq(v6, v7, Address(coeffs, c2Start + incr3)); + + int k = 4 * level + i; + + if (k > 7) { + startIncr = 256; + } else if (k == 5) { + startIncr = 384; + } else { + startIncr = 128; + } + + c1Start += startIncr; + c2Start += startIncr; + } + + c2 /= 2; + } + } + + // Dilithium NTT function except for the final "normalization" to |coeff| < Q. + // Implements the method + // static int implDilithiumAlmostNtt(int[] coeffs, int zetas[]) {} + // of the Java class sun.security.provider + // + // coeffs (int[256]) = c_rarg0 + // zetas (int[256]) = c_rarg1 + address generate_dilithiumAlmostNtt() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::dilithiumAlmostNtt_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register tmpAddr = r9; + const Register dilithiumConsts = r10; + const Register result = r11; + + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // Each level represents one iteration of the outer for loop of the Java version + + // level 0-4 + dilithiumNttLevel0_4(dilithiumConsts, coeffs, zetas); + + // level 5 + for (int i = 0; i < 1024; i += 256) { + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ ldr(v0, __ Q, Address(coeffs, i + 16)); + __ ldr(v1, __ Q, Address(coeffs, i + 48)); + __ ldr(v2, __ Q, Address(coeffs, i + 80)); + __ ldr(v3, __ Q, Address(coeffs, i + 112)); + __ ldr(v4, __ Q, Address(coeffs, i + 144)); + __ ldr(v5, __ Q, Address(coeffs, i + 176)); + __ ldr(v6, __ Q, Address(coeffs, i + 208)); + __ ldr(v7, __ Q, Address(coeffs, i + 240)); + dilithium_load32zetas(zetas); + dilithium_montmul32(false); + __ ldr(v0, __ Q, Address(coeffs, i)); + __ ldr(v1, __ Q, Address(coeffs, i + 32)); + __ ldr(v2, __ Q, Address(coeffs, i + 64)); + __ ldr(v3, __ Q, Address(coeffs, i + 96)); + __ ldr(v4, __ Q, Address(coeffs, i + 128)); + __ ldr(v5, __ Q, Address(coeffs, i + 160)); + __ ldr(v6, __ Q, Address(coeffs, i + 192)); + __ ldr(v7, __ Q, Address(coeffs, i + 224)); + dilithium_add_sub32(); + __ str(v24, __ Q, Address(coeffs, i)); + __ str(v25, __ Q, Address(coeffs, i + 32)); + __ str(v26, __ Q, Address(coeffs, i + 64)); + __ str(v27, __ Q, Address(coeffs, i + 96)); + __ str(v28, __ Q, Address(coeffs, i + 128)); + __ str(v29, __ Q, Address(coeffs, i + 160)); + __ str(v30, __ Q, Address(coeffs, i + 192)); + __ str(v31, __ Q, Address(coeffs, i + 224)); + __ str(v0, __ Q, Address(coeffs, i + 16)); + __ str(v1, __ Q, Address(coeffs, i + 48)); + __ str(v2, __ Q, Address(coeffs, i + 80)); + __ str(v3, __ Q, Address(coeffs, i + 112)); + __ str(v4, __ Q, Address(coeffs, i + 144)); + __ str(v5, __ Q, Address(coeffs, i + 176)); + __ str(v6, __ Q, Address(coeffs, i + 208)); + __ str(v7, __ Q, Address(coeffs, i + 240)); + } + + // level 6 + for (int i = 0; i < 1024; i += 128) { + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ add(tmpAddr, coeffs, i); + __ ld2(v0, v1, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ ld2(v2, v3, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ ld2(v4, v5, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ ld2(v6, v7, __ T2D, tmpAddr); + dilithium_load16zetas(16, zetas); + dilithium_montmul_sub_add16(); + __ add(tmpAddr, coeffs, i); + __ st2(v0, v1, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ st2(v2, v3, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ st2(v4, v5, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ st2(v6, v7, __ T2D, tmpAddr); + } + + // level 7 + for (int i = 0; i < 1024; i += 128) { + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ add(tmpAddr, coeffs, i); + __ ld2(v0, v1, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ ld2(v2, v3, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ ld2(v4, v5, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ ld2(v6, v7, __ T4S, tmpAddr); + dilithium_load16zetas(16, zetas); + dilithium_montmul_sub_add16(); + __ add(tmpAddr, coeffs, i); + __ st2(v0, v1, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ st2(v2, v3, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ st2(v4, v5, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ st2(v6, v7, __ T4S, tmpAddr); + } + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + + } + + // Do the computations that can be found in the body of the loop in + // sun.security.provider.ML_DSA.implDilithiumAlmostInverseNttJava() + // for 16 coefficients in parallel: + // tmp = coeffs[j]; + // coeffs[j] = (tmp + coeffs[j + l]); + // coeffs[j + l] = montMul(tmp - coeffs[j + l], -MONT_ZETAS_FOR_NTT[m]); + // coefss[j]s are loaded in v0, v2, v4 and v6, + // coeffs[j + l]s in v1, v3, v5 and v7, + // the corresponding zetas in v16, v17, v18 and v19. + void dilithium_sub_add_montmul16() { + __ subv(v20, __ T4S, v0, v1); + __ subv(v21, __ T4S, v2, v3); + __ subv(v22, __ T4S, v4, v5); + __ subv(v23, __ T4S, v6, v7); + + __ addv(v0, __ T4S, v0, v1); + __ addv(v2, __ T4S, v2, v3); + __ addv(v4, __ T4S, v4, v5); + __ addv(v6, __ T4S, v6, v7); + + __ sqdmulh(v24, __ T4S, v20, v16); // aHigh = hi32(2 * b * c) + __ mulv(v1, __ T4S, v20, v16); // aLow = lo32(b * c) + __ sqdmulh(v25, __ T4S, v21, v17); + __ mulv(v3, __ T4S, v21, v17); + __ sqdmulh(v26, __ T4S, v22, v18); + __ mulv(v5, __ T4S, v22, v18); + __ sqdmulh(v27, __ T4S, v23, v19); + __ mulv(v7, __ T4S, v23, v19); + + __ mulv(v1, __ T4S, v1, v30); // m = (aLow * q) + __ mulv(v3, __ T4S, v3, v30); + __ mulv(v5, __ T4S, v5, v30); + __ mulv(v7, __ T4S, v7, v30); + + __ sqdmulh(v1, __ T4S, v1, v31); // n = hi32(2 * m * q) + __ sqdmulh(v3, __ T4S, v3, v31); + __ sqdmulh(v5, __ T4S, v5, v31); + __ sqdmulh(v7, __ T4S, v7, v31); + + __ shsubv(v1, __ T4S, v24, v1); // a = (aHigh - n) / 2 + __ shsubv(v3, __ T4S, v25, v3); + __ shsubv(v5, __ T4S, v26, v5); + __ shsubv(v7, __ T4S, v27, v7); + } + + // At these levels, the indices that correspond to the 'j's (and 'j+l's) + // in the Java implementation come in sequences of at least 8, so we + // can use ldpq to collect the corresponding data into pairs of vector + // registers + // We collect the coefficients that correspond to the 'j's into v0-v7 + // the coefficiets that correspond to the 'j+l's into v16-v23 then + // do the additions into v24-v31 and the subtractions into v0-v7 then + // save the result of the additions, load the zetas into v16-v23 + // do the (Montgomery) multiplications by zeta in parallel into v16-v23 + // finally save the results back to the coeffs array + void dilithiumInverseNttLevel3_7(const Register dilithiumConsts, + const Register coeffs, const Register zetas) { + int c1 = 0; + int c2 = 32; + int startIncr; + int incr1; + int incr2; + int incr3; + + for (int level = 3; level < 8; level++) { + int c1Start = c1; + int c2Start = c2; + if (level == 3) { + incr1 = 64; + incr2 = 128; + incr3 = 192; + } else if (level == 4) { + incr1 = 32; + incr2 = 128; + incr3 = 160; + } else { + incr1 = 32; + incr2 = 64; + incr3 = 96; + } + + for (int i = 0; i < 4; i++) { + __ ldpq(v0, v1, Address(coeffs, c1Start)); + __ ldpq(v2, v3, Address(coeffs, c1Start + incr1)); + __ ldpq(v4, v5, Address(coeffs, c1Start + incr2)); + __ ldpq(v6, v7, Address(coeffs, c1Start + incr3)); + __ ldpq(v16, v17, Address(coeffs, c2Start)); + __ ldpq(v18, v19, Address(coeffs, c2Start + incr1)); + __ ldpq(v20, v21, Address(coeffs, c2Start + incr2)); + __ ldpq(v22, v23, Address(coeffs, c2Start + incr3)); + dilithium_add_sub32(); + __ stpq(v24, v25, Address(coeffs, c1Start)); + __ stpq(v26, v27, Address(coeffs, c1Start + incr1)); + __ stpq(v28, v29, Address(coeffs, c1Start + incr2)); + __ stpq(v30, v31, Address(coeffs, c1Start + incr3)); + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + dilithium_load32zetas(zetas); + dilithium_montmul32(false); + __ stpq(v16, v17, Address(coeffs, c2Start)); + __ stpq(v18, v19, Address(coeffs, c2Start + incr1)); + __ stpq(v20, v21, Address(coeffs, c2Start + incr2)); + __ stpq(v22, v23, Address(coeffs, c2Start + incr3)); + + int k = 4 * level + i; + + if (k < 24) { + startIncr = 256; + } else if (k == 25) { + startIncr = 384; + } else { + startIncr = 128; + } + + c1Start += startIncr; + c2Start += startIncr; + } + + c2 *= 2; + } + } + + // Dilithium Inverse NTT function except the final mod Q division by 2^256. + // Implements the method + // static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) {} of + // the sun.security.provider.ML_DSA class. + // + // coeffs (int[256]) = c_rarg0 + // zetas (int[256]) = c_rarg1 + address generate_dilithiumAlmostInverseNtt() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::dilithiumAlmostInverseNtt_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register tmpAddr = r9; + const Register dilithiumConsts = r10; + const Register result = r11; + + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // Each level represents one iteration of the outer for loop of the Java version + // level0 + for (int i = 0; i < 1024; i += 128) { + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ add(tmpAddr, coeffs, i); + __ ld2(v0, v1, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ ld2(v2, v3, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ ld2(v4, v5, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ ld2(v6, v7, __ T4S, tmpAddr); + dilithium_load16zetas(16, zetas); + dilithium_sub_add_montmul16(); + __ add(tmpAddr, coeffs, i); + __ st2(v0, v1, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ st2(v2, v3, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ st2(v4, v5, __ T4S, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ st2(v6, v7, __ T4S, tmpAddr); + } + + // level 1 + for (int i = 0; i < 1024; i += 128) { + __ add(tmpAddr, coeffs, i); + __ ld2(v0, v1, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ ld2(v2, v3, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ ld2(v4, v5, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ ld2(v6, v7, __ T2D, tmpAddr); + dilithium_load16zetas(16, zetas); + dilithium_sub_add_montmul16(); + __ add(tmpAddr, coeffs, i); + __ st2(v0, v1, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 32); + __ st2(v2, v3, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 64); + __ st2(v4, v5, __ T2D, tmpAddr); + __ add(tmpAddr, coeffs, i + 96); + __ st2(v6, v7, __ T2D, tmpAddr); + } + + //level 2 + for (int i = 0; i < 1024; i += 256) { + __ ldr(v0, __ Q, Address(coeffs, i)); + __ ldr(v1, __ Q, Address(coeffs, i + 32)); + __ ldr(v2, __ Q, Address(coeffs, i + 64)); + __ ldr(v3, __ Q, Address(coeffs, i + 96)); + __ ldr(v4, __ Q, Address(coeffs, i + 128)); + __ ldr(v5, __ Q, Address(coeffs, i + 160)); + __ ldr(v6, __ Q, Address(coeffs, i + 192)); + __ ldr(v7, __ Q, Address(coeffs, i + 224)); + __ ldr(v16, __ Q, Address(coeffs, i + 16)); + __ ldr(v17, __ Q, Address(coeffs, i + 48)); + __ ldr(v18, __ Q, Address(coeffs, i + 80)); + __ ldr(v19, __ Q, Address(coeffs, i + 112)); + __ ldr(v20, __ Q, Address(coeffs, i + 144)); + __ ldr(v21, __ Q, Address(coeffs, i + 176)); + __ ldr(v22, __ Q, Address(coeffs, i + 208)); + __ ldr(v23, __ Q, Address(coeffs, i + 240)); + dilithium_add_sub32(); + __ str(v24, __ Q, Address(coeffs, i)); + __ str(v25, __ Q, Address(coeffs, i + 32)); + __ str(v26, __ Q, Address(coeffs, i + 64)); + __ str(v27, __ Q, Address(coeffs, i + 96)); + __ str(v28, __ Q, Address(coeffs, i + 128)); + __ str(v29, __ Q, Address(coeffs, i + 160)); + __ str(v30, __ Q, Address(coeffs, i + 192)); + __ str(v31, __ Q, Address(coeffs, i + 224)); + dilithium_load32zetas(zetas); + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + dilithium_montmul32(false); + __ str(v16, __ Q, Address(coeffs, i + 16)); + __ str(v17, __ Q, Address(coeffs, i + 48)); + __ str(v18, __ Q, Address(coeffs, i + 80)); + __ str(v19, __ Q, Address(coeffs, i + 112)); + __ str(v20, __ Q, Address(coeffs, i + 144)); + __ str(v21, __ Q, Address(coeffs, i + 176)); + __ str(v22, __ Q, Address(coeffs, i + 208)); + __ str(v23, __ Q, Address(coeffs, i + 240)); + } + + // level 3-7 + dilithiumInverseNttLevel3_7(dilithiumConsts, coeffs, zetas); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + + } + + // Dilithium multiply polynomials in the NTT domain. + // Straightforward implementation of the method + // static int implDilithiumNttMult( + // int[] result, int[] ntta, int[] nttb {} of + // the sun.security.provider.ML_DSA class. + // + // result (int[256]) = c_rarg0 + // poly1 (int[256]) = c_rarg1 + // poly2 (int[256]) = c_rarg2 + address generate_dilithiumNttMult() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::dilithiumNttMult_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register result = c_rarg0; + const Register poly1 = c_rarg1; + const Register poly2 = c_rarg2; + + const Register dilithiumConsts = r10; + const Register len = r11; + + __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ ldr(v29, __ Q, Address(dilithiumConsts, 48)); // rSquare + + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + __ ldpq(v0, v1, __ post(poly1, 32)); + __ ldpq(v2, v3, __ post(poly1, 32)); + __ ldpq(v4, v5, __ post(poly1, 32)); + __ ldpq(v6, v7, __ post(poly1, 32)); + __ ldpq(v16, v17, __ post(poly2, 32)); + __ ldpq(v18, v19, __ post(poly2, 32)); + __ ldpq(v20, v21, __ post(poly2, 32)); + __ ldpq(v22, v23, __ post(poly2, 32)); + dilithium_montmul32(false); + dilithium_montmul32(true); + __ stpq(v16, v17, __ post(result, 32)); + __ stpq(v18, v19, __ post(result, 32)); + __ stpq(v20, v21, __ post(result, 32)); + __ stpq(v22, v23, __ post(result, 32)); + + __ sub(len, len, 128); + __ cmp(len, (u1)128); + __ br(Assembler::GE, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + + } + + // Dilithium Motgomery multiply an array by a constant. + // A straightforward implementation of the method + // static int implDilithiumMontMulByConstant(int[] coeffs, int constant) {} + // of the sun.security.provider.MLDSA class + // + // coeffs (int[256]) = c_rarg0 + // constant (int) = c_rarg1 + address generate_dilithiumMontMulByConstant() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::dilithiumMontMulByConstant_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register coeffs = c_rarg0; + const Register constant = c_rarg1; + + const Register dilithiumConsts = r10; + const Register result = r11; + const Register len = r12; + + __ add(result, coeffs, 0); + __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + __ ldpq(v30, v31, Address(dilithiumConsts, 0)); // qInv, q + __ dup(v29, __ T4S, constant); + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + __ ldpq(v16, v17, __ post(coeffs, 32)); + __ ldpq(v18, v19, __ post(coeffs, 32)); + __ ldpq(v20, v21, __ post(coeffs, 32)); + __ ldpq(v22, v23, __ post(coeffs, 32)); + dilithium_montmul32(true); + __ stpq(v16, v17, __ post(result, 32)); + __ stpq(v18, v19, __ post(result, 32)); + __ stpq(v20, v21, __ post(result, 32)); + __ stpq(v22, v23, __ post(result, 32)); + + __ sub(len, len, 128); + __ cmp(len, (u1)128); + __ br(Assembler::GE, L_loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + + // Dilithium decompose poly. + // Implements the method + // static int implDilithiumDecomposePoly(int[] coeffs, int constant) {} + // of the sun.security.provider.ML_DSA class + // + // input (int[256]) = c_rarg0 + // lowPart (int[256]) = c_rarg1 + // highPart (int[256]) = c_rarg2 + // twoGamma2 (int) = c_rarg3 + // multiplier (int) = c_rarg4 + address generate_dilithiumDecomposePoly() { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::dilithiumDecomposePoly_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + __ enter(); + + Label L_loop; + + const Register input = c_rarg0; + const Register lowPart = c_rarg1; + const Register highPart = c_rarg2; + const Register twoGamma2 = c_rarg3; + const Register multiplier = c_rarg4; + + const Register len = r9; + const Register dilithiumConsts = r10; + const Register tmp = r11; + + __ lea(dilithiumConsts, ExternalAddress((address) StubRoutines::aarch64::_dilithiumConsts)); + + // save callee-saved registers + __ stpd(v8, v9, __ pre(sp, -64)); + __ stpd(v10, v11, Address(sp, 16)); + __ stpd(v12, v13, Address(sp, 32)); + __ stpd(v14, v15, Address(sp, 48)); + + + __ mov(tmp, zr); + __ add(tmp, tmp, 1); + __ dup(v25, __ T4S, tmp); // 1 + __ ldr(v30, __ Q, Address(dilithiumConsts, 16)); // q + __ ldr(v31, __ Q, Address(dilithiumConsts, 64)); // addend for mod q reduce + __ dup(v28, __ T4S, twoGamma2); // 2 * gamma2 + __ dup(v29, __ T4S, multiplier); // multiplier for mod 2 * gamma reduce + __ subv(v26, __ T4S, v30, v25); // q - 1 + __ sshr(v27, __ T4S, v28, 1); // gamma2 + + __ mov(len, zr); + __ add(len, len, 1024); + + __ BIND(L_loop); + + __ ld4(v0, v1, v2, v3, __ T4S, __ post(input, 64)); + + // rplus in v0 + // rplus = rplus - ((rplus + 5373807) >> 23) * dilithium_q; + __ addv(v4, __ T4S, v0, v31); + __ addv(v5, __ T4S, v1, v31); + __ addv(v6, __ T4S, v2, v31); + __ addv(v7, __ T4S, v3, v31); + + __ sshr(v4, __ T4S, v4, 23); + __ sshr(v5, __ T4S, v5, 23); + __ sshr(v6, __ T4S, v6, 23); + __ sshr(v7, __ T4S, v7, 23); + + __ mulv(v4, __ T4S, v4, v30); + __ mulv(v5, __ T4S, v5, v30); + __ mulv(v6, __ T4S, v6, v30); + __ mulv(v7, __ T4S, v7, v30); + + __ subv(v0, __ T4S, v0, v4); + __ subv(v1, __ T4S, v1, v5); + __ subv(v2, __ T4S, v2, v6); + __ subv(v3, __ T4S, v3, v7); + + // rplus in v0 + // rplus = rplus + ((rplus >> 31) & dilithium_q); + __ sshr(v4, __ T4S, v0, 31); + __ sshr(v5, __ T4S, v1, 31); + __ sshr(v6, __ T4S, v2, 31); + __ sshr(v7, __ T4S, v3, 31); + + __ andr(v4, __ T16B, v4, v30); + __ andr(v5, __ T16B, v5, v30); + __ andr(v6, __ T16B, v6, v30); + __ andr(v7, __ T16B, v7, v30); + + __ addv(v0, __ T4S, v0, v4); + __ addv(v1, __ T4S, v1, v5); + __ addv(v2, __ T4S, v2, v6); + __ addv(v3, __ T4S, v3, v7); + + // rplus in v0 + // int quotient = (rplus * multiplier) >> 22; + __ mulv(v4, __ T4S, v0, v29); + __ mulv(v5, __ T4S, v1, v29); + __ mulv(v6, __ T4S, v2, v29); + __ mulv(v7, __ T4S, v3, v29); + + __ sshr(v4, __ T4S, v4, 22); + __ sshr(v5, __ T4S, v5, 22); + __ sshr(v6, __ T4S, v6, 22); + __ sshr(v7, __ T4S, v7, 22); + + // quotient in v4 + // int r0 = rplus - quotient * twoGamma2; + __ mulv(v8, __ T4S, v4, v28); + __ mulv(v9, __ T4S, v5, v28); + __ mulv(v10, __ T4S, v6, v28); + __ mulv(v11, __ T4S, v7, v28); + + __ subv(v8, __ T4S, v0, v8); + __ subv(v9, __ T4S, v1, v9); + __ subv(v10, __ T4S, v2, v10); + __ subv(v11, __ T4S, v3, v11); + + // r0 in v8 + // int mask = (twoGamma2 - r0) >> 22; + __ subv(v12, __ T4S, v28, v8); + __ subv(v13, __ T4S, v28, v9); + __ subv(v14, __ T4S, v28, v10); + __ subv(v15, __ T4S, v28, v11); + + __ sshr(v12, __ T4S, v12, 22); + __ sshr(v13, __ T4S, v13, 22); + __ sshr(v14, __ T4S, v14, 22); + __ sshr(v15, __ T4S, v15, 22); + + // mask in v12 + // r0 -= (mask & twoGamma2); + __ andr(v16, __ T16B, v12, v28); + __ andr(v17, __ T16B, v13, v28); + __ andr(v18, __ T16B, v14, v28); + __ andr(v19, __ T16B, v15, v28); + + __ subv(v8, __ T4S, v8, v16); + __ subv(v9, __ T4S, v9, v17); + __ subv(v10, __ T4S, v10, v18); + __ subv(v11, __ T4S, v11, v19); + + // r0 in v8 + // quotient += (mask & 1); + __ andr(v16, __ T16B, v12, v25); + __ andr(v17, __ T16B, v13, v25); + __ andr(v18, __ T16B, v14, v25); + __ andr(v19, __ T16B, v15, v25); + + __ addv(v4, __ T4S, v4, v16); + __ addv(v5, __ T4S, v5, v17); + __ addv(v6, __ T4S, v6, v18); + __ addv(v7, __ T4S, v7, v19); + + // mask = (twoGamma2 / 2 - r0) >> 31; + __ subv(v12, __ T4S, v27, v8); + __ subv(v13, __ T4S, v27, v9); + __ subv(v14, __ T4S, v27, v10); + __ subv(v15, __ T4S, v27, v11); + + __ sshr(v12, __ T4S, v12, 31); + __ sshr(v13, __ T4S, v13, 31); + __ sshr(v14, __ T4S, v14, 31); + __ sshr(v15, __ T4S, v15, 31); + + // r0 -= (mask & twoGamma2); + __ andr(v16, __ T16B, v12, v28); + __ andr(v17, __ T16B, v13, v28); + __ andr(v18, __ T16B, v14, v28); + __ andr(v19, __ T16B, v15, v28); + + __ subv(v8, __ T4S, v8, v16); + __ subv(v9, __ T4S, v9, v17); + __ subv(v10, __ T4S, v10, v18); + __ subv(v11, __ T4S, v11, v19); + + // quotient += (mask & 1); + __ andr(v16, __ T16B, v12, v25); + __ andr(v17, __ T16B, v13, v25); + __ andr(v18, __ T16B, v14, v25); + __ andr(v19, __ T16B, v15, v25); + + __ addv(v4, __ T4S, v4, v16); + __ addv(v5, __ T4S, v5, v17); + __ addv(v6, __ T4S, v6, v18); + __ addv(v7, __ T4S, v7, v19); + + // int r1 = rplus - r0 - (dilithium_q - 1); + __ subv(v16, __ T4S, v0, v8); + __ subv(v17, __ T4S, v1, v9); + __ subv(v18, __ T4S, v2, v10); + __ subv(v19, __ T4S, v3, v11); + + __ subv(v16, __ T4S, v16, v26); + __ subv(v17, __ T4S, v17, v26); + __ subv(v18, __ T4S, v18, v26); + __ subv(v19, __ T4S, v19, v26); + + // r1 in v16 + // r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise + __ negr(v20, __ T4S, v16); + __ negr(v21, __ T4S, v17); + __ negr(v22, __ T4S, v18); + __ negr(v23, __ T4S, v19); + + __ orr(v16, __ T16B, v16, v20); + __ orr(v17, __ T16B, v17, v21); + __ orr(v18, __ T16B, v18, v22); + __ orr(v19, __ T16B, v19, v23); + + __ sshr(v0, __ T4S, v16, 31); + __ sshr(v1, __ T4S, v17, 31); + __ sshr(v2, __ T4S, v18, 31); + __ sshr(v3, __ T4S, v19, 31); + + // r1 in v0 + // r0 += ~r1; + __ notr(v20, __ T16B, v0); + __ notr(v21, __ T16B, v1); + __ notr(v22, __ T16B, v2); + __ notr(v23, __ T16B, v3); + + __ addv(v8, __ T4S, v8, v20); + __ addv(v9, __ T4S, v9, v21); + __ addv(v10, __ T4S, v10, v22); + __ addv(v11, __ T4S, v11, v23); + + // r0 in v8 + // r1 = r1 & quotient; + __ andr(v0, __ T16B, v4, v0); + __ andr(v1, __ T16B, v5, v1); + __ andr(v2, __ T16B, v6, v2); + __ andr(v3, __ T16B, v7, v3); + + // r1 in v0 + // lowPart[m] = r0; + // highPart[m] = r1; + __ st4(v8, v9, v10, v11, __ T4S, __ post(lowPart, 64)); + __ st4(v0, v1, v2, v3, __ T4S, __ post(highPart, 64)); + + + __ sub(len, len, 64); + __ cmp(len, (u1)64); + __ br(Assembler::GE, L_loop); + + // restore callee-saved vector registers + __ ldpd(v14, v15, Address(sp, 48)); + __ ldpd(v12, v13, Address(sp, 32)); + __ ldpd(v10, v11, Address(sp, 16)); + __ ldpd(v8, v9, __ post(sp, 64)); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov(r0, zr); // return 0 + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -8939,6 +9999,14 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_chacha20Block = generate_chacha20Block_qrpar(); } + if (UseDilithiumIntrinsics) { + StubRoutines::_dilithiumAlmostNtt = generate_dilithiumAlmostNtt(); + StubRoutines::_dilithiumAlmostInverseNtt = generate_dilithiumAlmostInverseNtt(); + StubRoutines::_dilithiumNttMult = generate_dilithiumNttMult(); + StubRoutines::_dilithiumMontMulByConstant = generate_dilithiumMontMulByConstant(); + StubRoutines::_dilithiumDecomposePoly = generate_dilithiumDecomposePoly(); + } + if (UseBASE64Intrinsics) { StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock(); @@ -8981,6 +10049,7 @@ class StubGenerator: public StubCodeGenerator { } if (UseSHA3Intrinsics) { StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubGenStubId::sha3_implCompress_id); + StubRoutines::_double_keccak = generate_double_keccak(); StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubGenStubId::sha3_implCompressMB_id); } diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 3fa1616bf65..536583ff40c 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -48,6 +48,15 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) bool StubRoutines::aarch64::_completed = false; +ATTRIBUTE_ALIGNED(64) uint32_t StubRoutines::aarch64::_dilithiumConsts[] = +{ + 58728449, 58728449, 58728449, 58728449, // montQInvModR + 8380417, 8380417, 8380417, 8380417, // dilithium_q + 16382, 16382, 16382, 16382, // toMont((dilithium_n)^-1 (mod dilithium_q)) + 2365951, 2365951, 2365951, 2365951, // montRSquareModQ + 5373807, 5373807, 5373807, 5373807 // addend for modular reduce +}; + /** * crc_table[] from jdk/src/share/native/java/util/zip/zlib-1.2.5/crc32.h */ diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index a5ed87cdca4..857bb2ff10a 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -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, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -110,6 +110,7 @@ private: } private: + static uint32_t _dilithiumConsts[]; static juint _crc_table[]; static jubyte _adler_table[]; // begin trigonometric tables block. See comments in .cpp file diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index bca39ae9db2..91930f6bc26 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -417,6 +417,17 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } + if (_features & CPU_ASIMD) { + if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + UseDilithiumIntrinsics = true; + } + } else if (UseDilithiumIntrinsics) { + if (!FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { + warning("Dilithium intrinsic requires ASIMD instructions"); + } + FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); + } + if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { UseBASE64Intrinsics = true; } diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 2943f9d4af3..8011b059697 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -475,6 +475,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_sha5_implCompress: if (!UseSHA512Intrinsics) return true; break; + case vmIntrinsics::_double_keccak: case vmIntrinsics::_sha3_implCompress: if (!UseSHA3Intrinsics) return true; break; @@ -487,6 +488,13 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_chacha20Block: if (!UseChaCha20Intrinsics) return true; break; + case vmIntrinsics::_dilithiumAlmostNtt: + case vmIntrinsics::_dilithiumAlmostInverseNtt: + case vmIntrinsics::_dilithiumNttMult: + case vmIntrinsics::_dilithiumMontMulByConstant: + case vmIntrinsics::_dilithiumDecomposePoly: + if (!UseDilithiumIntrinsics) return true; + break; case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: if (!UseBASE64Intrinsics) return true; diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 0c95f6ab410..7dbfb862ac2 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -516,6 +516,12 @@ class methodHandle; do_class(sun_security_provider_sha3, "sun/security/provider/SHA3") \ do_intrinsic(_sha3_implCompress, sun_security_provider_sha3, implCompress_name, implCompress_signature, F_R) \ \ + /* support for sun.security.provider.SHAKE128Parallel */ \ + do_class(sun_security_provider_sha3_parallel, "sun/security/provider/SHA3Parallel") \ + do_intrinsic(_double_keccak, sun_security_provider_sha3_parallel, double_keccak_name, double_keccak_signature, F_S) \ + do_name( double_keccak_name, "doubleKeccak") \ + do_signature(double_keccak_signature, "([J[J)I") \ + \ /* support for sun.security.provider.DigestBase */ \ do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \ do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \ @@ -561,6 +567,26 @@ class methodHandle; do_name(chacha20Block_name, "implChaCha20Block") \ do_signature(chacha20Block_signature, "([I[B)I") \ \ + /* support for sun.security.provider.ML_DSA */ \ + do_class(sun_security_provider_ML_DSA, "sun/security/provider/ML_DSA") \ + do_signature(IaII_signature, "([II)I") \ + do_signature(IaIaI_signature, "([I[I)I") \ + do_signature(IaIaIaI_signature, "([I[I[I)I") \ + do_signature(IaIaIaIII_signature, "([I[I[III)I") \ + do_intrinsic(_dilithiumAlmostNtt, sun_security_provider_ML_DSA, dilithiumAlmostNtt_name, IaIaI_signature, F_S) \ + do_name(dilithiumAlmostNtt_name, "implDilithiumAlmostNtt") \ + do_intrinsic(_dilithiumAlmostInverseNtt, sun_security_provider_ML_DSA, \ + dilithiumAlmostInverseNtt_name, IaIaI_signature, F_S) \ + do_name(dilithiumAlmostInverseNtt_name, "implDilithiumAlmostInverseNtt") \ + do_intrinsic(_dilithiumNttMult, sun_security_provider_ML_DSA, dilithiumNttMult_name, IaIaIaI_signature, F_S) \ + do_name(dilithiumNttMult_name, "implDilithiumNttMult") \ + do_intrinsic(_dilithiumMontMulByConstant, sun_security_provider_ML_DSA, \ + dilithiumMontMulByConstant_name, IaII_signature, F_S) \ + do_name(dilithiumMontMulByConstant_name, "implDilithiumMontMulByConstant") \ + do_intrinsic(_dilithiumDecomposePoly, sun_security_provider_ML_DSA, \ + dilithiumDecomposePoly_name, IaIaIaIII_signature, F_S) \ + do_name(dilithiumDecomposePoly_name, "implDilithiumDecomposePoly") \ + \ /* support for java.util.zip */ \ do_class(java_util_zip_CRC32, "java/util/zip/CRC32") \ do_intrinsic(_updateCRC32, java_util_zip_CRC32, update_name, int2_int_signature, F_SN) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 48c9f8a64dc..7567caad712 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -394,7 +394,13 @@ static_field(StubRoutines, _sha512_implCompress, address) \ static_field(StubRoutines, _sha512_implCompressMB, address) \ static_field(StubRoutines, _sha3_implCompress, address) \ + static_field(StubRoutines, _double_keccak, address) \ static_field(StubRoutines, _sha3_implCompressMB, address) \ + static_field(StubRoutines, _dilithiumAlmostNtt, address) \ + static_field(StubRoutines, _dilithiumAlmostInverseNtt, address) \ + static_field(StubRoutines, _dilithiumNttMult, address) \ + static_field(StubRoutines, _dilithiumMontMulByConstant, address) \ + static_field(StubRoutines, _dilithiumDecomposePoly, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ static_field(StubRoutines, _crc32c_table_addr, address) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 0a769211c82..790512d310d 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -780,6 +780,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_sha2_implCompress: case vmIntrinsics::_sha5_implCompress: case vmIntrinsics::_sha3_implCompress: + case vmIntrinsics::_double_keccak: case vmIntrinsics::_digestBase_implCompressMB: case vmIntrinsics::_multiplyToLen: case vmIntrinsics::_squareToLen: @@ -789,6 +790,11 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_ghash_processBlocks: case vmIntrinsics::_chacha20Block: + case vmIntrinsics::_dilithiumAlmostNtt: + case vmIntrinsics::_dilithiumAlmostInverseNtt: + case vmIntrinsics::_dilithiumNttMult: + case vmIntrinsics::_dilithiumMontMulByConstant: + case vmIntrinsics::_dilithiumDecomposePoly: case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: case vmIntrinsics::_poly1305_processBlocks: diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index a90c27861c1..068a2c0b100 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -2192,6 +2192,11 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "intpoly_assign") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "chacha20Block") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumAlmostInverseNtt") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumNttMult") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumMontMulByConstant") == 0 || + strcmp(call->as_CallLeaf()->_name, "dilithiumDecomposePoly") == 0 || strcmp(call->as_CallLeaf()->_name, "encodeBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "decodeBlock") == 0 || strcmp(call->as_CallLeaf()->_name, "md5_implCompress") == 0 || @@ -2203,6 +2208,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 || strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "sha3_implCompress") == 0 || + strcmp(call->as_CallLeaf()->_name, "double_keccak") == 0 || strcmp(call->as_CallLeaf()->_name, "sha3_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 || strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 || diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6f651db58ce..05efda3c64b 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -594,6 +594,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_sha5_implCompress: case vmIntrinsics::_sha3_implCompress: return inline_digestBase_implCompress(intrinsic_id()); + case vmIntrinsics::_double_keccak: + return inline_double_keccak(); case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB(predicate); @@ -624,6 +626,16 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_ghash_processBlocks(); case vmIntrinsics::_chacha20Block: return inline_chacha20Block(); + case vmIntrinsics::_dilithiumAlmostNtt: + return inline_dilithiumAlmostNtt(); + case vmIntrinsics::_dilithiumAlmostInverseNtt: + return inline_dilithiumAlmostInverseNtt(); + case vmIntrinsics::_dilithiumNttMult: + return inline_dilithiumNttMult(); + case vmIntrinsics::_dilithiumMontMulByConstant: + return inline_dilithiumMontMulByConstant(); + case vmIntrinsics::_dilithiumDecomposePoly: + return inline_dilithiumDecomposePoly(); case vmIntrinsics::_base64_encodeBlock: return inline_base64_encodeBlock(); case vmIntrinsics::_base64_decodeBlock: @@ -7588,6 +7600,176 @@ bool LibraryCallKit::inline_chacha20Block() { return true; } +//------------------------------inline_dilithiumAlmostNtt +bool LibraryCallKit::inline_dilithiumAlmostNtt() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumAlmostNtt has 2 parameters"); + + stubAddr = StubRoutines::dilithiumAlmostNtt(); + stubName = "dilithiumAlmostNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* ntt_zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + ntt_zetas = must_be_not_null(ntt_zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* ntt_zetas_start = array_element_address(ntt_zetas, intcon(0), T_INT); + assert(ntt_zetas_start, "ntt_zetas is null"); + Node* dilithiumAlmostNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumAlmostNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, ntt_zetas_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumAlmostNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_dilithiumAlmostInverseNtt +bool LibraryCallKit::inline_dilithiumAlmostInverseNtt() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumAlmostInverseNtt has 2 parameters"); + + stubAddr = StubRoutines::dilithiumAlmostInverseNtt(); + stubName = "dilithiumAlmostInverseNtt"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* zetas = argument(1); + + coeffs = must_be_not_null(coeffs, true); + zetas = must_be_not_null(zetas, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* zetas_start = array_element_address(zetas, intcon(0), T_INT); + assert(zetas_start, "inverseNtt_zetas is null"); + Node* dilithiumAlmostInverseNtt = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumAlmostInverseNtt_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, zetas_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumAlmostInverseNtt, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + +//------------------------------inline_dilithiumNttMult +bool LibraryCallKit::inline_dilithiumNttMult() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 3, "dilithiumNttMult has 3 parameters"); + + stubAddr = StubRoutines::dilithiumNttMult(); + stubName = "dilithiumNttMult"; + if (!stubAddr) return false; + + Node* result = argument(0); + Node* ntta = argument(1); + Node* nttb = argument(2); + + result = must_be_not_null(result, true); + ntta = must_be_not_null(ntta, true); + nttb = must_be_not_null(nttb, true); + + Node* result_start = array_element_address(result, intcon(0), T_INT); + assert(result_start, "result is null"); + Node* ntta_start = array_element_address(ntta, intcon(0), T_INT); + assert(ntta_start, "ntta is null"); + Node* nttb_start = array_element_address(nttb, intcon(0), T_INT); + assert(nttb_start, "nttb is null"); + Node* dilithiumNttMult = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumNttMult_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + result_start, ntta_start, nttb_start); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumNttMult, TypeFunc::Parms)); + set_result(retvalue); + + return true; +} + +//------------------------------inline_dilithiumMontMulByConstant +bool LibraryCallKit::inline_dilithiumMontMulByConstant() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 2, "dilithiumMontMulByConstant has 2 parameters"); + + stubAddr = StubRoutines::dilithiumMontMulByConstant(); + stubName = "dilithiumMontMulByConstant"; + if (!stubAddr) return false; + + Node* coeffs = argument(0); + Node* constant = argument(1); + + coeffs = must_be_not_null(coeffs, true); + + Node* coeffs_start = array_element_address(coeffs, intcon(0), T_INT); + assert(coeffs_start, "coeffs is null"); + Node* dilithiumMontMulByConstant = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumMontMulByConstant_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + coeffs_start, constant); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumMontMulByConstant, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + + +//------------------------------inline_dilithiumDecomposePoly +bool LibraryCallKit::inline_dilithiumDecomposePoly() { + address stubAddr; + const char *stubName; + assert(UseDilithiumIntrinsics, "need Dilithium intrinsics support"); + assert(callee()->signature()->size() == 5, "dilithiumDecomposePoly has 5 parameters"); + + stubAddr = StubRoutines::dilithiumDecomposePoly(); + stubName = "dilithiumDecomposePoly"; + if (!stubAddr) return false; + + Node* input = argument(0); + Node* lowPart = argument(1); + Node* highPart = argument(2); + Node* twoGamma2 = argument(3); + Node* multiplier = argument(4); + + input = must_be_not_null(input, true); + lowPart = must_be_not_null(lowPart, true); + highPart = must_be_not_null(highPart, true); + + Node* input_start = array_element_address(input, intcon(0), T_INT); + assert(input_start, "input is null"); + Node* lowPart_start = array_element_address(lowPart, intcon(0), T_INT); + assert(lowPart_start, "lowPart is null"); + Node* highPart_start = array_element_address(highPart, intcon(0), T_INT); + assert(highPart_start, "highPart is null"); + + Node* dilithiumDecomposePoly = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::dilithiumDecomposePoly_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + input_start, lowPart_start, highPart_start, + twoGamma2, multiplier); + + // return an int + Node* retvalue = _gvn.transform(new ProjNode(dilithiumDecomposePoly, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + bool LibraryCallKit::inline_base64_encodeBlock() { address stubAddr; const char *stubName; @@ -7851,6 +8033,38 @@ bool LibraryCallKit::inline_digestBase_implCompress(vmIntrinsics::ID id) { return true; } +//------------------------------inline_double_keccak +bool LibraryCallKit::inline_double_keccak() { + address stubAddr; + const char *stubName; + assert(UseSHA3Intrinsics, "need SHA3 intrinsics support"); + assert(callee()->signature()->size() == 2, "double_keccak has 2 parameters"); + + stubAddr = StubRoutines::double_keccak(); + stubName = "double_keccak"; + if (!stubAddr) return false; + + Node* status0 = argument(0); + Node* status1 = argument(1); + + status0 = must_be_not_null(status0, true); + status1 = must_be_not_null(status1, true); + + Node* status0_start = array_element_address(status0, intcon(0), T_LONG); + assert(status0_start, "status0 is null"); + Node* status1_start = array_element_address(status1, intcon(0), T_LONG); + assert(status1_start, "status1 is null"); + Node* double_keccak = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::double_keccak_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + status0_start, status1_start); + // return an int + Node* retvalue = _gvn.transform(new ProjNode(double_keccak, TypeFunc::Parms)); + set_result(retvalue); + return true; +} + + //------------------------------inline_digestBase_implCompressMB----------------------- // // Calculate MD5/SHA/SHA2/SHA5/SHA3 for multi-block byte[] array. diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 51dda136bc1..afc8d329228 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -316,12 +316,18 @@ class LibraryCallKit : public GraphKit { Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); bool inline_ghash_processBlocks(); bool inline_chacha20Block(); + bool inline_dilithiumAlmostNtt(); + bool inline_dilithiumAlmostInverseNtt(); + bool inline_dilithiumNttMult(); + bool inline_dilithiumMontMulByConstant(); + bool inline_dilithiumDecomposePoly(); bool inline_base64_encodeBlock(); bool inline_base64_decodeBlock(); bool inline_poly1305_processBlocks(); bool inline_intpoly_montgomeryMult_P256(); bool inline_intpoly_assign(); bool inline_digestBase_implCompress(vmIntrinsics::ID id); + bool inline_double_keccak(); bool inline_digestBase_implCompressMB(int predicate); bool inline_digestBase_implCompressMB(Node* digestBaseObj, ciInstanceKlass* instklass, BasicType elem_type, address stubAddr, const char *stubName, diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index b288f21f99e..7774c8a49c9 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -230,6 +230,7 @@ const TypeFunc* OptoRuntime::_digestBase_implCompress_with_sha3_Type = null const TypeFunc* OptoRuntime::_digestBase_implCompress_without_sha3_Type = nullptr; const TypeFunc* OptoRuntime::_digestBase_implCompressMB_with_sha3_Type = nullptr; const TypeFunc* OptoRuntime::_digestBase_implCompressMB_without_sha3_Type = nullptr; +const TypeFunc* OptoRuntime::_double_keccak_Type = nullptr; const TypeFunc* OptoRuntime::_multiplyToLen_Type = nullptr; const TypeFunc* OptoRuntime::_montgomeryMultiply_Type = nullptr; const TypeFunc* OptoRuntime::_montgomerySquare_Type = nullptr; @@ -239,6 +240,13 @@ const TypeFunc* OptoRuntime::_bigIntegerShift_Type = nullptr; const TypeFunc* OptoRuntime::_vectorizedMismatch_Type = nullptr; const TypeFunc* OptoRuntime::_ghash_processBlocks_Type = nullptr; const TypeFunc* OptoRuntime::_chacha20Block_Type = nullptr; + +const TypeFunc* OptoRuntime::_dilithiumAlmostNtt_Type = nullptr; +const TypeFunc* OptoRuntime::_dilithiumAlmostInverseNtt_Type = nullptr; +const TypeFunc* OptoRuntime::_dilithiumNttMult_Type = nullptr; +const TypeFunc* OptoRuntime::_dilithiumMontMulByConstant_Type = nullptr; +const TypeFunc* OptoRuntime::_dilithiumDecomposePoly_Type = nullptr; + const TypeFunc* OptoRuntime::_base64_encodeBlock_Type = nullptr; const TypeFunc* OptoRuntime::_base64_decodeBlock_Type = nullptr; const TypeFunc* OptoRuntime::_string_IndexOf_Type = nullptr; @@ -1171,6 +1179,9 @@ static const TypeFunc* make_digestBase_implCompress_Type(bool is_sha3) { return TypeFunc::make(domain, range); } +/* + * int implCompressMultiBlock(byte[] b, int ofs, int limit) + */ static const TypeFunc* make_digestBase_implCompressMB_Type(bool is_sha3) { // create input type (domain) int num_args = is_sha3 ? 5 : 4; @@ -1192,6 +1203,25 @@ static const TypeFunc* make_digestBase_implCompressMB_Type(bool is_sha3) { return TypeFunc::make(domain, range); } +// SHAKE128Parallel doubleKeccak function +static const TypeFunc* make_double_keccak_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // status0 + fields[argp++] = TypePtr::NOTNULL; // status1 + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + static const TypeFunc* make_multiplyToLen_Type() { // create input type (domain) int num_args = 5; @@ -1377,6 +1407,105 @@ static const TypeFunc* make_chacha20Block_Type() { return TypeFunc::make(domain, range); } +// Dilithium NTT function except for the final "normalization" to |coeff| < Q +static const TypeFunc* make_dilithiumAlmostNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium inverse NTT function except the final mod Q division by 2^256 +static const TypeFunc* make_dilithiumAlmostInverseNtt_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypePtr::NOTNULL; // inverse NTT zetas + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium NTT multiply function +static const TypeFunc* make_dilithiumNttMult_Type() { + int argcnt = 3; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // result + fields[argp++] = TypePtr::NOTNULL; // ntta + fields[argp++] = TypePtr::NOTNULL; // nttb + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium Montgomery multiply a polynome coefficient array by a constant +static const TypeFunc* make_dilithiumMontMulByConstant_Type() { + int argcnt = 2; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // coeffs + fields[argp++] = TypeInt::INT; // constant multiplier + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + +// Dilithium decompose polynomial +static const TypeFunc* make_dilithiumDecomposePoly_Type() { + int argcnt = 5; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // input + fields[argp++] = TypePtr::NOTNULL; // lowPart + fields[argp++] = TypePtr::NOTNULL; // highPart + fields[argp++] = TypeInt::INT; // 2 * gamma2 + fields[argp++] = TypeInt::INT; // multiplier + + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + static const TypeFunc* make_base64_encodeBlock_Type() { int argcnt = 6; @@ -1980,6 +2109,7 @@ void OptoRuntime::initialize_types() { _digestBase_implCompress_without_sha3_Type = make_digestBase_implCompress_Type( /* is_sha3= */ false);; _digestBase_implCompressMB_with_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ true); _digestBase_implCompressMB_without_sha3_Type = make_digestBase_implCompressMB_Type(/* is_sha3= */ false); + _double_keccak_Type = make_double_keccak_Type(); _multiplyToLen_Type = make_multiplyToLen_Type(); _montgomeryMultiply_Type = make_montgomeryMultiply_Type(); _montgomerySquare_Type = make_montgomerySquare_Type(); @@ -1989,6 +2119,13 @@ void OptoRuntime::initialize_types() { _vectorizedMismatch_Type = make_vectorizedMismatch_Type(); _ghash_processBlocks_Type = make_ghash_processBlocks_Type(); _chacha20Block_Type = make_chacha20Block_Type(); + + _dilithiumAlmostNtt_Type = make_dilithiumAlmostNtt_Type(); + _dilithiumAlmostInverseNtt_Type = make_dilithiumAlmostInverseNtt_Type(); + _dilithiumNttMult_Type = make_dilithiumNttMult_Type(); + _dilithiumMontMulByConstant_Type = make_dilithiumMontMulByConstant_Type(); + _dilithiumDecomposePoly_Type = make_dilithiumDecomposePoly_Type(); + _base64_encodeBlock_Type = make_base64_encodeBlock_Type(); _base64_decodeBlock_Type = make_base64_decodeBlock_Type(); _string_IndexOf_Type = make_string_IndexOf_Type(); diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index fceece73f66..dab8fb724fc 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -170,6 +170,7 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _digestBase_implCompress_without_sha3_Type; static const TypeFunc* _digestBase_implCompressMB_with_sha3_Type; static const TypeFunc* _digestBase_implCompressMB_without_sha3_Type; + static const TypeFunc* _double_keccak_Type; static const TypeFunc* _multiplyToLen_Type; static const TypeFunc* _montgomeryMultiply_Type; static const TypeFunc* _montgomerySquare_Type; @@ -179,6 +180,11 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _vectorizedMismatch_Type; static const TypeFunc* _ghash_processBlocks_Type; static const TypeFunc* _chacha20Block_Type; + static const TypeFunc* _dilithiumAlmostNtt_Type; + static const TypeFunc* _dilithiumAlmostInverseNtt_Type; + static const TypeFunc* _dilithiumNttMult_Type; + static const TypeFunc* _dilithiumMontMulByConstant_Type; + static const TypeFunc* _dilithiumDecomposePoly_Type; static const TypeFunc* _base64_encodeBlock_Type; static const TypeFunc* _base64_decodeBlock_Type; static const TypeFunc* _string_IndexOf_Type; @@ -525,6 +531,11 @@ private: return is_sha3 ? _digestBase_implCompressMB_with_sha3_Type : _digestBase_implCompressMB_without_sha3_Type; } + static inline const TypeFunc* double_keccak_Type() { + assert(_double_keccak_Type != nullptr, "should be initialized"); + return _double_keccak_Type; + } + static inline const TypeFunc* multiplyToLen_Type() { assert(_multiplyToLen_Type != nullptr, "should be initialized"); return _multiplyToLen_Type; @@ -573,6 +584,31 @@ private: return _chacha20Block_Type; } + static inline const TypeFunc* dilithiumAlmostNtt_Type() { + assert(_dilithiumAlmostNtt_Type != nullptr, "should be initialized"); + return _dilithiumAlmostNtt_Type; + } + + static inline const TypeFunc* dilithiumAlmostInverseNtt_Type() { + assert(_dilithiumAlmostInverseNtt_Type != nullptr, "should be initialized"); + return _dilithiumAlmostInverseNtt_Type; + } + + static inline const TypeFunc* dilithiumNttMult_Type() { + assert(_dilithiumNttMult_Type != nullptr, "should be initialized"); + return _dilithiumNttMult_Type; + } + + static inline const TypeFunc* dilithiumMontMulByConstant_Type() { + assert(_dilithiumMontMulByConstant_Type != nullptr, "should be initialized"); + return _dilithiumMontMulByConstant_Type; + } + + static inline const TypeFunc* dilithiumDecomposePoly_Type() { + assert(_dilithiumDecomposePoly_Type != nullptr, "should be initialized"); + return _dilithiumDecomposePoly_Type; + } + // Base64 encode function static inline const TypeFunc* base64_encodeBlock_Type() { assert(_base64_encodeBlock_Type != nullptr, "should be initialized"); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index e7aa034612b..e58d8c2b5b1 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -325,6 +325,9 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseChaCha20Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for the vectorized version of ChaCha20") \ \ + product(bool, UseDilithiumIntrinsics, false, DIAGNOSTIC, \ + "Use intrinsics for the vectorized version of Dilithium") \ + \ product(bool, UseMD5Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for MD5 crypto hash function") \ \ diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index 804bdc579b1..fd86f2ced3f 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -497,7 +497,7 @@ // Currently there is no support for a do_arch_array_entry template. // Include arch-specific stub and entry declarations and make sure the -// relevant template macros ahve been defined +// relevant template macros have been defined #include CPU_HEADER(stubDeclarations) @@ -678,6 +678,21 @@ ghash_processBlocks) \ do_stub(compiler, chacha20Block) \ do_entry(compiler, chacha20Block, chacha20Block, chacha20Block) \ + do_stub(compiler, dilithiumAlmostNtt) \ + do_entry(compiler, dilithiumAlmostNtt, \ + dilithiumAlmostNtt, dilithiumAlmostNtt) \ + do_stub(compiler, dilithiumAlmostInverseNtt) \ + do_entry(compiler, dilithiumAlmostInverseNtt, \ + dilithiumAlmostInverseNtt, dilithiumAlmostInverseNtt) \ + do_stub(compiler, dilithiumNttMult) \ + do_entry(compiler, dilithiumNttMult, \ + dilithiumNttMult, dilithiumNttMult) \ + do_stub(compiler, dilithiumMontMulByConstant) \ + do_entry(compiler, dilithiumMontMulByConstant, \ + dilithiumMontMulByConstant, dilithiumMontMulByConstant) \ + do_stub(compiler, dilithiumDecomposePoly) \ + do_entry(compiler, dilithiumDecomposePoly, \ + dilithiumDecomposePoly, dilithiumDecomposePoly) \ do_stub(compiler, data_cache_writeback) \ do_entry(compiler, data_cache_writeback, data_cache_writeback, \ data_cache_writeback) \ @@ -728,6 +743,8 @@ do_stub(compiler, sha3_implCompressMB) \ do_entry(compiler, sha3_implCompressMB, sha3_implCompressMB, \ sha3_implCompressMB) \ + do_stub(compiler, double_keccak) \ + do_entry(compiler, double_keccak, double_keccak, double_keccak) \ do_stub(compiler, updateBytesAdler32) \ do_entry(compiler, updateBytesAdler32, updateBytesAdler32, \ updateBytesAdler32) \ @@ -1043,7 +1060,6 @@ DO_ARCH_BLOB_EMPTY2, \ DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6) \ - // client macro to operate only on StubGenerator arch blobs #define STUBGEN_ARCH_BLOBS_DO(do_arch_blob) \ @@ -1065,4 +1081,3 @@ do_arch_entry, do_arch_entry_init) \ #endif // SHARE_RUNTIME_STUBDECLARATIONS_HPP - diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index dd1da2c9e66..b1b1f1d6056 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -99,6 +99,7 @@ STUBGEN_ENTRIES_DO(DEFINE_ENTRY_FIELD, DEFINE_ENTRY_FIELD_INIT, DEFINE_ENTRY_FIE jint StubRoutines::_verify_oop_count = 0; + address StubRoutines::_string_indexof_array[4] = { nullptr }; address StubRoutines::_vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; address StubRoutines::_vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index f3b72f53a32..969b8fffa39 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 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 @@ -25,9 +25,12 @@ package sun.security.provider; +import jdk.internal.vm.annotation.IntrinsicCandidate; import sun.security.provider.SHA3.SHAKE128; import sun.security.provider.SHA3.SHAKE256; +import sun.security.provider.SHA3Parallel.Shake128Parallel; +import java.security.InvalidAlgorithmParameterException; import java.security.MessageDigest; import java.security.InvalidKeyException; import java.security.SignatureException; @@ -44,7 +47,7 @@ public class ML_DSA { private static final int ML_DSA_Q = 8380417; private static final int ML_DSA_N = 256; private static final int SHAKE256_BLOCK_SIZE = 136; // the block length for SHAKE256 - + private static final int SHAKE128_BLOCK_SIZE = 168; // the block length for SHAKE128 private final int A_SEED_LEN = 32; private final int S1S2_SEED_LEN = 64; private final int K_LEN = 32; @@ -98,39 +101,280 @@ public class ML_DSA { -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782 }; - private static final int[] MONT_ZETAS_FOR_INVERSE_NTT = new int[]{ - -1976782, 846154, -1400424, -3937738, 1362209, 48306, -3919660, 554416, - 3545687, -1612842, 976891, -183443, 2286327, 420899, 2235985, 2939036, - 3833893, 260646, 1104333, 1667432, -1910376, 1803090, -1723600, 426683, - -472078, -1717735, 975884, -2213111, -269760, -3866901, -3523897, 3038916, - 1799107, 3694233, -1652634, -810149, -3014001, -1616392, -162844, 3183426, - 1207385, -185531, -3369112, -1957272, 164721, -2454455, -2432395, 2013608, - 3776993, -594136, 3724270, 2584293, 1846953, 1671176, 2831860, 542412, - -3406031, -2235880, -777191, -1500165, 1374803, 2546312, -1917081, 1279661, - 1962642, -3306115, -1312455, 451100, 1430225, 3318210, -1237275, 1333058, - 1050970, -1903435, -1869119, 2994039, 3548272, -2635921, -1250494, 3767016, - -1595974, -2486353, -1247620, -4055324, -1265009, 2590150, -2691481, -2842341, - -203044, -1735879, 3342277, -3437287, -4108315, 2437823, -286988, -342297, - 3595838, 768622, 525098, 3556995, -3207046, -2031748, 3122442, 655327, - 522500, 43260, 1613174, -495491, -819034, -909542, -1859098, -900702, - 3193378, 1197226, 3759364, 3520352, -3513181, 1235728, -2434439, -266997, - 3562462, 2446433, -2244091, 3342478, -3817976, -2316500, -3407706, -2091667, - -3839961, 3628969, 3881060, 3019102, 1439742, 812732, 1584928, -1285669, - -1341330, -1315589, 177440, 2409325, 1851402, -3159746, 3553272, -189548, - 1316856, -759969, 210977, -2389356, 3249728, -1653064, 8578, 3724342, - -3958618, -904516, 1100098, -44288, -3097992, -508951, -264944, 3343383, - 1430430, -1852771, -1349076, 381987, 1308169, 22981, 1228525, 671102, - 2477047, 411027, 3693493, 2967645, -2715295, -2147896, 983419, -3412210, - -126922, 3632928, 3157330, 3190144, 1000202, 4083598, -1939314, 1257611, - 1585221, -2176455, -3475950, 1452451, 3041255, 3677745, 1528703, 3930395, - 2797779, -2071892, 2556880, -3900724, -3881043, -954230, -531354, -811944, - -3699596, 1600420, 2140649, -3507263, 3821735, -3505694, 1643818, 1699267, - 539299, -2348700, 300467, -3539968, 2867647, -3574422, 3043716, 3861115, - -3915439, 2537516, 3592148, 1661693, -3530437, -3077325, -95776, -2706023, - -280005, -4010497, 19422, -1757237, 3277672, 1399561, 3859737, 2118186, - 2108549, -2619752, 1119584, 549488, -3585928, 1079900, -1024112, -2725464, - -2680103, -3111497, 2884855, -3119733, 2091905, 359251, -2353451, -1826347, - -466468, 876248, 777960, -237124, 518909, 2608894, -25847 + private static final int[] MONT_ZETAS_FOR_VECTOR_NTT = new int[]{ + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + 25847, 25847, 25847, 25847, 25847, 25847, 25847, 25847, + + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, -2608894, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + -518909, -518909, -518909, -518909, -518909, -518909, -518909, -518909, + + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + 237124, 237124, 237124, 237124, 237124, 237124, 237124, 237124, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -777960, -777960, -777960, -777960, -777960, -777960, -777960, -777960, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + -876248, -876248, -876248, -876248, -876248, -876248, -876248, -876248, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + 466468, 466468, 466468, 466468, 466468, 466468, 466468, 466468, + + 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, + 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, 1826347, + 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, + 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, 2353451, + -359251, -359251, -359251, -359251, -359251, -359251, -359251, -359251, + -359251, -359251, -359251, -359251, -359251, -359251, -359251, -359251, + -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, + -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, -2091905, + 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, + 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, 3119733, + -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, + -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, -2884855, + 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, + 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, 3111497, + 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, + 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, 2680103, + + 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, 2725464, + 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, 1024112, + -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, -1079900, + 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, 3585928, + -549488, -549488, -549488, -549488, -549488, -549488, -549488, -549488, + -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, -1119584, + 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, 2619752, + -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, -2108549, + -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, -2118186, + -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, -3859737, + -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, -1399561, + -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, -3277672, + 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, 1757237, + -19422, -19422, -19422, -19422, -19422, -19422, -19422, -19422, + 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, 4010497, + 280005, 280005, 280005, 280005, 280005, 280005, 280005, 280005, + + 2706023, 2706023, 2706023, 2706023, 95776, 95776, 95776, 95776, + 3077325, 3077325, 3077325, 3077325, 3530437, 3530437, 3530437, 3530437, + -1661693, -1661693, -1661693, -1661693, -3592148, -3592148, -3592148, -3592148, + -2537516, -2537516, -2537516, -2537516, 3915439, 3915439, 3915439, 3915439, + -3861115, -3861115, -3861115, -3861115, -3043716, -3043716, -3043716, -3043716, + 3574422, 3574422, 3574422, 3574422, -2867647, -2867647, -2867647, -2867647, + 3539968, 3539968, 3539968, 3539968, -300467, -300467, -300467, -300467, + 2348700, 2348700, 2348700, 2348700, -539299, -539299, -539299, -539299, + -1699267, -1699267, -1699267, -1699267, -1643818, -1643818, -1643818, -1643818, + 3505694, 3505694, 3505694, 3505694, -3821735, -3821735, -3821735, -3821735, + 3507263, 3507263, 3507263, 3507263, -2140649, -2140649, -2140649, -2140649, + -1600420, -1600420, -1600420, -1600420, 3699596, 3699596, 3699596, 3699596, + 811944, 811944, 811944, 811944, 531354, 531354, 531354, 531354, + 954230, 954230, 954230, 954230, 3881043, 3881043, 3881043, 3881043, + 3900724, 3900724, 3900724, 3900724, -2556880, -2556880, -2556880, -2556880, + 2071892, 2071892, 2071892, 2071892, -2797779, -2797779, -2797779, -2797779, + + -3930395, -3930395, -1528703, -1528703, -3677745, -3677745, -3041255, -3041255, + -1452451, -1452451, 3475950, 3475950, 2176455, 2176455, -1585221, -1585221, + -1257611, -1257611, 1939314, 1939314, -4083598, -4083598, -1000202, -1000202, + -3190144, -3190144, -3157330, -3157330, -3632928, -3632928, 126922, 126922, + 3412210, 3412210, -983419, -983419, 2147896, 2147896, 2715295, 2715295, + -2967645, -2967645, -3693493, -3693493, -411027, -411027, -2477047, -2477047, + -671102, -671102, -1228525, -1228525, -22981, -22981, -1308169, -1308169, + -381987, -381987, 1349076, 1349076, 1852771, 1852771, -1430430, -1430430, + -3343383, -3343383, 264944, 264944, 508951, 508951, 3097992, 3097992, + 44288, 44288, -1100098, -1100098, 904516, 904516, 3958618, 3958618, + -3724342, -3724342, -8578, -8578, 1653064, 1653064, -3249728, -3249728, + 2389356, 2389356, -210977, -210977, 759969, 759969, -1316856, -1316856, + 189548, 189548, -3553272, -3553272, 3159746, 3159746, -1851402, -1851402, + -2409325, -2409325, -177440, -177440, 1315589, 1315589, 1341330, 1341330, + 1285669, 1285669, -1584928, -1584928, -812732, -812732, -1439742, -1439742, + -3019102, -3019102, -3881060, -3881060, -3628969, -3628969, 3839961, 3839961, + + 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, + 266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, + 900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500, + -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, + 342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, + 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, + -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, + -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642, + -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, + -542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, + -2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385, + -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, + -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078, + -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, + -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, + -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782 + }; + + private static final int[] MONT_ZETAS_FOR_VECTOR_INVERSE_NTT = new int[]{ + -1976782, 846154, -1400424, -3937738, 1362209, 48306, -3919660, 554416, + 3545687, -1612842, 976891, -183443, 2286327, 420899, 2235985, 2939036, + 3833893, 260646, 1104333, 1667432, -1910376, 1803090, -1723600, 426683, + -472078, -1717735, 975884, -2213111, -269760, -3866901, -3523897, 3038916, + 1799107, 3694233, -1652634, -810149, -3014001, -1616392, -162844, 3183426, + 1207385, -185531, -3369112, -1957272, 164721, -2454455, -2432395, 2013608, + 3776993, -594136, 3724270, 2584293, 1846953, 1671176, 2831860, 542412, + -3406031, -2235880, -777191, -1500165, 1374803, 2546312, -1917081, 1279661, + 1962642, -3306115, -1312455, 451100, 1430225, 3318210, -1237275, 1333058, + 1050970, -1903435, -1869119, 2994039, 3548272, -2635921, -1250494, 3767016, + -1595974, -2486353, -1247620, -4055324, -1265009, 2590150, -2691481, -2842341, + -203044, -1735879, 3342277, -3437287, -4108315, 2437823, -286988, -342297, + 3595838, 768622, 525098, 3556995, -3207046, -2031748, 3122442, 655327, + 522500, 43260, 1613174, -495491, -819034, -909542, -1859098, -900702, + 3193378, 1197226, 3759364, 3520352, -3513181, 1235728, -2434439, -266997, + 3562462, 2446433, -2244091, 3342478, -3817976, -2316500, -3407706, -2091667, + + -3839961, -3839961, 3628969, 3628969, 3881060, 3881060, 3019102, 3019102, + 1439742, 1439742, 812732, 812732, 1584928, 1584928, -1285669, -1285669, + -1341330, - 1341330, -1315589, -1315589, 177440, 177440, 2409325, 2409325, + 1851402, 1851402, -3159746, -3159746, 3553272, 3553272, -189548, -189548, + 1316856, 1316856, -759969, -759969, 210977, 210977, -2389356, -2389356, + 3249728, 3249728, -1653064, -1653064, 8578, 8578, 3724342, 3724342, + -3958618, -3958618, -904516, -904516, 1100098, 1100098, -44288, -44288, + -3097992, -3097992, -508951, -508951, -264944, -264944, 3343383, 3343383, + 1430430, 1430430, -1852771, -1852771, -1349076, -1349076, 381987, 381987, + 1308169, 1308169, 22981, 22981, 1228525, 1228525, 671102, 671102, + 2477047, 2477047, 411027, 411027, 3693493, 3693493, 2967645, 2967645, + -2715295, -2715295, -2147896, -2147896, 983419, 983419, -3412210, -3412210, + -126922, -126922, 3632928, 3632928, 3157330, 3157330, 3190144, 3190144, + 1000202, 1000202, 4083598, 4083598, -1939314, -1939314, 1257611, 1257611, + 1585221, 1585221, -2176455, -2176455, -3475950, -3475950, 1452451, 1452451, + 3041255, 3041255, 3677745, 3677745, 1528703, 1528703, 3930395, 3930395, + + 2797779, 2797779, 2797779, 2797779, -2071892, -2071892, -2071892, -2071892, + 2556880, 2556880, 2556880, 2556880, -3900724, -3900724, -3900724, -3900724, + -3881043, -3881043, -3881043, -3881043, -954230, -954230, -954230, -954230, + -531354, -531354, -531354, -531354, -811944, -811944, -811944, -811944, + -3699596, -3699596, -3699596, -3699596, 1600420, 1600420, 1600420, 1600420, + 2140649, 2140649, 2140649, 2140649, -3507263, -3507263, -3507263, -3507263, + 3821735, 3821735, 3821735, 3821735, -3505694, -3505694, -3505694, -3505694, + 1643818, 1643818, 1643818, 1643818, 1699267, 1699267, 1699267, 1699267, + 539299, 539299, 539299, 539299, -2348700, -2348700, -2348700, -2348700, + 300467, 300467, 300467, 300467, -3539968, -3539968, -3539968, -3539968, + 2867647, 2867647, 2867647, 2867647, -3574422, -3574422, -3574422, -3574422, + 3043716, 3043716, 3043716, 3043716, 3861115, 3861115, 3861115, 3861115, + -3915439, -3915439, -3915439, -3915439, 2537516, 2537516, 2537516, 2537516, + 3592148, 3592148, 3592148, 3592148, 1661693, 1661693, 1661693, 1661693, + -3530437, -3530437, -3530437, -3530437, -3077325, -3077325, -3077325, -3077325, + -95776, -95776, -95776, -95776, -2706023, -2706023, -2706023, -2706023, + + -280005, -280005, -280005, -280005, -280005, -280005, -280005, -280005, + -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, -4010497, + 19422, 19422, 19422, 19422, 19422, 19422, 19422, 19422, + -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, -1757237, + 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, 3277672, + 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, 1399561, + 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, 3859737, + 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, 2118186, + 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, 2108549, + -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, -2619752, + 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, 1119584, + 549488, 549488, 549488, 549488, 549488, 549488, 549488, 549488, + -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, -3585928, + 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, 1079900, + -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, -1024112, + -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, -2725464, + + -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, + -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, -2680103, + -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, + -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, -3111497, + 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, + 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, 2884855, + -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, + -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, -3119733, + 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, + 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, 2091905, + 359251, 359251, 359251, 359251, 359251, 359251, 359251, 359251, + 359251, 359251, 359251, 359251, 359251, 359251, 359251, 359251, + -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, + -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, -2353451, + -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, + -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, -1826347, + + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + -466468, -466468, -466468, -466468, -466468, -466468, -466468, -466468, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 876248, 876248, 876248, 876248, 876248, 876248, 876248, 876248, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + 777960, 777960, 777960, 777960, 777960, 777960, 777960, 777960, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + -237124, -237124, -237124, -237124, -237124, -237124, -237124, -237124, + + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 518909, 518909, 518909, 518909, 518909, 518909, 518909, 518909, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, 2608894, + + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847, + -25847, -25847, -25847, -25847, -25847, -25847, -25847, -25847 }; // Constants defined for each security level @@ -848,43 +1092,85 @@ public class ML_DSA { } } - int[][][] generateA(byte[] seed) { - int blockSize = 168; // the size of one block of SHAKE128 output - var xof = new SHAKE128(0); - byte[] xofSeed = new byte[A_SEED_LEN + 2]; - System.arraycopy(seed, 0, xofSeed, 0, A_SEED_LEN); + private int[][][] generateA(byte[] seed) { int[][][] a = new int[mlDsa_k][mlDsa_l][]; - for (int i = 0; i < mlDsa_k; i++) { - for (int j = 0; j < mlDsa_l; j++) { - xofSeed[A_SEED_LEN] = (byte) j; - xofSeed[A_SEED_LEN + 1] = (byte) i; - xof.reset(); - xof.update(xofSeed); + int nrPar = 2; + int rhoLen = seed.length; + byte[] seedBuf = new byte[SHAKE128_BLOCK_SIZE]; + System.arraycopy(seed, 0, seedBuf, 0, seed.length); + seedBuf[rhoLen + 2] = 0x1F; + seedBuf[SHAKE128_BLOCK_SIZE - 1] = (byte)0x80; + byte[][] xofBufArr = new byte[nrPar][SHAKE128_BLOCK_SIZE]; + int[] iIndex = new int[nrPar]; + int[] jIndex = new int[nrPar]; - byte[] rawAij = new byte[blockSize]; - int[] aij = new int[ML_DSA_N]; - int ofs = 0; - int rawOfs = blockSize; - int tmp; - while (ofs < ML_DSA_N) { - if (rawOfs == blockSize) { - // works because 3 divides blockSize (=168) - xof.squeeze(rawAij, 0, blockSize); - rawOfs = 0; - } - tmp = (rawAij[rawOfs] & 0xFF) + - ((rawAij[rawOfs + 1] & 0xFF) << 8) + - ((rawAij[rawOfs + 2] & 0x7F) << 16); - rawOfs += 3; - if (tmp < ML_DSA_Q) { - aij[ofs] = tmp; - ofs++; + int[] parsedBuf = new int[SHAKE128_BLOCK_SIZE / 3]; + + int parInd = 0; + boolean allDone; + int[] ofs = new int[nrPar]; + Arrays.fill(ofs, 0); + int[][] aij = new int[nrPar][]; + try { + Shake128Parallel parXof = new Shake128Parallel(xofBufArr); + + for (int i = 0; i < mlDsa_k; i++) { + for (int j = 0; j < mlDsa_l; j++) { + xofBufArr[parInd] = seedBuf.clone(); + xofBufArr[parInd][rhoLen] = (byte) j; + xofBufArr[parInd][rhoLen + 1] = (byte) i; + iIndex[parInd] = i; + jIndex[parInd] = j; + ofs[parInd] = 0; + aij[parInd] = new int[ML_DSA_N]; + parInd++; + + if ((parInd == nrPar) || + ((i == mlDsa_k - 1) && (j == mlDsa_l - 1))) { + parXof.reset(xofBufArr); + + allDone = false; + while (!allDone) { + allDone = true; + parXof.squeezeBlock(); + for (int k = 0; k < parInd; k++) { + int parsedOfs = 0; + int tmp; + if (ofs[k] < ML_DSA_N) { + for (int l = 0; l < SHAKE128_BLOCK_SIZE; l += 3) { + byte[] rawBuf = xofBufArr[k]; + parsedBuf[l / 3] = (rawBuf[l] & 0xFF) + + ((rawBuf[l + 1] & 0xFF) << 8) + + ((rawBuf[l + 2] & 0x7F) << 16); + } + } + while ((ofs[k] < ML_DSA_N) && + (parsedOfs < SHAKE128_BLOCK_SIZE / 3)) { + tmp = parsedBuf[parsedOfs++]; + if (tmp < ML_DSA_Q) { + aij[k][ofs[k]] = tmp; + ofs[k]++; + } + } + if (ofs[k] < ML_DSA_N) { + allDone = false; + } + } + } + + for (int k = 0; k < parInd; k++) { + a[iIndex[k]][jIndex[k]] = aij[k]; + } + parInd = 0; } } - a[i][j] = aij; } + } catch (InvalidAlgorithmParameterException e) { + // This should never happen since xofBufArr is of the correct size + throw new RuntimeException("Internal error."); } + return a; } @@ -979,7 +1265,7 @@ public class ML_DSA { private void decompose(int[][] input, int[][] lowPart, int[][] highPart) { int multiplier = (gamma2 == 95232 ? 22 : 8); for (int i = 0; i < mlDsa_k; i++) { - ML_DSA.mlDsaDecomposePoly(input[i], lowPart[i], + mlDsaDecomposePoly(input[i], lowPart[i], highPart[i], gamma2 * 2, multiplier); } } @@ -1011,7 +1297,7 @@ public class ML_DSA { private int[][] useHint(boolean[][] h, int[][] r) { int m = (ML_DSA_Q - 1) / (2*gamma2); - int[][] lowPart = new int[mlDsa_k][ML_DSA_N]; + int[][] lowPart = r; int[][] highPart = new int[mlDsa_k][ML_DSA_N]; decompose(r, lowPart, highPart); @@ -1030,7 +1316,18 @@ public class ML_DSA { NTT functions as specified in Section 7.5 of specification */ - public static int[] mlDsaNtt(int[] coeffs) { + public static void mlDsaNtt(int[] coeffs) { + implDilithiumAlmostNtt(coeffs, MONT_ZETAS_FOR_VECTOR_NTT); + implDilithiumMontMulByConstant(coeffs, MONT_R_MOD_Q); + } + + @IntrinsicCandidate + static int implDilithiumAlmostNtt(int[] coeffs, int[] zetas) { + implDilithiumAlmostNttJava(coeffs); + return 1; + } + + static void implDilithiumAlmostNttJava(int[] coeffs) { int dimension = ML_DSA_N; int m = 0; for (int l = dimension / 2; l > 0; l /= 2) { @@ -1043,26 +1340,33 @@ public class ML_DSA { m++; } } - montMulByConstant(coeffs, MONT_R_MOD_Q); - return coeffs; } - public static int[] mlDsaInverseNtt(int[] coeffs) { + public static void mlDsaInverseNtt(int[] coeffs) { + implDilithiumAlmostInverseNtt(coeffs, MONT_ZETAS_FOR_VECTOR_INVERSE_NTT); + implDilithiumMontMulByConstant(coeffs, MONT_DIM_INVERSE); + } + + @IntrinsicCandidate + static int implDilithiumAlmostInverseNtt(int[] coeffs, int[] zetas) { + implDilithiumAlmostInverseNttJava(coeffs); + return 1; + } + + static void implDilithiumAlmostInverseNttJava(int[] coeffs) { int dimension = ML_DSA_N; - int m = 0; + int m = MONT_ZETAS_FOR_NTT.length - 1; for (int l = 1; l < dimension; l *= 2) { for (int s = 0; s < dimension; s += 2 * l) { for (int j = s; j < s + l; j++) { int tmp = coeffs[j]; coeffs[j] = (tmp + coeffs[j + l]); coeffs[j + l] = montMul(tmp - coeffs[j + l], - MONT_ZETAS_FOR_INVERSE_NTT[m]); + -MONT_ZETAS_FOR_NTT[m]); } - m++; + m--; } } - montMulByConstant(coeffs, MONT_DIM_INVERSE); - return coeffs; } void mlDsaVectorNtt(int[][] vector) { @@ -1078,12 +1382,29 @@ public class ML_DSA { } public static void mlDsaNttMultiply(int[] product, int[] coeffs1, int[] coeffs2) { + implDilithiumNttMult(product, coeffs1, coeffs2); + } + + + @IntrinsicCandidate + static int implDilithiumNttMult(int[] product, int[] coeffs1, int[] coeffs2) { + implDilithiumNttMultJava(product, coeffs1, coeffs2); + return 1; + } + + static void implDilithiumNttMultJava(int[] product, int[] coeffs1, int[] coeffs2) { for (int i = 0; i < ML_DSA_N; i++) { product[i] = montMul(coeffs1[i], toMont(coeffs2[i])); } } - public static void montMulByConstant(int[] coeffs, int constant) { + @IntrinsicCandidate + static int implDilithiumMontMulByConstant(int[] coeffs, int constant) { + implDilithiumMontMulByConstantJava(coeffs, constant); + return 1; + } + + static void implDilithiumMontMulByConstantJava(int[] coeffs, int constant) { for (int i = 0; i < ML_DSA_N; i++) { coeffs[i] = montMul((coeffs[i]), constant); } @@ -1091,17 +1412,39 @@ public class ML_DSA { public static void mlDsaDecomposePoly(int[] input, int[] lowPart, int[] highPart, int twoGamma2, int multiplier) { + implDilithiumDecomposePoly(input, lowPart, highPart,twoGamma2, multiplier); + } + + @IntrinsicCandidate + static int implDilithiumDecomposePoly(int[] input, int[] lowPart, int[] highPart, + int twoGamma2, int multiplier) { + decomposePolyJava(input, lowPart, highPart, twoGamma2, multiplier); + return 1; + } + + static void decomposePolyJava(int[] input, int[] lowPart, int[] highPart, + int twoGamma2, int multiplier) { + int dilithiumBarrettAddend = 5373807; for (int m = 0; m < ML_DSA_N; m++) { int rplus = input[m]; - rplus = rplus - ((rplus + 5373807) >> 23) * ML_DSA_Q; - rplus = rplus + ((rplus >> 31) & ML_DSA_Q); - int r0 = rplus - ((rplus * multiplier) >> 22) * twoGamma2; - r0 -= (((twoGamma2 - r0) >> 22) & twoGamma2); - r0 -= (((twoGamma2 / 2 - r0) >> 31) & twoGamma2); + rplus -= ((rplus + dilithiumBarrettAddend) >> 23) * ML_DSA_Q; + rplus += ((rplus >> 31) & ML_DSA_Q); + + int quotient = (rplus * multiplier) >> 22; + int r0 = rplus - quotient * twoGamma2; + int mask = (twoGamma2 - r0) >> 22; + r0 -= (mask & twoGamma2); + quotient += (mask & 1); + mask = (twoGamma2 / 2 - r0) >> 31; + r0 -= (mask & twoGamma2); + quotient += (mask & 1); + int r1 = rplus - r0 - (ML_DSA_Q - 1); - r1 = (r1 | (-r1)) >> 31; + r1 = (r1 | (-r1)) >> 31; // 0 if rplus - r0 == (dilithium_q - 1), -1 otherwise r0 += ~r1; - r1 = r1 & ((rplus - r0) / twoGamma2); + // quotient = (rplus - r0) / twoGamma2; + r1 = r1 & quotient; + lowPart[m] = r0; highPart[m] = r1; } @@ -1207,6 +1550,7 @@ public class ML_DSA { // precondition: -2^31 * MONT_Q <= a, b < 2^31, -2^31 < a * b < 2^31 * MONT_Q // computes a * b * 2^-32 mod MONT_Q // the result is greater than -MONT_Q and less than MONT_Q + // see e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf private static int montMul(int b, int c) { long a = (long) b * (long) c; int aHigh = (int) (a >> MONT_R_BITS); diff --git a/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java b/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java index d9abfbe413f..0851d4a9216 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3Parallel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 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 @@ -35,6 +35,20 @@ import static sun.security.provider.ByteArrayAccess.l2bLittle; import static sun.security.provider.SHA3.keccak; +/* + * This class is for making it possible that NRPAR (= 2) (rather restricted) + * SHAKE computations execute in parallel. + * The restrictions are: + * 1. The messages processed should be such that the absorb phase should + * execute a single keccak() call and the byte arrays passed to the constructor + * (or reset() method) of this class should be the message padded with the + * appropriate padding described in + * https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf. + * 2. The only available way for extracting data is the squeeze() method + * that extracts exactly 1 block of data of each computation, delivering it + * in the arrays that were passed to the class in the constructor (or the + * reset() call). + */ public class SHA3Parallel { private int blockSize = 0; private static final int DM = 5; // dimension of lanesArr diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 64f3e787356..45ecf57e971 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -1833,6 +1833,11 @@ generate(ThreeRegNEONOp, ["sminp", "sminp", "8B"], ["sminp", "sminp", "16B"], ["sminp", "sminp", "4H"], ["sminp", "sminp", "8H"], ["sminp", "sminp", "2S"], ["sminp", "sminp", "4S"], + ["sqdmulh", "sqdmulh", "4H"], ["sqdmulh", "sqdmulh", "8H"], + ["sqdmulh", "sqdmulh", "2S"], ["sqdmulh", "sqdmulh", "4S"], + ["shsubv", "shsub", "8B"], ["shsubv", "shsub", "16B"], + ["shsubv", "shsub", "4H"], ["shsubv", "shsub", "8H"], + ["shsubv", "shsub", "2S"], ["shsubv", "shsub", "4S"], ["fmin", "fmin", "2S"], ["fmin", "fmin", "4S"], ["fmin", "fmin", "2D"], ["facgt", "facgt", "2S"], ["facgt", "facgt", "4S"], diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 9805a05c5c1..3bcd40ba2aa 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -745,93 +745,103 @@ __ sminp(v2, __ T8H, v3, v4); // sminp v2.8H, v3.8H, v4.8H __ sminp(v0, __ T2S, v1, v2); // sminp v0.2S, v1.2S, v2.2S __ sminp(v9, __ T4S, v10, v11); // sminp v9.4S, v10.4S, v11.4S - __ fmin(v24, __ T2S, v25, v26); // fmin v24.2S, v25.2S, v26.2S - __ fmin(v26, __ T4S, v27, v28); // fmin v26.4S, v27.4S, v28.4S - __ fmin(v16, __ T2D, v17, v18); // fmin v16.2D, v17.2D, v18.2D - __ facgt(v30, __ T2S, v31, v0); // facgt v30.2S, v31.2S, v0.2S - __ facgt(v3, __ T4S, v4, v5); // facgt v3.4S, v4.4S, v5.4S - __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D + __ sqdmulh(v24, __ T4H, v25, v26); // sqdmulh v24.4H, v25.4H, v26.4H + __ sqdmulh(v26, __ T8H, v27, v28); // sqdmulh v26.8H, v27.8H, v28.8H + __ sqdmulh(v16, __ T2S, v17, v18); // sqdmulh v16.2S, v17.2S, v18.2S + __ sqdmulh(v30, __ T4S, v31, v0); // sqdmulh v30.4S, v31.4S, v0.4S + __ shsubv(v3, __ T8B, v4, v5); // shsub v3.8B, v4.8B, v5.8B + __ shsubv(v10, __ T16B, v11, v12); // shsub v10.16B, v11.16B, v12.16B + __ shsubv(v23, __ T4H, v24, v25); // shsub v23.4H, v24.4H, v25.4H + __ shsubv(v10, __ T8H, v11, v12); // shsub v10.8H, v11.8H, v12.8H + __ shsubv(v4, __ T2S, v5, v6); // shsub v4.2S, v5.2S, v6.2S + __ shsubv(v18, __ T4S, v19, v20); // shsub v18.4S, v19.4S, v20.4S + __ fmin(v2, __ T2S, v3, v4); // fmin v2.2S, v3.2S, v4.2S + __ fmin(v11, __ T4S, v12, v13); // fmin v11.4S, v12.4S, v13.4S + __ fmin(v8, __ T2D, v9, v10); // fmin v8.2D, v9.2D, v10.2D + __ facgt(v10, __ T2S, v11, v12); // facgt v10.2S, v11.2S, v12.2S + __ facgt(v15, __ T4S, v16, v17); // facgt v15.4S, v16.4S, v17.4S + __ facgt(v17, __ T2D, v18, v19); // facgt v17.2D, v18.2D, v19.2D // VectorScalarNEONInstruction - __ fmlavs(v5, __ T2S, v6, v7, 1); // fmla v5.2S, v6.2S, v7.S[1] - __ mulvs(v9, __ T4S, v10, v11, 0); // mul v9.4S, v10.4S, v11.S[0] - __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] - __ fmlsvs(v5, __ T2S, v6, v7, 0); // fmls v5.2S, v6.2S, v7.S[0] - __ mulvs(v8, __ T4S, v9, v10, 1); // mul v8.4S, v9.4S, v10.S[1] - __ fmlsvs(v5, __ T2D, v6, v7, 0); // fmls v5.2D, v6.2D, v7.D[0] - __ fmulxvs(v6, __ T2S, v7, v8, 0); // fmulx v6.2S, v7.2S, v8.S[0] + __ fmlavs(v5, __ T2S, v6, v7, 0); // fmla v5.2S, v6.2S, v7.S[0] __ mulvs(v6, __ T4S, v7, v8, 1); // mul v6.4S, v7.4S, v8.S[1] - __ fmulxvs(v3, __ T2D, v4, v5, 0); // fmulx v3.2D, v4.2D, v5.D[0] - __ mulvs(v13, __ T4H, v14, v15, 2); // mul v13.4H, v14.4H, v15.H[2] - __ mulvs(v2, __ T8H, v3, v4, 4); // mul v2.8H, v3.8H, v4.H[4] - __ mulvs(v2, __ T2S, v3, v4, 0); // mul v2.2S, v3.2S, v4.S[0] + __ fmlavs(v6, __ T2D, v7, v8, 0); // fmla v6.2D, v7.2D, v8.D[0] + __ fmlsvs(v3, __ T2S, v4, v5, 0); // fmls v3.2S, v4.2S, v5.S[0] + __ mulvs(v13, __ T4S, v14, v15, 2); // mul v13.4S, v14.4S, v15.S[2] + __ fmlsvs(v2, __ T2D, v3, v4, 1); // fmls v2.2D, v3.2D, v4.D[1] + __ fmulxvs(v2, __ T2S, v3, v4, 0); // fmulx v2.2S, v3.2S, v4.S[0] __ mulvs(v9, __ T4S, v10, v11, 1); // mul v9.4S, v10.4S, v11.S[1] + __ fmulxvs(v8, __ T2D, v9, v10, 1); // fmulx v8.2D, v9.2D, v10.D[1] + __ mulvs(v5, __ T4H, v6, v7, 2); // mul v5.4H, v6.4H, v7.H[2] + __ mulvs(v11, __ T8H, v12, v13, 5); // mul v11.8H, v12.8H, v13.H[5] + __ mulvs(v13, __ T2S, v14, v15, 0); // mul v13.2S, v14.2S, v15.S[0] + __ mulvs(v14, __ T4S, v15, v16, 2); // mul v14.4S, v15.4S, v16.S[2] // NEONVectorCompare - __ cm(Assembler::GT, v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B - __ cm(Assembler::GT, v16, __ T16B, v17, v18); // cmgt v16.16B, v17.16B, v18.16B - __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H - __ cm(Assembler::GT, v11, __ T8H, v12, v13); // cmgt v11.8H, v12.8H, v13.8H - __ cm(Assembler::GT, v21, __ T2S, v22, v23); // cmgt v21.2S, v22.2S, v23.2S - __ cm(Assembler::GT, v23, __ T4S, v24, v25); // cmgt v23.4S, v24.4S, v25.4S - __ cm(Assembler::GT, v12, __ T2D, v13, v14); // cmgt v12.2D, v13.2D, v14.2D - __ cm(Assembler::GE, v26, __ T8B, v27, v28); // cmge v26.8B, v27.8B, v28.8B - __ cm(Assembler::GE, v23, __ T16B, v24, v25); // cmge v23.16B, v24.16B, v25.16B - __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H - __ cm(Assembler::GE, v14, __ T8H, v15, v16); // cmge v14.8H, v15.8H, v16.8H - __ cm(Assembler::GE, v11, __ T2S, v12, v13); // cmge v11.2S, v12.2S, v13.2S - __ cm(Assembler::GE, v24, __ T4S, v25, v26); // cmge v24.4S, v25.4S, v26.4S - __ cm(Assembler::GE, v1, __ T2D, v2, v3); // cmge v1.2D, v2.2D, v3.2D - __ cm(Assembler::EQ, v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B - __ cm(Assembler::EQ, v31, __ T16B, v0, v1); // cmeq v31.16B, v0.16B, v1.16B - __ cm(Assembler::EQ, v10, __ T4H, v11, v12); // cmeq v10.4H, v11.4H, v12.4H - __ cm(Assembler::EQ, v16, __ T8H, v17, v18); // cmeq v16.8H, v17.8H, v18.8H - __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S - __ cm(Assembler::EQ, v2, __ T4S, v3, v4); // cmeq v2.4S, v3.4S, v4.4S - __ cm(Assembler::EQ, v3, __ T2D, v4, v5); // cmeq v3.2D, v4.2D, v5.2D - __ cm(Assembler::HI, v13, __ T8B, v14, v15); // cmhi v13.8B, v14.8B, v15.8B - __ cm(Assembler::HI, v19, __ T16B, v20, v21); // cmhi v19.16B, v20.16B, v21.16B - __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H - __ cm(Assembler::HI, v16, __ T8H, v17, v18); // cmhi v16.8H, v17.8H, v18.8H - __ cm(Assembler::HI, v3, __ T2S, v4, v5); // cmhi v3.2S, v4.2S, v5.2S - __ cm(Assembler::HI, v1, __ T4S, v2, v3); // cmhi v1.4S, v2.4S, v3.4S - __ cm(Assembler::HI, v11, __ T2D, v12, v13); // cmhi v11.2D, v12.2D, v13.2D - __ cm(Assembler::HS, v30, __ T8B, v31, v0); // cmhs v30.8B, v31.8B, v0.8B - __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B - __ cm(Assembler::HS, v8, __ T4H, v9, v10); // cmhs v8.4H, v9.4H, v10.4H - __ cm(Assembler::HS, v15, __ T8H, v16, v17); // cmhs v15.8H, v16.8H, v17.8H - __ cm(Assembler::HS, v29, __ T2S, v30, v31); // cmhs v29.2S, v30.2S, v31.2S - __ cm(Assembler::HS, v30, __ T4S, v31, v0); // cmhs v30.4S, v31.4S, v0.4S - __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D - __ fcm(Assembler::EQ, v20, __ T2S, v21, v22); // fcmeq v20.2S, v21.2S, v22.2S - __ fcm(Assembler::EQ, v7, __ T4S, v8, v9); // fcmeq v7.4S, v8.4S, v9.4S - __ fcm(Assembler::EQ, v20, __ T2D, v21, v22); // fcmeq v20.2D, v21.2D, v22.2D - __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S - __ fcm(Assembler::GT, v28, __ T4S, v29, v30); // fcmgt v28.4S, v29.4S, v30.4S - __ fcm(Assembler::GT, v21, __ T2D, v22, v23); // fcmgt v21.2D, v22.2D, v23.2D - __ fcm(Assembler::GE, v27, __ T2S, v28, v29); // fcmge v27.2S, v28.2S, v29.2S - __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S - __ fcm(Assembler::GE, v5, __ T2D, v6, v7); // fcmge v5.2D, v6.2D, v7.2D + __ cm(Assembler::GT, v14, __ T8B, v15, v16); // cmgt v14.8B, v15.8B, v16.8B + __ cm(Assembler::GT, v11, __ T16B, v12, v13); // cmgt v11.16B, v12.16B, v13.16B + __ cm(Assembler::GT, v24, __ T4H, v25, v26); // cmgt v24.4H, v25.4H, v26.4H + __ cm(Assembler::GT, v1, __ T8H, v2, v3); // cmgt v1.8H, v2.8H, v3.8H + __ cm(Assembler::GT, v12, __ T2S, v13, v14); // cmgt v12.2S, v13.2S, v14.2S + __ cm(Assembler::GT, v31, __ T4S, v0, v1); // cmgt v31.4S, v0.4S, v1.4S + __ cm(Assembler::GT, v10, __ T2D, v11, v12); // cmgt v10.2D, v11.2D, v12.2D + __ cm(Assembler::GE, v16, __ T8B, v17, v18); // cmge v16.8B, v17.8B, v18.8B + __ cm(Assembler::GE, v7, __ T16B, v8, v9); // cmge v7.16B, v8.16B, v9.16B + __ cm(Assembler::GE, v2, __ T4H, v3, v4); // cmge v2.4H, v3.4H, v4.4H + __ cm(Assembler::GE, v3, __ T8H, v4, v5); // cmge v3.8H, v4.8H, v5.8H + __ cm(Assembler::GE, v13, __ T2S, v14, v15); // cmge v13.2S, v14.2S, v15.2S + __ cm(Assembler::GE, v19, __ T4S, v20, v21); // cmge v19.4S, v20.4S, v21.4S + __ cm(Assembler::GE, v17, __ T2D, v18, v19); // cmge v17.2D, v18.2D, v19.2D + __ cm(Assembler::EQ, v16, __ T8B, v17, v18); // cmeq v16.8B, v17.8B, v18.8B + __ cm(Assembler::EQ, v3, __ T16B, v4, v5); // cmeq v3.16B, v4.16B, v5.16B + __ cm(Assembler::EQ, v1, __ T4H, v2, v3); // cmeq v1.4H, v2.4H, v3.4H + __ cm(Assembler::EQ, v11, __ T8H, v12, v13); // cmeq v11.8H, v12.8H, v13.8H + __ cm(Assembler::EQ, v30, __ T2S, v31, v0); // cmeq v30.2S, v31.2S, v0.2S + __ cm(Assembler::EQ, v5, __ T4S, v6, v7); // cmeq v5.4S, v6.4S, v7.4S + __ cm(Assembler::EQ, v8, __ T2D, v9, v10); // cmeq v8.2D, v9.2D, v10.2D + __ cm(Assembler::HI, v15, __ T8B, v16, v17); // cmhi v15.8B, v16.8B, v17.8B + __ cm(Assembler::HI, v29, __ T16B, v30, v31); // cmhi v29.16B, v30.16B, v31.16B + __ cm(Assembler::HI, v30, __ T4H, v31, v0); // cmhi v30.4H, v31.4H, v0.4H + __ cm(Assembler::HI, v0, __ T8H, v1, v2); // cmhi v0.8H, v1.8H, v2.8H + __ cm(Assembler::HI, v20, __ T2S, v21, v22); // cmhi v20.2S, v21.2S, v22.2S + __ cm(Assembler::HI, v7, __ T4S, v8, v9); // cmhi v7.4S, v8.4S, v9.4S + __ cm(Assembler::HI, v20, __ T2D, v21, v22); // cmhi v20.2D, v21.2D, v22.2D + __ cm(Assembler::HS, v23, __ T8B, v24, v25); // cmhs v23.8B, v24.8B, v25.8B + __ cm(Assembler::HS, v28, __ T16B, v29, v30); // cmhs v28.16B, v29.16B, v30.16B + __ cm(Assembler::HS, v21, __ T4H, v22, v23); // cmhs v21.4H, v22.4H, v23.4H + __ cm(Assembler::HS, v27, __ T8H, v28, v29); // cmhs v27.8H, v28.8H, v29.8H + __ cm(Assembler::HS, v25, __ T2S, v26, v27); // cmhs v25.2S, v26.2S, v27.2S + __ cm(Assembler::HS, v5, __ T4S, v6, v7); // cmhs v5.4S, v6.4S, v7.4S + __ cm(Assembler::HS, v1, __ T2D, v2, v3); // cmhs v1.2D, v2.2D, v3.2D + __ fcm(Assembler::EQ, v23, __ T2S, v24, v25); // fcmeq v23.2S, v24.2S, v25.2S + __ fcm(Assembler::EQ, v16, __ T4S, v17, v18); // fcmeq v16.4S, v17.4S, v18.4S + __ fcm(Assembler::EQ, v31, __ T2D, v0, v1); // fcmeq v31.2D, v0.2D, v1.2D + __ fcm(Assembler::GT, v5, __ T2S, v6, v7); // fcmgt v5.2S, v6.2S, v7.2S + __ fcm(Assembler::GT, v12, __ T4S, v13, v14); // fcmgt v12.4S, v13.4S, v14.4S + __ fcm(Assembler::GT, v9, __ T2D, v10, v11); // fcmgt v9.2D, v10.2D, v11.2D + __ fcm(Assembler::GE, v28, __ T2S, v29, v30); // fcmge v28.2S, v29.2S, v30.2S + __ fcm(Assembler::GE, v15, __ T4S, v16, v17); // fcmge v15.4S, v16.4S, v17.4S + __ fcm(Assembler::GE, v29, __ T2D, v30, v31); // fcmge v29.2D, v30.2D, v31.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p0, __ D, p7, z23, 0.0); // fcmeq p0.d, p7/z, z23.d, #0.0 - __ sve_fcm(Assembler::GT, p2, __ S, p7, z12, 0.0); // fcmgt p2.s, p7/z, z12.s, #0.0 - __ sve_fcm(Assembler::GE, p7, __ D, p7, z29, 0.0); // fcmge p7.d, p7/z, z29.d, #0.0 - __ sve_fcm(Assembler::LT, p9, __ S, p3, z31, 0.0); // fcmlt p9.s, p3/z, z31.s, #0.0 - __ sve_fcm(Assembler::LE, p9, __ D, p6, z31, 0.0); // fcmle p9.d, p6/z, z31.d, #0.0 - __ sve_fcm(Assembler::NE, p10, __ S, p2, z16, 0.0); // fcmne p10.s, p2/z, z16.s, #0.0 + __ sve_fcm(Assembler::EQ, p11, __ D, p7, z31, 0.0); // fcmeq p11.d, p7/z, z31.d, #0.0 + __ sve_fcm(Assembler::GT, p2, __ D, p7, z14, 0.0); // fcmgt p2.d, p7/z, z14.d, #0.0 + __ sve_fcm(Assembler::GE, p9, __ D, p4, z27, 0.0); // fcmge p9.d, p4/z, z27.d, #0.0 + __ sve_fcm(Assembler::LT, p6, __ S, p1, z11, 0.0); // fcmlt p6.s, p1/z, z11.s, #0.0 + __ sve_fcm(Assembler::LE, p15, __ D, p7, z17, 0.0); // fcmle p15.d, p7/z, z17.d, #0.0 + __ sve_fcm(Assembler::NE, p15, __ S, p5, z7, 0.0); // fcmne p15.s, p5/z, z7.s, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p4, __ D, p4, z6, 11); // cmpeq p4.d, p4/z, z6.d, #11 - __ sve_cmp(Assembler::GT, p14, __ B, p2, z30, 4); // cmpgt p14.b, p2/z, z30.b, #4 - __ sve_cmp(Assembler::GE, p5, __ D, p4, z4, 1); // cmpge p5.d, p4/z, z4.d, #1 - __ sve_cmp(Assembler::LT, p11, __ D, p3, z3, 6); // cmplt p11.d, p3/z, z3.d, #6 - __ sve_cmp(Assembler::LE, p9, __ S, p0, z19, -1); // cmple p9.s, p0/z, z19.s, #-1 - __ sve_cmp(Assembler::NE, p3, __ S, p2, z12, -3); // cmpne p3.s, p2/z, z12.s, #-3 - __ sve_cmp(Assembler::HS, p11, __ D, p4, z1, 20); // cmphs p11.d, p4/z, z1.d, #20 - __ sve_cmp(Assembler::HI, p8, __ S, p5, z2, 53); // cmphi p8.s, p5/z, z2.s, #53 - __ sve_cmp(Assembler::LS, p5, __ D, p6, z21, 49); // cmpls p5.d, p6/z, z21.d, #49 - __ sve_cmp(Assembler::LO, p13, __ B, p7, z3, 97); // cmplo p13.b, p7/z, z3.b, #97 + __ sve_cmp(Assembler::EQ, p5, __ D, p4, z4, 1); // cmpeq p5.d, p4/z, z4.d, #1 + __ sve_cmp(Assembler::GT, p11, __ D, p3, z3, 6); // cmpgt p11.d, p3/z, z3.d, #6 + __ sve_cmp(Assembler::GE, p9, __ S, p0, z19, -1); // cmpge p9.s, p0/z, z19.s, #-1 + __ sve_cmp(Assembler::LT, p3, __ S, p2, z12, -3); // cmplt p3.s, p2/z, z12.s, #-3 + __ sve_cmp(Assembler::LE, p11, __ D, p4, z1, -11); // cmple p11.d, p4/z, z1.d, #-11 + __ sve_cmp(Assembler::NE, p8, __ S, p5, z2, -3); // cmpne p8.s, p5/z, z2.s, #-3 + __ sve_cmp(Assembler::HS, p5, __ D, p6, z21, 49); // cmphs p5.d, p6/z, z21.d, #49 + __ sve_cmp(Assembler::HI, p13, __ B, p7, z3, 97); // cmphi p13.b, p7/z, z3.b, #97 + __ sve_cmp(Assembler::LS, p9, __ H, p7, z17, 109); // cmpls p9.h, p7/z, z17.h, #109 + __ sve_cmp(Assembler::LO, p7, __ S, p5, z7, 127); // cmplo p7.s, p5/z, z7.s, #127 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1086,229 +1096,229 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r19, r17, r9); // swp x19, x17, [x9] - __ ldadd(Assembler::xword, r28, r27, r15); // ldadd x28, x27, [x15] - __ ldbic(Assembler::xword, r7, r21, r23); // ldclr x7, x21, [x23] - __ ldeor(Assembler::xword, zr, r25, r2); // ldeor xzr, x25, [x2] - __ ldorr(Assembler::xword, zr, r27, r15); // ldset xzr, x27, [x15] - __ ldsmin(Assembler::xword, r10, r23, r19); // ldsmin x10, x23, [x19] - __ ldsmax(Assembler::xword, r3, r16, r0); // ldsmax x3, x16, [x0] - __ ldumin(Assembler::xword, r25, r26, r23); // ldumin x25, x26, [x23] - __ ldumax(Assembler::xword, r2, r16, r12); // ldumax x2, x16, [x12] + __ swp(Assembler::xword, r25, r2, sp); // swp x25, x2, [sp] + __ ldadd(Assembler::xword, r27, r16, r10); // ldadd x27, x16, [x10] + __ ldbic(Assembler::xword, r23, r19, r3); // ldclr x23, x19, [x3] + __ ldeor(Assembler::xword, r16, r0, r25); // ldeor x16, x0, [x25] + __ ldorr(Assembler::xword, r26, r23, r2); // ldset x26, x23, [x2] + __ ldsmin(Assembler::xword, r16, r12, r4); // ldsmin x16, x12, [x4] + __ ldsmax(Assembler::xword, r28, r30, r29); // ldsmax x28, x30, [x29] + __ ldumin(Assembler::xword, r16, r27, r6); // ldumin x16, x27, [x6] + __ ldumax(Assembler::xword, r9, r29, r15); // ldumax x9, x29, [x15] // LSEOp - __ swpa(Assembler::xword, r4, r28, r30); // swpa x4, x28, [x30] - __ ldadda(Assembler::xword, r29, r16, r27); // ldadda x29, x16, [x27] - __ ldbica(Assembler::xword, r6, r9, r29); // ldclra x6, x9, [x29] - __ ldeora(Assembler::xword, r16, r7, r4); // ldeora x16, x7, [x4] - __ ldorra(Assembler::xword, r7, r15, r9); // ldseta x7, x15, [x9] - __ ldsmina(Assembler::xword, r23, r8, r2); // ldsmina x23, x8, [x2] - __ ldsmaxa(Assembler::xword, r28, r21, sp); // ldsmaxa x28, x21, [sp] - __ ldumina(Assembler::xword, r5, r27, r0); // ldumina x5, x27, [x0] - __ ldumaxa(Assembler::xword, r17, r15, r4); // ldumaxa x17, x15, [x4] + __ swpa(Assembler::xword, r7, r4, r7); // swpa x7, x4, [x7] + __ ldadda(Assembler::xword, r15, r9, r23); // ldadda x15, x9, [x23] + __ ldbica(Assembler::xword, r8, r2, r28); // ldclra x8, x2, [x28] + __ ldeora(Assembler::xword, r21, zr, r5); // ldeora x21, xzr, [x5] + __ ldorra(Assembler::xword, r27, r0, r17); // ldseta x27, x0, [x17] + __ ldsmina(Assembler::xword, r15, r4, r26); // ldsmina x15, x4, [x26] + __ ldsmaxa(Assembler::xword, r8, r28, r22); // ldsmaxa x8, x28, [x22] + __ ldumina(Assembler::xword, r27, r27, r25); // ldumina x27, x27, [x25] + __ ldumaxa(Assembler::xword, r23, r0, r4); // ldumaxa x23, x0, [x4] // LSEOp - __ swpal(Assembler::xword, r26, r8, r28); // swpal x26, x8, [x28] - __ ldaddal(Assembler::xword, r22, r27, r27); // ldaddal x22, x27, [x27] - __ ldbical(Assembler::xword, r25, r23, r0); // ldclral x25, x23, [x0] - __ ldeoral(Assembler::xword, r4, r6, r15); // ldeoral x4, x6, [x15] - __ ldorral(Assembler::xword, r0, r4, r15); // ldsetal x0, x4, [x15] - __ ldsminal(Assembler::xword, r1, r10, r7); // ldsminal x1, x10, [x7] - __ ldsmaxal(Assembler::xword, r5, r10, r28); // ldsmaxal x5, x10, [x28] - __ lduminal(Assembler::xword, r7, r20, r23); // lduminal x7, x20, [x23] - __ ldumaxal(Assembler::xword, r21, r6, r11); // ldumaxal x21, x6, [x11] + __ swpal(Assembler::xword, r6, r16, r0); // swpal x6, x16, [x0] + __ ldaddal(Assembler::xword, r4, r15, r1); // ldaddal x4, x15, [x1] + __ ldbical(Assembler::xword, r10, r7, r5); // ldclral x10, x7, [x5] + __ ldeoral(Assembler::xword, r10, r28, r7); // ldeoral x10, x28, [x7] + __ ldorral(Assembler::xword, r20, r23, r21); // ldsetal x20, x23, [x21] + __ ldsminal(Assembler::xword, r6, r11, r8); // ldsminal x6, x11, [x8] + __ ldsmaxal(Assembler::xword, r17, zr, r6); // ldsmaxal x17, xzr, [x6] + __ lduminal(Assembler::xword, r17, r2, r12); // lduminal x17, x2, [x12] + __ ldumaxal(Assembler::xword, r30, r29, r3); // ldumaxal x30, x29, [x3] // LSEOp - __ swpl(Assembler::xword, r8, r17, sp); // swpl x8, x17, [sp] - __ ldaddl(Assembler::xword, r6, r17, r2); // ldaddl x6, x17, [x2] - __ ldbicl(Assembler::xword, r12, r30, r29); // ldclrl x12, x30, [x29] - __ ldeorl(Assembler::xword, r3, r27, r22); // ldeorl x3, x27, [x22] - __ ldorrl(Assembler::xword, r29, r14, r13); // ldsetl x29, x14, [x13] - __ ldsminl(Assembler::xword, r28, r17, r24); // ldsminl x28, x17, [x24] - __ ldsmaxl(Assembler::xword, r5, r2, r14); // ldsmaxl x5, x2, [x14] - __ lduminl(Assembler::xword, r10, r16, r11); // lduminl x10, x16, [x11] - __ ldumaxl(Assembler::xword, r27, r23, r12); // ldumaxl x27, x23, [x12] + __ swpl(Assembler::xword, r27, r22, r29); // swpl x27, x22, [x29] + __ ldaddl(Assembler::xword, r14, r13, r28); // ldaddl x14, x13, [x28] + __ ldbicl(Assembler::xword, r17, r24, r5); // ldclrl x17, x24, [x5] + __ ldeorl(Assembler::xword, r2, r14, r10); // ldeorl x2, x14, [x10] + __ ldorrl(Assembler::xword, r16, r11, r27); // ldsetl x16, x11, [x27] + __ ldsminl(Assembler::xword, r23, r12, r4); // ldsminl x23, x12, [x4] + __ ldsmaxl(Assembler::xword, r22, r17, r4); // ldsmaxl x22, x17, [x4] + __ lduminl(Assembler::xword, r1, r19, r16); // lduminl x1, x19, [x16] + __ ldumaxl(Assembler::xword, r16, r13, r14); // ldumaxl x16, x13, [x14] // LSEOp - __ swp(Assembler::word, r4, r22, r17); // swp w4, w22, [x17] - __ ldadd(Assembler::word, r4, r1, r19); // ldadd w4, w1, [x19] - __ ldbic(Assembler::word, r16, r16, r13); // ldclr w16, w16, [x13] - __ ldeor(Assembler::word, r14, r12, r2); // ldeor w14, w12, [x2] - __ ldorr(Assembler::word, r17, r3, r21); // ldset w17, w3, [x21] - __ ldsmin(Assembler::word, r23, r5, r6); // ldsmin w23, w5, [x6] - __ ldsmax(Assembler::word, r7, r19, r13); // ldsmax w7, w19, [x13] - __ ldumin(Assembler::word, r28, r17, r16); // ldumin w28, w17, [x16] - __ ldumax(Assembler::word, r6, r2, r29); // ldumax w6, w2, [x29] + __ swp(Assembler::word, r12, r2, r17); // swp w12, w2, [x17] + __ ldadd(Assembler::word, r3, r21, r23); // ldadd w3, w21, [x23] + __ ldbic(Assembler::word, r5, r6, r7); // ldclr w5, w6, [x7] + __ ldeor(Assembler::word, r19, r13, r28); // ldeor w19, w13, [x28] + __ ldorr(Assembler::word, r17, r16, r6); // ldset w17, w16, [x6] + __ ldsmin(Assembler::word, r2, r29, r3); // ldsmin w2, w29, [x3] + __ ldsmax(Assembler::word, r4, r6, r15); // ldsmax w4, w6, [x15] + __ ldumin(Assembler::word, r20, r13, r12); // ldumin w20, w13, [x12] + __ ldumax(Assembler::word, r20, r8, r25); // ldumax w20, w8, [x25] // LSEOp - __ swpa(Assembler::word, r3, r4, r6); // swpa w3, w4, [x6] - __ ldadda(Assembler::word, r16, r20, r13); // ldadda w16, w20, [x13] - __ ldbica(Assembler::word, r12, r20, r8); // ldclra w12, w20, [x8] - __ ldeora(Assembler::word, r25, r20, r19); // ldeora w25, w20, [x19] - __ ldorra(Assembler::word, r0, r11, r24); // ldseta w0, w11, [x24] - __ ldsmina(Assembler::word, r6, r20, sp); // ldsmina w6, w20, [sp] - __ ldsmaxa(Assembler::word, r14, r16, r6); // ldsmaxa w14, w16, [x6] - __ ldumina(Assembler::word, r0, r7, r15); // ldumina w0, w7, [x15] - __ ldumaxa(Assembler::word, r19, r26, r9); // ldumaxa w19, w26, [x9] + __ swpa(Assembler::word, r20, r19, r0); // swpa w20, w19, [x0] + __ ldadda(Assembler::word, r11, r24, r6); // ldadda w11, w24, [x6] + __ ldbica(Assembler::word, r20, zr, r14); // ldclra w20, wzr, [x14] + __ ldeora(Assembler::word, r16, r6, r0); // ldeora w16, w6, [x0] + __ ldorra(Assembler::word, r7, r15, r19); // ldseta w7, w15, [x19] + __ ldsmina(Assembler::word, r26, r9, r10); // ldsmina w26, w9, [x10] + __ ldsmaxa(Assembler::word, r23, r21, r22); // ldsmaxa w23, w21, [x22] + __ ldumina(Assembler::word, r28, r2, r3); // ldumina w28, w2, [x3] + __ ldumaxa(Assembler::word, r15, r19, r20); // ldumaxa w15, w19, [x20] // LSEOp - __ swpal(Assembler::word, r10, r23, r21); // swpal w10, w23, [x21] - __ ldaddal(Assembler::word, r22, r28, r2); // ldaddal w22, w28, [x2] - __ ldbical(Assembler::word, r3, r15, r19); // ldclral w3, w15, [x19] - __ ldeoral(Assembler::word, r20, r7, r4); // ldeoral w20, w7, [x4] - __ ldorral(Assembler::word, r29, r7, r0); // ldsetal w29, w7, [x0] - __ ldsminal(Assembler::word, r9, r16, r20); // ldsminal w9, w16, [x20] - __ ldsmaxal(Assembler::word, r23, r4, r16); // ldsmaxal w23, w4, [x16] - __ lduminal(Assembler::word, r10, r23, r11); // lduminal w10, w23, [x11] - __ ldumaxal(Assembler::word, r25, r6, sp); // ldumaxal w25, w6, [sp] + __ swpal(Assembler::word, r7, r4, r29); // swpal w7, w4, [x29] + __ ldaddal(Assembler::word, r7, r0, r9); // ldaddal w7, w0, [x9] + __ ldbical(Assembler::word, r16, r20, r23); // ldclral w16, w20, [x23] + __ ldeoral(Assembler::word, r4, r16, r10); // ldeoral w4, w16, [x10] + __ ldorral(Assembler::word, r23, r11, r25); // ldsetal w23, w11, [x25] + __ ldsminal(Assembler::word, r6, zr, r16); // ldsminal w6, wzr, [x16] + __ ldsmaxal(Assembler::word, r13, r23, r12); // ldsmaxal w13, w23, [x12] + __ lduminal(Assembler::word, r1, r14, r9); // lduminal w1, w14, [x9] + __ ldumaxal(Assembler::word, r21, r16, r26); // ldumaxal w21, w16, [x26] // LSEOp - __ swpl(Assembler::word, r16, r13, r23); // swpl w16, w13, [x23] - __ ldaddl(Assembler::word, r12, r1, r14); // ldaddl w12, w1, [x14] - __ ldbicl(Assembler::word, r9, r21, r16); // ldclrl w9, w21, [x16] - __ ldeorl(Assembler::word, r26, r15, r4); // ldeorl w26, w15, [x4] - __ ldorrl(Assembler::word, r4, r16, r8); // ldsetl w4, w16, [x8] - __ ldsminl(Assembler::word, r6, r30, r4); // ldsminl w6, w30, [x4] - __ ldsmaxl(Assembler::word, r29, r17, r29); // ldsmaxl w29, w17, [x29] - __ lduminl(Assembler::word, r26, r9, r15); // lduminl w26, w9, [x15] - __ ldumaxl(Assembler::word, r2, r11, r29); // ldumaxl w2, w11, [x29] + __ swpl(Assembler::word, r15, r4, r4); // swpl w15, w4, [x4] + __ ldaddl(Assembler::word, r16, r8, r6); // ldaddl w16, w8, [x6] + __ ldbicl(Assembler::word, r30, r4, r29); // ldclrl w30, w4, [x29] + __ ldeorl(Assembler::word, r17, r29, r26); // ldeorl w17, w29, [x26] + __ ldorrl(Assembler::word, r9, r15, r2); // ldsetl w9, w15, [x2] + __ ldsminl(Assembler::word, r11, r29, r3); // ldsminl w11, w29, [x3] + __ ldsmaxl(Assembler::word, r7, r1, r27); // ldsmaxl w7, w1, [x27] + __ lduminl(Assembler::word, r21, r16, r14); // lduminl w21, w16, [x14] + __ ldumaxl(Assembler::word, r8, r16, r22); // ldumaxl w8, w16, [x22] // SHA3SIMDOp - __ bcax(v3, __ T16B, v7, v1, v27); // bcax v3.16B, v7.16B, v1.16B, v27.16B - __ eor3(v21, __ T16B, v18, v14, v8); // eor3 v21.16B, v18.16B, v14.16B, v8.16B - __ rax1(v18, __ T2D, v22, v25); // rax1 v18.2D, v22.2D, v25.2D - __ xar(v5, __ T2D, v20, v21, 37); // xar v5.2D, v20.2D, v21.2D, #37 + __ bcax(v25, __ T16B, v5, v20, v21); // bcax v25.16B, v5.16B, v20.16B, v21.16B + __ eor3(v18, __ T16B, v23, v16, v30); // eor3 v18.16B, v23.16B, v16.16B, v30.16B + __ rax1(v20, __ T2D, v20, v0); // rax1 v20.2D, v20.2D, v0.2D + __ xar(v4, __ T2D, v19, v24, 9); // xar v4.2D, v19.2D, v24.2D, #9 // SHA512SIMDOp - __ sha512h(v23, __ T2D, v16, v30); // sha512h q23, q16, v30.2D - __ sha512h2(v20, __ T2D, v20, v0); // sha512h2 q20, q20, v0.2D - __ sha512su0(v4, __ T2D, v19); // sha512su0 v4.2D, v19.2D - __ sha512su1(v24, __ T2D, v4, v20); // sha512su1 v24.2D, v4.2D, v20.2D + __ sha512h(v20, __ T2D, v4, v24); // sha512h q20, q4, v24.2D + __ sha512h2(v26, __ T2D, v19, v2); // sha512h2 q26, q19, v2.2D + __ sha512su0(v8, __ T2D, v8); // sha512su0 v8.2D, v8.2D + __ sha512su1(v14, __ T2D, v24, v18); // sha512su1 v14.2D, v24.2D, v18.2D // SVEBinaryImmOp - __ sve_add(z4, __ D, 210u); // add z4.d, z4.d, #0xd2 - __ sve_sub(z19, __ B, 71u); // sub z19.b, z19.b, #0x47 - __ sve_and(z8, __ H, 49663u); // and z8.h, z8.h, #0xc1ff - __ sve_eor(z31, __ S, 4294967231u); // eor z31.s, z31.s, #0xffffffbf - __ sve_orr(z1, __ H, 16368u); // orr z1.h, z1.h, #0x3ff0 + __ sve_add(z31, __ S, 36u); // add z31.s, z31.s, #0x24 + __ sve_sub(z31, __ B, 85u); // sub z31.b, z31.b, #0x55 + __ sve_and(z20, __ H, 4032u); // and z20.h, z20.h, #0xfc0 + __ sve_eor(z7, __ D, 274877904896u); // eor z7.d, z7.d, #0x3ffffff800 + __ sve_orr(z27, __ B, 243u); // orr z27.b, z27.b, #0xf3 // SVEBinaryImmOp - __ sve_add(z0, __ H, 61u); // add z0.h, z0.h, #0x3d - __ sve_sub(z24, __ S, 36u); // sub z24.s, z24.s, #0x24 - __ sve_and(z27, __ B, 243u); // and z27.b, z27.b, #0xf3 - __ sve_eor(z24, __ H, 65534u); // eor z24.h, z24.h, #0xfffe - __ sve_orr(z22, __ S, 4294967293u); // orr z22.s, z22.s, #0xfffffffd + __ sve_add(z24, __ H, 132u); // add z24.h, z24.h, #0x84 + __ sve_sub(z31, __ S, 183u); // sub z31.s, z31.s, #0xb7 + __ sve_and(z20, __ D, 4503599627354112u); // and z20.d, z20.d, #0xfffffffffc000 + __ sve_eor(z14, __ S, 4042322160u); // eor z14.s, z14.s, #0xf0f0f0f0 + __ sve_orr(z28, __ H, 32256u); // orr z28.h, z28.h, #0x7e00 // SVEBinaryImmOp - __ sve_add(z29, __ H, 113u); // add z29.h, z29.h, #0x71 - __ sve_sub(z20, __ B, 165u); // sub z20.b, z20.b, #0xa5 - __ sve_and(z28, __ H, 32256u); // and z28.h, z28.h, #0x7e00 - __ sve_eor(z12, __ S, 4287102855u); // eor z12.s, z12.s, #0xff87ff87 - __ sve_orr(z9, __ S, 3825205247u); // orr z9.s, z9.s, #0xe3ffffff + __ sve_add(z12, __ S, 13u); // add z12.s, z12.s, #0xd + __ sve_sub(z24, __ H, 159u); // sub z24.h, z24.h, #0x9f + __ sve_and(z13, __ S, 2151677951u); // and z13.s, z13.s, #0x803fffff + __ sve_eor(z5, __ B, 124u); // eor z5.b, z5.b, #0x7c + __ sve_orr(z8, __ H, 32768u); // orr z8.h, z8.h, #0x8000 // SVEBinaryImmOp - __ sve_add(z18, __ S, 41u); // add z18.s, z18.s, #0x29 - __ sve_sub(z0, __ B, 98u); // sub z0.b, z0.b, #0x62 - __ sve_and(z8, __ H, 32768u); // and z8.h, z8.h, #0x8000 - __ sve_eor(z4, __ H, 508u); // eor z4.h, z4.h, #0x1fc - __ sve_orr(z0, __ H, 64512u); // orr z0.h, z0.h, #0xfc00 + __ sve_add(z4, __ H, 243u); // add z4.h, z4.h, #0xf3 + __ sve_sub(z5, __ B, 86u); // sub z5.b, z5.b, #0x56 + __ sve_and(z22, __ D, 8064u); // and z22.d, z22.d, #0x1f80 + __ sve_eor(z9, __ S, 130023424u); // eor z9.s, z9.s, #0x7c00000 + __ sve_orr(z24, __ B, 62u); // orr z24.b, z24.b, #0x3e // SVEBinaryImmOp - __ sve_add(z3, __ B, 79u); // add z3.b, z3.b, #0x4f - __ sve_sub(z19, __ D, 84u); // sub z19.d, z19.d, #0x54 - __ sve_and(z24, __ B, 62u); // and z24.b, z24.b, #0x3e - __ sve_eor(z24, __ D, 18428729675200069887u); // eor z24.d, z24.d, #0xffc00000000000ff - __ sve_orr(z11, __ D, 17296056810822168583u); // orr z11.d, z11.d, #0xf007f007f007f007 + __ sve_add(z24, __ D, 113u); // add z24.d, z24.d, #0x71 + __ sve_sub(z21, __ H, 217u); // sub z21.h, z21.h, #0xd9 + __ sve_and(z13, __ S, 3221229567u); // and z13.s, z13.s, #0xc0000fff + __ sve_eor(z14, __ B, 131u); // eor z14.b, z14.b, #0x83 + __ sve_orr(z22, __ S, 4042322160u); // orr z22.s, z22.s, #0xf0f0f0f0 // SVEBinaryImmOp - __ sve_add(z31, __ S, 115u); // add z31.s, z31.s, #0x73 - __ sve_sub(z3, __ D, 134u); // sub z3.d, z3.d, #0x86 - __ sve_and(z22, __ S, 4042322160u); // and z22.s, z22.s, #0xf0f0f0f0 - __ sve_eor(z3, __ B, 225u); // eor z3.b, z3.b, #0xe1 - __ sve_orr(z9, __ S, 4164941887u); // orr z9.s, z9.s, #0xf83ff83f + __ sve_add(z3, __ B, 215u); // add z3.b, z3.b, #0xd7 + __ sve_sub(z19, __ H, 134u); // sub z19.h, z19.h, #0x86 + __ sve_and(z17, __ S, 491520u); // and z17.s, z17.s, #0x78000 + __ sve_eor(z2, __ D, 8796093020160u); // eor z2.d, z2.d, #0x7fffffff800 + __ sve_orr(z11, __ S, 3221229567u); // orr z11.s, z11.s, #0xc0000fff // SVEVectorOp - __ sve_add(z0, __ D, z4, z2); // add z0.d, z4.d, z2.d - __ sve_sub(z14, __ S, z6, z11); // sub z14.s, z6.s, z11.s - __ sve_fadd(z14, __ S, z17, z30); // fadd z14.s, z17.s, z30.s - __ sve_fmul(z3, __ S, z3, z23); // fmul z3.s, z3.s, z23.s - __ sve_fsub(z3, __ S, z24, z28); // fsub z3.s, z24.s, z28.s - __ sve_abs(z19, __ D, p5, z7); // abs z19.d, p5/m, z7.d - __ sve_add(z21, __ H, p3, z5); // add z21.h, p3/m, z21.h, z5.h - __ sve_and(z26, __ S, p1, z22); // and z26.s, p1/m, z26.s, z22.s - __ sve_asr(z17, __ H, p0, z3); // asr z17.h, p0/m, z17.h, z3.h - __ sve_bic(z20, __ H, p3, z8); // bic z20.h, p3/m, z20.h, z8.h - __ sve_clz(z14, __ H, p4, z17); // clz z14.h, p4/m, z17.h - __ sve_cnt(z13, __ D, p6, z18); // cnt z13.d, p6/m, z18.d - __ sve_eor(z19, __ H, p2, z16); // eor z19.h, p2/m, z19.h, z16.h - __ sve_lsl(z27, __ S, p5, z28); // lsl z27.s, p5/m, z27.s, z28.s - __ sve_lsr(z8, __ D, p2, z5); // lsr z8.d, p2/m, z8.d, z5.d - __ sve_mul(z28, __ H, p2, z0); // mul z28.h, p2/m, z28.h, z0.h - __ sve_neg(z25, __ B, p5, z21); // neg z25.b, p5/m, z21.b - __ sve_not(z3, __ B, p5, z26); // not z3.b, p5/m, z26.b - __ sve_orr(z26, __ S, p7, z19); // orr z26.s, p7/m, z26.s, z19.s - __ sve_rbit(z1, __ D, p3, z14); // rbit z1.d, p3/m, z14.d - __ sve_revb(z14, __ H, p0, z18); // revb z14.h, p0/m, z18.h - __ sve_smax(z31, __ S, p5, z23); // smax z31.s, p5/m, z31.s, z23.s - __ sve_smin(z30, __ B, p3, z8); // smin z30.b, p3/m, z30.b, z8.b - __ sve_sub(z0, __ S, p3, z23); // sub z0.s, p3/m, z0.s, z23.s - __ sve_fabs(z0, __ D, p4, z26); // fabs z0.d, p4/m, z26.d - __ sve_fadd(z24, __ D, p3, z22); // fadd z24.d, p3/m, z24.d, z22.d - __ sve_fdiv(z2, __ D, p0, z11); // fdiv z2.d, p0/m, z2.d, z11.d - __ sve_fmax(z12, __ D, p5, z24); // fmax z12.d, p5/m, z12.d, z24.d - __ sve_fmin(z9, __ D, p7, z17); // fmin z9.d, p7/m, z9.d, z17.d - __ sve_fmul(z20, __ D, p5, z4); // fmul z20.d, p5/m, z20.d, z4.d - __ sve_fneg(z13, __ D, p7, z22); // fneg z13.d, p7/m, z22.d - __ sve_frintm(z31, __ D, p6, z18); // frintm z31.d, p6/m, z18.d - __ sve_frintn(z15, __ D, p2, z13); // frintn z15.d, p2/m, z13.d - __ sve_frintp(z20, __ S, p1, z1); // frintp z20.s, p1/m, z1.s - __ sve_fsqrt(z14, __ S, p0, z7); // fsqrt z14.s, p0/m, z7.s - __ sve_fsub(z12, __ D, p4, z4); // fsub z12.d, p4/m, z12.d, z4.d - __ sve_fmad(z15, __ S, p0, z3, z30); // fmad z15.s, p0/m, z3.s, z30.s - __ sve_fmla(z20, __ D, p1, z20, z31); // fmla z20.d, p1/m, z20.d, z31.d - __ sve_fmls(z13, __ D, p3, z9, z14); // fmls z13.d, p3/m, z9.d, z14.d - __ sve_fmsb(z1, __ S, p3, z28, z3); // fmsb z1.s, p3/m, z28.s, z3.s - __ sve_fnmad(z26, __ S, p2, z25, z9); // fnmad z26.s, p2/m, z25.s, z9.s - __ sve_fnmsb(z26, __ D, p2, z14, z1); // fnmsb z26.d, p2/m, z14.d, z1.d - __ sve_fnmla(z26, __ D, p1, z29, z20); // fnmla z26.d, p1/m, z29.d, z20.d - __ sve_fnmls(z6, __ D, p7, z13, z1); // fnmls z6.d, p7/m, z13.d, z1.d - __ sve_mla(z11, __ B, p2, z1, z1); // mla z11.b, p2/m, z1.b, z1.b - __ sve_mls(z27, __ B, p6, z15, z2); // mls z27.b, p6/m, z15.b, z2.b - __ sve_and(z30, z17, z25); // and z30.d, z17.d, z25.d - __ sve_eor(z2, z24, z3); // eor z2.d, z24.d, z3.d - __ sve_orr(z29, z13, z3); // orr z29.d, z13.d, z3.d - __ sve_bic(z14, z16, z28); // bic z14.d, z16.d, z28.d - __ sve_uzp1(z4, __ S, z11, z27); // uzp1 z4.s, z11.s, z27.s - __ sve_uzp2(z2, __ D, z16, z1); // uzp2 z2.d, z16.d, z1.d - __ sve_fabd(z7, __ D, p5, z31); // fabd z7.d, p5/m, z7.d, z31.d - __ sve_bext(z16, __ S, z10, z22); // bext z16.s, z10.s, z22.s - __ sve_bdep(z29, __ B, z7, z22); // bdep z29.b, z7.b, z22.b - __ sve_eor3(z12, z24, z11); // eor3 z12.d, z12.d, z24.d, z11.d + __ sve_add(z30, __ B, z12, z3); // add z30.b, z12.b, z3.b + __ sve_sub(z23, __ D, z9, z3); // sub z23.d, z9.d, z3.d + __ sve_fadd(z28, __ D, z3, z19); // fadd z28.d, z3.d, z19.d + __ sve_fmul(z7, __ S, z26, z21); // fmul z7.s, z26.s, z21.s + __ sve_fsub(z5, __ S, z8, z26); // fsub z5.s, z8.s, z26.s + __ sve_abs(z22, __ B, p4, z17); // abs z22.b, p4/m, z17.b + __ sve_add(z3, __ H, p2, z20); // add z3.h, p2/m, z3.h, z20.h + __ sve_and(z8, __ S, p3, z14); // and z8.s, p3/m, z8.s, z14.s + __ sve_asr(z17, __ D, p2, z13); // asr z17.d, p2/m, z17.d, z13.d + __ sve_bic(z18, __ H, p7, z19); // bic z18.h, p7/m, z18.h, z19.h + __ sve_clz(z16, __ S, p3, z27); // clz z16.s, p3/m, z27.s + __ sve_cnt(z28, __ H, p5, z8); // cnt z28.h, p5/m, z8.h + __ sve_eor(z5, __ H, p7, z28); // eor z5.h, p7/m, z5.h, z28.h + __ sve_lsl(z0, __ S, p3, z25); // lsl z0.s, p3/m, z0.s, z25.s + __ sve_lsr(z21, __ S, p0, z3); // lsr z21.s, p0/m, z21.s, z3.s + __ sve_mul(z26, __ D, p1, z26); // mul z26.d, p1/m, z26.d, z26.d + __ sve_neg(z19, __ H, p4, z1); // neg z19.h, p4/m, z1.h + __ sve_not(z14, __ B, p7, z14); // not z14.b, p7/m, z14.b + __ sve_orr(z18, __ S, p0, z31); // orr z18.s, p0/m, z18.s, z31.s + __ sve_rbit(z23, __ H, p5, z30); // rbit z23.h, p5/m, z30.h + __ sve_revb(z8, __ S, p0, z0); // revb z8.s, p0/m, z0.s + __ sve_smax(z23, __ S, p5, z0); // smax z23.s, p5/m, z23.s, z0.s + __ sve_smin(z26, __ H, p6, z24); // smin z26.h, p6/m, z26.h, z24.h + __ sve_sub(z22, __ B, p5, z2); // sub z22.b, p5/m, z22.b, z2.b + __ sve_fabs(z11, __ D, p5, z12); // fabs z11.d, p5/m, z12.d + __ sve_fadd(z24, __ D, p6, z9); // fadd z24.d, p6/m, z24.d, z9.d + __ sve_fdiv(z17, __ D, p5, z20); // fdiv z17.d, p5/m, z17.d, z20.d + __ sve_fmax(z4, __ D, p5, z13); // fmax z4.d, p5/m, z4.d, z13.d + __ sve_fmin(z22, __ D, p7, z31); // fmin z22.d, p7/m, z22.d, z31.d + __ sve_fmul(z18, __ S, p4, z15); // fmul z18.s, p4/m, z18.s, z15.s + __ sve_fneg(z13, __ S, p7, z20); // fneg z13.s, p7/m, z20.s + __ sve_frintm(z1, __ S, p3, z14); // frintm z1.s, p3/m, z14.s + __ sve_frintn(z7, __ D, p2, z12); // frintn z7.d, p2/m, z12.d + __ sve_frintp(z4, __ S, p6, z15); // frintp z4.s, p6/m, z15.s + __ sve_fsqrt(z3, __ D, p7, z1); // fsqrt z3.d, p7/m, z1.d + __ sve_fsub(z5, __ D, p5, z31); // fsub z5.d, p5/m, z5.d, z31.d + __ sve_fmad(z13, __ D, p3, z9, z14); // fmad z13.d, p3/m, z9.d, z14.d + __ sve_fmla(z1, __ S, p3, z28, z3); // fmla z1.s, p3/m, z28.s, z3.s + __ sve_fmls(z26, __ S, p2, z25, z9); // fmls z26.s, p2/m, z25.s, z9.s + __ sve_fmsb(z26, __ D, p2, z14, z1); // fmsb z26.d, p2/m, z14.d, z1.d + __ sve_fnmad(z26, __ D, p1, z29, z20); // fnmad z26.d, p1/m, z29.d, z20.d + __ sve_fnmsb(z6, __ D, p7, z13, z1); // fnmsb z6.d, p7/m, z13.d, z1.d + __ sve_fnmla(z11, __ S, p2, z1, z1); // fnmla z11.s, p2/m, z1.s, z1.s + __ sve_fnmls(z27, __ S, p6, z15, z2); // fnmls z27.s, p6/m, z15.s, z2.s + __ sve_mla(z30, __ B, p4, z25, z2); // mla z30.b, p4/m, z25.b, z2.b + __ sve_mls(z24, __ H, p0, z26, z29); // mls z24.h, p0/m, z26.h, z29.h + __ sve_and(z3, z22, z14); // and z3.d, z22.d, z14.d + __ sve_eor(z28, z17, z4); // eor z28.d, z17.d, z4.d + __ sve_orr(z27, z16, z2); // orr z27.d, z16.d, z2.d + __ sve_bic(z1, z28, z7); // bic z1.d, z28.d, z7.d + __ sve_uzp1(z31, __ H, z28, z16); // uzp1 z31.h, z28.h, z16.h + __ sve_uzp2(z22, __ B, z17, z29); // uzp2 z22.b, z17.b, z29.b + __ sve_fabd(z22, __ D, p1, z12); // fabd z22.d, p1/m, z22.d, z12.d + __ sve_bext(z11, __ H, z9, z11); // bext z11.h, z9.h, z11.h + __ sve_bdep(z0, __ S, z4, z23); // bdep z0.s, z4.s, z23.s + __ sve_eor3(z20, z4, z3); // eor3 z20.d, z20.d, z4.d, z3.d // SVEReductionOp - __ sve_andv(v11, __ B, p2, z0); // andv b11, p2, z0.b - __ sve_orv(v23, __ B, p5, z20); // orv b23, p5, z20.b - __ sve_eorv(v3, __ B, p3, z15); // eorv b3, p3, z15.b - __ sve_smaxv(v30, __ B, p6, z27); // smaxv b30, p6, z27.b - __ sve_sminv(v21, __ D, p6, z10); // sminv d21, p6, z10.d - __ sve_fminv(v3, __ S, p6, z4); // fminv s3, p6, z4.s - __ sve_fmaxv(v6, __ S, p0, z21); // fmaxv s6, p0, z21.s - __ sve_fadda(v25, __ D, p6, z30); // fadda d25, p6, d25, z30.d - __ sve_uaddv(v31, __ H, p4, z1); // uaddv d31, p4, z1.h + __ sve_andv(v15, __ D, p1, z30); // andv d15, p1, z30.d + __ sve_orv(v27, __ D, p1, z21); // orv d27, p1, z21.d + __ sve_eorv(v10, __ D, p7, z3); // eorv d10, p7, z3.d + __ sve_smaxv(v4, __ B, p2, z6); // smaxv b4, p2, z6.b + __ sve_sminv(v21, __ D, p1, z25); // sminv d21, p1, z25.d + __ sve_fminv(v30, __ D, p6, z31); // fminv d30, p6, z31.d + __ sve_fmaxv(v1, __ D, p2, z12); // fmaxv d1, p2, z12.d + __ sve_fadda(v13, __ D, p2, z25); // fadda d13, p2, d13, z25.d + __ sve_uaddv(v1, __ D, p7, z23); // uaddv d1, p7, z23.d // AddWideNEONOp - __ saddwv(v12, v13, __ T8H, v14, __ T8B); // saddw v12.8H, v13.8H, v14.8B - __ saddwv2(v30, v31, __ T8H, v0, __ T16B); // saddw2 v30.8H, v31.8H, v0.16B - __ saddwv(v13, v14, __ T4S, v15, __ T4H); // saddw v13.4S, v14.4S, v15.4H - __ saddwv2(v8, v9, __ T4S, v10, __ T8H); // saddw2 v8.4S, v9.4S, v10.8H - __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S + __ saddwv(v20, v21, __ T8H, v22, __ T8B); // saddw v20.8H, v21.8H, v22.8B + __ saddwv2(v0, v1, __ T8H, v2, __ T16B); // saddw2 v0.8H, v1.8H, v2.16B + __ saddwv(v21, v22, __ T4S, v23, __ T4H); // saddw v21.4S, v22.4S, v23.4H + __ saddwv2(v7, v8, __ T4S, v9, __ T8H); // saddw2 v7.4S, v8.4S, v9.8H + __ saddwv(v31, v0, __ T2D, v1, __ T2S); // saddw v31.2D, v0.2D, v1.2S __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S - __ uaddwv(v1, v2, __ T8H, v3, __ T8B); // uaddw v1.8H, v2.8H, v3.8B - __ uaddwv2(v31, v0, __ T8H, v1, __ T16B); // uaddw2 v31.8H, v0.8H, v1.16B - __ uaddwv(v23, v24, __ T4S, v25, __ T4H); // uaddw v23.4S, v24.4S, v25.4H - __ uaddwv2(v31, v0, __ T4S, v1, __ T8H); // uaddw2 v31.4S, v0.4S, v1.8H - __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S - __ uaddwv2(v0, v1, __ T2D, v2, __ T4S); // uaddw2 v0.2D, v1.2D, v2.4S + __ uaddwv(v27, v28, __ T8H, v29, __ T8B); // uaddw v27.8H, v28.8H, v29.8B + __ uaddwv2(v22, v23, __ T8H, v24, __ T16B); // uaddw2 v22.8H, v23.8H, v24.16B + __ uaddwv(v8, v9, __ T4S, v10, __ T4H); // uaddw v8.4S, v9.4S, v10.4H + __ uaddwv2(v29, v30, __ T4S, v31, __ T8H); // uaddw2 v29.4S, v30.4S, v31.8H + __ uaddwv(v26, v27, __ T2D, v28, __ T2S); // uaddw v26.2D, v27.2D, v28.2S + __ uaddwv2(v20, v21, __ T2D, v22, __ T4S); // uaddw2 v20.2D, v21.2D, v22.4S __ bind(forth); @@ -1327,30 +1337,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x14000441, 0x94000000, - 0x97ffffd4, 0x9400043e, 0x3400000a, 0x34fffa2a, - 0x3400876a, 0x35000008, 0x35fff9c8, 0x35008708, - 0xb400000b, 0xb4fff96b, 0xb40086ab, 0xb500001d, - 0xb5fff91d, 0xb500865d, 0x10000013, 0x10fff8b3, - 0x100085f3, 0x90000013, 0x36300016, 0x3637f836, - 0x36308576, 0x3758000c, 0x375ff7cc, 0x3758850c, + 0x14000000, 0x17ffffd7, 0x1400044b, 0x94000000, + 0x97ffffd4, 0x94000448, 0x3400000a, 0x34fffa2a, + 0x340088aa, 0x35000008, 0x35fff9c8, 0x35008848, + 0xb400000b, 0xb4fff96b, 0xb40087eb, 0xb500001d, + 0xb5fff91d, 0xb500879d, 0x10000013, 0x10fff8b3, + 0x10008733, 0x90000013, 0x36300016, 0x3637f836, + 0x363086b6, 0x3758000c, 0x375ff7cc, 0x3758864c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x540082e0, 0x54000001, 0x54fff541, 0x54008281, - 0x54000002, 0x54fff4e2, 0x54008222, 0x54000002, - 0x54fff482, 0x540081c2, 0x54000003, 0x54fff423, - 0x54008163, 0x54000003, 0x54fff3c3, 0x54008103, - 0x54000004, 0x54fff364, 0x540080a4, 0x54000005, - 0x54fff305, 0x54008045, 0x54000006, 0x54fff2a6, - 0x54007fe6, 0x54000007, 0x54fff247, 0x54007f87, - 0x54000008, 0x54fff1e8, 0x54007f28, 0x54000009, - 0x54fff189, 0x54007ec9, 0x5400000a, 0x54fff12a, - 0x54007e6a, 0x5400000b, 0x54fff0cb, 0x54007e0b, - 0x5400000c, 0x54fff06c, 0x54007dac, 0x5400000d, - 0x54fff00d, 0x54007d4d, 0x5400000e, 0x54ffefae, - 0x54007cee, 0x5400000f, 0x54ffef4f, 0x54007c8f, + 0x54008420, 0x54000001, 0x54fff541, 0x540083c1, + 0x54000002, 0x54fff4e2, 0x54008362, 0x54000002, + 0x54fff482, 0x54008302, 0x54000003, 0x54fff423, + 0x540082a3, 0x54000003, 0x54fff3c3, 0x54008243, + 0x54000004, 0x54fff364, 0x540081e4, 0x54000005, + 0x54fff305, 0x54008185, 0x54000006, 0x54fff2a6, + 0x54008126, 0x54000007, 0x54fff247, 0x540080c7, + 0x54000008, 0x54fff1e8, 0x54008068, 0x54000009, + 0x54fff189, 0x54008009, 0x5400000a, 0x54fff12a, + 0x54007faa, 0x5400000b, 0x54fff0cb, 0x54007f4b, + 0x5400000c, 0x54fff06c, 0x54007eec, 0x5400000d, + 0x54fff00d, 0x54007e8d, 0x5400000e, 0x54ffefae, + 0x54007e2e, 0x5400000f, 0x54ffef4f, 0x54007dcf, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1471,134 +1481,137 @@ 0x4e60f7fe, 0x0e3c6f7a, 0x4e346e72, 0x0e6b6d49, 0x4e6a6d28, 0x0eae6dac, 0x4ea26c20, 0x0e36aeb4, 0x4e23ac41, 0x0e7aaf38, 0x4e64ac62, 0x0ea2ac20, - 0x4eabad49, 0x0ebaf738, 0x4ebcf77a, 0x4ef2f630, - 0x2ea0effe, 0x6ea5ec83, 0x6eeced6a, 0x0fa710c5, - 0x4f8b8149, 0x4fc710c5, 0x0f8750c5, 0x4faa8128, - 0x4fc750c5, 0x2f8890e6, 0x4fa880e6, 0x6fc59083, - 0x0f6f81cd, 0x4f448862, 0x0f848062, 0x4fab8149, - 0x0e3736d5, 0x4e323630, 0x0e743672, 0x4e6d358b, - 0x0eb736d5, 0x4eb93717, 0x4eee35ac, 0x0e3c3f7a, - 0x4e393f17, 0x0e7e3fbc, 0x4e703dee, 0x0ead3d8b, - 0x4eba3f38, 0x4ee33c41, 0x2e2e8dac, 0x6e218c1f, - 0x2e6c8d6a, 0x6e728e30, 0x2ea98d07, 0x6ea48c62, - 0x6ee58c83, 0x2e2f35cd, 0x6e353693, 0x2e733651, - 0x6e723630, 0x2ea53483, 0x6ea33441, 0x6eed358b, - 0x2e203ffe, 0x6e273cc5, 0x2e6a3d28, 0x6e713e0f, - 0x2ebf3fdd, 0x6ea03ffe, 0x6ee23c20, 0x0e36e6b4, - 0x4e29e507, 0x4e76e6b4, 0x2eb9e717, 0x6ebee7bc, - 0x6ef7e6d5, 0x2e3de79b, 0x6e3be759, 0x6e67e4c5, - 0x65d23ee0, 0x65903d92, 0x65d03fa7, 0x65912fe9, - 0x65d13bf9, 0x65932a0a, 0x25cb90c4, 0x25040bde, - 0x25c11085, 0x25c62c6b, 0x259f2279, 0x259d8993, - 0x24e5102b, 0x24ad5458, 0x24ec7ab5, 0x24387c6d, - 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, - 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, - 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, - 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, - 0x4e062c20, 0x4e052c20, 0x4e083c20, 0x0e0c3c20, - 0x0e0a3c20, 0x0e073c20, 0x9eae0020, 0x0f03f409, - 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, - 0x4e61b8a4, 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, 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, - 0xf8338131, 0xf83c01fb, 0xf82712f5, 0xf83f2059, - 0xf83f31fb, 0xf82a5277, 0xf8234010, 0xf83972fa, - 0xf8226190, 0xf8a483dc, 0xf8bd0370, 0xf8a613a9, - 0xf8b02087, 0xf8a7312f, 0xf8b75048, 0xf8bc43f5, - 0xf8a5701b, 0xf8b1608f, 0xf8fa8388, 0xf8f6037b, - 0xf8f91017, 0xf8e421e6, 0xf8e031e4, 0xf8e150ea, - 0xf8e5438a, 0xf8e772f4, 0xf8f56166, 0xf86883f1, - 0xf8660051, 0xf86c13be, 0xf86322db, 0xf87d31ae, - 0xf87c5311, 0xf86541c2, 0xf86a7170, 0xf87b6197, - 0xb8248236, 0xb8240261, 0xb83011b0, 0xb82e204c, - 0xb83132a3, 0xb83750c5, 0xb82741b3, 0xb83c7211, - 0xb82663a2, 0xb8a380c4, 0xb8b001b4, 0xb8ac1114, - 0xb8b92274, 0xb8a0330b, 0xb8a653f4, 0xb8ae40d0, - 0xb8a071e7, 0xb8b3613a, 0xb8ea82b7, 0xb8f6005c, - 0xb8e3126f, 0xb8f42087, 0xb8fd3007, 0xb8e95290, - 0xb8f74204, 0xb8ea7177, 0xb8f963e6, 0xb87082ed, - 0xb86c01c1, 0xb8691215, 0xb87a208f, 0xb8643110, - 0xb866509e, 0xb87d43b1, 0xb87a71e9, 0xb86263ab, - 0xce216ce3, 0xce0e2255, 0xce798ed2, 0xce959685, - 0xce7e8217, 0xce608694, 0xcec08264, 0xce748898, - 0x25e0da44, 0x2521c8f3, 0x05801548, 0x0540cbdf, - 0x05006521, 0x2560c7a0, 0x25a1c498, 0x058026bb, - 0x05407dd8, 0x0500f3d6, 0x2560ce3d, 0x2521d4b4, - 0x05803cbc, 0x05404d6c, 0x05001b89, 0x25a0c532, - 0x2521cc40, 0x05800c08, 0x054074c4, 0x050034a0, - 0x2520c9e3, 0x25e1ca93, 0x05803e98, 0x05425238, - 0x050024cb, 0x25a0ce7f, 0x25e1d0c3, 0x05802676, - 0x05401e63, 0x05002d49, 0x04e20080, 0x04ab04ce, - 0x659e022e, 0x65970863, 0x659c0703, 0x04d6b4f3, - 0x04400cb5, 0x049a06da, 0x04508071, 0x045b0d14, - 0x0459b22e, 0x04daba4d, 0x04590a13, 0x0493979b, - 0x04d188a8, 0x0450081c, 0x0417b6b9, 0x041eb743, - 0x04981e7a, 0x05e78dc1, 0x0564824e, 0x048816ff, - 0x040a0d1e, 0x04810ee0, 0x04dcb340, 0x65c08ed8, - 0x65cd8162, 0x65c6970c, 0x65c79e29, 0x65c29494, - 0x04ddbecd, 0x65c2ba5f, 0x65c0a9af, 0x6581a434, - 0x658da0ee, 0x65c1908c, 0x65be806f, 0x65ff0694, - 0x65ee2d2d, 0x65a3af81, 0x65a9cb3a, 0x65e1e9da, - 0x65f447ba, 0x65e17da6, 0x0401482b, 0x040279fb, - 0x0439323e, 0x04a33302, 0x046331bd, 0x04fc320e, - 0x05bb6964, 0x05e16e02, 0x65c897e7, 0x4596b150, - 0x4516b4fd, 0x0438396c, 0x041a280b, 0x04183697, - 0x04192de3, 0x04083b7e, 0x04ca3955, 0x65873883, - 0x658622a6, 0x65d83bd9, 0x0441303f, 0x0e2e11ac, - 0x4e2013fe, 0x0e6f11cd, 0x4e6a1128, 0x0ebb1359, - 0x4ebf13dd, 0x2e231041, 0x6e21101f, 0x2e791317, - 0x6e61101f, 0x2eb612b4, 0x6ea21020, + 0x4eabad49, 0x0e7ab738, 0x4e7cb77a, 0x0eb2b630, + 0x4ea0b7fe, 0x0e252483, 0x4e2c256a, 0x0e792717, + 0x4e6c256a, 0x0ea624a4, 0x4eb42672, 0x0ea4f462, + 0x4eadf58b, 0x4eeaf528, 0x2eaced6a, 0x6eb1ee0f, + 0x6ef3ee51, 0x0f8710c5, 0x4fa880e6, 0x4fc810e6, + 0x0f855083, 0x4f8f89cd, 0x4fc45862, 0x2f849062, + 0x4fab8149, 0x6fca9928, 0x0f6780c5, 0x4f5d898b, + 0x0f8f81cd, 0x4f9089ee, 0x0e3035ee, 0x4e2d358b, + 0x0e7a3738, 0x4e633441, 0x0eae35ac, 0x4ea1341f, + 0x4eec356a, 0x0e323e30, 0x4e293d07, 0x0e643c62, + 0x4e653c83, 0x0eaf3dcd, 0x4eb53e93, 0x4ef33e51, + 0x2e328e30, 0x6e258c83, 0x2e638c41, 0x6e6d8d8b, + 0x2ea08ffe, 0x6ea78cc5, 0x6eea8d28, 0x2e31360f, + 0x6e3f37dd, 0x2e6037fe, 0x6e623420, 0x2eb636b4, + 0x6ea93507, 0x6ef636b4, 0x2e393f17, 0x6e3e3fbc, + 0x2e773ed5, 0x6e7d3f9b, 0x2ebb3f59, 0x6ea73cc5, + 0x6ee33c41, 0x0e39e717, 0x4e32e630, 0x4e61e41f, + 0x2ea7e4c5, 0x6eaee5ac, 0x6eebe549, 0x2e3ee7bc, + 0x6e31e60f, 0x6e7fe7dd, 0x65d23feb, 0x65d03dd2, + 0x65d03369, 0x65912566, 0x65d13e3f, 0x659334ef, + 0x25c19085, 0x25c60c7b, 0x259f0269, 0x259d2983, + 0x25d5303b, 0x259d9458, 0x24ec5aa5, 0x24385c7d, + 0x247b7e39, 0x24bff4e7, 0xba5fd3e3, 0x3a5f03e5, + 0xfa411be4, 0x7a42cbe2, 0x93df03ff, 0xc820ffff, + 0x8822fc7f, 0xc8247cbf, 0x88267fff, 0x4e010fe0, + 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, + 0x4e071fe1, 0x4e042c20, 0x4e062c20, 0x4e052c20, + 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, 0x0e073c20, + 0x9eae0020, 0x0f03f409, 0x6f03f40e, 0x4cc0ac3f, + 0x0ea1b820, 0x4e21c862, 0x4e61b8a4, 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, 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, 0xf83983e2, 0xf83b0150, + 0xf8371073, 0xf8302320, 0xf83a3057, 0xf830508c, + 0xf83c43be, 0xf83070db, 0xf82961fd, 0xf8a780e4, + 0xf8af02e9, 0xf8a81382, 0xf8b520bf, 0xf8bb3220, + 0xf8af5344, 0xf8a842dc, 0xf8bb733b, 0xf8b76080, + 0xf8e68010, 0xf8e4002f, 0xf8ea10a7, 0xf8ea20fc, + 0xf8f432b7, 0xf8e6510b, 0xf8f140df, 0xf8f17182, + 0xf8fe607d, 0xf87b83b6, 0xf86e038d, 0xf87110b8, + 0xf862214e, 0xf870336b, 0xf877508c, 0xf8764091, + 0xf8617213, 0xf87061cd, 0xb82c8222, 0xb82302f5, + 0xb82510e6, 0xb833238d, 0xb83130d0, 0xb822507d, + 0xb82441e6, 0xb834718d, 0xb8346328, 0xb8b48013, + 0xb8ab00d8, 0xb8b411df, 0xb8b02006, 0xb8a7326f, + 0xb8ba5149, 0xb8b742d5, 0xb8bc7062, 0xb8af6293, + 0xb8e783a4, 0xb8e70120, 0xb8f012f4, 0xb8e42150, + 0xb8f7332b, 0xb8e6521f, 0xb8ed4197, 0xb8e1712e, + 0xb8f56350, 0xb86f8084, 0xb87000c8, 0xb87e13a4, + 0xb871235d, 0xb869304f, 0xb86b507d, 0xb8674361, + 0xb87571d0, 0xb86862d0, 0xce3454b9, 0xce107af2, + 0xce608e94, 0xce982664, 0xce788094, 0xce62867a, + 0xcec08108, 0xce728b0e, 0x25a0c49f, 0x2521cabf, + 0x058054b4, 0x0543ab47, 0x050026bb, 0x2560d098, + 0x25a1d6ff, 0x058394b4, 0x0540266e, 0x05003cbc, + 0x25a0c1ac, 0x2561d3f8, 0x05800acd, 0x05403685, + 0x05000c08, 0x2560de64, 0x2521cac5, 0x0583c8b6, + 0x05405089, 0x05003e98, 0x25e0ce38, 0x2561db35, + 0x058011ad, 0x05400e4e, 0x05002676, 0x2520dae3, + 0x2561d0d3, 0x05808871, 0x0543abe2, 0x050011ab, + 0x0423019e, 0x04e30537, 0x65d3007c, 0x65950b47, + 0x659a0505, 0x0416b236, 0x04400a83, 0x049a0dc8, + 0x04d089b1, 0x045b1e72, 0x0499af70, 0x045ab51c, + 0x04591f85, 0x04938f20, 0x04918075, 0x04d0075a, + 0x0457b033, 0x041ebdce, 0x049803f2, 0x056797d7, + 0x05a48008, 0x04881417, 0x044a1b1a, 0x04011456, + 0x04dcb58b, 0x65c09938, 0x65cd9691, 0x65c695a4, + 0x65c79ff6, 0x658291f2, 0x049dbe8d, 0x6582adc1, + 0x65c0a987, 0x6581b9e4, 0x65cdbc23, 0x65c197e5, + 0x65ee8d2d, 0x65a30f81, 0x65a92b3a, 0x65e1a9da, + 0x65f4c7ba, 0x65e1fda6, 0x65a1482b, 0x65a279fb, + 0x0402533e, 0x045d6358, 0x042e32c3, 0x04a4323c, + 0x0462321b, 0x04e73381, 0x05706b9f, 0x053d6e36, + 0x65c88596, 0x454bb12b, 0x4597b480, 0x04243874, + 0x04da27cf, 0x04d826bb, 0x04d93c6a, 0x040828c4, + 0x04ca2735, 0x65c73bfe, 0x65c62981, 0x65d82b2d, + 0x04c13ee1, 0x0e3612b4, 0x4e221020, 0x0e7712d5, + 0x4e691107, 0x0ea1101f, 0x4ebf13dd, 0x2e3d139b, + 0x6e3812f6, 0x2e6a1128, 0x6e7f13dd, 0x2ebc137a, + 0x6eb612b4, }; // END Generated code -- do not edit From 216f113f8b377054bcfccf875ab29e967164d8ab Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 4 Mar 2025 15:42:03 +0000 Subject: [PATCH 215/587] 8344892: beans/finder/MethodFinder.findMethod incorrectly returns null Reviewed-by: aivanov, serb --- .../share/classes/com/sun/beans/finder/MethodFinder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java b/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java index 5283cbfce0d..d05e2f81cf5 100644 --- a/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java +++ b/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.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 @@ -77,8 +77,7 @@ public final class MethodFinder extends AbstractFinder { Signature signature = new Signature(type, name, args); try { - Method method = CACHE.get(signature); - return (method == null) ? method : CACHE.create(signature); + return CACHE.get(signature); } catch (SignatureException exception) { throw exception.toNoSuchMethodException("Method '" + name + "' is not found"); From 6a31aaeb00b6c37e2e19c5f2759c4aa9ed87f25a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Mar 2025 16:22:28 +0000 Subject: [PATCH 216/587] 8350594: Misleading warning about install dir for DMG packaging Reviewed-by: almatvee --- .../internal/MacBaseInstallerBundler.java | 20 ++- .../resources/MacResources.properties | 4 +- .../jdk/jpackage/test/JPackageCommand.java | 9 +- .../helpers/jdk/jpackage/test/MacHelper.java | 26 +++- .../tools/jpackage/share/InstallDirTest.java | 140 ++++++++++++++++-- 5 files changed, 167 insertions(+), 32 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index 69ecce068e7..beb8072ea37 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.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 @@ -102,16 +102,20 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { static String getInstallDir( Map params, boolean defaultOnly) { String returnValue = INSTALL_DIR.fetchFrom(params); - if (defaultOnly && returnValue != null) { - Log.info(I18N.getString("message.install-dir-ignored")); + + final String defaultInstallDir; + if (StandardBundlerParam.isRuntimeInstaller(params)) { + defaultInstallDir = "/Library/Java/JavaVirtualMachines"; + } else { + defaultInstallDir = "/Applications"; + } + + if (defaultOnly && returnValue != null && !Path.of(returnValue).equals(Path.of(defaultInstallDir))) { + Log.info(MessageFormat.format(I18N.getString("message.install-dir-ignored"), defaultInstallDir)); returnValue = null; } if (returnValue == null) { - if (StandardBundlerParam.isRuntimeInstaller(params)) { - returnValue = "/Library/Java/JavaVirtualMachines"; - } else { - returnValue = "/Applications"; - } + returnValue = defaultInstallDir; } return returnValue; } 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 e0a555b3698..2f6d5b02bb6 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 @@ -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 @@ -91,7 +91,7 @@ message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. -message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to /Applications. +message.install-dir-ignored=Warning: "--install-dir" option is ignored for DMG packaging. The installation directory will default to {0}. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. 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}. 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 6fc5cfad3f9..2d5d035512b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -71,6 +71,7 @@ public class JPackageCommand extends CommandArguments { ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; immutable = cmd.immutable; + dmgInstallDir = cmd.dmgInstallDir; prerequisiteActions = new Actions(cmd.prerequisiteActions); verifyActions = new Actions(cmd.verifyActions); appLayoutAsserts = cmd.appLayoutAsserts; @@ -497,7 +498,11 @@ public class JPackageCommand extends CommandArguments { } if (TKit.isOSX()) { - return MacHelper.getInstallationDirectory(this); + if (packageType() == PackageType.MAC_DMG && dmgInstallDir != null) { + return dmgInstallDir; + } else { + return MacHelper.getInstallationDirectory(this); + } } throw TKit.throwUnknownPlatformError(); @@ -868,6 +873,7 @@ public class JPackageCommand extends CommandArguments { var copy = new JPackageCommand(cmd); copy.immutable = false; copy.removeArgumentWithValue("--runtime-image"); + copy.dmgInstallDir = cmd.appInstallationDirectory(); return copy; } @@ -1165,6 +1171,7 @@ public class JPackageCommand extends CommandArguments { private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; private boolean immutable; + private Path dmgInstallDir; private final Actions prerequisiteActions; private final Actions verifyActions; private Path executeInDirectory; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 2256963999a..72706129213 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -22,6 +22,8 @@ */ package jdk.jpackage.test; +import static java.util.stream.Collectors.toSet; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -29,13 +31,12 @@ import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static java.util.stream.Collectors.toSet; import java.util.stream.Stream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -43,13 +44,13 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.RetryExecutor; +import jdk.jpackage.internal.util.PathUtils; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; -import jdk.jpackage.internal.RetryExecutor; -import jdk.jpackage.internal.util.PathUtils; -import org.xml.sax.SAXException; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; public final class MacHelper { @@ -298,9 +299,18 @@ public final class MacHelper { static Path getInstallationDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); - return Path.of(cmd.getArgumentValue("--install-dir", - () -> cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications")).resolve( - cmd.name() + (cmd.isRuntime() ? "" : ".app")); + + final var defaultInstallLocation = Path.of( + cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications"); + + final Path installLocation; + if (cmd.packageType() == PackageType.MAC_DMG) { + installLocation = defaultInstallLocation; + } else { + installLocation = cmd.getArgumentValue("--install-dir", () -> defaultInstallLocation, Path::of); + } + + return installLocation.resolve(cmd.name() + (cmd.isRuntime() ? "" : ".app")); } static Path getUninstallCommand(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 672a435d220..2c14e863910 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -22,12 +22,20 @@ */ import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; -import jdk.jpackage.test.TKit; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Annotations.Parameter; -import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.TKit.TextStreamVerifier; /** * Test --install-dir parameter. Output of the test should be @@ -57,6 +65,7 @@ import jdk.jpackage.test.Annotations.Test; * @key jpackagePlatformPackage * @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 * --jpt-run=InstallDirTest.testCommon */ @@ -68,10 +77,9 @@ import jdk.jpackage.test.Annotations.Test; * @key jpackagePlatformPackage * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror InstallDirTest.java - * @requires (os.family == "linux") * @requires (jpackage.test.SQETest == null) - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=InstallDirTest.testLinuxInvalid + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=InstallDirTest */ public class InstallDirTest { @@ -92,11 +100,6 @@ public class InstallDirTest { @Parameter("foo") @Parameter("/opt/foo/.././.") public static void testLinuxInvalid(String installDir) { - testLinuxBad(installDir, "Invalid installation directory"); - } - - private static void testLinuxBad(String installDir, - String errorMessageSubstring) { new PackageTest().configureHelloApp() .setExpectedExitCode(1) .forTypes(PackageType.LINUX) @@ -105,9 +108,120 @@ public class InstallDirTest { cmd.saveConsoleOutput(true); }) .addBundleVerifier((cmd, result) -> { - TKit.assertTextStream(errorMessageSubstring).apply( - result.getOutput().stream()); + cmd.validateOutput(JPackageStringBundle.MAIN.cannedFormattedString("error.invalid-install-dir")); }) .run(); } + + record DmgTestSpec(Path installDir, boolean installDirIgnored, boolean runtimeInstaller) { + + DmgTestSpec { + Objects.requireNonNull(installDir); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + Builder ignoredInstallDir(String v) { + installDir = Path.of(v); + installDirIgnored = true; + return this; + } + + Builder acceptedInstallDir(String v) { + installDir = Path.of(v); + installDirIgnored = false; + return this; + } + + Builder runtimeInstaller() { + runtimeInstaller = true; + return this; + } + + DmgTestSpec create() { + return new DmgTestSpec(installDir, installDirIgnored, runtimeInstaller); + } + + private Path installDir; + private boolean installDirIgnored; + private boolean runtimeInstaller; + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append(installDir); + if (installDirIgnored) { + sb.append(", ignore"); + } + if (runtimeInstaller) { + sb.append(", runtime"); + } + return sb.toString(); + } + + void run() { + final var test = new PackageTest().forTypes(PackageType.MAC_DMG).ignoreBundleOutputDir(); + if (runtimeInstaller) { + test.addInitializer(cmd -> { + cmd.removeArgumentWithValue("--input"); + }); + } else { + test.configureHelloApp(); + } + + test.addInitializer(JPackageCommand::setFakeRuntime).addInitializer(cmd -> { + cmd.addArguments("--install-dir", installDir); + cmd.validateOutput(createInstallDirWarningVerifier()); + }).run(Action.CREATE_AND_UNPACK); + } + + private TextStreamVerifier createInstallDirWarningVerifier() { + final var verifier = TKit.assertTextStream( + JPackageStringBundle.MAIN.cannedFormattedString("message.install-dir-ignored", defaultDmgInstallDir()).getValue()); + if (installDirIgnored) { + return verifier; + } else { + return verifier.negate(); + } + } + + private String defaultDmgInstallDir() { + if (runtimeInstaller) { + return "/Library/Java/JavaVirtualMachines"; + } else { + return "/Applications"; + } + } + } + + @Test(ifOS = OperatingSystem.MACOS) + @ParameterSupplier + public static void testDmg(DmgTestSpec testSpec) { + testSpec.run(); + } + + public static List testDmg() { + return Stream.of( + DmgTestSpec.build().ignoredInstallDir("/foo"), + DmgTestSpec.build().ignoredInstallDir("/foo/bar"), + DmgTestSpec.build().ignoredInstallDir("/foo").runtimeInstaller(), + DmgTestSpec.build().ignoredInstallDir("/foo/bar").runtimeInstaller(), + + DmgTestSpec.build().ignoredInstallDir("/Library/Java/JavaVirtualMachines"), + DmgTestSpec.build().ignoredInstallDir("/Applications").runtimeInstaller(), + + DmgTestSpec.build().acceptedInstallDir("/Applications"), + DmgTestSpec.build().ignoredInstallDir("/Applications/foo/bar/buz"), + + DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines"), + DmgTestSpec.build().runtimeInstaller().ignoredInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz") + ).map(DmgTestSpec.Builder::create).map(testSpec -> { + return new Object[] { testSpec }; + }).toList(); + } } From daf0213abc2c860246564b361061dbda9bd9982f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 4 Mar 2025 16:58:15 +0000 Subject: [PATCH 217/587] 8350924: javax/swing/JMenu/4213634/bug4213634.java fails Reviewed-by: aivanov, tr --- .../javax/swing/JMenu/4213634/bug4213634.java | 90 ++++++++----------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/test/jdk/javax/swing/JMenu/4213634/bug4213634.java b/test/jdk/javax/swing/JMenu/4213634/bug4213634.java index dd699b7e5bc..ad26ff2bc59 100644 --- a/test/jdk/javax/swing/JMenu/4213634/bug4213634.java +++ b/test/jdk/javax/swing/JMenu/4213634/bug4213634.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 @@ -21,103 +21,91 @@ * questions. */ -import java.awt.AWTException; import java.awt.Robot; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.KeyEvent; -import java.lang.reflect.InvocationTargetException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; -import javax.swing.JTextArea; import javax.swing.SwingUtilities; /* * @test * @key headful * @bug 4213634 8017187 - * @author Scott Violet * @library ../../regtesthelpers * @build Util + * @summary Verifies if Alt+mnemonic char works when + * menu & menuitem have same mnemonic char * @run main bug4213634 */ - public class bug4213634 { - private JMenu menu; + private static JMenu menu; + private static JFrame frame; + private static Robot robot; - private JFrame frame; + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + SwingUtilities.invokeAndWait(bug4213634::createAndShowGUI); - public static void main(String[] args) throws Throwable { - new bug4213634(); + robot.waitForIdle(); + robot.delay(1000); + test(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } } - bug4213634() throws AWTException, InterruptedException, InvocationTargetException { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - createAndShowGUI(); - } - }); - - test(); - } - - public void createAndShowGUI() { - frame = new JFrame("TEST"); + public static void createAndShowGUI() { + frame = new JFrame("bug4213634"); JMenuBar mb = new JMenuBar(); menu = mb.add(createMenu("1 - First Menu", true)); mb.add(createMenu("2 - Second Menu", false)); frame.setJMenuBar(mb); - JTextArea ta = new JTextArea("This test dedicated to Nancy and Kathleen, testers and bowlers extraordinaire\n\n\nNo exception means pass."); - frame.getContentPane().add("Center", ta); JButton button = new JButton("Test"); frame.getContentPane().add("South", button); - frame.setBounds(100, 100, 400, 400); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); frame.setVisible(true); button.requestFocusInWindow(); } - private void test() throws AWTException, InterruptedException, InvocationTargetException { - Robot robot = new Robot(); - robot.setAutoDelay(50); - robot.waitForIdle(); - + private static void test() throws Exception { Util.hitMnemonics(robot, KeyEvent.VK_1); robot.waitForIdle(); + robot.delay(100); - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - if (!menu.isSelected()) { - throw new RuntimeException( - "Failed: Menu didn't remain posted at end of test"); - } else { - System.out.println("Test passed!"); - frame.dispose(); - } + SwingUtilities.invokeAndWait(() -> { + if (!menu.isSelected()) { + throw new RuntimeException( + "Failed: Menu didn't remain posted at end of test"); + } else { + System.out.println("Test passed!"); } }); } - private JMenu createMenu(String str, boolean bFlag) { + + private static JMenu createMenu(String str, boolean bFlag) { JMenuItem menuitem; JMenu menu = new JMenu(str); menu.setMnemonic(str.charAt(0)); - for(int i = 0; i < 10; i ++) { + for (int i = 0; i < 10; i++) { menuitem = new JMenuItem("JMenuItem" + i); - menuitem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - throw new RuntimeException( - "Failed: Mnemonic activated"); - } + menuitem.addActionListener(e -> { + throw new RuntimeException("Failed: Mnemonic activated"); }); - if(bFlag) + if (bFlag) { menuitem.setMnemonic('0' + i); + } menu.add(menuitem); } return menu; From 4aa4b46440dcdb0c7707cc145171a45a9f895c07 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 4 Mar 2025 16:59:19 +0000 Subject: [PATCH 218/587] 8351154: Use -ftrivial-auto-var-init=pattern for clang too Reviewed-by: kbarrett, erikj --- make/autoconf/flags-cflags.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 238c9752fd1..73786587735 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -482,7 +482,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], else DEBUG_CFLAGS_JDK="-DDEBUG" - if test "x$TOOLCHAIN_TYPE" = xgcc; then + if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang ; then INIT_PATTERN_FLAG="-ftrivial-auto-var-init=pattern" FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$INIT_PATTERN_FLAG], IF_TRUE: [ From 5b8d3491bf685a64b72b0ae763697353d09f61a1 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 4 Mar 2025 17:08:54 +0000 Subject: [PATCH 219/587] 4745837: Make grouping usage during parsing apparent in relevant NumberFormat methods Reviewed-by: naoto --- .../share/classes/java/text/NumberFormat.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index e397d4ba15d..710c4e771ff 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.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 @@ -883,14 +883,22 @@ public abstract class NumberFormat extends Format { } /** - * Returns true if grouping is used in this format. For example, in the - * English locale, with grouping on, the number 1234567 might be formatted - * as "1,234,567". The grouping separator as well as the size of each group - * is locale dependent and is determined by sub-classes of NumberFormat. + * Returns true if grouping is used in this format. This applies to both + * formatting and parsing. The grouping separator as well as the size of each + * group is locale dependent and is determined by sub-classes of NumberFormat. + * For example, consider a {@code NumberFormat} that expects a "{@code ,}" + * grouping separator symbol with a grouping size of 3. + *
    + *
  • Formatting {@code 1234567} with grouping on returns {@code "1,234,567"} + *
  • Parsing {@code "1,234,567"} with grouping off returns {@code 1} + *
  • Parsing {@code "1,234,567"} with grouping off when {@link #isStrict()} + * returns {@code true} throws {@code ParseException} + *
* * @return {@code true} if grouping is used; * {@code false} otherwise * @see #setGroupingUsed + * @see ##leniency Leniency Section */ public boolean isGroupingUsed() { return groupingUsed; @@ -898,6 +906,7 @@ public abstract class NumberFormat extends Format { /** * Set whether or not grouping will be used in this format. + * This applies to both formatting and parsing. * * @param newValue {@code true} if grouping is used; * {@code false} otherwise From fe806caa160b2d550db273af17dc08270f143819 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 4 Mar 2025 17:11:59 +0000 Subject: [PATCH 220/587] 8350605: assert(!heap->is_uncommit_in_progress()) failed: Cannot uncommit bitmaps while resetting them Reviewed-by: kdnilsen, ysr --- .../shenandoah/shenandoahUncommitThread.cpp | 79 +++++++++++-------- .../shenandoah/shenandoahUncommitThread.hpp | 14 ++-- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.cpp index 5f9bc7c9b91..ec708b198e7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.cpp @@ -31,8 +31,7 @@ ShenandoahUncommitThread::ShenandoahUncommitThread(ShenandoahHeap* heap) : _heap(heap), - _stop_lock(Mutex::safepoint - 2, "ShenandoahUncommitStop_lock", true), - _uncommit_lock(Mutex::safepoint - 2, "ShenandoahUncommitCancel_lock", true) { + _uncommit_lock(Mutex::safepoint - 2, "ShenandoahUncommit_lock", true) { set_name("Shenandoah Uncommit Thread"); create_and_start(); @@ -68,11 +67,10 @@ void ShenandoahUncommitThread::run_service() { uncommit(shrink_before, shrink_until); } } - { - MonitorLocker locker(&_stop_lock, Mutex::_no_safepoint_check_flag); - if (!_stop_requested.is_set()) { - timed_out = locker.wait(poll_interval); - } + + if (!should_terminate()) { + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); + timed_out = locker.wait(poll_interval); } } } @@ -104,7 +102,7 @@ bool ShenandoahUncommitThread::has_work(double shrink_before, size_t shrink_unti void ShenandoahUncommitThread::notify_soft_max_changed() { assert(is_uncommit_allowed(), "Only notify if uncommit is allowed"); if (_soft_max_changed.try_set()) { - MonitorLocker locker(&_stop_lock, Mutex::_no_safepoint_check_flag); + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); locker.notify_all(); } } @@ -112,7 +110,7 @@ void ShenandoahUncommitThread::notify_soft_max_changed() { void ShenandoahUncommitThread::notify_explicit_gc_requested() { assert(is_uncommit_allowed(), "Only notify if uncommit is allowed"); if (_explicit_gc_requested.try_set()) { - MonitorLocker locker(&_stop_lock, Mutex::_no_safepoint_check_flag); + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); locker.notify_all(); } } @@ -125,33 +123,64 @@ void ShenandoahUncommitThread::uncommit(double shrink_before, size_t shrink_unti assert(ShenandoahUncommit, "should be enabled"); assert(_uncommit_in_progress.is_unset(), "Uncommit should not be in progress"); - if (!is_uncommit_allowed()) { + { + // Final check, under the lock, if uncommit is allowed. + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); + if (is_uncommit_allowed()) { + _uncommit_in_progress.set(); + } + } + + // If not allowed to start, do nothing. + if (!_uncommit_in_progress.is_set()) { return; } + // From here on, uncommit is in progress. Attempts to stop the uncommit must wait + // until the cancellation request is acknowledged and uncommit is no longer in progress. const char* msg = "Concurrent uncommit"; + const double start = os::elapsedTime(); EventMark em("%s", msg); - double start = os::elapsedTime(); log_info(gc, start)("%s", msg); - _uncommit_in_progress.set(); + // This is the number of regions uncommitted during this increment of uncommit work. + const size_t uncommitted_region_count = do_uncommit_work(shrink_before, shrink_until); + { + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); + _uncommit_in_progress.unset(); + locker.notify_all(); + } + + if (uncommitted_region_count > 0) { + _heap->notify_heap_changed(); + } + + const double elapsed = os::elapsedTime() - start; + log_info(gc)("%s " PROPERFMT " (" PROPERFMT ") %.3fms", + msg, PROPERFMTARGS(uncommitted_region_count * ShenandoahHeapRegion::region_size_bytes()), PROPERFMTARGS(_heap->capacity()), + elapsed * MILLIUNITS); +} + +size_t ShenandoahUncommitThread::do_uncommit_work(double shrink_before, size_t shrink_until) const { + size_t count = 0; // Application allocates from the beginning of the heap, and GC allocates at // the end of it. It is more efficient to uncommit from the end, so that applications // could enjoy the near committed regions. GC allocations are much less frequent, // and therefore can accept the committing costs. - size_t count = 0; for (size_t i = _heap->num_regions(); i > 0; i--) { if (!is_uncommit_allowed()) { + // GC wants to start, so the uncommit operation must stop break; } ShenandoahHeapRegion* r = _heap->get_region(i - 1); if (r->is_empty_committed() && (r->empty_time() < shrink_before)) { SuspendibleThreadSetJoiner sts_joiner; - ShenandoahHeapLocker locker(_heap->lock()); + ShenandoahHeapLocker heap_locker(_heap->lock()); if (r->is_empty_committed()) { if (_heap->committed() < shrink_until + ShenandoahHeapRegion::region_size_bytes()) { + // We have uncommitted enough regions to hit the target heap committed size break; } @@ -161,26 +190,13 @@ void ShenandoahUncommitThread::uncommit(double shrink_before, size_t shrink_unti } SpinPause(); // allow allocators to take the lock } - - { - MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); - _uncommit_in_progress.unset(); - locker.notify_all(); - } - - if (count > 0) { - _heap->notify_heap_changed(); - } - - double elapsed = os::elapsedTime() - start; - log_info(gc)("%s " PROPERFMT " (" PROPERFMT ") %.3fms", - msg, PROPERFMTARGS(count * ShenandoahHeapRegion::region_size_bytes()), PROPERFMTARGS(_heap->capacity()), - elapsed * MILLIUNITS); + return count; } + void ShenandoahUncommitThread::stop_service() { - MonitorLocker locker(&_stop_lock, Mutex::_safepoint_check_flag); - _stop_requested.set(); + MonitorLocker locker(&_uncommit_lock, Mutex::_safepoint_check_flag); + _uncommit_allowed.unset(); locker.notify_all(); } @@ -193,5 +209,6 @@ void ShenandoahUncommitThread::forbid_uncommit() { } void ShenandoahUncommitThread::allow_uncommit() { + MonitorLocker locker(&_uncommit_lock, Mutex::_no_safepoint_check_flag); _uncommit_allowed.set(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.hpp index 6c4e26e4e0f..caffd2ef87b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUncommitThread.hpp @@ -38,18 +38,12 @@ class ShenandoahUncommitThread : public ConcurrentGCThread { // Indicates that an explicit gc has been requested ShenandoahSharedFlag _explicit_gc_requested; - // Indicates that the thread should stop and terminate - ShenandoahSharedFlag _stop_requested; - // Indicates whether it is safe to uncommit regions ShenandoahSharedFlag _uncommit_allowed; // Indicates that regions are being actively uncommitted ShenandoahSharedFlag _uncommit_in_progress; - // This lock is used to coordinate stopping and terminating this thread - Monitor _stop_lock; - // This lock is used to coordinate allowing or forbidding regions to be uncommitted Monitor _uncommit_lock; @@ -66,6 +60,12 @@ class ShenandoahUncommitThread : public ConcurrentGCThread { // True if the control thread has allowed this thread to uncommit regions bool is_uncommit_allowed() const; + // Iterate over and uncommit eligible regions until committed heap falls below + // `shrink_until` bytes. A region is eligible for uncommit if the timestamp at which + // it was last made empty is before `shrink_before` seconds since jvm start. + // Returns the number of regions uncommitted. May be interrupted by `forbid_uncommit`. + size_t do_uncommit_work(double shrink_before, size_t shrink_until) const; + public: explicit ShenandoahUncommitThread(ShenandoahHeap* heap); @@ -85,7 +85,7 @@ public: void allow_uncommit(); // True if uncommit is in progress - bool is_uncommit_in_progress() { + bool is_uncommit_in_progress() const { return _uncommit_in_progress.is_set(); } protected: From 55987925fd8ba5d7782934194141fe425a9041be Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 4 Mar 2025 17:39:55 +0000 Subject: [PATCH 221/587] 8351064: JFR: Consistent timestamps Reviewed-by: mgronlun --- .../classes/jdk/jfr/internal/consumer/ChunkParser.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java index e664f2c728b..67143ee1265 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java @@ -127,7 +127,11 @@ public final class ChunkParser { this.configuration = previous.configuration; } this.metadata = header.readMetadata(previousMetadata); - this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset() + metadata.getDST()); + if (previous == null) { + this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset() + metadata.getDST()); + } else { + this.timeConverter = previous.timeConverter; + } if (metadata != previousMetadata) { ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); parsers = factory.getParsers(); From 0753376b0c3d0d98e3db14d26020b23822176557 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 4 Mar 2025 19:32:33 +0000 Subject: [PATCH 222/587] 8297531: sun/security/krb5/MicroTime.java fails with "Exception: What? only 100 musec precision?" Reviewed-by: mullan, abarashev --- test/jdk/sun/security/krb5/MicroTime.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jdk/sun/security/krb5/MicroTime.java b/test/jdk/sun/security/krb5/MicroTime.java index 8b6b9232415..84a88cedf83 100644 --- a/test/jdk/sun/security/krb5/MicroTime.java +++ b/test/jdk/sun/security/krb5/MicroTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, 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 @@ -44,9 +44,10 @@ public class MicroTime { count++; } } - // We believe a nice KerberosTime can at least tell the - // difference of 100 musec. - if (count < 10000) { + // Before JDK-6882687, KerberosTime was measured in milliseconds. + // Now it's in microseconds. We should be able to record more than + // 1000 distinct KerberosTime values within one second. + if (count < 1001) { throw new Exception("What? only " + (1000000/count) + " musec precision?"); } From a21302bb3244b85dd9809c42d1c0fd502bd677cc Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 4 Mar 2025 20:10:57 +0000 Subject: [PATCH 223/587] 8351036: [JVMCI] value not an s2: -32776 Reviewed-by: yzheng, dlong --- .../share/jvmci/jvmciCodeInstaller.cpp | 11 +++++-- .../share/jvmci/jvmciCodeInstaller.hpp | 4 +++ src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +++ .../ci/hotspot/HotSpotCompiledCodeStream.java | 33 +++++++++++++++---- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 1732719d64c..79aaacec809 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -388,6 +388,7 @@ Handle CodeInstaller::read_oop(HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_ ScopeValue* CodeInstaller::get_scope_value(HotSpotCompiledCodeStream* stream, u1 tag, BasicType type, ScopeValue* &second, JVMCI_TRAPS) { second = nullptr; + bool stack_slot_is_s2 = true; switch (tag) { case ILLEGAL: { if (type != T_ILLEGAL) { @@ -436,11 +437,17 @@ ScopeValue* CodeInstaller::get_scope_value(HotSpotCompiledCodeStream* stream, u1 return value; } } + case STACK_SLOT4_PRIMITIVE: + case STACK_SLOT4_NARROW_OOP: + case STACK_SLOT4_OOP: + case STACK_SLOT4_VECTOR: + stack_slot_is_s2 = false; + // fall through case STACK_SLOT_PRIMITIVE: case STACK_SLOT_NARROW_OOP: case STACK_SLOT_OOP: case STACK_SLOT_VECTOR: { - jint offset = (jshort) stream->read_s2("offset"); + jint offset = stack_slot_is_s2 ? (jshort) stream->read_s2("offset") : stream->read_s4("offset4"); if (stream->read_bool("addRawFrameSize")) { offset += _total_frame_size; } @@ -854,7 +861,7 @@ void CodeInstaller::initialize_fields(HotSpotCompiledCodeStream* stream, u1 code if (!is_set(code_flags, HCC_HAS_DEOPT_RESCUE_SLOT)) { _orig_pc_offset = -1; } else { - _orig_pc_offset = stream->read_s2("offset"); + _orig_pc_offset = stream->read_s4("offset"); if (stream->read_bool("addRawFrameSize")) { _orig_pc_offset += _total_frame_size; } diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp index b493c48e348..a8279e99dc2 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp @@ -207,6 +207,10 @@ private: STACK_SLOT_OOP, STACK_SLOT_NARROW_OOP, STACK_SLOT_VECTOR, + STACK_SLOT4_PRIMITIVE, + STACK_SLOT4_OOP, + STACK_SLOT4_NARROW_OOP, + STACK_SLOT4_VECTOR, VIRTUAL_OBJECT_ID, VIRTUAL_OBJECT_ID2, NULL_CONSTANT, diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7567caad712..e574fa780f4 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -585,6 +585,10 @@ declare_constant(CodeInstaller::STACK_SLOT_OOP) \ declare_constant(CodeInstaller::STACK_SLOT_NARROW_OOP) \ declare_constant(CodeInstaller::STACK_SLOT_VECTOR) \ + declare_constant(CodeInstaller::STACK_SLOT4_PRIMITIVE) \ + declare_constant(CodeInstaller::STACK_SLOT4_OOP) \ + declare_constant(CodeInstaller::STACK_SLOT4_NARROW_OOP) \ + declare_constant(CodeInstaller::STACK_SLOT4_VECTOR) \ declare_constant(CodeInstaller::VIRTUAL_OBJECT_ID) \ declare_constant(CodeInstaller::VIRTUAL_OBJECT_ID2) \ declare_constant(CodeInstaller::NULL_CONSTANT) \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java index 49dfdcea5a2..2cd5e839ee8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java @@ -63,6 +63,10 @@ import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT_NARROW_ import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT_OOP; import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT_PRIMITIVE; import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT_VECTOR; +import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT4_NARROW_OOP; +import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT4_OOP; +import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT4_PRIMITIVE; +import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.STACK_SLOT4_VECTOR; import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.VIRTUAL_OBJECT_ID; import static jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag.VIRTUAL_OBJECT_ID2; @@ -178,6 +182,10 @@ final class HotSpotCompiledCodeStream implements AutoCloseable { STACK_SLOT_OOP, STACK_SLOT_NARROW_OOP, STACK_SLOT_VECTOR, + STACK_SLOT4_PRIMITIVE, + STACK_SLOT4_OOP, + STACK_SLOT4_NARROW_OOP, + STACK_SLOT4_VECTOR, VIRTUAL_OBJECT_ID, VIRTUAL_OBJECT_ID2, NULL_CONSTANT, @@ -457,8 +465,12 @@ final class HotSpotCompiledCodeStream implements AutoCloseable { rawWriteU2(name, value); } + private static boolean isS2(int value) { + return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; + } + private void writeS2(String name, int value) { - if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + if (!isS2(value)) { throw error("value not an s2: " + value); } rawWriteU2(name, value); @@ -581,7 +593,8 @@ final class HotSpotCompiledCodeStream implements AutoCloseable { writeInt("targetCodeSize", code.targetCodeSize); writeInt("totalFrameSize", code.totalFrameSize); if (isSet(flags, HAS_DEOPT_RESCUE_SLOT)) { - writeS2("offset", deoptRescueSlot.getRawOffset()); + int offset = deoptRescueSlot.getRawOffset(); + writeInt("offset", offset); writeBoolean("addRawFrameSize", deoptRescueSlot.getRawAddFrameSize()); } writeInt("dataSectionSize", code.dataSection.length); @@ -1063,17 +1076,25 @@ final class HotSpotCompiledCodeStream implements AutoCloseable { } else if (value instanceof StackSlot) { StackSlot slot = (StackSlot) value; Tag tag; + int offset = slot.getRawOffset(); + boolean s2 = isS2(offset); if (kind == JavaKind.Object) { if (isVector(slot)) { - tag = STACK_SLOT_VECTOR; + tag = s2 ? STACK_SLOT_VECTOR : STACK_SLOT4_VECTOR; + } else if (isNarrowOop(slot)) { + tag = s2 ? STACK_SLOT_NARROW_OOP : STACK_SLOT4_NARROW_OOP; } else { - tag = isNarrowOop(slot) ? STACK_SLOT_NARROW_OOP : STACK_SLOT_OOP; + tag = s2 ? STACK_SLOT_OOP : STACK_SLOT4_OOP; } } else { - tag = STACK_SLOT_PRIMITIVE; + tag = s2 ? STACK_SLOT_PRIMITIVE : STACK_SLOT4_PRIMITIVE; } writeTag(tag); - writeS2("offset", slot.getRawOffset()); + if (s2) { + writeS2("offset", slot.getRawOffset()); + } else { + writeInt("offset4", slot.getRawOffset()); + } writeBoolean("addRawFrameSize", slot.getRawAddFrameSize()); } else if (value instanceof VirtualObject) { VirtualObject vo = (VirtualObject) value; From 3e86b3a879c7a425e7c689142cb1f0fdd4f679ed Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 4 Mar 2025 20:30:52 +0000 Subject: [PATCH 224/587] 8350013: Add a test for JDK-8150442 Reviewed-by: almatvee --- .../jdk/jpackage/test/PackageTestTest.java | 894 ++++++++++++++++++ .../jdk/jpackage/test/JPackageCommand.java | 19 + .../jdk/jpackage/test/LinuxHelper.java | 99 +- .../helpers/jdk/jpackage/test/MacHelper.java | 178 ++-- .../jdk/jpackage/test/PackageTest.java | 603 +++++++----- .../jdk/jpackage/test/WindowsHelper.java | 298 +++--- .../jpackage/resources/fail-os-condition.wxf | 32 + .../jpackage/windows/WinOSConditionTest.java | 77 ++ 8 files changed, 1719 insertions(+), 481 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java create mode 100644 test/jdk/tools/jpackage/resources/fail-os-condition.wxf create mode 100644 test/jdk/tools/jpackage/windows/WinOSConditionTest.java diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java new file mode 100644 index 00000000000..433db6fc6f6 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/PackageTestTest.java @@ -0,0 +1,894 @@ +/* + * 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.test; + +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.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import jdk.jpackage.internal.util.function.ThrowingConsumer; +import jdk.jpackage.internal.util.function.ThrowingRunnable; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.PackageTest.PackageHandlers; +import jdk.jpackage.test.RunnablePackageTest.Action; + +public class PackageTestTest extends JUnitAdapter { + + private interface Verifiable { + void verify(); + } + + private static class CallbackFactory { + + CallbackFactory(int tickCount) { + this.tickCount = tickCount; + } + + CountingInstaller createInstaller(int exitCode) { + return new CountingInstaller(tickCount, exitCode); + } + + CountingConsumer createUninstaller() { + return new CountingConsumer(tickCount, "uninstall"); + } + + CountingUnpacker createUnpacker() { + return new CountingUnpacker(tickCount); + } + + CountingConsumer createInitializer() { + return new CountingConsumer(tickCount, "init"); + } + + CountingRunnable createRunOnceInitializer() { + return new CountingRunnable(tickCount, "once-init"); + } + + CountingConsumer createInstallVerifier() { + return new CountingConsumer(tickCount, "on-install"); + } + + CountingConsumer createUninstallVerifier() { + return new CountingConsumer(tickCount, "on-uninstall"); + } + + CountingConsumer createBundleVerifier() { + return new CountingConsumer(tickCount, "on-bundle"); + } + + CountingBundleVerifier createBundleVerifier(int jpackageExitCode) { + return new CountingBundleVerifier(tickCount, jpackageExitCode); + } + + private final int tickCount; + } + + private final static int ERROR_EXIT_CODE_JPACKAGE = 35; + private final static int ERROR_EXIT_CODE_INSTALL = 27; + + private final static CallbackFactory NEVER = new CallbackFactory(0); + private final static CallbackFactory ONCE = new CallbackFactory(1); + private final static CallbackFactory TWICE = new CallbackFactory(2); + + enum BundleVerifier { + ONCE_SUCCESS(ONCE), + ONCE_FAIL(ONCE), + NEVER(PackageTestTest.NEVER), + ONCE_SUCCESS_EXIT_CODE(ONCE, 0), + ONCE_FAIL_EXIT_CODE(ONCE, ERROR_EXIT_CODE_JPACKAGE), + NEVER_EXIT_CODE(PackageTestTest.NEVER, 0); + + BundleVerifier(CallbackFactory factory) { + specSupplier = () -> new BundleVerifierSpec(Optional.of(factory.createBundleVerifier()), Optional.empty()); + } + + BundleVerifier(CallbackFactory factory, int jpackageExitCode) { + specSupplier = () -> new BundleVerifierSpec(Optional.empty(), + Optional.of(factory.createBundleVerifier(jpackageExitCode))); + } + + BundleVerifierSpec spec() { + return specSupplier.get(); + } + + private final Supplier specSupplier; + } + + private static class TickCounter implements Verifiable { + + TickCounter(int expectedTicks) { + this.expectedTicks = expectedTicks; + } + + void tick() { + ticks++; + } + + @Override + public void verify() { + switch (expectedTicks) { + case 0 -> { + TKit.assertEquals(expectedTicks, ticks, String.format("%s: never called", this)); + } + case 1 -> { + TKit.assertEquals(expectedTicks, ticks, String.format("%s: called once", this)); + } + case 2 -> { + TKit.assertEquals(expectedTicks, ticks, String.format("%s: called twice", this)); + } + default -> { + TKit.assertEquals(expectedTicks, ticks, toString()); + } + } + } + + protected int tickCount() { + return ticks; + } + + protected static String getDescription(TickCounter o) { + return "tk=" + o.expectedTicks; + } + + private int ticks; + protected final int expectedTicks; + } + + private static class CountingConsumer extends TickCounter implements ThrowingConsumer { + + @Override + public void accept(JPackageCommand cmd) { + tick(); + } + + @Override + public String toString() { + return String.format("%s(%s)", label, TickCounter.getDescription(this)); + } + + CountingConsumer(int expectedTicks, String label) { + super(expectedTicks); + this.label = Objects.requireNonNull(label); + } + + private final String label; + } + + private static class CountingRunnable extends TickCounter implements ThrowingRunnable { + + @Override + public void run() { + tick(); + } + + @Override + public String toString() { + return String.format("%s(%s)", label, TickCounter.getDescription(this)); + } + + CountingRunnable(int expectedTicks, String label) { + super(expectedTicks); + this.label = Objects.requireNonNull(label); + } + + private final String label; + } + + private static class CountingBundleVerifier extends TickCounter implements ThrowingBiConsumer { + + @Override + public void accept(JPackageCommand cmd, Executor.Result result) { + tick(); + jpackageExitCode = result.exitCode(); + } + + @Override + public void verify() { + super.verify(); + if (expectedTicks > 0) { + TKit.assertEquals(expectedJPackageExitCode, jpackageExitCode, String.format("%s: run jpackage", this)); + } + } + + @Override + public String toString() { + return String.format("on-bundle-ex(exit=%d, %s)", expectedJPackageExitCode, TickCounter.getDescription(this)); + } + + CountingBundleVerifier(int expectedTicks, int expectedJPackageExitCode) { + super(expectedTicks); + this.expectedJPackageExitCode = expectedJPackageExitCode; + } + + private int jpackageExitCode; + private final int expectedJPackageExitCode; + } + + private final static class CountingInstaller extends TickCounter implements Function { + + @Override + public Integer apply(JPackageCommand cmd) { + tick(); + return exitCode; + } + + @Override + public String toString() { + return String.format("install(exit=%d, %s)", exitCode, TickCounter.getDescription(this)); + } + + CountingInstaller(int expectedTicks, int exitCode) { + super(expectedTicks); + this.exitCode = exitCode; + } + + private final int exitCode; + } + + private static class CountingUnpacker extends TickCounter implements BiFunction { + + @Override + public Path apply(JPackageCommand cmd, Path path) { + tick(); + try { + Files.createDirectories(path.resolve("mockup-installdir")); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + unpackPaths.add(path); + return path; + } + + @Override + public String toString() { + return String.format("unpack(%s)", TickCounter.getDescription(this)); + } + + CountingUnpacker(int expectedTicks) { + super(expectedTicks); + } + + List unpackPaths() { + return unpackPaths; + } + + private final List unpackPaths = new ArrayList<>(); + } + + record BundleVerifierSpec(Optional verifier, Optional verifierWithExitCode) { + BundleVerifierSpec { + if (verifier.isPresent() == verifierWithExitCode.isPresent()) { + throw new IllegalArgumentException(); + } + } + + Verifiable apply(PackageTest test) { + verifier.ifPresent(test::addBundleVerifier); + verifierWithExitCode.ifPresent(test::addBundleVerifier); + return verifier.map(Verifiable.class::cast).orElseGet(verifierWithExitCode::orElseThrow); + } + + @Override + public String toString() { + return verifier.map(Verifiable.class::cast).orElseGet(verifierWithExitCode::orElseThrow).toString(); + } + } + + record PackageHandlersSpec(CountingInstaller installer, CountingConsumer uninstaller, + Optional unpacker, int installExitCode) { + + PackageHandlers createPackageHandlers(Consumer verifiableAccumulator) { + List.of(installer, uninstaller).forEach(verifiableAccumulator::accept); + unpacker.ifPresent(verifiableAccumulator::accept); + return new PackageHandlers(installer, uninstaller::accept, unpacker); + } + } + + record TestSpec(PackageType type, PackageHandlersSpec handlersSpec, + List initializers, List bundleVerifierSpecs, + List installVerifiers, List uninstallVerifiers, + int expectedJPackageExitCode, int actualJPackageExitCode, List actions) { + + PackageTest createTest(Consumer verifiableAccumulator) { + return createTest(handlersSpec.createPackageHandlers(verifiableAccumulator)); + } + + PackageTest createTest(PackageHandlers handlers) { + return new PackageTest().jpackageFactory(() -> { + return new JPackageCommand() { + @Override + public Path outputBundle() { + return outputDir().resolve("mockup-bundle" + super.packageType().getSuffix()); + } + + @Override + public PackageType packageType() { + return null; + } + + @Override + JPackageCommand assertAppLayout() { + return this; + } + + @Override + JPackageCommand createImmutableCopy() { + return this; + } + + @Override + public void verifyIsOfType(PackageType ... types) { + } + + @Override + public String getPrintableCommandLine() { + return "'mockup jpackage'"; + } + + @Override + public Executor.Result execute(int expectedExitCode) { + final var outputBundle = outputBundle(); + try { + Files.createDirectories(outputBundle.getParent()); + if (actualJPackageExitCode == 0) { + Files.createFile(outputBundle); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + return new Executor.Result(actualJPackageExitCode, null, + this::getPrintableCommandLine).assertExitCodeIs(expectedExitCode); + } + }; + }).setExpectedExitCode(expectedJPackageExitCode) + .setExpectedInstallExitCode(handlersSpec.installExitCode) + .isPackageTypeSupported(type -> true) + .forTypes().packageHandlers(handlers); + } + + void configureInitializers(PackageTest test, Consumer verifiableAccumulator) { + for (final var initializer : initializers) { + verifiableAccumulator.accept(initializer); + test.addInitializer(initializer); + } + } + + void configureBundleVerifiers(PackageTest test, Consumer verifiableAccumulator) { + for (final var verifierSpec : bundleVerifierSpecs) { + verifiableAccumulator.accept(verifierSpec.apply(test)); + } + } + + void configureInstallVerifiers(PackageTest test, Consumer verifiableAccumulator) { + for (final var verifier : installVerifiers) { + verifiableAccumulator.accept(verifier); + test.addInstallVerifier(verifier); + } + } + + void configureUninstallVerifiers(PackageTest test, Consumer verifiableAccumulator) { + for (final var verifier : uninstallVerifiers) { + verifiableAccumulator.accept(verifier); + test.addUninstallVerifier(verifier); + } + } + + void run(PackageTest test) { + final boolean expectedSuccess = (expectedJPackageExitCode == actualJPackageExitCode); + + TKit.assertAssert(expectedSuccess, () -> { + test.run(actions.toArray(Action[]::new)); + }); + } + + List run() { + return run(Optional.empty()); + } + + List run(Consumer customConfigure) { + return run(Optional.of(customConfigure)); + } + + private List run(Optional> customConfigure) { + final List verifiers = new ArrayList<>(); + + final var test = createTest(verifiers::add); + test.forTypes(type); + configureInitializers(test, verifiers::add); + configureBundleVerifiers(test, verifiers::add); + configureInstallVerifiers(test, verifiers::add); + configureUninstallVerifiers(test, verifiers::add); + customConfigure.ifPresent(callback -> callback.accept(test)); + run(test); + verifiers.forEach(Verifiable::verify); + return verifiers; + } + } + + private final static class TestSpecBuilder { + + TestSpecBuilder type(PackageType v) { + type = Objects.requireNonNull(v); + return this; + } + + TestSpecBuilder install(CallbackFactory v) { + install = Objects.requireNonNull(v); + return this; + } + + TestSpecBuilder uninstall(CallbackFactory v) { + uninstall = Objects.requireNonNull(v); + return this; + } + + TestSpecBuilder unpack(CallbackFactory v) { + unpack = v; + return this; + } + + TestSpecBuilder installExitCode(int v) { + installExitCode = v; + return this; + } + + TestSpecBuilder jpackageExitCode(int v) { + return expectedJPackageExitCode(v).actualJPackageExitCode(v); + } + + TestSpecBuilder expectedJPackageExitCode(int v) { + expectedJPackageExitCode = v; + return this; + } + + TestSpecBuilder actualJPackageExitCode(int v) { + actualJPackageExitCode = v; + return this; + } + + TestSpecBuilder addActions(Action... v) { + actions.addAll(List.of(v)); + return this; + } + + TestSpecBuilder actions(Action... v) { + actions.clear(); + return addActions(v); + } + + TestSpecBuilder doCreateAndUnpack() { + actions(Action.CREATE_AND_UNPACK); + install(NEVER); + uninstall(NEVER); + if (willHaveBundle()) { + overrideNonNullUnpack(ONCE); + } else { + overrideNonNullUnpack(NEVER); + } + initializers(ONCE); + if (expectedJPackageExitCode != actualJPackageExitCode) { + bundleVerifiers(BundleVerifier.NEVER.spec()); + } else if (expectedJPackageExitCode == 0) { + bundleVerifiers(BundleVerifier.ONCE_SUCCESS.spec()); + bundleVerifiers(BundleVerifier.ONCE_SUCCESS_EXIT_CODE.spec()); + } else { + bundleVerifiers(BundleVerifier.ONCE_FAIL.spec()); + if (expectedJPackageExitCode == ERROR_EXIT_CODE_JPACKAGE) { + bundleVerifiers(BundleVerifier.ONCE_FAIL_EXIT_CODE.spec()); + } + } + uninstallVerifiers(NEVER); + if (willVerifyUnpack()) { + installVerifiers(ONCE); + } else { + installVerifiers(NEVER); + } + return this; + } + + TestSpecBuilder doCreateUnpackInstallUninstall() { + actions(Action.CREATE, Action.UNPACK, Action.VERIFY_INSTALL, Action.INSTALL, + Action.VERIFY_INSTALL, Action.UNINSTALL, Action.VERIFY_UNINSTALL); + initializers(ONCE); + uninstallVerifiers(NEVER); + if (willHaveBundle()) { + overrideNonNullUnpack(ONCE); + install(ONCE); + if (installExitCode == 0) { + uninstall(ONCE); + uninstallVerifiers(ONCE); + } else { + uninstall(NEVER); + } + } else { + overrideNonNullUnpack(NEVER); + install(NEVER); + uninstall(NEVER); + } + + if (expectedJPackageExitCode != actualJPackageExitCode) { + bundleVerifiers(BundleVerifier.NEVER.spec()); + installVerifiers(NEVER); + } else if (expectedJPackageExitCode == 0) { + bundleVerifiers(BundleVerifier.ONCE_SUCCESS.spec()); + bundleVerifiers(BundleVerifier.ONCE_SUCCESS_EXIT_CODE.spec()); + if (installExitCode == 0) { + if (willVerifyUnpack()) { + installVerifiers(TWICE); + } else { + installVerifiers(ONCE); + } + } else { + if (willVerifyUnpack()) { + installVerifiers(ONCE); + } else { + installVerifiers(NEVER); + } + } + } else { + bundleVerifiers(BundleVerifier.ONCE_FAIL.spec()); + if (expectedJPackageExitCode == ERROR_EXIT_CODE_JPACKAGE) { + bundleVerifiers(BundleVerifier.ONCE_FAIL_EXIT_CODE.spec()); + } + installVerifiers(NEVER); + } + return this; + } + + TestSpecBuilder addInitializers(CallbackFactory... v) { + initializers.addAll(List.of(v)); + return this; + } + + TestSpecBuilder addBundleVerifiers(BundleVerifierSpec... v) { + bundleVerifiers.addAll(List.of(v)); + return this; + } + + TestSpecBuilder addInstallVerifiers(CallbackFactory... v) { + installVerifiers.addAll(List.of(v)); + return this; + } + + TestSpecBuilder addUninstallVerifiers(CallbackFactory... v) { + uninstallVerifiers.addAll(List.of(v)); + return this; + } + + TestSpecBuilder initializers(CallbackFactory... v) { + initializers.clear(); + return addInitializers(v); + } + + TestSpecBuilder bundleVerifiers(BundleVerifierSpec... v) { + bundleVerifiers.clear(); + return addBundleVerifiers(v); + } + + TestSpecBuilder installVerifiers(CallbackFactory... v) { + installVerifiers.clear(); + return addInstallVerifiers(v); + } + + TestSpecBuilder uninstallVerifiers(CallbackFactory... v) { + uninstallVerifiers.clear(); + return addUninstallVerifiers(v); + } + + TestSpec create() { + final var handlersSpec = new PackageHandlersSpec( + install.createInstaller(installExitCode), uninstall.createUninstaller(), + Optional.ofNullable(unpack).map(CallbackFactory::createUnpacker), installExitCode); + return new TestSpec(type, handlersSpec, + initializers.stream().map(CallbackFactory::createInitializer).toList(), + bundleVerifiers, + installVerifiers.stream().map(CallbackFactory::createInstallVerifier).toList(), + uninstallVerifiers.stream().map(CallbackFactory::createUninstallVerifier).toList(), + expectedJPackageExitCode, + actualJPackageExitCode, actions); + } + + boolean willVerifyCreate() { + return actions.contains(Action.CREATE) && actualJPackageExitCode == 0 && expectedJPackageExitCode == actualJPackageExitCode; + } + + boolean willHaveBundle() { + return !actions.contains(Action.CREATE) || willVerifyCreate(); + } + + boolean willVerifyUnpack() { + return actions.contains(Action.UNPACK) && willHaveBundle() && unpack != null; + } + + boolean willVerifyInstall() { + return (actions.contains(Action.INSTALL) && installExitCode == 0) && willHaveBundle(); + } + + private void overrideNonNullUnpack(CallbackFactory v) { + if (unpack != null) { + unpack(v); + } + } + + private PackageType type = PackageType.LINUX_RPM; + private CallbackFactory install = NEVER; + private CallbackFactory uninstall = NEVER; + private CallbackFactory unpack = NEVER; + private int installExitCode; + private final List initializers = new ArrayList<>(); + private final List bundleVerifiers = new ArrayList<>(); + private final List installVerifiers = new ArrayList<>(); + private final List uninstallVerifiers = new ArrayList<>(); + private int expectedJPackageExitCode; + private int actualJPackageExitCode; + private final List actions = new ArrayList<>(); + } + + @Test + @ParameterSupplier + public void test(TestSpec spec) { + spec.run(); + } + + public static List test() { + List data = new ArrayList<>(); + + for (boolean withUnpack : List.of(false, true)) { + for (int actualJPackageExitCode : List.of(0, 1, ERROR_EXIT_CODE_INSTALL)) { + for (int expectedJPackageExitCode : List.of(0, 1, ERROR_EXIT_CODE_INSTALL)) { + data.add(new TestSpecBuilder() + .unpack(withUnpack ? ONCE : null) + .actualJPackageExitCode(actualJPackageExitCode) + .expectedJPackageExitCode(expectedJPackageExitCode) + .doCreateAndUnpack().create()); + } + } + } + + for (boolean withUnpack : List.of(false, true)) { + for (int installExitCode : List.of(0, 1, ERROR_EXIT_CODE_INSTALL)) { + for (int actualJPackageExitCode : List.of(0, 1, ERROR_EXIT_CODE_JPACKAGE)) { + for (int expectedJPackageExitCode : List.of(0, 1, ERROR_EXIT_CODE_JPACKAGE)) { + data.add(new TestSpecBuilder() + .unpack(withUnpack ? ONCE : null) + .installExitCode(installExitCode) + .actualJPackageExitCode(actualJPackageExitCode) + .expectedJPackageExitCode(expectedJPackageExitCode) + .doCreateUnpackInstallUninstall().create()); + } + } + } + } + + data.add(new TestSpecBuilder() + .actions(Action.VERIFY_INSTALL, Action.UNINSTALL, Action.VERIFY_INSTALL, Action.VERIFY_UNINSTALL) + .uninstall(ONCE) + .initializers(ONCE) + .bundleVerifiers(BundleVerifier.NEVER.spec()) + .installVerifiers(TWICE) + .uninstallVerifiers(ONCE) + .create()); + + return data.stream().map(v -> { + return new Object[] {v}; + }).toList(); + } + + @Test + @ParameterSupplier + public void testDisableInstallerUninstaller(TestSpec spec, boolean disableInstaller, boolean disableUninstaller) { + spec.run(test -> { + if (disableInstaller) { + test.disablePackageInstaller(); + } + if (disableUninstaller) { + test.disablePackageUninstaller(); + } + }); + } + + public static List testDisableInstallerUninstaller() { + List data = new ArrayList<>(); + + for (boolean disableInstaller : List.of(true, false)) { + for (boolean disableUninstaller : List.of(true, false)) { + if (disableInstaller || disableUninstaller) { + final var builder = new TestSpecBuilder().doCreateUnpackInstallUninstall(); + if (disableInstaller) { + builder.install(NEVER); + } + if (disableUninstaller) { + builder.uninstall(NEVER); + } + data.add(new Object[] { builder.create(), disableInstaller, disableUninstaller }); + } + } + } + + return data; + } + + private static List getUnpackPaths(Collection verifiers) { + return verifiers.stream() + .filter(CountingUnpacker.class::isInstance) + .map(CountingUnpacker.class::cast) + .map(CountingUnpacker::unpackPaths) + .reduce((x , y) -> { + throw new UnsupportedOperationException(); + }).orElseThrow(); + } + + @Test + public void testUnpackTwice() { + final var testSpec = new TestSpecBuilder() + .actions(Action.CREATE, Action.UNPACK, Action.VERIFY_INSTALL, Action.UNPACK, Action.VERIFY_INSTALL) + .unpack(TWICE) + .initializers(ONCE) + .installVerifiers(TWICE) + .create(); + + final var unpackPaths = getUnpackPaths(testSpec.run()); + + TKit.assertEquals(2, unpackPaths.size(), "Check the bundle was unpacked in different directories"); + + unpackPaths.forEach(dir -> { + TKit.assertTrue(dir.startsWith(TKit.workDir()), "Check unpack directory is inside of the test work directory"); + }); + } + + @Test + public void testDeleteUnpackDirs() { + final int unpackActionCount = 4; + final var testSpec = new TestSpecBuilder() + .actions(Action.UNPACK, Action.UNPACK, Action.UNPACK, Action.UNPACK) + .unpack(new CallbackFactory(unpackActionCount) { + @Override + CountingUnpacker createUnpacker() { + return new CountingUnpacker(unpackActionCount) { + @Override + public Path apply(JPackageCommand cmd, Path path) { + switch (tickCount()) { + case 0 -> { + } + + case 2 -> { + path = path.resolve("foo"); + } + + case 1, 3 -> { + try { + path = Files.createTempDirectory("jpackage-test"); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + default -> { + throw new IllegalStateException(); + } + } + return super.apply(cmd, path); + } + }; + } + }) + .initializers(ONCE) + .create(); + + final var unpackPaths = getUnpackPaths(testSpec.run()); + + TKit.assertEquals(unpackActionCount, unpackPaths.size(), "Check the bundle was unpacked in different directories"); + + // Unpack directories within the test work directory must exist. + TKit.assertDirectoryExists(unpackPaths.get(0)); + TKit.assertDirectoryExists(unpackPaths.get(2)); + + // Unpack directories outside of the test work directory must be deleted. + TKit.assertPathExists(unpackPaths.get(1), false); + TKit.assertPathExists(unpackPaths.get(3), false); + } + + @Test + public void testRunOnceInitializer() { + final var testSpec = new TestSpecBuilder().doCreateAndUnpack().unpack(TWICE).create(); + + final var initializer = TWICE.createInitializer(); + final var runOnceInitializer = ONCE.createRunOnceInitializer(); + testSpec.run(test -> { + test.forTypes(PackageType.LINUX_RPM, PackageType.WIN_MSI) + .addRunOnceInitializer(runOnceInitializer) + .addInitializer(initializer); + }); + + initializer.verify(); + runOnceInitializer.verify(); + } + + @Test + @Parameter("0") + @Parameter("1") + public void testPurge(int jpackageExitCode) { + + Path[] outputBundle = new Path[1]; + + final var builder = new TestSpecBuilder(); + + builder.actions(Action.CREATE).initializers(new CallbackFactory(1) { + @Override + CountingConsumer createInitializer() { + return new CountingConsumer(1, "custom-init") { + @Override + public void accept(JPackageCommand cmd) { + outputBundle[0] = cmd.outputBundle(); + super.accept(cmd); + } + }; + } + }).create().run(); + TKit.assertFileExists(outputBundle[0]); + + builder.actions(Action.PURGE).initializers(ONCE).jpackageExitCode(jpackageExitCode).create().run(); + TKit.assertPathExists(outputBundle[0], false); + } + + @Test + public void testPackageTestOrder() { + + Set packageTypes = new LinkedHashSet<>(); + + final var initializer = new CountingConsumer(PackageType.NATIVE.size(), "custom-init") { + @Override + public void accept(JPackageCommand cmd) { + packageTypes.add(new JPackageCommand().setArgumentValue( + "--type", cmd.getArgumentValue("--type")).packageType()); + super.accept(cmd); + } + }; + + new TestSpecBuilder().actions(Action.CREATE).create().run(test -> { + test.forTypes().addInitializer(initializer); + }); + + initializer.verify(); + + final var expectedOrder = PackageType.NATIVE.stream() + .sorted().map(PackageType::name).toList(); + final var actualOrder = packageTypes.stream().map(PackageType::name).toList(); + + TKit.assertStringListEquals(expectedOrder, actualOrder, "Check the order or packaging"); + } +} 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 2d5d035512b..efcd0041579 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -25,6 +25,7 @@ package jdk.jpackage.test; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.SecureRandom; @@ -77,6 +78,7 @@ public class JPackageCommand extends CommandArguments { appLayoutAsserts = cmd.appLayoutAsserts; outputValidator = cmd.outputValidator; executeInDirectory = cmd.executeInDirectory; + winMsiLogFile = cmd.winMsiLogFile; } JPackageCommand createImmutableCopy() { @@ -998,6 +1000,22 @@ public class JPackageCommand extends CommandArguments { return this; } + JPackageCommand winMsiLogFile(Path v) { + this.winMsiLogFile = v; + return this; + } + + public Optional winMsiLogFile() { + return Optional.ofNullable(winMsiLogFile); + } + + public Optional> winMsiLogFileContents() { + return winMsiLogFile().map(ThrowingFunction.toFunction(msiLog -> { + // MSI log files are UTF16LE-encoded + return Files.lines(msiLog, StandardCharsets.UTF_16LE); + })); + } + private JPackageCommand adjustArgumentsBeforeExecution() { if (!isWithToolProvider()) { // if jpackage is launched as a process then set the jlink.debug system property @@ -1175,6 +1193,7 @@ public class JPackageCommand extends CommandArguments { private final Actions prerequisiteActions; private final Actions verifyActions; private Path executeInDirectory; + private Path winMsiLogFile; private Set appLayoutAsserts = Set.of(AppLayoutAssert.values()); private Consumer> outputValidator; private static boolean defaultWithToolProvider; 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 f97b695d98f..d94b8aee8ac 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -195,58 +195,61 @@ public final class LinuxHelper { } static PackageHandlers createDebPackageHandlers() { - PackageHandlers deb = new PackageHandlers(); - deb.installHandler = cmd -> { - cmd.verifyIsOfType(PackageType.LINUX_DEB); - Executor.of("sudo", "dpkg", "-i") - .addArgument(cmd.outputBundle()) - .execute(); - }; - deb.uninstallHandler = cmd -> { - cmd.verifyIsOfType(PackageType.LINUX_DEB); - var packageName = getPackageName(cmd); - String script = String.format("! dpkg -s %s || sudo dpkg -r %s", - packageName, packageName); - Executor.of("sh", "-c", script).execute(); - }; - deb.unpackHandler = (cmd, destinationDir) -> { - cmd.verifyIsOfType(PackageType.LINUX_DEB); - Executor.of("dpkg", "-x") - .addArgument(cmd.outputBundle()) - .addArgument(destinationDir) - .execute(); - return destinationDir; - }; - return deb; + return new PackageHandlers(LinuxHelper::installDeb, LinuxHelper::uninstallDeb, LinuxHelper::unpackDeb); + } + + private static int installDeb(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.LINUX_DEB); + return Executor.of("sudo", "dpkg", "-i") + .addArgument(cmd.outputBundle()) + .execute().getExitCode(); + } + + private static void uninstallDeb(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.LINUX_DEB); + var packageName = getPackageName(cmd); + String script = String.format("! dpkg -s %s || sudo dpkg -r %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); + } + + private static Path unpackDeb(JPackageCommand cmd, Path destinationDir) { + cmd.verifyIsOfType(PackageType.LINUX_DEB); + Executor.of("dpkg", "-x") + .addArgument(cmd.outputBundle()) + .addArgument(destinationDir) + .execute(0); + return destinationDir; } static PackageHandlers createRpmPackageHandlers() { - PackageHandlers rpm = new PackageHandlers(); - rpm.installHandler = cmd -> { - cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-U") - .addArgument(cmd.outputBundle()) - .execute(); - }; - rpm.uninstallHandler = cmd -> { - cmd.verifyIsOfType(PackageType.LINUX_RPM); - var packageName = getPackageName(cmd); - String script = String.format("! rpm -q %s || sudo rpm -e %s", - packageName, packageName); - Executor.of("sh", "-c", script).execute(); - }; - rpm.unpackHandler = (cmd, destinationDir) -> { - cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sh", "-c", String.format( - "rpm2cpio '%s' | cpio -idm --quiet", - JPackageCommand.escapeAndJoin( - cmd.outputBundle().toAbsolutePath().toString()))) - .setDirectory(destinationDir) - .execute(); - return destinationDir; - }; + return new PackageHandlers(LinuxHelper::installRpm, LinuxHelper::uninstallRpm, LinuxHelper::unpackRpm); + } - return rpm; + private static int installRpm(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.LINUX_RPM); + return Executor.of("sudo", "rpm", "-U") + .addArgument(cmd.outputBundle()) + .execute().getExitCode(); + } + + private static void uninstallRpm(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.LINUX_RPM); + var packageName = getPackageName(cmd); + String script = String.format("! rpm -q %s || sudo rpm -e %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); + } + + private static Path unpackRpm(JPackageCommand cmd, Path destinationDir) { + cmd.verifyIsOfType(PackageType.LINUX_RPM); + Executor.of("sh", "-c", String.format( + "rpm2cpio '%s' | cpio -idm --quiet", + JPackageCommand.escapeAndJoin( + cmd.outputBundle().toAbsolutePath().toString()))) + .setDirectory(destinationDir) + .execute(0); + return destinationDir; } static Path getLauncherPath(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 72706129213..8d245fb4d96 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -150,113 +150,115 @@ public final class MacHelper { } static PackageHandlers createDmgPackageHandlers() { - PackageHandlers dmg = new PackageHandlers(); + return new PackageHandlers(MacHelper::installDmg, MacHelper::uninstallDmg, MacHelper::unpackDmg); + } - dmg.installHandler = cmd -> { - withExplodedDmg(cmd, dmgImage -> { - Executor.of("sudo", "cp", "-r") - .addArgument(dmgImage) - .addArgument(getInstallationDirectory(cmd).getParent()) - .execute(); - }); - }; - dmg.unpackHandler = (cmd, destinationDir) -> { - Path unpackDir = destinationDir.resolve( - TKit.removeRootFromAbsolutePath( - getInstallationDirectory(cmd)).getParent()); - try { - Files.createDirectories(unpackDir); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + private static int installDmg(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.MAC_DMG); + withExplodedDmg(cmd, dmgImage -> { + Executor.of("sudo", "cp", "-r") + .addArgument(dmgImage) + .addArgument(getInstallationDirectory(cmd).getParent()) + .execute(0); + }); + return 0; + } - withExplodedDmg(cmd, dmgImage -> { - Executor.of("cp", "-r") - .addArgument(dmgImage) - .addArgument(unpackDir) - .execute(); - }); - return destinationDir; - }; - dmg.uninstallHandler = cmd -> { - cmd.verifyIsOfType(PackageType.MAC_DMG); - Executor.of("sudo", "rm", "-rf") - .addArgument(cmd.appInstallationDirectory()) + private static void uninstallDmg(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.MAC_DMG); + Executor.of("sudo", "rm", "-rf") + .addArgument(cmd.appInstallationDirectory()) + .execute(); + } + + private static Path unpackDmg(JPackageCommand cmd, Path destinationDir) { + cmd.verifyIsOfType(PackageType.MAC_DMG); + Path unpackDir = destinationDir.resolve( + TKit.removeRootFromAbsolutePath( + getInstallationDirectory(cmd)).getParent()); + try { + Files.createDirectories(unpackDir); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + withExplodedDmg(cmd, dmgImage -> { + Executor.of("cp", "-r") + .addArgument(dmgImage) + .addArgument(unpackDir) .execute(); - }; - - return dmg; + }); + return destinationDir; } static PackageHandlers createPkgPackageHandlers() { - PackageHandlers pkg = new PackageHandlers(); + return new PackageHandlers(MacHelper::installPkg, MacHelper::uninstallPkg, MacHelper::unpackPkg); + } - pkg.installHandler = cmd -> { - cmd.verifyIsOfType(PackageType.MAC_PKG); - Executor.of("sudo", "/usr/sbin/installer", "-allowUntrusted", "-pkg") - .addArgument(cmd.outputBundle()) - .addArguments("-target", "/") + private static int installPkg(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.MAC_PKG); + return Executor.of("sudo", "/usr/sbin/installer", "-allowUntrusted", "-pkg") + .addArgument(cmd.outputBundle()) + .addArguments("-target", "/") + .execute().getExitCode(); + } + + private static void uninstallPkg(JPackageCommand cmd) { + cmd.verifyIsOfType(PackageType.MAC_PKG); + if (Files.exists(getUninstallCommand(cmd))) { + Executor.of("sudo", "/bin/sh", + getUninstallCommand(cmd).toString()).execute(); + } else { + Executor.of("sudo", "rm", "-rf") + .addArgument(cmd.appInstallationDirectory()) .execute(); - }; - pkg.unpackHandler = (cmd, destinationDir) -> { - cmd.verifyIsOfType(PackageType.MAC_PKG); + } + } - var dataDir = destinationDir.resolve("data"); + private static Path unpackPkg(JPackageCommand cmd, Path destinationDir) { + cmd.verifyIsOfType(PackageType.MAC_PKG); - Executor.of("pkgutil", "--expand") - .addArgument(cmd.outputBundle()) - .addArgument(dataDir) // We need non-existing folder - .execute(); + var dataDir = destinationDir.resolve("data"); - final Path unpackRoot = destinationDir.resolve("unpacked"); + Executor.of("pkgutil", "--expand") + .addArgument(cmd.outputBundle()) + .addArgument(dataDir) // We need non-existing folder + .execute(); - // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder - try (var dataListing = Files.list(dataDir)) { - dataListing.filter(file -> { - return ".pkg".equals(PathUtils.getSuffix(file.getFileName())); - }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { - // Installation root of the package is stored in - // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file - var doc = createDocumentBuilder().parse( - new ByteArrayInputStream(Files.readAllBytes( - pkgDir.resolve("PackageInfo")))); - var xPath = XPathFactory.newInstance().newXPath(); + final Path unpackRoot = destinationDir.resolve("unpacked"); - final String installRoot = (String) xPath.evaluate( - "/pkg-info/@install-location", doc, - XPathConstants.STRING); + // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder + try (var dataListing = Files.list(dataDir)) { + dataListing.filter(file -> { + return ".pkg".equals(PathUtils.getSuffix(file.getFileName())); + }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { + // Installation root of the package is stored in + // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file + var doc = createDocumentBuilder().parse( + new ByteArrayInputStream(Files.readAllBytes( + pkgDir.resolve("PackageInfo")))); + var xPath = XPathFactory.newInstance().newXPath(); - final Path unpackDir = unpackRoot.resolve( - TKit.removeRootFromAbsolutePath(Path.of(installRoot))); + final String installRoot = (String) xPath.evaluate( + "/pkg-info/@install-location", doc, + XPathConstants.STRING); - Files.createDirectories(unpackDir); + final Path unpackDir = unpackRoot.resolve( + TKit.removeRootFromAbsolutePath(Path.of(installRoot))); - Executor.of("tar", "-C") - .addArgument(unpackDir) - .addArgument("-xvf") - .addArgument(pkgDir.resolve("Payload")) - .execute(); - })); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + Files.createDirectories(unpackDir); - return unpackRoot; - }; - pkg.uninstallHandler = cmd -> { - cmd.verifyIsOfType(PackageType.MAC_PKG); - - if (Files.exists(getUninstallCommand(cmd))) { - Executor.of("sudo", "/bin/sh", - getUninstallCommand(cmd).toString()).execute(); - } else { - Executor.of("sudo", "rm", "-rf") - .addArgument(cmd.appInstallationDirectory()) + Executor.of("tar", "-C") + .addArgument(unpackDir) + .addArgument("-xvf") + .addArgument(pkgDir.resolve("Payload")) .execute(); - } - }; + })); + } catch (IOException ex) { + throw new RuntimeException(ex); + } - return pkg; + return unpackRoot; } static void verifyBundleStructure(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index f89bd0a60c8..e7b3f3e3a44 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -22,6 +22,15 @@ */ package jdk.jpackage.test; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.PackageType.LINUX; +import static jdk.jpackage.test.PackageType.MAC_PKG; +import static jdk.jpackage.test.PackageType.NATIVE; +import static jdk.jpackage.test.PackageType.WINDOWS; + import java.awt.GraphicsEnvironment; import java.io.IOException; import java.nio.file.Files; @@ -29,6 +38,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -40,27 +50,15 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; -import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.internal.util.function.ThrowingConsumer; -import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import jdk.jpackage.internal.util.function.ThrowingRunnable; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; -import static jdk.jpackage.test.PackageType.LINUX; -import static jdk.jpackage.test.PackageType.LINUX_DEB; -import static jdk.jpackage.test.PackageType.LINUX_RPM; -import static jdk.jpackage.test.PackageType.MAC_DMG; -import static jdk.jpackage.test.PackageType.MAC_PKG; -import static jdk.jpackage.test.PackageType.NATIVE; -import static jdk.jpackage.test.PackageType.WINDOWS; -import static jdk.jpackage.test.PackageType.WIN_EXE; -import static jdk.jpackage.test.PackageType.WIN_MSI; /** @@ -73,13 +71,18 @@ import static jdk.jpackage.test.PackageType.WIN_MSI; public final class PackageTest extends RunnablePackageTest { public PackageTest() { + isPackageTypeSupported = PackageType::isSupported; + jpackageFactory = JPackageCommand::new; + packageHandlers = new HashMap<>(); + disabledInstallers = new HashSet<>(); + disabledUninstallers = new HashSet<>(); excludeTypes = new HashSet<>(); forTypes(); setExpectedExitCode(0); + setExpectedInstallExitCode(0); namedInitializers = new HashSet<>(); - handlers = currentTypes.stream() + handlers = NATIVE.stream() .collect(Collectors.toMap(v -> v, v -> new Handler())); - packageHandlers = createDefaultPackageHandlers(); } public PackageTest excludeTypes(PackageType... types) { @@ -93,13 +96,13 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest forTypes(PackageType... types) { Collection newTypes; - if (types == null || types.length == 0) { + if (types.length == 0) { newTypes = NATIVE; } else { newTypes = Stream.of(types).collect(Collectors.toSet()); } currentTypes = newTypes.stream() - .filter(PackageType::isSupported) + .filter(isPackageTypeSupported) .filter(Predicate.not(excludeTypes::contains)) .collect(Collectors.toUnmodifiableSet()); return this; @@ -124,6 +127,11 @@ public final class PackageTest extends RunnablePackageTest { return this; } + public PackageTest setExpectedInstallExitCode(int v) { + expectedInstallExitCode = v; + return this; + } + public PackageTest ignoreBundleOutputDir() { return ignoreBundleOutputDir(true); } @@ -133,8 +141,8 @@ public final class PackageTest extends RunnablePackageTest { return this; } - private PackageTest addInitializer(ThrowingConsumer v, - String id) { + private PackageTest addInitializer(ThrowingConsumer v, String id) { + Objects.requireNonNull(v); if (id != null) { if (namedInitializers.contains(id)) { return this; @@ -142,12 +150,12 @@ public final class PackageTest extends RunnablePackageTest { namedInitializers.add(id); } - currentTypes.forEach(type -> handlers.get(type).addInitializer( - toConsumer(v))); + currentTypes.forEach(type -> handlers.get(type).addInitializer(toConsumer(v))); return this; } private PackageTest addRunOnceInitializer(ThrowingRunnable v, String id) { + Objects.requireNonNull(v); return addInitializer(new ThrowingConsumer() { @Override public void accept(JPackageCommand unused) throws Throwable { @@ -169,24 +177,26 @@ public final class PackageTest extends RunnablePackageTest { return addRunOnceInitializer(v, null); } - public PackageTest addBundleVerifier( - ThrowingBiConsumer v) { - currentTypes.forEach(type -> handlers.get(type).addBundleVerifier( - toBiConsumer(v))); + public PackageTest addBundleVerifier(ThrowingBiConsumer v) { + Objects.requireNonNull(v); + currentTypes.forEach(type -> handlers.get(type).addBundleVerifier(toBiConsumer(v))); return this; } public PackageTest addBundleVerifier(ThrowingConsumer v) { + Objects.requireNonNull(v); return addBundleVerifier((cmd, unused) -> toConsumer(v).accept(cmd)); } public PackageTest addBundlePropertyVerifier(String propertyName, Predicate pred, String predLabel) { + Objects.requireNonNull(propertyName); + Objects.requireNonNull(pred); return addBundleVerifier(cmd -> { final String value; - if (TKit.isLinux()) { + if (isOfType(cmd, LINUX)) { value = LinuxHelper.getBundleProperty(cmd, propertyName); - } else if (TKit.isWindows()) { + } else if (isOfType(cmd, WINDOWS)) { value = WindowsHelper.getMsiProperty(cmd, propertyName); } else { throw new IllegalStateException(); @@ -223,19 +233,23 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest disablePackageInstaller() { - currentTypes.forEach( - type -> packageHandlers.get(type).installHandler = cmd -> {}); + currentTypes.forEach(disabledInstallers::add); return this; } public PackageTest disablePackageUninstaller() { - currentTypes.forEach( - type -> packageHandlers.get(type).uninstallHandler = cmd -> {}); + currentTypes.forEach(disabledUninstallers::add); + return this; + } + + public PackageTest createMsiLog(boolean v) { + createMsiLog = v; return this; } static void withFileAssociationsTestRuns(FileAssociations fa, ThrowingBiConsumer> consumer) { + Objects.requireNonNull(consumer); for (var testRun : fa.getTestRuns()) { TKit.withTempDirectory("fa-test-files", tempDir -> { List testFiles = StreamSupport.stream(testRun.getFileNames().spliterator(), false).map(fname -> { @@ -254,6 +268,7 @@ public final class PackageTest extends RunnablePackageTest { } PackageTest addHelloAppFileAssociationsVerifier(FileAssociations fa) { + Objects.requireNonNull(fa); // Setup test app to have valid jpackage command line before // running check of type of environment. @@ -290,7 +305,7 @@ public final class PackageTest extends RunnablePackageTest { Collections.emptyMap()); }); - if (TKit.isWindows()) { + if (isOfType(cmd, WINDOWS)) { // Verify context menu label in registry. String progId = WindowsHelper.queryRegistryValue( String.format("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\%s", fa.getSuffix()), ""); @@ -307,8 +322,7 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest forTypes(Collection types, Runnable action) { - Set oldTypes = Set.of(currentTypes.toArray( - PackageType[]::new)); + final var oldTypes = Set.of(currentTypes.toArray(PackageType[]::new)); try { forTypes(types); action.run(); @@ -374,10 +388,59 @@ public final class PackageTest extends RunnablePackageTest { private final List> handlers; } - static final class PackageHandlers { - Consumer installHandler; - Consumer uninstallHandler; - BiFunction unpackHandler; + PackageTest packageHandlers(PackageHandlers v) { + Objects.requireNonNull(v); + currentTypes.forEach(type -> packageHandlers.put(type, v)); + return this; + } + + PackageTest isPackageTypeSupported(Predicate v) { + Objects.requireNonNull(v); + isPackageTypeSupported = v; + return this; + } + + PackageTest jpackageFactory(Supplier v) { + Objects.requireNonNull(v); + jpackageFactory = v; + return this; + } + + record PackageHandlers(Function installHandler, + Consumer uninstallHandler, + Optional> unpackHandler) { + + PackageHandlers(Function installHandler, + Consumer uninstallHandler, + BiFunction unpackHandler) { + this(installHandler, uninstallHandler, Optional.of(unpackHandler)); + } + + PackageHandlers { + Objects.requireNonNull(installHandler); + Objects.requireNonNull(uninstallHandler); + Objects.requireNonNull(unpackHandler); + } + + PackageHandlers copyWithNopInstaller() { + return new PackageHandlers(cmd -> 0, uninstallHandler, unpackHandler); + } + + PackageHandlers copyWithNopUninstaller() { + return new PackageHandlers(installHandler, cmd -> {}, unpackHandler); + } + + int install(JPackageCommand cmd) { + return installHandler.apply(cmd); + } + + Path unpack(JPackageCommand cmd, Path unpackDir) { + return unpackHandler.orElseThrow().apply(cmd, unpackDir); + } + + void uninstall(JPackageCommand cmd) { + uninstallHandler.accept(cmd); + } } @Override @@ -393,164 +456,197 @@ public final class PackageTest extends RunnablePackageTest { } private List> createPackageTypeHandlers() { - return NATIVE.stream() - .map(type -> { - Handler handler = handlers.entrySet().stream() - .filter(entry -> !entry.getValue().isVoid()) - .filter(entry -> entry.getKey() == type) - .map(entry -> entry.getValue()) - .findAny().orElse(null); - Map.Entry result = null; - if (handler != null) { - result = Map.entry(type, handler); - } - return result; - }) - .filter(Objects::nonNull) - .map(entry -> createPackageTypeHandler( - entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + return handlers.entrySet().stream() + .filter(entry -> !entry.getValue().isVoid()) + .filter(entry -> NATIVE.contains(entry.getKey())) + .sorted(Comparator.comparing(Map.Entry::getKey)) + .map(entry -> { + return createPackageTypeHandler(entry.getKey(), entry.getValue()); + }).toList(); } - private Consumer createPackageTypeHandler( - PackageType type, Handler handler) { - return toConsumer(new ThrowingConsumer() { - @Override - public void accept(Action action) throws Throwable { - if (terminated) { - throw new IllegalStateException(); + private record PackageTypePipeline(PackageType type, int expectedJPackageExitCode, + int expectedInstallExitCode, PackageHandlers packageHandlers, Handler handler, + JPackageCommand cmd, State state) implements Consumer { + + PackageTypePipeline { + Objects.requireNonNull(type); + Objects.requireNonNull(packageHandlers); + Objects.requireNonNull(handler); + Objects.requireNonNull(cmd); + Objects.requireNonNull(state); + } + + PackageTypePipeline(PackageType type, int expectedJPackageExitCode, + int expectedInstallExitCode, PackageHandlers packageHandlers, + Handler handler, JPackageCommand cmd) { + this(type, expectedJPackageExitCode, expectedInstallExitCode, + packageHandlers, handler, cmd, new State()); + } + + @Override + public void accept(Action action) { + switch(analizeAction(action)) { + case SKIP_NO_PACKAGE_HANDLER -> { + TKit.trace(String.format("No handler of [%s] action for %s command", + action, cmd.getPrintableCommandLine())); + return; } - - if (action == Action.FINALIZE) { - if (unpackDir != null) { - if (Files.isDirectory(unpackDir) - && !unpackDir.startsWith(TKit.workDir())) { - TKit.deleteDirectoryRecursive(unpackDir); - } - unpackDir = null; - } - terminated = true; - } - - boolean skip = false; - - if (unhandledAction != null) { - switch (unhandledAction) { - case CREATE: - skip = true; - break; - case UNPACK: - case INSTALL: - skip = (action == Action.VERIFY_INSTALL); - break; - case UNINSTALL: - skip = (action == Action.VERIFY_UNINSTALL); - break; - default: // NOP - } - } - - if (skip) { + case SKIP -> { TKit.trace(String.format("Skip [%s] action of %s command", action, cmd.getPrintableCommandLine())); return; } - - final Supplier curCmd = () -> { - if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { - return cmd; - } else { - return cmd.createImmutableCopy(); - } - }; - - switch (action) { - case UNPACK: { - cmd.setUnpackedPackageLocation(null); - handleAction(action, - packageHandlers.get(type).unpackHandler, - handler -> { - unpackDir = TKit.createTempDirectory( - String.format("unpacked-%s", - type.getName())); - unpackDir = handler.apply(cmd, unpackDir); - cmd.setUnpackedPackageLocation(unpackDir); - }); - break; - } - - case INSTALL: { - cmd.setUnpackedPackageLocation(null); - handleAction(action, - packageHandlers.get(type).installHandler, - handler -> { - handler.accept(curCmd.get()); - }); - break; - } - - case UNINSTALL: { - handleAction(action, - packageHandlers.get(type).uninstallHandler, - handler -> { - handler.accept(curCmd.get()); - }); - break; - } - - case CREATE: - cmd.setUnpackedPackageLocation(null); - handler.accept(action, curCmd.get()); - handleAction(action, - (expectedJPackageExitCode == 0) ? Boolean.TRUE : null, - handler -> { - }); - return; - - default: - handler.accept(action, curCmd.get()); - break; - } - - Optional.ofNullable(unhandledAction).ifPresent(v -> { - TKit.trace(String.format( - "No handler of [%s] action for %s command", v, - cmd.getPrintableCommandLine())); - }); - } - - private void handleAction(Action action, T handler, - ThrowingConsumer consumer) throws Throwable { - if (handler == null) { - unhandledAction = action; - } else { - unhandledAction = null; - consumer.accept(handler); + case PROCESS -> { } } - private Path unpackDir; - private Action unhandledAction; - private boolean terminated; - private final JPackageCommand cmd = Functional.identity(() -> { - JPackageCommand result = new JPackageCommand(); - result.setDefaultInputOutput().setDefaultAppName(); - if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { - result.setArgumentValue("--dest", BUNDLE_OUTPUT_DIR.toString()); + switch (action) { + case UNPACK -> { + cmd.setUnpackedPackageLocation(null); + final var unpackRootDir = TKit.createTempDirectory( + String.format("unpacked-%s", type.getName())); + final Path unpackDir = packageHandlers.unpack(cmd, unpackRootDir); + if (!unpackDir.startsWith(TKit.workDir())) { + state.deleteUnpackDirs.add(unpackDir); + } + cmd.setUnpackedPackageLocation(unpackDir); } - type.applyTo(result); - return result; - }).get(); - }); + + case INSTALL -> { + cmd.setUnpackedPackageLocation(null); + final int installExitCode = packageHandlers.install(cmd); + TKit.assertEquals(expectedInstallExitCode, installExitCode, + String.format("Check installer exited with %d code", expectedInstallExitCode)); + } + + case UNINSTALL -> { + cmd.setUnpackedPackageLocation(null); + packageHandlers.uninstall(cmd); + } + + case CREATE -> { + cmd.setUnpackedPackageLocation(null); + handler.processAction(action, cmd, expectedJPackageExitCode); + } + + case INITIALIZE -> { + handler.processAction(action, cmd, expectedJPackageExitCode); + } + + case FINALIZE -> { + state.deleteUnpackDirs.forEach(TKit::deleteDirectoryRecursive); + state.deleteUnpackDirs.clear(); + } + + default -> { + handler.processAction(action, cmd.createImmutableCopy(), expectedJPackageExitCode); + } + } + } + + private enum ActionAction { + PROCESS, + SKIP, + SKIP_NO_PACKAGE_HANDLER + } + + private ActionAction analizeAction(Action action) { + Objects.requireNonNull(action); + + if (jpackageFailed()) { + return ActionAction.SKIP; + } + + switch (action) { + case CREATE -> { + state.packageActions.add(action); + } + case INSTALL -> { + state.packageActions.add(action); + state.packageActions.remove(Action.UNPACK); + } + case UNINSTALL -> { + state.packageActions.add(action); + if (installFailed()) { + return ActionAction.SKIP; + } + } + case UNPACK -> { + state.packageActions.add(action); + state.packageActions.remove(Action.INSTALL); + if (unpackNotSupported()) { + return ActionAction.SKIP_NO_PACKAGE_HANDLER; + } + } + case VERIFY_INSTALL -> { + if (unpackNotSupported()) { + return ActionAction.SKIP; + } + + if (installFailed()) { + return ActionAction.SKIP; + } + } + case VERIFY_UNINSTALL -> { + if (installFailed() && processed(Action.UNINSTALL)) { + return ActionAction.SKIP; + } + } + default -> { + // NOP + } + } + + return ActionAction.PROCESS; + } + + private boolean processed(Action action) { + Objects.requireNonNull(action); + return state.packageActions.contains(action); + } + + private boolean installFailed() { + return processed(Action.INSTALL) && expectedInstallExitCode != 0; + } + + private boolean jpackageFailed() { + return processed(Action.CREATE) && expectedJPackageExitCode != 0; + } + + private boolean unpackNotSupported() { + return processed(Action.UNPACK) && packageHandlers.unpackHandler().isEmpty(); + } + + private final static class State { + private final Set packageActions = new HashSet<>(); + private final List deleteUnpackDirs = new ArrayList<>(); + } } - private class Handler implements BiConsumer { + private Consumer createPackageTypeHandler(PackageType type, Handler handler) { + final var cmd = jpackageFactory.get(); + cmd.setDefaultInputOutput().setDefaultAppName(); + if (BUNDLE_OUTPUT_DIR != null && !ignoreBundleOutputDir) { + cmd.setArgumentValue("--dest", BUNDLE_OUTPUT_DIR.toString()); + } + type.applyTo(cmd); + return new PackageTypePipeline(type, expectedJPackageExitCode, + expectedInstallExitCode, getPackageHandlers(type), handler.copy(), cmd); + } + + private record Handler(List> initializers, + List> bundleVerifiers, + List> installVerifiers, + List> uninstallVerifiers) { Handler() { - initializers = new ArrayList<>(); - bundleVerifiers = new ArrayList<>(); - installVerifiers = new ArrayList<>(); - uninstallVerifiers = new ArrayList<>(); + this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + } + + Handler copy() { + return new Handler(List.copyOf(initializers), List.copyOf(bundleVerifiers), + List.copyOf(installVerifiers), List.copyOf(uninstallVerifiers)); } boolean isVoid() { @@ -573,18 +669,17 @@ public final class PackageTest extends RunnablePackageTest { uninstallVerifiers.add(v); } - @Override - public void accept(Action action, JPackageCommand cmd) { + public void processAction(Action action, JPackageCommand cmd, int expectedJPackageExitCode) { switch (action) { - case INITIALIZE: + case INITIALIZE -> { initializers.forEach(v -> v.accept(cmd)); if (cmd.isImagePackageType()) { throw new UnsupportedOperationException(); } cmd.executePrerequisiteActions(); - break; + } - case CREATE: + case CREATE -> { Executor.Result result = cmd.execute(expectedJPackageExitCode); if (expectedJPackageExitCode == 0) { TKit.assertFileExists(cmd.outputBundle()); @@ -593,39 +688,38 @@ public final class PackageTest extends RunnablePackageTest { TKit.assertPathExists(outputBundle, false); }); } - verifyPackageBundle(cmd, result); - break; + verifyPackageBundle(cmd, result, expectedJPackageExitCode); + } - case VERIFY_INSTALL: + case VERIFY_INSTALL -> { if (expectedJPackageExitCode == 0) { verifyPackageInstalled(cmd); } - break; + } - case VERIFY_UNINSTALL: + case VERIFY_UNINSTALL -> { if (expectedJPackageExitCode == 0) { verifyPackageUninstalled(cmd); } - break; + } - case PURGE: - if (expectedJPackageExitCode == 0) { - var bundle = cmd.outputBundle(); - if (toSupplier(() -> TKit.deleteIfExists(bundle)).get()) { - TKit.trace(String.format("Deleted [%s] package", - bundle)); - } + case PURGE -> { + var bundle = cmd.outputBundle(); + if (toSupplier(() -> TKit.deleteIfExists(bundle)).get()) { + TKit.trace(String.format("Deleted [%s] package", bundle)); } - break; + } - default: // NOP + default -> { + // NOP + } } } private void verifyPackageBundle(JPackageCommand cmd, - Executor.Result result) { + Executor.Result result, int expectedJPackageExitCode) { if (expectedJPackageExitCode == 0) { - if (LINUX.contains(cmd.packageType())) { + if (isOfType(cmd, LINUX)) { LinuxHelper.verifyPackageBundleEssential(cmd); } } @@ -647,9 +741,7 @@ public final class PackageTest extends RunnablePackageTest { }); if (!cmd.isRuntime()) { - if (WINDOWS.contains(cmd.packageType()) - && !cmd.isPackageUnpacked( - "Not verifying desktop integration")) { + if (isOfType(cmd, WINDOWS) && !cmd.isPackageUnpacked("Not verifying desktop integration")) { // Check main launcher WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers @@ -659,8 +751,7 @@ public final class PackageTest extends RunnablePackageTest { } } - if (LauncherAsServiceVerifier.SUPPORTED_PACKAGES.contains( - cmd.packageType())) { + if (isOfType(cmd, LauncherAsServiceVerifier.SUPPORTED_PACKAGES)) { LauncherAsServiceVerifier.verify(cmd); } @@ -676,13 +767,13 @@ public final class PackageTest extends RunnablePackageTest { && !LauncherAsServiceVerifier.getLaunchersAsServices(cmd).isEmpty(); final long expectedRootCount; - if (WINDOWS.contains(cmd.packageType())) { + if (isOfType(cmd, WINDOWS)) { // On Windows it is always two entries: // installation home directory and MSI file expectedRootCount = 2; - } else if (withServices && MAC_PKG.equals(cmd.packageType())) { + } else if (withServices && isOfType(cmd, MAC_PKG)) { expectedRootCount = 2; - } else if (LINUX.contains(cmd.packageType())) { + } else if (isOfType(cmd, LINUX)) { Set roots = new HashSet<>(); roots.add(Path.of("/").resolve(Path.of(cmd.getArgumentValue( "--install-dir", () -> "/opt")).getName(0))); @@ -732,7 +823,7 @@ public final class PackageTest extends RunnablePackageTest { if (!cmd.isRuntime()) { TKit.assertPathExists(cmd.appLauncherPath(), false); - if (WINDOWS.contains(cmd.packageType())) { + if (isOfType(cmd, WINDOWS)) { // Check main launcher WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers @@ -743,54 +834,94 @@ public final class PackageTest extends RunnablePackageTest { } Path appInstallDir = cmd.appInstallationDirectory(); - if (TKit.isLinux() && Path.of("/").equals(appInstallDir)) { + if (isOfType(cmd, LINUX) && Path.of("/").equals(appInstallDir)) { ApplicationLayout appLayout = cmd.appLayout(); TKit.assertPathExists(appLayout.runtimeDirectory(), false); } else { TKit.assertPathExists(appInstallDir, false); } - if (LauncherAsServiceVerifier.SUPPORTED_PACKAGES.contains( - cmd.packageType())) { + if (isOfType(cmd, LauncherAsServiceVerifier.SUPPORTED_PACKAGES)) { LauncherAsServiceVerifier.verifyUninstalled(cmd); } uninstallVerifiers.forEach(v -> v.accept(cmd)); } - - private final List> initializers; - private final List> bundleVerifiers; - private final List> installVerifiers; - private final List> uninstallVerifiers; } - private static Map createDefaultPackageHandlers() { - HashMap handlers = new HashMap<>(); - if (TKit.isLinux()) { - handlers.put(LINUX_DEB, LinuxHelper.createDebPackageHandlers()); - handlers.put(LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); + private PackageHandlers getDefaultPackageHandlers(PackageType type) { + switch (type) { + case LINUX_DEB -> { + return LinuxHelper.createDebPackageHandlers(); + } + case LINUX_RPM -> { + return LinuxHelper.createRpmPackageHandlers(); + } + case WIN_MSI -> { + return WindowsHelper.createMsiPackageHandlers(createMsiLog); + } + case WIN_EXE -> { + return WindowsHelper.createExePackageHandlers(createMsiLog); + } + case MAC_DMG -> { + return MacHelper.createDmgPackageHandlers(); + } + case MAC_PKG -> { + return MacHelper.createPkgPackageHandlers(); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + private PackageHandlers getPackageHandlers(PackageType type) { + Objects.requireNonNull(type); + + var reply = Optional.ofNullable(packageHandlers.get(type)).orElseGet(() -> { + if (TKit.isLinux() && !PackageType.LINUX.contains(type)) { + throw new IllegalArgumentException(); + } else if (TKit.isWindows() && !PackageType.WINDOWS.contains(type)) { + throw new IllegalArgumentException(); + } else if (TKit.isOSX() && !PackageType.MAC.contains(type)) { + throw new IllegalArgumentException(); + } else { + return getDefaultPackageHandlers(type); + } + }); + + if (disabledInstallers.contains(type)) { + reply = reply.copyWithNopInstaller(); } - if (TKit.isWindows()) { - handlers.put(WIN_MSI, WindowsHelper.createMsiPackageHandlers()); - handlers.put(WIN_EXE, WindowsHelper.createExePackageHandlers()); + if (disabledUninstallers.contains(type)) { + reply = reply.copyWithNopUninstaller(); } - if (TKit.isOSX()) { - handlers.put(MAC_DMG, MacHelper.createDmgPackageHandlers()); - handlers.put(MAC_PKG, MacHelper.createPkgPackageHandlers()); - } + return reply; + } - return handlers; + private static boolean isOfType(JPackageCommand cmd, PackageType packageTypes) { + return isOfType(cmd, Set.of(packageTypes)); + } + + private static boolean isOfType(JPackageCommand cmd, Set packageTypes) { + return Optional.ofNullable(cmd.packageType()).map(packageTypes::contains).orElse(false); } private Collection currentTypes; private Set excludeTypes; private int expectedJPackageExitCode; - private Map handlers; - private Set namedInitializers; - private Map packageHandlers; + private int expectedInstallExitCode; + private final Map handlers; + private final Set namedInitializers; + private final Map packageHandlers; + private final Set disabledInstallers; + private final Set disabledUninstallers; + private Predicate isPackageTypeSupported; + private Supplier jpackageFactory; private boolean ignoreBundleOutputDir; + private boolean createMsiLog; private static final Path BUNDLE_OUTPUT_DIR; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 48643463e0b..91705afd5fe 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -22,24 +22,25 @@ */ package jdk.jpackage.test; +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.IOException; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.BiConsumer; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; import jdk.jpackage.internal.util.function.ThrowingRunnable; -import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; public class WindowsHelper { @@ -67,21 +68,24 @@ public class WindowsHelper { return Path.of(cmd.getArgumentValue("--install-dir", cmd::name)); } - private static void runMsiexecWithRetries(Executor misexec) { + private static int runMsiexecWithRetries(Executor misexec, Optional msiLog) { Executor.Result result = null; + final boolean isUnpack = misexec.getExecutable().orElseThrow().equals(Path.of("cmd")); + final List origArgs = msiLog.isPresent() ? misexec.getAllArguments() : null; for (int attempt = 0; attempt < 8; ++attempt) { + msiLog.ifPresent(v -> misexec.clearArguments().addArguments(origArgs).addArgument("/L*v").addArgument(v)); result = misexec.executeWithoutExitCodeCheck(); if (result.exitCode() == 1605) { // ERROR_UNKNOWN_PRODUCT, attempt to uninstall not installed // package - return; + return result.exitCode(); } // The given Executor may either be of an msiexec command or an // unpack.bat script containing the msiexec command. In the later // case, when misexec returns 1618, the unpack.bat may return 1603 - if ((result.exitCode() == 1618) || (result.exitCode() == 1603)) { + if ((result.exitCode() == 1618) || (result.exitCode() == 1603 && isUnpack)) { // Another installation is already in progress. // Wait a little and try again. Long timeout = 1000L * (attempt + 3); // from 3 to 10 seconds @@ -91,74 +95,123 @@ public class WindowsHelper { break; } - result.assertExitCodeIsZero(); + return result.exitCode(); } - static PackageHandlers createMsiPackageHandlers() { - BiConsumer installMsi = (cmd, install) -> { - cmd.verifyIsOfType(PackageType.WIN_MSI); - var msiPath = TransientMsi.create(cmd).path(); - runMsiexecWithRetries(Executor.of("msiexec", "/qn", "/norestart", - install ? "/i" : "/x").addArgument(msiPath)); - }; + static PackageHandlers createMsiPackageHandlers(boolean createMsiLog) { + return new PackageHandlers(cmd -> installMsi(cmd, createMsiLog), + cmd -> uninstallMsi(cmd, createMsiLog), WindowsHelper::unpackMsi); + } - PackageHandlers msi = new PackageHandlers(); - msi.installHandler = cmd -> installMsi.accept(cmd, true); - msi.uninstallHandler = cmd -> { - if (Files.exists(cmd.outputBundle())) { - installMsi.accept(cmd, false); + private static Optional configureMsiLogFile(JPackageCommand cmd, boolean createMsiLog) { + final Optional msiLogFile; + if (createMsiLog) { + msiLogFile = Optional.of(TKit.createTempFile(String.format("logs\\%s-msi.log", + cmd.packageType().getName()))); + } else { + msiLogFile = Optional.empty(); + } + + cmd.winMsiLogFile(msiLogFile.orElse(null)); + + return msiLogFile; + } + + private static int runMsiInstaller(JPackageCommand cmd, boolean createMsiLog, boolean install) { + cmd.verifyIsOfType(PackageType.WIN_MSI); + final var msiPath = TransientMsi.create(cmd).path(); + return runMsiexecWithRetries(Executor.of("msiexec", "/qn", "/norestart", + install ? "/i" : "/x").addArgument(msiPath), configureMsiLogFile(cmd, createMsiLog)); + } + + private static int installMsi(JPackageCommand cmd, boolean createMsiLog) { + return runMsiInstaller(cmd, createMsiLog, true); + } + + private static void uninstallMsi(JPackageCommand cmd, boolean createMsiLog) { + if (Files.exists(cmd.outputBundle())) { + runMsiInstaller(cmd, createMsiLog, false); + } else { + configureMsiLogFile(cmd, false); + } + } + + private static Path unpackMsi(JPackageCommand cmd, Path destinationDir) { + cmd.verifyIsOfType(PackageType.WIN_MSI); + configureMsiLogFile(cmd, false); + final Path unpackBat = destinationDir.resolve("unpack.bat"); + final Path unpackDir = destinationDir.resolve( + TKit.removeRootFromAbsolutePath( + getInstallationRootDirectory(cmd))); + + final Path msiPath = TransientMsi.create(cmd).path(); + + // Put msiexec in .bat file because can't pass value of TARGETDIR + // property containing spaces through ProcessBuilder properly. + // Set folder permissions to allow msiexec unpack msi bundle. + TKit.createTextFile(unpackBat, List.of( + String.format("icacls \"%s\" /inheritance:e /grant Users:M", + destinationDir), + String.join(" ", List.of( + "msiexec", + "/a", + String.format("\"%s\"", msiPath), + "/qn", + String.format("TARGETDIR=\"%s\"", + unpackDir.toAbsolutePath().normalize()))))); + runMsiexecWithRetries(Executor.of("cmd", "/c", unpackBat.toString()), Optional.empty()); + + // + // WiX3 uses "." as the value of "DefaultDir" field for "ProgramFiles64Folder" folder in msi's Directory table + // WiX4 uses "PFiles64" as the value of "DefaultDir" field for "ProgramFiles64Folder" folder in msi's Directory table + // msiexec creates "Program Files/./" from WiX3 msi which translates to "Program Files/" + // msiexec creates "Program Files/PFiles64/" from WiX4 msi + // So for WiX4 msi we need to transform "Program Files/PFiles64/" into "Program Files/" + // + // WiX4 does the same thing for %LocalAppData%. + // + for (var extraPathComponent : List.of("PFiles64", "LocalApp")) { + if (Files.isDirectory(unpackDir.resolve(extraPathComponent))) { + Path installationSubDirectory = getInstallationSubDirectory(cmd); + Path from = Path.of(extraPathComponent).resolve(installationSubDirectory); + Path to = installationSubDirectory; + TKit.trace(String.format("Convert [%s] into [%s] in [%s] directory", from, to, + unpackDir)); + ThrowingRunnable.toRunnable(() -> { + Files.createDirectories(unpackDir.resolve(to).getParent()); + Files.move(unpackDir.resolve(from), unpackDir.resolve(to)); + TKit.deleteDirectoryRecursive(unpackDir.resolve(extraPathComponent)); + }).run(); } - }; - msi.unpackHandler = (cmd, destinationDir) -> { - cmd.verifyIsOfType(PackageType.WIN_MSI); - final Path unpackBat = destinationDir.resolve("unpack.bat"); - final Path unpackDir = destinationDir.resolve( - TKit.removeRootFromAbsolutePath( - getInstallationRootDirectory(cmd))); + } + return destinationDir; + } - final Path msiPath = TransientMsi.create(cmd).path(); + static PackageHandlers createExePackageHandlers(boolean createMsiLog) { + return new PackageHandlers(cmd -> installExe(cmd, createMsiLog), WindowsHelper::uninstallExe, Optional.empty()); + } - // Put msiexec in .bat file because can't pass value of TARGETDIR - // property containing spaces through ProcessBuilder properly. - // Set folder permissions to allow msiexec unpack msi bundle. - TKit.createTextFile(unpackBat, List.of( - String.format("icacls \"%s\" /inheritance:e /grant Users:M", - destinationDir), - String.join(" ", List.of( - "msiexec", - "/a", - String.format("\"%s\"", msiPath), - "/qn", - String.format("TARGETDIR=\"%s\"", - unpackDir.toAbsolutePath().normalize()))))); - runMsiexecWithRetries(Executor.of("cmd", "/c", unpackBat.toString())); + private static int runExeInstaller(JPackageCommand cmd, boolean createMsiLog, boolean install) { + cmd.verifyIsOfType(PackageType.WIN_EXE); + Executor exec = new Executor().setExecutable(cmd.outputBundle()); + if (install) { + exec.addArgument("/qn").addArgument("/norestart"); + } else { + exec.addArgument("uninstall"); + } + return runMsiexecWithRetries(exec, configureMsiLogFile(cmd, createMsiLog)); + } - // - // WiX3 uses "." as the value of "DefaultDir" field for "ProgramFiles64Folder" folder in msi's Directory table - // WiX4 uses "PFiles64" as the value of "DefaultDir" field for "ProgramFiles64Folder" folder in msi's Directory table - // msiexec creates "Program Files/./" from WiX3 msi which translates to "Program Files/" - // msiexec creates "Program Files/PFiles64/" from WiX4 msi - // So for WiX4 msi we need to transform "Program Files/PFiles64/" into "Program Files/" - // - // WiX4 does the same thing for %LocalAppData%. - // - for (var extraPathComponent : List.of("PFiles64", "LocalApp")) { - if (Files.isDirectory(unpackDir.resolve(extraPathComponent))) { - Path installationSubDirectory = getInstallationSubDirectory(cmd); - Path from = Path.of(extraPathComponent).resolve(installationSubDirectory); - Path to = installationSubDirectory; - TKit.trace(String.format("Convert [%s] into [%s] in [%s] directory", from, to, - unpackDir)); - ThrowingRunnable.toRunnable(() -> { - Files.createDirectories(unpackDir.resolve(to).getParent()); - Files.move(unpackDir.resolve(from), unpackDir.resolve(to)); - TKit.deleteDirectoryRecursive(unpackDir.resolve(extraPathComponent)); - }).run(); - } - } - return destinationDir; - }; - return msi; + private static int installExe(JPackageCommand cmd, boolean createMsiLog) { + return runExeInstaller(cmd, createMsiLog, true); + } + + private static void uninstallExe(JPackageCommand cmd) { + if (Files.exists(cmd.outputBundle())) { + runExeInstaller(cmd, false, false); + } else { + configureMsiLogFile(cmd, false); + } } record TransientMsi(Path path) { @@ -204,28 +257,6 @@ public class WindowsHelper { } } - static PackageHandlers createExePackageHandlers() { - BiConsumer installExe = (cmd, install) -> { - cmd.verifyIsOfType(PackageType.WIN_EXE); - Executor exec = new Executor().setExecutable(cmd.outputBundle()); - if (install) { - exec.addArgument("/qn").addArgument("/norestart"); - } else { - exec.addArgument("uninstall"); - } - runMsiexecWithRetries(exec); - }; - - PackageHandlers exe = new PackageHandlers(); - exe.installHandler = cmd -> installExe.accept(cmd, true); - exe.uninstallHandler = cmd -> { - if (Files.exists(cmd.outputBundle())) { - installExe.accept(cmd, false); - } - }; - return exe; - } - static void verifyDesktopIntegration(JPackageCommand cmd, String launcherName) { new DesktopIntegrationVerifier(cmd, launcherName); @@ -415,14 +446,12 @@ public class WindowsHelper { } private void verifySystemDesktopShortcut(boolean exists) { - Path dir = Path.of(queryRegistryValueCache( - SYSTEM_SHELL_FOLDERS_REGKEY, "Common Desktop")); + Path dir = SpecialFolder.COMMON_DESKTOP.getPath(); verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyUserLocalDesktopShortcut(boolean exists) { - Path dir = Path.of( - queryRegistryValueCache(USER_SHELL_FOLDERS_REGKEY, "Desktop")); + Path dir = SpecialFolder.USER_DESKTOP.getPath(); verifyShortcut(dir.resolve(desktopShortcutPath), exists); } @@ -445,19 +474,22 @@ public class WindowsHelper { Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath); verifyShortcut(shortcutPath, exists); if (!exists) { - TKit.assertDirectoryNotEmpty(shortcutPath.getParent()); + final var parentDir = shortcutPath.getParent(); + if (Files.isDirectory(parentDir)) { + TKit.assertDirectoryNotEmpty(parentDir); + } else { + TKit.assertPathExists(parentDir, false); + } } } private void verifySystemStartMenuShortcut(boolean exists) { - verifyStartMenuShortcut(Path.of(queryRegistryValueCache( - SYSTEM_SHELL_FOLDERS_REGKEY, "Common Programs")), exists); + verifyStartMenuShortcut(SpecialFolder.COMMON_START_MENU_PROGRAMS.getPath(), exists); } private void verifyUserLocalStartMenuShortcut(boolean exists) { - verifyStartMenuShortcut(Path.of(queryRegistryValueCache( - USER_SHELL_FOLDERS_REGKEY, "Programs")), exists); + verifyStartMenuShortcut(SpecialFolder.USER_START_MENU_PROGRAMS.getPath(), exists); } private void verifyFileAssociationsRegistry(Path faFile) { @@ -565,16 +597,66 @@ public class WindowsHelper { return value; } - private static String queryRegistryValueCache(String keyPath, - String valueName) { - String key = String.format("[%s][%s]", keyPath, valueName); - String value = REGISTRY_VALUES.get(key); - if (value == null) { - value = queryRegistryValue(keyPath, valueName); - REGISTRY_VALUES.put(key, value); + // See .NET special folders + private enum SpecialFolderDotNet { + Desktop, + CommonDesktop, + + Programs, + CommonPrograms; + + Path getPath() { + final var str = Executor.of("powershell", "-NoLogo", "-NoProfile", + "-NonInteractive", "-Command", + String.format("[Environment]::GetFolderPath('%s')", name()) + ).saveFirstLineOfOutput().execute().getFirstLineOfOutput(); + + TKit.trace(String.format("Value of .NET special folder '%s' is [%s]", name(), str)); + + return Path.of(str); + } + } + + private record RegValuePath(String keyPath, String valueName) { + RegValuePath { + Objects.requireNonNull(keyPath); + Objects.requireNonNull(valueName); } - return value; + Optional findValue() { + return Optional.ofNullable(queryRegistryValue(keyPath, valueName)); + } + } + + private enum SpecialFolder { + COMMON_START_MENU_PROGRAMS(SYSTEM_SHELL_FOLDERS_REGKEY, "Common Programs", SpecialFolderDotNet.CommonPrograms), + USER_START_MENU_PROGRAMS(USER_SHELL_FOLDERS_REGKEY, "Programs", SpecialFolderDotNet.Programs), + + COMMON_DESKTOP(SYSTEM_SHELL_FOLDERS_REGKEY, "Common Desktop", SpecialFolderDotNet.CommonDesktop), + USER_DESKTOP(USER_SHELL_FOLDERS_REGKEY, "Desktop", SpecialFolderDotNet.Desktop); + + SpecialFolder(String keyPath, String valueName) { + reg = new RegValuePath(keyPath, valueName); + alt = Optional.empty(); + } + + SpecialFolder(String keyPath, String valueName, SpecialFolderDotNet alt) { + reg = new RegValuePath(keyPath, valueName); + this.alt = Optional.of(alt); + } + + Path getPath() { + return CACHE.computeIfAbsent(this, k -> reg.findValue().map(Path::of).orElseGet(() -> { + return alt.map(SpecialFolderDotNet::getPath).orElseThrow(() -> { + return new NoSuchElementException(String.format("Failed to find path to %s folder", name())); + }); + })); + } + + private final RegValuePath reg; + private final Optional alt; + + private final static Map CACHE = new ConcurrentHashMap<>(); } private static final class ShortPathUtils { @@ -617,7 +699,5 @@ public class WindowsHelper { private static final String SYSTEM_SHELL_FOLDERS_REGKEY = "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; private static final String USER_SHELL_FOLDERS_REGKEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; - private static final Map REGISTRY_VALUES = new HashMap<>(); - private static final int WIN_MAX_PATH = 260; } diff --git a/test/jdk/tools/jpackage/resources/fail-os-condition.wxf b/test/jdk/tools/jpackage/resources/fail-os-condition.wxf new file mode 100644 index 00000000000..3b3a79ff2ae --- /dev/null +++ b/test/jdk/tools/jpackage/resources/fail-os-condition.wxf @@ -0,0 +1,32 @@ + + + + + + 0 + + + diff --git a/test/jdk/tools/jpackage/windows/WinOSConditionTest.java b/test/jdk/tools/jpackage/windows/WinOSConditionTest.java new file mode 100644 index 00000000000..3cf4fdd541c --- /dev/null +++ b/test/jdk/tools/jpackage/windows/WinOSConditionTest.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. + */ + +import java.io.IOException; +import java.nio.file.Files; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary jpackage test that installer blocks on Windows of older version + * @library /test/jdk/tools/jpackage/helpers + * @key jpackagePlatformPackage + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror WinOSConditionTest.java + * @requires (os.family == "windows") + * @requires (jpackage.test.SQETest == null) + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=WinOSConditionTest + */ +public class WinOSConditionTest { + + @Test + public static void test() throws IOException { + // Use custom always failing condition. Installation is expected to fail. + // This way the test covers: + // 1. If jpackage picks custom OS version condition from the resource directory; + // 2. If the installer created by jpackage uses OS version condition. + new PackageTest().ignoreBundleOutputDir() + .forTypes(PackageType.WINDOWS) + .configureHelloApp() + .addInitializer(JPackageCommand::setFakeRuntime) + .addInitializer(cmd -> { + final var resourceDir = TKit.createTempDirectory("resource-dir"); + Files.copy(TKit.TEST_SRC_ROOT.resolve("resources/fail-os-condition.wxf"), resourceDir.resolve("os-condition.wxf")); + // Create a per-user installer to let user without admin privileges install it. + cmd.addArguments("--win-per-user-install", + "--resource-dir", resourceDir.toString()).setFakeRuntime(); + }) + .addUninstallVerifier(cmd -> { + // MSI error code 1603 is generic. + // Dig into the last msi log file for log messages specific to failed condition. + try (final var lines = cmd.winMsiLogFileContents().orElseThrow()) { + TKit.assertTextStream("Doing action: LaunchConditions").predicate(String::endsWith) + .andThen(TKit.assertTextStream("Not supported on this version of Windows").predicate(String::endsWith)).apply(lines); + } + }) + .createMsiLog(true) + .setExpectedInstallExitCode(1603) + // Create, try install the package (installation should fail) and verify it is not installed. + .run(Action.CREATE, Action.INSTALL, Action.VERIFY_UNINSTALL); + } +} From 29de20dbc22e0b68698a1b9cb1241ae5861a6b9a Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 4 Mar 2025 20:55:45 +0000 Subject: [PATCH 225/587] 8280991: [XWayland] No displayChanged event after setDisplayMode call Reviewed-by: honkar, prr --- .../classes/sun/awt/X11GraphicsDevice.java | 38 ++++++++++++++- test/jdk/ProblemList.txt | 1 - .../FullscreenWindowProps.java | 6 ++- .../NoResizeEventOnDMChangeTest.java | 46 ++++++++++++++++++- 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index b17b4c45644..39ecb13c6a4 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.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 @@ -72,6 +72,15 @@ public final class X11GraphicsDevice extends GraphicsDevice private boolean shutdownHookRegistered; private int scale; + // Wayland clients are by design not allowed to change the resolution in Wayland. + // XRandR in Xwayland is just an emulation, it doesn't actually change the resolution. + // This emulation is per window/x11 client, so different clients can have + // different emulated resolutions at the same time. + // So any request to get the current display mode will always return + // the original screen resolution, even if we are in emulated resolution. + // To handle this situation, we store the last set display mode in this variable. + private volatile DisplayMode xwlCurrentDisplayMode; + public X11GraphicsDevice(int screennum) { this.screen = screennum; this.scale = initScaleFactor(); @@ -117,6 +126,20 @@ public final class X11GraphicsDevice extends GraphicsDevice private Rectangle getBoundsImpl() { Rectangle rect = pGetBounds(getScreen()); + + if (XToolkit.isOnWayland() && xwlCurrentDisplayMode != null) { + // XRandR resolution change in Xwayland is an emulation, + // and implemented in such a way that multiple display modes + // for a device are only available in a single screen scenario, + // if we have multiple screens they will each have a single display mode + // (no emulated resolution change is available). + // So we don't have to worry about x and y for a screen here. + rect.setSize( + xwlCurrentDisplayMode.getWidth(), + xwlCurrentDisplayMode.getHeight() + ); + } + if (getScaleFactor() != 1) { rect.x = scaleDown(rect.x); rect.y = scaleDown(rect.y); @@ -400,10 +423,19 @@ public final class X11GraphicsDevice extends GraphicsDevice @Override public synchronized DisplayMode getDisplayMode() { if (isFullScreenSupported()) { + if (XToolkit.isOnWayland() && xwlCurrentDisplayMode != null) { + return xwlCurrentDisplayMode; + } + DisplayMode mode = getCurrentDisplayMode(screen); if (mode == null) { mode = getDefaultDisplayMode(); } + + if (XToolkit.isOnWayland()) { + xwlCurrentDisplayMode = mode; + } + return mode; } else { if (origDisplayMode == null) { @@ -474,6 +506,10 @@ public final class X11GraphicsDevice extends GraphicsDevice dm.getWidth(), dm.getHeight(), dm.getRefreshRate()); + if (XToolkit.isOnWayland()) { + xwlCurrentDisplayMode = dm; + } + // update bounds of the fullscreen window w.setBounds(0, 0, dm.getWidth(), dm.getHeight()); diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 37401913840..5ba6b33433c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -499,7 +499,6 @@ java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 m # Wayland related -java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java 8280991 linux-x64 java/awt/FullScreen/SetFullScreenTest.java 8332155 linux-x64 ############################################################################ diff --git a/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java b/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java index f5f77d47319..66f358d64ce 100644 --- a/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java +++ b/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.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 @@ -52,6 +52,10 @@ public final class FullscreenWindowProps { super.paint(g); g.setColor(Color.GREEN); g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(Color.RED); + DisplayMode displayMode = + getGraphicsConfiguration().getDevice().getDisplayMode(); + g.drawString(displayMode.toString(), 100, 100); } }; try { diff --git a/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java b/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java index 455ad2f2b0a..c7277e8b96c 100644 --- a/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java +++ b/test/jdk/java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, 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 @@ -26,6 +26,8 @@ * @bug 6646411 * @summary Tests that full screen window and its children receive resize event when display mode changes + * @library /test/lib + * @build jdk.test.lib.Platform jtreg.SkippedException * @run main/othervm NoResizeEventOnDMChangeTest * @run main/othervm -Dsun.java2d.d3d=false NoResizeEventOnDMChangeTest */ @@ -44,9 +46,21 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.BufferedReader; +import java.io.IOException; + +import static java.util.concurrent.TimeUnit.SECONDS; +import jdk.test.lib.Platform; +import jtreg.SkippedException; public class NoResizeEventOnDMChangeTest { + public static void main(String[] args) { + if (Platform.isOnWayland() && !isFixDelivered()) { + throw new SkippedException("Test skipped because fix was not" + + "delivered in current GnomeShell version"); + } + final GraphicsDevice gd = GraphicsEnvironment. getLocalGraphicsEnvironment().getDefaultScreenDevice(); @@ -231,4 +245,34 @@ public class NoResizeEventOnDMChangeTest { return dmChanges; } } + + private static boolean isFixDelivered() { + try { + Process process = + new ProcessBuilder("/usr/bin/gnome-shell", "--version") + .start(); + + try (BufferedReader reader = process.inputReader()) { + if (process.waitFor(2, SECONDS) && process.exitValue() == 0) { + String line = reader.readLine(); + if (line != null) { + System.out.println("Gnome shell version: " + line); + String[] versionComponents = line + .replaceAll("[^\\d.]", "") + .split("\\."); + + if (versionComponents.length >= 1) { + return Integer.parseInt(versionComponents[0]) > 42; + } + } + } + } + } catch (IOException + | InterruptedException + | IllegalThreadStateException + | NumberFormatException ignored) { + } + + return false; + } } From 38b4d46c1ff3701d75ff8347e5edbb01acd9b512 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Tue, 4 Mar 2025 21:44:40 +0000 Subject: [PATCH 226/587] 8351081: Off-by-one error in ShenandoahCardCluster Reviewed-by: wkemper --- src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index f5acb4f10ed..e28f2f03052 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -402,7 +402,7 @@ public: ShenandoahCardCluster(ShenandoahDirectCardMarkRememberedSet* rs) { _rs = rs; - _object_starts = NEW_C_HEAP_ARRAY(crossing_info, rs->total_cards(), mtGC); + _object_starts = NEW_C_HEAP_ARRAY(crossing_info, rs->total_cards() + 1, mtGC); // the +1 is to account for card table guarding entry for (size_t i = 0; i < rs->total_cards(); i++) { _object_starts[i].short_word = 0; } From 20ea218ce52f79704445acfe2d4a3dc9d04e86d2 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 4 Mar 2025 23:10:52 +0000 Subject: [PATCH 227/587] 8336042: Caller/callee param size mismatch in deoptimization causes crash Co-authored-by: Richard Reingruber Reviewed-by: pchilanomate, rrich, vlivanov, never --- .../aarch64/abstractInterpreter_aarch64.cpp | 3 +- .../cpu/arm/abstractInterpreter_arm.cpp | 9 ++ .../cpu/ppc/abstractInterpreter_ppc.cpp | 9 ++ .../cpu/riscv/abstractInterpreter_riscv.cpp | 3 +- .../cpu/s390/abstractInterpreter_s390.cpp | 7 ++ .../cpu/x86/abstractInterpreter_x86.cpp | 5 +- src/hotspot/share/interpreter/bytecode.hpp | 2 + .../share/interpreter/bytecode.inline.hpp | 10 ++ src/hotspot/share/runtime/deoptimization.cpp | 21 ++-- src/hotspot/share/runtime/vframeArray.cpp | 6 +- .../jtreg/compiler/jsr292/MHDeoptTest.java | 97 +++++++++++++++++++ 11 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/jsr292/MHDeoptTest.java diff --git a/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp b/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp index a3c729fdd56..b543c96f3b8 100644 --- a/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/abstractInterpreter_aarch64.cpp @@ -149,7 +149,8 @@ void AbstractInterpreter::layout_activation(Method* method, #ifdef ASSERT if (caller->is_interpreted_frame()) { - assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement"); + assert(locals <= caller->interpreter_frame_expression_stack(), "bad placement"); + assert(locals >= interpreter_frame->sender_sp() + max_locals - 1, "bad placement"); } #endif diff --git a/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp b/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp index 075db4736f1..978011491a0 100644 --- a/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp +++ b/src/hotspot/cpu/arm/abstractInterpreter_arm.cpp @@ -131,6 +131,15 @@ void AbstractInterpreter::layout_activation(Method* method, intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1; +#ifdef ASSERT + if (caller->is_interpreted_frame()) { + // Test exact placement on top of caller args + intptr_t* l2 = caller->interpreter_frame_last_sp() + caller_actual_parameters - 1; + assert(l2 <= caller->interpreter_frame_expression_stack(), "bad placement"); + assert(l2 >= locals, "bad placement"); + } +#endif + interpreter_frame->interpreter_frame_set_locals(locals); BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin(); BasicObjectLock* monbot = montop - moncount; diff --git a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp index cc094ad4f99..beadce33637 100644 --- a/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp +++ b/src/hotspot/cpu/ppc/abstractInterpreter_ppc.cpp @@ -128,6 +128,15 @@ void AbstractInterpreter::layout_activation(Method* method, caller->interpreter_frame_esp() + caller_actual_parameters : caller->sp() + method->max_locals() - 1 + (frame::java_abi_size / Interpreter::stackElementSize); +#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); + assert(locals_base >= l2, "bad placement"); + } +#endif + intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize; intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); intptr_t* esp_base = monitor - 1; diff --git a/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp b/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp index 843a58e28d7..00a6877684a 100644 --- a/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp +++ b/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp @@ -141,7 +141,8 @@ void AbstractInterpreter::layout_activation(Method* method, #ifdef ASSERT if (caller->is_interpreted_frame()) { - assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement"); + assert(locals <= caller->interpreter_frame_expression_stack(), "bad placement"); + assert(locals >= interpreter_frame->sender_sp() + max_locals - 1, "bad placement"); } #endif diff --git a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp index 37aa9d9a0e8..e815542a51e 100644 --- a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp +++ b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp @@ -182,6 +182,13 @@ void AbstractInterpreter::layout_activation(Method* method, intptr_t* sender_sp; if (caller->is_interpreted_frame()) { sender_sp = caller->interpreter_frame_top_frame_sp(); +#ifdef ASSERT + assert(locals_base <= caller->interpreter_frame_expression_stack(), "bad placement"); + // Test caller-aligned placement vs callee-aligned + intptr_t* l2 = (caller->sp() + method->max_locals() - 1 + + frame::z_parent_ijava_frame_abi_size / Interpreter::stackElementSize); + assert(locals_base >= l2, "bad placement"); +#endif } else if (caller->is_compiled_frame()) { sender_sp = caller->fp() - caller->cb()->frame_size(); // The bottom frame's sender_sp is its caller's unextended_sp. diff --git a/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp index 68ac5b6ca9a..6680b8c4c03 100644 --- a/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp +++ b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp @@ -87,7 +87,10 @@ void AbstractInterpreter::layout_activation(Method* method, #ifdef ASSERT if (caller->is_interpreted_frame()) { - assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement"); + // Test exact placement on top of caller args + intptr_t* l2 = caller->interpreter_frame_last_sp() + caller_actual_parameters - 1; + assert(l2 <= caller->interpreter_frame_expression_stack(), "bad placement"); + assert(l2 >= locals, "bad placement"); } #endif diff --git a/src/hotspot/share/interpreter/bytecode.hpp b/src/hotspot/share/interpreter/bytecode.hpp index 870fcb7784e..de83cfe5d71 100644 --- a/src/hotspot/share/interpreter/bytecode.hpp +++ b/src/hotspot/share/interpreter/bytecode.hpp @@ -226,6 +226,8 @@ class Bytecode_invoke: public Bytecode_member_ref { bool has_appendix(); + bool has_member_arg() const; + int size_of_parameters() const; private: diff --git a/src/hotspot/share/interpreter/bytecode.inline.hpp b/src/hotspot/share/interpreter/bytecode.inline.hpp index 43e0cf2991d..139f477d397 100644 --- a/src/hotspot/share/interpreter/bytecode.inline.hpp +++ b/src/hotspot/share/interpreter/bytecode.inline.hpp @@ -28,6 +28,7 @@ #include "interpreter/bytecode.hpp" #include "oops/cpCache.inline.hpp" +#include "prims/methodHandles.hpp" inline bool Bytecode_invoke::has_appendix() { if (invoke_code() == Bytecodes::_invokedynamic) { @@ -37,4 +38,13 @@ inline bool Bytecode_invoke::has_appendix() { } } +inline bool Bytecode_invoke::has_member_arg() const { + // NOTE: We could resolve the call and use the resolved adapter method here, but this function + // is used by deoptimization, where resolving could lead to problems, so we avoid that here + // by doing things symbolically. + // + // invokedynamic instructions don't have a class but obviously don't have a MemberName appendix. + return !is_invokedynamic() && MethodHandles::has_member_arg(klass(), name()); +} + #endif // SHARE_INTERPRETER_BYTECODE_INLINE_HPP diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 4a51e2cbd92..167b3095fa9 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -36,6 +36,7 @@ #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" #include "interpreter/oopMapCache.hpp" @@ -641,11 +642,12 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread bool caller_was_method_handle = false; if (deopt_sender.is_interpreted_frame()) { methodHandle method(current, deopt_sender.interpreter_frame_method()); - Bytecode_invoke cur = Bytecode_invoke_check(method, deopt_sender.interpreter_frame_bci()); - if (cur.is_invokedynamic() || cur.is_invokehandle()) { - // Method handle invokes may involve fairly arbitrary chains of - // calls so it's impossible to know how much actual space the - // caller has for locals. + Bytecode_invoke cur(method, deopt_sender.interpreter_frame_bci()); + if (cur.has_member_arg()) { + // This should cover all real-world cases. One exception is a pathological chain of + // MH.linkToXXX() linker calls, which only trusted code could do anyway. To handle that case, we + // would need to get the size from the resolved method entry. Another exception would + // be an invokedynamic with an adapter that is really a MethodHandle linker. caller_was_method_handle = true; } } @@ -748,9 +750,14 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread } #endif + int caller_actual_parameters = -1; // value not used except for interpreted frames, see below + if (deopt_sender.is_interpreted_frame()) { + caller_actual_parameters = callee_parameters + (caller_was_method_handle ? 1 : 0); + } + UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord, caller_adjustment * BytesPerWord, - caller_was_method_handle ? 0 : callee_parameters, + caller_actual_parameters, number_of_frames, frame_sizes, frame_pcs, @@ -939,7 +946,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m if (Bytecodes::is_invoke(cur_code)) { Bytecode_invoke invoke(mh, iframe->interpreter_frame_bci()); cur_invoke_parameter_size = invoke.size_of_parameters(); - if (i != 0 && !invoke.is_invokedynamic() && MethodHandles::has_member_arg(invoke.klass(), invoke.name())) { + if (i != 0 && invoke.has_member_arg()) { callee_size_of_parameters++; } } diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 1640b08c479..e17961fc424 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -25,6 +25,7 @@ #include "classfile/vmSymbols.hpp" #include "code/vmreg.inline.hpp" #include "interpreter/bytecode.hpp" +#include "interpreter/bytecode.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -610,10 +611,7 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller methodHandle caller(current, elem->method()); methodHandle callee(current, element(index - 1)->method()); Bytecode_invoke inv(caller, elem->bci()); - // invokedynamic instructions don't have a class but obviously don't have a MemberName appendix. - // NOTE: Use machinery here that avoids resolving of any kind. - const bool has_member_arg = - !inv.is_invokedynamic() && MethodHandles::has_member_arg(inv.klass(), inv.name()); + const bool has_member_arg = inv.has_member_arg(); callee_parameters = callee->size_of_parameters() + (has_member_arg ? 1 : 0); callee_locals = callee->max_locals(); } diff --git a/test/hotspot/jtreg/compiler/jsr292/MHDeoptTest.java b/test/hotspot/jtreg/compiler/jsr292/MHDeoptTest.java new file mode 100644 index 00000000000..61dd330cfdd --- /dev/null +++ b/test/hotspot/jtreg/compiler/jsr292/MHDeoptTest.java @@ -0,0 +1,97 @@ +/* + * 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.jsr292; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; + +/* + * @test + * @bug 8336042 + * @library /test/lib / + * + * @run main/bootclasspath/othervm -Xbatch -XX:-TieredCompilation compiler.jsr292.MHDeoptTest + * + */ +public class MHDeoptTest { + + static int xx = 0; + + public static void main(String[] args) throws Throwable { + MethodHandle mh1 = MethodHandles.lookup().findStatic(MHDeoptTest.class, "body1", MethodType.methodType(int.class)); + MethodHandle mh2 = MethodHandles.lookup().findStatic(MHDeoptTest.class, "body2", MethodType.methodType(int.class)); + MethodHandle[] arr = new MethodHandle[] {mh2, mh1}; + + for (MethodHandle mh : arr) { + for (int i = 1; i < 50_000; i++) { + xx = i; + mainLink(mh); + } + } + + } + + static int mainLink(MethodHandle mh) throws Throwable { + return (int)mh.invokeExact(); + } + + static int cnt = 1000; + + static int body1() { + int limit = 0x7fff; + // uncommon trap + if (xx == limit) { + // OSR + for (int i = 0; i < 50_000; i++) { + } + ++cnt; + ++xx; + } + if (xx == limit + 1) { + return cnt + 1; + } + return cnt; + } + + static int body2() { + int limit = 0x7fff; + int dummy = 0; + // uncommon trap + if (xx == limit) { + // OSR + for (int i = 0; i < 50_000; i++) { + } + ++cnt; + ++xx; + } + if (xx == limit + 1) { + return cnt + 1; + } + return cnt; + } + +} From 62fa33a8704aef9fd08a8221f4fde217ab749dfc Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 5 Mar 2025 01:34:15 +0000 Subject: [PATCH 228/587] 8351158: Incorrect APX EGPR register save ordering Reviewed-by: kvn, sviswanathan --- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 35 ++++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index bbe62db33f0..d3e7e23678a 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -101,24 +101,23 @@ class RegisterSaver { ymm_off = xmm_off + (XSAVE_AREA_YMM_BEGIN - XSAVE_AREA_BEGIN)/BytesPerInt, DEF_YMM_OFFS(0), DEF_YMM_OFFS(1), - // 2..15 are implied in range usage - r31_off = xmm_off + (XSAVE_AREA_EGPRS - XSAVE_AREA_BEGIN)/BytesPerInt, - r31H_off, - r30_off, r30H_off, - r29_off, r29H_off, - r28_off, r28H_off, - r27_off, r27H_off, - r26_off, r26H_off, - r25_off, r25H_off, - r24_off, r24H_off, - r23_off, r23H_off, - r22_off, r22H_off, - r21_off, r21H_off, - r20_off, r20H_off, - r19_off, r19H_off, - r18_off, r18H_off, + r16_off = xmm_off + (XSAVE_AREA_EGPRS - XSAVE_AREA_BEGIN)/BytesPerInt, + r16H_off, r17_off, r17H_off, - r16_off, r16H_off, + r18_off, r18H_off, + r19_off, r19H_off, + r20_off, r20H_off, + r21_off, r21H_off, + r22_off, r22H_off, + r23_off, r23H_off, + r24_off, r24H_off, + r25_off, r25H_off, + r26_off, r26H_off, + r27_off, r27H_off, + r28_off, r28H_off, + r29_off, r29H_off, + r30_off, r30H_off, + r31_off, r31H_off, opmask_off = xmm_off + (XSAVE_AREA_OPMASK_BEGIN - XSAVE_AREA_BEGIN)/BytesPerInt, DEF_OPMASK_OFFS(0), DEF_OPMASK_OFFS(1), @@ -265,7 +264,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ if (UseAPX) { int base_addr = XSAVE_AREA_EGPRS; off = 0; - for(int n = 16; n < Register::number_of_registers; n++) { + for (int n = 16; n < Register::number_of_registers; n++) { __ movq(Address(rsp, base_addr+(off++*8)), as_Register(n)); } } From b1a21b563e3ae13fa5c409a4f0c04686c3f5b34a Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 5 Mar 2025 02:17:22 +0000 Subject: [PATCH 229/587] 8351101: RISC-V: C2: Small improvement to MacroAssembler::revb Reviewed-by: fjiang, mli --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index f2bdd20890b..d3daef7664d 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2892,7 +2892,6 @@ void MacroAssembler::revb(Register Rd, Register Rs, Register tmp1, Register tmp2 slli(tmp1, tmp1, 8); } srli(Rd, Rs, 56); - zext(Rd, Rd, 8); orr(Rd, tmp1, Rd); } From 75f028b46b245bdcbde8391af69020befda66b7d Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 5 Mar 2025 10:01:26 +0000 Subject: [PATCH 230/587] 8348657: compiler/loopopts/superword/TestEquivalentInvariants.java timed out Reviewed-by: thartmann --- .../compiler/loopopts/superword/TestEquivalentInvariants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index 09b087bee54..b3032b1fa4e 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 compiler.loopopts.superword.TestEquivalentInvariants + * @run driver/timeout=1200 compiler.loopopts.superword.TestEquivalentInvariants */ public class TestEquivalentInvariants { From de29ef3bf3a029f99f340de9f093cd20544217fd Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Wed, 5 Mar 2025 10:32:36 +0000 Subject: [PATCH 231/587] 8343191: Cgroup v1 subsystem fails to set subsystem path Co-authored-by: Severin Gehwolf Reviewed-by: sgehwolf, mbaesken --- src/hotspot/os/linux/cgroupUtil_linux.cpp | 30 ++++- .../os/linux/cgroupV1Subsystem_linux.cpp | 77 +++++++++-- .../os/linux/cgroupV2Subsystem_linux.cpp | 6 +- .../cgroupv1/CgroupV1SubsystemController.java | 42 +++--- .../runtime/test_cgroupSubsystem_linux.cpp | 78 ++++++++++- .../docker/TestMemoryWithSubgroups.java | 126 ++++++++++++++++++ .../CgroupV1SubsystemControllerTest.java | 17 ++- .../cgroup/TestCgroupSubsystemFactory.java | 34 ++++- .../TestDockerMemoryMetricsSubgroup.java | 120 +++++++++++++++++ 9 files changed, 488 insertions(+), 42 deletions(-) create mode 100644 test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java create mode 100644 test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index bc0e018d6be..b52ef87dcae 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2024, 2025, Red Hat, Inc. * 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,12 +49,18 @@ int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { } void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { + assert(mem->cgroup_path() != nullptr, "invariant"); + if (strstr(mem->cgroup_path(), "../") != nullptr) { + log_warning(os, container)("Cgroup memory controller path at '%s' seems to have moved to '%s', detected limits won't be accurate", + mem->mount_point(), mem->cgroup_path()); + mem->set_subsystem_path("/"); + return; + } if (!mem->needs_hierarchy_adjustment()) { // nothing to do return; } log_trace(os, container)("Adjusting controller path for memory: %s", mem->subsystem_path()); - assert(mem->cgroup_path() != nullptr, "invariant"); char* orig = os::strdup(mem->cgroup_path()); char* cg_path = os::strdup(orig); char* last_slash; @@ -62,7 +68,8 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { julong phys_mem = os::Linux::physical_memory(); char* limit_cg_path = nullptr; jlong limit = mem->read_memory_limit_in_bytes(phys_mem); - jlong lowest_limit = phys_mem; + jlong lowest_limit = limit < 0 ? phys_mem : limit; + julong orig_limit = ((julong)lowest_limit) != phys_mem ? lowest_limit : phys_mem; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { *last_slash = '\0'; // strip path // update to shortened path and try again @@ -83,7 +90,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { limit_cg_path = os::strdup("/"); } assert(lowest_limit >= 0, "limit must be positive"); - if ((julong)lowest_limit != phys_mem) { + if ((julong)lowest_limit != orig_limit) { // we've found a lower limit anywhere in the hierarchy, // set the path to the limit path assert(limit_cg_path != nullptr, "limit path must be set"); @@ -93,6 +100,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { mem->subsystem_path(), lowest_limit); } else { + log_trace(os, container)("Lowest limit was: " JLONG_FORMAT, lowest_limit); log_trace(os, container)("No lower limit found for memory in hierarchy %s, " "adjusting to original path %s", mem->mount_point(), orig); @@ -104,19 +112,26 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { } void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { + assert(cpu->cgroup_path() != nullptr, "invariant"); + if (strstr(cpu->cgroup_path(), "../") != nullptr) { + log_warning(os, container)("Cgroup cpu controller path at '%s' seems to have moved to '%s', detected limits won't be accurate", + cpu->mount_point(), cpu->cgroup_path()); + cpu->set_subsystem_path("/"); + return; + } if (!cpu->needs_hierarchy_adjustment()) { // nothing to do return; } log_trace(os, container)("Adjusting controller path for cpu: %s", cpu->subsystem_path()); - assert(cpu->cgroup_path() != nullptr, "invariant"); char* orig = os::strdup(cpu->cgroup_path()); char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); int host_cpus = os::Linux::active_processor_count(); int cpus = CgroupUtil::processor_count(cpu, host_cpus); - int lowest_limit = host_cpus; + int lowest_limit = cpus < host_cpus ? cpus: host_cpus; + int orig_limit = lowest_limit != host_cpus ? lowest_limit : host_cpus; char* limit_cg_path = nullptr; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { *last_slash = '\0'; // strip path @@ -138,7 +153,7 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { limit_cg_path = os::strdup(cg_path); } assert(lowest_limit >= 0, "limit must be positive"); - if (lowest_limit != host_cpus) { + if (lowest_limit != orig_limit) { // we've found a lower limit anywhere in the hierarchy, // set the path to the limit path assert(limit_cg_path != nullptr, "limit path must be set"); @@ -148,6 +163,7 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { cpu->subsystem_path(), lowest_limit); } else { + log_trace(os, container)("Lowest limit was: %d", lowest_limit); log_trace(os, container)("No lower limit found for cpu in hierarchy %s, " "adjusting to original path %s", cpu->mount_point(), orig); diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index a6ac2822b25..8d9c3edb72a 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -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 @@ -37,6 +37,47 @@ /* * Set directory to subsystem specific files based * on the contents of the mountinfo and cgroup files. + * + * The method determines whether it runs in + * - host mode + * - container mode + * + * In the host mode, _root is equal to "/" and + * the subsystem path is equal to the _mount_point path + * joined with cgroup_path. + * + * In the container mode, it can be two possibilities: + * - private namespace (cgroupns=private) + * - host namespace (cgroupns=host, default mode in cgroup V1 hosts) + * + * Private namespace is equivalent to the host mode, i.e. + * the subsystem path is set by concatenating + * _mount_point and cgroup_path. + * + * In the host namespace, _root is equal to host's cgroup path + * of the control group to which the containerized process + * belongs to at the moment of creation. The mountinfo and + * cgroup files are mirrored from the host, while the subsystem + * specific files are mapped directly at _mount_point, i.e. + * at /sys/fs/cgroup//, the subsystem path is + * then set equal to _mount_point. + * + * A special case of the subsystem path is when a cgroup path + * includes a subgroup, when a containerized process was associated + * with an existing cgroup, that is different from cgroup + * in which the process has been created. + * Here, the _root is equal to the host's initial cgroup path, + * cgroup_path will be equal to host's new cgroup path. + * As host cgroup hierarchies are not accessible in the container, + * it needs to be determined which part of cgroup path + * is accessible inside container, i.e. mapped under + * /sys/fs/cgroup//. + * In Docker default setup, host's cgroup path can be + * of the form: /docker//, + * from which only is mapped. + * The method trims cgroup path from left, until the subgroup + * component is found. The subsystem path will be set to + * the _mount_point joined with the subgroup path. */ void CgroupV1Controller::set_subsystem_path(const char* cgroup_path) { if (_cgroup_path != nullptr) { @@ -49,28 +90,36 @@ void CgroupV1Controller::set_subsystem_path(const char* cgroup_path) { _cgroup_path = os::strdup(cgroup_path); stringStream ss; if (_root != nullptr && cgroup_path != nullptr) { + ss.print_raw(_mount_point); if (strcmp(_root, "/") == 0) { - ss.print_raw(_mount_point); + // host processes and containers with cgroupns=private if (strcmp(cgroup_path,"/") != 0) { ss.print_raw(cgroup_path); } - _path = os::strdup(ss.base()); } else { - if (strcmp(_root, cgroup_path) == 0) { - ss.print_raw(_mount_point); - _path = os::strdup(ss.base()); - } else { - char *p = strstr((char*)cgroup_path, _root); - if (p != nullptr && p == _root) { - if (strlen(cgroup_path) > strlen(_root)) { - ss.print_raw(_mount_point); - const char* cg_path_sub = cgroup_path + strlen(_root); - ss.print_raw(cg_path_sub); - _path = os::strdup(ss.base()); + // containers with cgroupns=host, default setting is _root==cgroup_path + if (strcmp(_root, cgroup_path) != 0) { + if (*cgroup_path != '\0' && strcmp(cgroup_path, "/") != 0) { + // When moved to a subgroup, between subgroups, the path suffix will change. + const char *suffix = cgroup_path; + while (suffix != nullptr) { + stringStream pp; + pp.print_raw(_mount_point); + pp.print_raw(suffix); + if (os::file_exists(pp.base())) { + ss.print_raw(suffix); + if (suffix != cgroup_path) { + log_trace(os, container)("set_subsystem_path: cgroup v1 path reduced to: %s.", suffix); + } + break; + } + log_trace(os, container)("set_subsystem_path: skipped non-existent directory: %s.", suffix); + suffix = strchr(suffix + 1, '/'); } } } } + _path = os::strdup(ss.base()); } } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 62e8cac3a62..cbadbb9db02 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Red Hat Inc. + * Copyright (c) 2020, 2025, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -292,6 +292,10 @@ jlong memory_swap_limit_value(CgroupV2Controller* ctrl) { } void CgroupV2Controller::set_subsystem_path(const char* cgroup_path) { + if (_cgroup_path != nullptr) { + os::free(_cgroup_path); + } + _cgroup_path = os::strdup(cgroup_path); if (_path != nullptr) { os::free(_path); } diff --git a/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/CgroupV1SubsystemController.java b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/CgroupV1SubsystemController.java index 051b4da5f78..fd325a8f8b4 100644 --- a/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/CgroupV1SubsystemController.java +++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv1/CgroupV1SubsystemController.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,6 +25,9 @@ package jdk.internal.platform.cgroupv1; +import java.lang.System.Logger.Level; +import java.nio.file.Path; +import java.nio.file.Files; import jdk.internal.platform.CgroupSubsystem; import jdk.internal.platform.CgroupSubsystemController; @@ -44,27 +47,36 @@ public class CgroupV1SubsystemController implements CgroupSubsystemController { public void setPath(String cgroupPath) { if (root != null && cgroupPath != null) { + String path = mountPoint; if (root.equals("/")) { + // host processes and containers with cgroupns=private if (!cgroupPath.equals("/")) { - path = mountPoint + cgroupPath; + path += cgroupPath; } - else { - path = mountPoint; - } - } - else { - if (root.equals(cgroupPath)) { - path = mountPoint; - } - else { - if (cgroupPath.startsWith(root)) { - if (cgroupPath.length() > root.length()) { - String cgroupSubstr = cgroupPath.substring(root.length()); - path = mountPoint + cgroupSubstr; + } else { + // containers with cgroupns=host, default setting is _root==cgroup_path + if (!cgroupPath.equals(root)) { + if (!cgroupPath.equals("") && !cgroupPath.equals("/")) { + // When moved to a subgroup, between subgroups, the path suffix will change. + Path cgp = Path.of(cgroupPath); + int nameCount = cgp.getNameCount(); + for (int i=0; i < nameCount; i++) { + Path dir = Path.of(mountPoint, cgp.toString()); + if (Files.isDirectory(dir)) { + path = dir.toString(); + if (i > 0) { + System.getLogger("jdk.internal.platform").log(Level.DEBUG, String.format( + "Cgroup v1 path reduced to: %s.", cgp)); + } + break; + } + int currentNameCount = cgp.getNameCount(); + cgp = (currentNameCount > 1) ? cgp.subpath(1, currentNameCount) : Path.of(""); } } } } + this.path = path; } } diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index c8e2beff52b..c090aa28e9a 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -25,6 +25,7 @@ #include "runtime/os.hpp" #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" #include "unittest.hpp" @@ -432,9 +433,16 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path) { "/user.slice/user-1000.slice/user@1000.service", // cgroup_path "/sys/fs/cgroup/mem" // expected_path }; - int length = 2; + TestCase container_moving_cgroup = { + "/sys/fs/cgroup/cpu,cpuacct", // mount_path + "/system.slice/garden.service/garden/good/2f57368b-0eda-4e52-64d8-af5c", // root_path + "/system.slice/garden.service/garden/bad/2f57368b-0eda-4e52-64d8-af5c", // cgroup_path + "/sys/fs/cgroup/cpu,cpuacct" // expected_path + }; + int length = 3; TestCase* testCases[] = { &host, - &container_engine }; + &container_engine, + &container_moving_cgroup }; for (int i = 0; i < length; i++) { CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, (char*)testCases[i]->mount_path, @@ -444,6 +452,72 @@ TEST(cgroupTest, set_cgroupv1_subsystem_path) { } } +TEST(cgroupTest, set_cgroupv1_subsystem_path_adjusted) { + TestCase memory = { + "/sys/fs/cgroup/memory", // mount_path + "/", // root_path + "../test1", // cgroup_path + "/sys/fs/cgroup/memory" // expected_path + }; + TestCase cpu = { + "/sys/fs/cgroup/cpu", // mount_path + "/", // root_path + "../../test2", // cgroup_path + "/sys/fs/cgroup/cpu" // expected_path + }; + CgroupCpuController* ccc = new CgroupV1CpuController(CgroupV1Controller((char*)cpu.root_path, + (char*)cpu.mount_path, + true /* read-only mount */)); + ccc->set_subsystem_path((char*)cpu.cgroup_path); + EXPECT_TRUE(ccc->needs_hierarchy_adjustment()); + + CgroupUtil::adjust_controller(ccc); + ASSERT_STREQ(cpu.expected_path, ccc->subsystem_path()); + EXPECT_FALSE(ccc->needs_hierarchy_adjustment()); + + CgroupMemoryController* cmc = new CgroupV1MemoryController(CgroupV1Controller((char*)memory.root_path, + (char*)memory.mount_path, + true /* read-only mount */)); + cmc->set_subsystem_path((char*)memory.cgroup_path); + EXPECT_TRUE(cmc->needs_hierarchy_adjustment()); + + CgroupUtil::adjust_controller(cmc); + ASSERT_STREQ(memory.expected_path, cmc->subsystem_path()); + EXPECT_FALSE(cmc->needs_hierarchy_adjustment()); +} + +TEST(cgroupTest, set_cgroupv2_subsystem_path_adjusted) { + TestCase memory = { + "/sys/fs/cgroup", // mount_path + "/", // root_path + "../test1", // cgroup_path + "/sys/fs/cgroup" // expected_path + }; + TestCase cpu = { + "/sys/fs/cgroup", // mount_path + "/", // root_path + "../../test2", // cgroup_path + "/sys/fs/cgroup" // expected_path + }; + CgroupCpuController* ccc = new CgroupV2CpuController(CgroupV2Controller((char*)cpu.mount_path, + (char*)cpu.cgroup_path, + true /* read-only mount */)); + EXPECT_TRUE(ccc->needs_hierarchy_adjustment()); + + CgroupUtil::adjust_controller(ccc); + ASSERT_STREQ(cpu.expected_path, ccc->subsystem_path()); + EXPECT_FALSE(ccc->needs_hierarchy_adjustment()); + + CgroupMemoryController* cmc = new CgroupV2MemoryController(CgroupV2Controller((char*)memory.mount_path, + (char*)memory.cgroup_path, + true /* read-only mount */)); + EXPECT_TRUE(cmc->needs_hierarchy_adjustment()); + + CgroupUtil::adjust_controller(cmc); + ASSERT_STREQ(memory.expected_path, cmc->subsystem_path()); + EXPECT_FALSE(cmc->needs_hierarchy_adjustment()); +} + TEST(cgroupTest, set_cgroupv2_subsystem_path) { TestCase at_mount_root = { "/sys/fs/cgroup", // mount_path diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java new file mode 100644 index 00000000000..e7989874d7a --- /dev/null +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025, BELLSOFT. All rights reserved. + * 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.test.lib.containers.docker.Common; +import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.containers.docker.DockerRunOptions; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.internal.platform.Metrics; + +import java.util.ArrayList; + +import jtreg.SkippedException; + +/* + * @test + * @bug 8343191 + * @requires os.family == "linux" + * @modules java.base/jdk.internal.platform + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox + * @run main TestMemoryWithSubgroups + */ +public class TestMemoryWithSubgroups { + + private static final String imageName = Common.imageName("subgroup"); + + public static void main(String[] args) throws Exception { + Metrics metrics = Metrics.systemMetrics(); + if (metrics == null) { + System.out.println("Cgroup not configured."); + return; + } + if (!DockerTestUtils.canTestDocker()) { + System.out.println("Unable to run docker tests."); + return; + } + Common.prepareWhiteBox(); + DockerTestUtils.buildJdkContainerImage(imageName); + + if ("cgroupv1".equals(metrics.getProvider())) { + try { + testMemoryLimitSubgroupV1("200m", "100m", "104857600", false); + testMemoryLimitSubgroupV1("1g", "500m", "524288000", false); + testMemoryLimitSubgroupV1("200m", "100m", "104857600", true); + testMemoryLimitSubgroupV1("1g", "500m", "524288000", true); + } finally { + DockerTestUtils.removeDockerImage(imageName); + } + } else if ("cgroupv2".equals(metrics.getProvider())) { + try { + testMemoryLimitSubgroupV2("200m", "100m", "104857600", false); + testMemoryLimitSubgroupV2("1g", "500m", "524288000", false); + testMemoryLimitSubgroupV2("200m", "100m", "104857600", true); + testMemoryLimitSubgroupV2("1g", "500m", "524288000", true); + } finally { + DockerTestUtils.removeDockerImage(imageName); + } + } else { + throw new SkippedException("Metrics are from neither cgroup v1 nor v2, skipped for now."); + } + } + + private static void testMemoryLimitSubgroupV1(String containerMemorySize, String valueToSet, String expectedValue, boolean privateNamespace) + throws Exception { + + Common.logNewTestCase("Cgroup V1 subgroup memory limit: " + valueToSet); + + DockerRunOptions opts = new DockerRunOptions(imageName, "sh", "-c"); + opts.javaOpts = new ArrayList<>(); + opts.appendTestJavaOptions = false; + opts.addDockerOpts("--privileged") + .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) + .addDockerOpts("--memory", containerMemorySize); + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.limit_in_bytes ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "/jdk/bin/java -Xlog:os+container=trace -version"); + + Common.run(opts) + .shouldMatch("Lowest limit was:.*" + expectedValue); + } + + private static void testMemoryLimitSubgroupV2(String containerMemorySize, String valueToSet, String expectedValue, boolean privateNamespace) + throws Exception { + + Common.logNewTestCase("Cgroup V2 subgroup memory limit: " + valueToSet); + + DockerRunOptions opts = new DockerRunOptions(imageName, "sh", "-c"); + opts.javaOpts = new ArrayList<>(); + opts.appendTestJavaOptions = false; + opts.addDockerOpts("--privileged") + .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) + .addDockerOpts("--memory", containerMemorySize); + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "echo '+memory' > /sys/fs/cgroup/cgroup.subtree_control ; " + + "echo '+memory' > /sys/fs/cgroup/memory/cgroup.subtree_control ; " + + "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.max ; " + + "/jdk/bin/java -Xlog:os+container=trace -version"); + + Common.run(opts) + .shouldMatch("Lowest limit was:.*" + expectedValue); + } +} diff --git a/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java b/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java index a97edd581fe..3ab8b35ae0a 100644 --- a/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java +++ b/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Red Hat, Inc. + * Copyright (c) 2022, 2025, Red Hat, Inc. * 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,6 +64,9 @@ public class CgroupV1SubsystemControllerTest { assertEquals(expectedPath, ctrl.path()); } + /* + * Less common cases: Containers + */ @Test public void testCgPathSubstring() { String root = "/foo/bar/baz"; @@ -71,8 +74,18 @@ public class CgroupV1SubsystemControllerTest { CgroupV1SubsystemController ctrl = new CgroupV1SubsystemController(root, mountPoint); String cgroupPath = "/foo/bar/baz/some"; ctrl.setPath(cgroupPath); - String expectedPath = mountPoint + "/some"; + String expectedPath = mountPoint; assertEquals(expectedPath, ctrl.path()); } + @Test + public void testCgPathToMovedPath() { + String root = "/system.slice/garden.service/garden/good/2f57368b-0eda-4e52-64d8-af5c"; + String mountPoint = "/sys/fs/cgroup/cpu,cpuacct"; + CgroupV1SubsystemController ctrl = new CgroupV1SubsystemController(root, mountPoint); + String cgroupPath = "/system.slice/garden.service/garden/bad/2f57368b-0eda-4e52-64d8-af5c"; + ctrl.setPath(cgroupPath); + String expectedPath = mountPoint; + assertEquals(expectedPath, ctrl.path()); + } } diff --git a/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java b/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java index ede74b5011e..8cf53c66e8a 100644 --- a/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java +++ b/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Red Hat Inc. + * Copyright (c) 2020, 2025, Red Hat Inc. * 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 jdk.internal.platform.CgroupSubsystemFactory; import jdk.internal.platform.CgroupSubsystemFactory.CgroupTypeResult; import jdk.internal.platform.CgroupV1MetricsImpl; import jdk.internal.platform.cgroupv1.CgroupV1Subsystem; +import jdk.internal.platform.cgroupv1.CgroupV1SubsystemController; import jdk.internal.platform.Metrics; import jdk.test.lib.Utils; import jdk.test.lib.util.FileUtils; @@ -75,8 +76,10 @@ public class TestCgroupSubsystemFactory { private Path cgroupv1MntInfoDoubleControllers; private Path cgroupv1MntInfoDoubleControllers2; private Path cgroupv1MntInfoColonsHierarchy; + private Path cgroupv1MntInfoNonTrivialRoot; private Path cgroupv1SelfCgroup; private Path cgroupv1SelfColons; + private Path cgroupv1SelfNonTrivialRoot; private Path cgroupv2SelfCgroup; private Path cgroupv1SelfCgroupJoinCtrl; private Path cgroupv1CgroupsOnlyCPUCtrl; @@ -175,6 +178,7 @@ public class TestCgroupSubsystemFactory { "42 30 0:38 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:14 - cgroup none rw,seclabel,cpuset\n" + "43 30 0:39 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup none rw,seclabel,blkio\n" + "44 30 0:40 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:16 - cgroup none rw,seclabel,freezer\n"; + private String mntInfoNonTrivialRoot = "2207 2196 0:43 /system.slice/garden.service/garden/good/2f57368b-0eda-4e52-64d8-af5c /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:25 - cgroup cgroup rw,cpu,cpuacct\n"; private String cgroupsNonZeroHierarchy = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset 9 1 1\n" + @@ -230,6 +234,7 @@ public class TestCgroupSubsystemFactory { "2:cpu,cpuacct:/\n" + "1:name=systemd:/user.slice/user-1000.slice/user@1000.service/apps.slice/apps-org.gnome.Terminal.slice/vte-spawn-3c00b338-5b65-439f-8e97-135e183d135d.scope\n" + "0::/user.slice/user-1000.slice/user@1000.service/apps.slice/apps-org.gnome.Terminal.slice/vte-spawn-3c00b338-5b65-439f-8e97-135e183d135d.scope\n"; + private String cgroupv1SelfNTRoot = "11:cpu,cpuacct:/system.slice/garden.service/garden/bad/2f57368b-0eda-4e52-64d8-af5c\n"; private String cgroupv2SelfCgroupContent = "0::/user.slice/user-1000.slice/session-2.scope"; // We have a mix of V1 and V2 controllers, but none of the V1 controllers @@ -294,12 +299,18 @@ public class TestCgroupSubsystemFactory { cgroupv1MntInfoColonsHierarchy = Paths.get(existingDirectory.toString(), "mountinfo_colons"); Files.writeString(cgroupv1MntInfoColonsHierarchy, mntInfoColons); + cgroupv1MntInfoNonTrivialRoot = Paths.get(existingDirectory.toString(), "mountinfo_nt_root"); + Files.writeString(cgroupv1MntInfoNonTrivialRoot, mntInfoNonTrivialRoot); + cgroupv1SelfCgroup = Paths.get(existingDirectory.toString(), "self_cgroup_cgv1"); Files.writeString(cgroupv1SelfCgroup, cgroupv1SelfCgroupContent); cgroupv1SelfColons = Paths.get(existingDirectory.toString(), "self_colons_cgv1"); Files.writeString(cgroupv1SelfColons, cgroupv1SelfColonsContent); + cgroupv1SelfNonTrivialRoot = Paths.get(existingDirectory.toString(), "self_nt_root_cgv1"); + Files.writeString(cgroupv1SelfNonTrivialRoot, cgroupv1SelfNTRoot); + cgroupv2SelfCgroup = Paths.get(existingDirectory.toString(), "self_cgroup_cgv2"); Files.writeString(cgroupv2SelfCgroup, cgroupv2SelfCgroupContent); @@ -449,6 +460,27 @@ public class TestCgroupSubsystemFactory { assertEquals(memoryInfo.getMountRoot(), memoryInfo.getCgroupPath()); } + @Test + public void testMountPrefixCgroupsV1() throws IOException { + String cgroups = cgroupv1CgInfoNonZeroHierarchy.toString(); + String mountInfo = cgroupv1MntInfoNonTrivialRoot.toString(); + String selfCgroup = cgroupv1SelfNonTrivialRoot.toString(); + Optional result = CgroupSubsystemFactory.determineType(mountInfo, cgroups, selfCgroup); + + assertTrue("Expected non-empty cgroup result", result.isPresent()); + CgroupTypeResult res = result.get(); + CgroupInfo cpuInfo = res.getInfos().get("cpu"); + assertEquals(cpuInfo.getCgroupPath(), "/system.slice/garden.service/garden/bad/2f57368b-0eda-4e52-64d8-af5c"); + String expectedMountPoint = "/sys/fs/cgroup/cpu,cpuacct"; + assertEquals(expectedMountPoint, cpuInfo.getMountPoint()); + CgroupV1SubsystemController cgroupv1MemoryController = new CgroupV1SubsystemController(cpuInfo.getMountRoot(), cpuInfo.getMountPoint()); + cgroupv1MemoryController.setPath(cpuInfo.getCgroupPath()); + String actualPath = cgroupv1MemoryController.path(); + assertNotNull(actualPath); + String expectedPath = expectedMountPoint; + assertEquals("Should be equal to the mount point path", expectedPath, actualPath); + } + @Test public void testZeroHierarchyCgroupsV1() throws IOException { String cgroups = cgroupv1CgInfoZeroHierarchy.toString(); diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java new file mode 100644 index 00000000000..2ac79c173ef --- /dev/null +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, BELLSOFT. All rights reserved. + * 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.platform.Metrics; +import jdk.test.lib.Utils; +import jdk.test.lib.containers.docker.Common; +import jdk.test.lib.containers.docker.DockerfileConfig; +import jdk.test.lib.containers.docker.DockerRunOptions; +import jdk.test.lib.containers.docker.DockerTestUtils; + +import java.util.ArrayList; + +import jtreg.SkippedException; + +/* + * @test + * @bug 8343191 + * @key cgroups + * @summary Cgroup v1 subsystem fails to set subsystem path + * @requires container.support + * @library /test/lib + * @modules java.base/jdk.internal.platform + * @build MetricsMemoryTester + * @run main TestDockerMemoryMetricsSubgroup + */ + +public class TestDockerMemoryMetricsSubgroup { + private static final String imageName = + DockerfileConfig.getBaseImageName() + ":" + + DockerfileConfig.getBaseImageVersion(); + + public static void main(String[] args) throws Exception { + Metrics metrics = Metrics.systemMetrics(); + if (metrics == null) { + System.out.println("Cgroup not configured."); + return; + } + if (!DockerTestUtils.canTestDocker()) { + System.out.println("Unable to run docker tests."); + return; + } + if ("cgroupv1".equals(metrics.getProvider())) { + testMemoryLimitSubgroupV1("200m", "400m", false); + testMemoryLimitSubgroupV1("500m", "1G", false); + testMemoryLimitSubgroupV1("200m", "400m", true); + testMemoryLimitSubgroupV1("500m", "1G", true); + } else if ("cgroupv2".equals(metrics.getProvider())) { + testMemoryLimitSubgroupV2("200m", "400m", false); + testMemoryLimitSubgroupV2("500m", "1G", false); + testMemoryLimitSubgroupV2("200m", "400m", true); + testMemoryLimitSubgroupV2("500m", "1G", true); + } else { + throw new SkippedException("Metrics are from neither cgroup v1 nor v2, skipped for now."); + } + } + + private static void testMemoryLimitSubgroupV1(String innerSize, String outerGroupMemorySize, boolean privateNamespace) throws Exception { + Common.logNewTestCase("testMemoryLimitSubgroup, innerSize = " + innerSize); + DockerRunOptions opts = + new DockerRunOptions(imageName, "sh", "-c"); + opts.javaOpts = new ArrayList<>(); + opts.appendTestJavaOptions = false; + opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + .addDockerOpts("--volume", Utils.TEST_JDK + ":/jdk") + .addDockerOpts("--privileged") + .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) + .addDockerOpts("--memory", outerGroupMemorySize); + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo " + innerSize + " > /sys/fs/cgroup/memory/test/memory.limit_in_bytes ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "/jdk/bin/java -cp /test-classes/ " + + "--add-exports java.base/jdk.internal.platform=ALL-UNNAMED " + + "MetricsMemoryTester memory " + innerSize); + + DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!"); + } + + private static void testMemoryLimitSubgroupV2(String innerSize, String outerGroupMemorySize, boolean privateNamespace) throws Exception { + Common.logNewTestCase("testMemoryLimitSubgroup, innerSize = " + innerSize); + DockerRunOptions opts = + new DockerRunOptions(imageName, "sh", "-c"); + opts.javaOpts = new ArrayList<>(); + opts.appendTestJavaOptions = false; + opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + .addDockerOpts("--volume", Utils.TEST_JDK + ":/jdk") + .addDockerOpts("--privileged") + .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) + .addDockerOpts("--memory", outerGroupMemorySize); + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "echo '+memory' > /sys/fs/cgroup/cgroup.subtree_control ; " + + "echo '+memory' > /sys/fs/cgroup/memory/cgroup.subtree_control ; " + + "echo " + innerSize + " > /sys/fs/cgroup/memory/test/memory.max ; " + + "/jdk/bin/java -cp /test-classes/ " + + "--add-exports java.base/jdk.internal.platform=ALL-UNNAMED " + + "MetricsMemoryTester memory " + innerSize); + + DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!"); + } +} From a88e8cd0d2a444187208b41875b9da45daadad6a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 5 Mar 2025 12:30:09 +0000 Subject: [PATCH 232/587] 8350952: Remove some non present files from OPT_SPEED_SRC list Reviewed-by: dholmes, clanger --- make/hotspot/lib/JvmFeatures.gmk | 3 --- 1 file changed, 3 deletions(-) diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index 0efb8671da8..0a897230f83 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -224,11 +224,9 @@ ifeq ($(call check-jvm-feature, opt-size), true) frame_ppc.cpp \ frame_s390.cpp \ frame_x86.cpp \ - genCollectedHeap.cpp \ generation.cpp \ growableArray.cpp \ handles.cpp \ - hashtable.cpp \ heap.cpp \ icache.cpp \ icache_arm.cpp \ @@ -246,7 +244,6 @@ ifeq ($(call check-jvm-feature, opt-size), true) linkResolver.cpp \ klass.cpp \ klassVtable.cpp \ - markSweep.cpp \ memRegion.cpp \ memoryPool.cpp \ method.cpp \ From 062b7c7348453e6a96c311082b112291913dc1d9 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 5 Mar 2025 12:55:33 +0000 Subject: [PATCH 233/587] 8351115: Test AOTClassLinkingVMOptions.java fails after JDK-8348322 Reviewed-by: dholmes, iklam --- .../cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java index af5c619d767..470bb699bc3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java @@ -82,7 +82,7 @@ public class AOTClassLinkingVMOptions { // Dumping with AOTInvokeDynamicLinking disabled TestCommon.testDump(appJar, TestCommon.list("Hello"), - "-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking"); + "-XX:+UnlockDiagnosticVMOptions", "-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking"); testCase("Archived full module graph must be enabled at runtime (with -XX:-AOTInvokeDynamicLinking)"); TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello") From caaf4098452476d981183ad4302b76b9c883a72b Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 5 Mar 2025 12:57:56 +0000 Subject: [PATCH 234/587] 8350546: Several java/net/InetAddress tests fails UnknownHostException Reviewed-by: dfuchs, myankelevich --- .../InetAddress/IsReachableViaLoopbackTest.java | 15 ++++++++------- .../java/net/InetAddress/getOriginalHostName.java | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/net/InetAddress/IsReachableViaLoopbackTest.java b/test/jdk/java/net/InetAddress/IsReachableViaLoopbackTest.java index 4d340a72fba..2f2ad0ac7dd 100644 --- a/test/jdk/java/net/InetAddress/IsReachableViaLoopbackTest.java +++ b/test/jdk/java/net/InetAddress/IsReachableViaLoopbackTest.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 @@ -21,22 +21,24 @@ * questions. */ -import java.io.*; -import java.net.*; -import java.util.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; /** * @test * @bug 8135305 * @key intermittent + * @library /test/lib * @summary ensure we can't ping external hosts via loopback if + * @run main IsReachableViaLoopbackTest */ public class IsReachableViaLoopbackTest { public static void main(String[] args) { try { - InetAddress addr = InetAddress.getByName("localhost"); - InetAddress remoteAddr = InetAddress.getByName("bugs.openjdk.org"); + InetAddress addr = InetAddress.getLoopbackAddress(); + InetAddress remoteAddr = InetAddress.getByName("23.197.138.208"); // use literal address to avoid DNS checks if (!addr.isReachable(10000)) throw new RuntimeException("Localhost should always be reachable"); NetworkInterface inf = NetworkInterface.getByInetAddress(addr); @@ -54,7 +56,6 @@ public class IsReachableViaLoopbackTest { } else { System.out.println("inf == null"); } - } catch (IOException e) { throw new RuntimeException("Unexpected exception:" + e); } diff --git a/test/jdk/java/net/InetAddress/getOriginalHostName.java b/test/jdk/java/net/InetAddress/getOriginalHostName.java index 9f1e6e965d1..71567a7915d 100644 --- a/test/jdk/java/net/InetAddress/getOriginalHostName.java +++ b/test/jdk/java/net/InetAddress/getOriginalHostName.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 @@ -41,7 +41,9 @@ public class getOriginalHostName { public static void main(String[] args) throws Exception { final String HOST = "dummyserver.java.net"; InetAddress ia = null; - ia = InetAddress.getByName(HOST); + ia = getInetAddress(HOST); + if (ia != null) testInetAddress(ia, HOST); + ia = InetAddress.getByAddress(HOST, new byte[] { 1, 2, 3, 4}); testInetAddress(ia, HOST); ia = InetAddress.getByName("255.255.255.0"); testInetAddress(ia, null); @@ -53,6 +55,14 @@ public class getOriginalHostName { testInetAddress(ia, ia.getHostName()); } + private static InetAddress getInetAddress(String host) { + try { + return InetAddress.getByName(host); + } catch (java.net.UnknownHostException uhe) { + System.out.println("Skipping " + host + " due to " + uhe); + return null; + } + } private static void testInetAddress(InetAddress ia, String expected) throws Exception { From ea9e3cfe03b5284ef0edc6f0eb92fcb6ffd62725 Mon Sep 17 00:00:00 2001 From: Serhiy Sachkov Date: Wed, 5 Mar 2025 16:16:58 +0000 Subject: [PATCH 235/587] 8281511: java/net/ipv6tests/UdpTest.java fails with checkTime failed Reviewed-by: dfuchs --- test/jdk/java/net/ipv6tests/TcpTest.java | 10 ++++++---- test/jdk/java/net/ipv6tests/Tests.java | 21 ++++++++------------- test/jdk/java/net/ipv6tests/UdpTest.java | 17 ++++++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/test/jdk/java/net/ipv6tests/TcpTest.java b/test/jdk/java/net/ipv6tests/TcpTest.java index e0ee7e49dc5..0ca35737a76 100644 --- a/test/jdk/java/net/ipv6tests/TcpTest.java +++ b/test/jdk/java/net/ipv6tests/TcpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -36,6 +36,7 @@ import java.net.*; import java.io.*; +import java.util.concurrent.TimeUnit; public class TcpTest extends Tests { static ServerSocket server, server1, server2; @@ -193,13 +194,14 @@ public class TcpTest extends Tests { server = new ServerSocket (0); server.setSoTimeout (5000); int port = server.getLocalPort(); - long t1 = System.currentTimeMillis(); + long t1 = System.nanoTime(); try { server.accept (); throw new RuntimeException ("accept should not have returned"); } catch (SocketTimeoutException e) {} - t1 = System.currentTimeMillis() - t1; - checkTime (t1, 5000); + t1 = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1); + final long expectedTime = TimeUnit.SECONDS.toMillis(5); + checkIfTimeOut(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1), expectedTime); c1 = new Socket (); c1.connect (new InetSocketAddress (ia4addr, port), 1000); diff --git a/test/jdk/java/net/ipv6tests/Tests.java b/test/jdk/java/net/ipv6tests/Tests.java index 7a6917a6038..21cc83571ae 100644 --- a/test/jdk/java/net/ipv6tests/Tests.java +++ b/test/jdk/java/net/ipv6tests/Tests.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 @@ -151,19 +151,14 @@ public class Tests { } } - /* check the time got is within 50% of the time expected */ - public static void checkTime (long got, long expected) { - checkTime(got, expected, expected); - } - /* check the time got is between start and end, given 50% tolerance */ - public static void checkTime(long got, long start, long end) { - dprintln("checkTime: got = " + got + " start = " + start + " end = " + end); - long upper = end + (end / 2); - long lower = start - (start / 2); - if (got > upper || got < lower) { - throw new RuntimeException("checkTime failed: got " + got - + ", expected between " + start + " and " + end); + /* check the timeout breached lower bound time rule */ + public static void checkIfTimeOut(long got, long expected) { + dprintln("checkIfTimeOut: got = " + got + " lower bound = " + expected); + + if (got < expected) { + throw new RuntimeException("checkIfTimeOut failed: got " + got + + ", expected at least " + expected ); } } diff --git a/test/jdk/java/net/ipv6tests/UdpTest.java b/test/jdk/java/net/ipv6tests/UdpTest.java index 8986af74ff4..6139db85407 100644 --- a/test/jdk/java/net/ipv6tests/UdpTest.java +++ b/test/jdk/java/net/ipv6tests/UdpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, 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 @@ -41,6 +41,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.PortUnreachableException; import java.net.SocketTimeoutException; +import java.util.concurrent.TimeUnit; public class UdpTest extends Tests { static DatagramSocket c3, s1, s2, s3; @@ -138,26 +139,27 @@ public class UdpTest extends Tests { s1 = new DatagramSocket (); s2 = new DatagramSocket (); s1.setSoTimeout (4000); - long t1 = System.currentTimeMillis(); + long t1 = System.nanoTime(); try { s1.receive (new DatagramPacket (new byte [128], 128)); throw new Exception ("expected receive timeout "); } catch (SocketTimeoutException e) { } - checkTime (System.currentTimeMillis() - t1, 4000); + final long expectedTime = TimeUnit.SECONDS.toMillis(4); + checkIfTimeOut(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1), expectedTime); /* check data can be exchanged now */ simpleDataExchange (s1, ia6addr, s2, ia4addr); /* double check timeout still works */ - t1 = System.currentTimeMillis(); + t1 = System.nanoTime(); try { s1.receive (new DatagramPacket (new byte [128], 128)); throw new Exception ("expected receive timeout "); } catch (SocketTimeoutException e) { } - checkTime (System.currentTimeMillis() - t1, 4000); + checkIfTimeOut(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1), expectedTime); /* check receive works after a delay < timeout */ @@ -174,9 +176,10 @@ public class UdpTest extends Tests { } catch (Exception e) {} } }); - t1 = System.currentTimeMillis(); + t1 = System.nanoTime(); s1.receive (new DatagramPacket (new byte [128], 128)); - checkTime (System.currentTimeMillis() - t1, 2000, 10000); + final long startTime = TimeUnit.SECONDS.toMillis(2); + checkIfTimeOut(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1), startTime); s1.close (); s2.close (); System.out.println ("Test2: OK"); From 61d9ab9717783e5bb0faa555f794499d0e5b3fdb Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 5 Mar 2025 16:35:46 +0000 Subject: [PATCH 236/587] 8350854: Include thread counts in safepoint logging Reviewed-by: shade, dholmes --- src/hotspot/share/runtime/safepoint.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 6f86aa09d95..b2bc8364eb5 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -989,13 +989,16 @@ void SafepointTracing::end() { "Reaching safepoint: " JLONG_FORMAT " ns, " "At safepoint: " JLONG_FORMAT " ns, " "Leaving safepoint: " JLONG_FORMAT " ns, " - "Total: " JLONG_FORMAT " ns", + "Total: " JLONG_FORMAT " ns, " + "Threads: %d runnable, %d total", VM_Operation::name(_current_type), _last_app_time_ns, _last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns, _last_safepoint_leave_time_ns - _last_safepoint_sync_time_ns, _last_safepoint_end_time_ns - _last_safepoint_leave_time_ns, - _last_safepoint_end_time_ns - _last_safepoint_begin_time_ns + _last_safepoint_end_time_ns - _last_safepoint_begin_time_ns, + _nof_running, + _nof_threads ); RuntimeService::record_safepoint_end(_last_safepoint_end_time_ns - _last_safepoint_sync_time_ns); From 661bd5bfe883a7449c6949c9f4bd6b5d82d20e10 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 5 Mar 2025 17:32:59 +0000 Subject: [PATCH 237/587] 8343478: Remove unnecessary @SuppressWarnings annotations (core-libs) Reviewed-by: darcy, asemenyuk, joehw --- .../src/classes/build/tools/cldrconverter/Bundle.java | 3 +-- .../build/tools/cldrconverter/LDMLParseHandler.java | 3 +-- src/java.base/share/classes/java/io/File.java | 1 - .../share/classes/java/io/FileDescriptor.java | 3 +-- src/java.base/share/classes/java/lang/Package.java | 1 - .../classes/java/lang/invoke/LambdaFormEditor.java | 4 ++-- .../share/classes/java/lang/invoke/MemberName.java | 4 ++-- .../share/classes/java/lang/invoke/MethodTypeForm.java | 7 +++---- .../share/classes/java/lang/reflect/Constructor.java | 4 ++-- .../share/classes/java/lang/reflect/Method.java | 4 ++-- .../classes/java/lang/reflect/ProxyGenerator.java | 3 +-- .../classes/java/time/chrono/ChronoLocalDate.java | 3 +-- .../java/time/chrono/ChronoLocalDateTimeImpl.java | 3 +-- src/java.base/share/classes/java/util/Arrays.java | 2 +- src/java.base/share/classes/java/util/Collections.java | 3 --- .../share/classes/java/util/ComparableTimSort.java | 10 +++++----- src/java.base/share/classes/java/util/HashMap.java | 4 ++-- .../share/classes/java/util/LinkedHashSet.java | 3 +-- src/java.base/share/classes/java/util/List.java | 4 ++-- src/java.base/share/classes/java/util/Map.java | 3 +-- .../share/classes/java/util/PrimitiveIterator.java | 3 +-- .../classes/java/util/PropertyResourceBundle.java | 3 +-- .../share/classes/java/util/ResourceBundle.java | 3 +-- .../share/classes/java/util/ReverseOrderDequeView.java | 3 +-- .../share/classes/java/util/ReverseOrderListView.java | 3 +-- .../classes/java/util/ReverseOrderSortedMapView.java | 3 +-- .../classes/java/util/ReverseOrderSortedSetView.java | 3 +-- .../share/classes/java/util/ServiceLoader.java | 4 ++-- src/java.base/share/classes/java/util/Spliterator.java | 4 +--- src/java.base/share/classes/java/util/TreeMap.java | 4 ++-- .../java/util/concurrent/ConcurrentHashMap.java | 2 +- .../java/util/concurrent/CopyOnWriteArrayList.java | 1 - .../share/classes/java/util/concurrent/Executors.java | 4 ---- .../classes/java/util/concurrent/ForkJoinTask.java | 1 - .../java/util/concurrent/LinkedBlockingDeque.java | 1 - .../java/util/concurrent/SubmissionPublisher.java | 1 - .../share/classes/java/util/regex/Pattern.java | 3 +-- .../classes/java/util/stream/AbstractPipeline.java | 6 ++---- .../share/classes/java/util/stream/DoublePipeline.java | 3 +-- .../share/classes/java/util/stream/IntPipeline.java | 3 +-- .../share/classes/java/util/stream/LongPipeline.java | 3 +-- src/java.base/share/classes/java/util/stream/Node.java | 3 +-- .../share/classes/java/util/stream/Nodes.java | 4 +--- .../classes/java/util/stream/ReferencePipeline.java | 6 +----- .../share/classes/java/util/stream/SpinedBuffer.java | 3 +-- .../jdk/internal/classfile/impl/ClassFileImpl.java | 3 +-- .../classes/jdk/internal/classfile/impl/CodeImpl.java | 3 +-- .../classes/jdk/internal/jimage/BasicImageReader.java | 6 +++--- .../classes/jdk/internal/jimage/NativeImageBuffer.java | 4 ++-- .../share/classes/jdk/internal/jrtfs/JrtFileStore.java | 3 +-- .../jdk/internal/jrtfs/JrtFileSystemProvider.java | 9 ++++----- .../share/classes/jdk/internal/jrtfs/SystemImage.java | 4 ++-- .../classes/jdk/internal/logger/BootstrapLogger.java | 7 +------ .../classes/jdk/internal/util/xml/impl/Parser.java | 3 +-- .../share/classes/jdk/internal/vm/VMSupport.java | 4 ++-- .../share/classes/sun/launcher/LauncherHelper.java | 4 +--- .../sun/net/www/protocol/http/HttpURLConnection.java | 3 +-- .../classes/sun/text/DictionaryBasedBreakIterator.java | 3 +-- .../share/classes/com/sun/jndi/ldap/LdapCtx.java | 4 +--- .../classes/com/sun/jndi/toolkit/ctx/Continuation.java | 3 +-- src/java.naming/share/classes/javax/naming/Name.java | 3 +-- .../classes/javax/naming/directory/Attribute.java | 3 +-- .../classes/java/util/prefs/FileSystemPreferences.java | 3 +-- .../share/classes/java/rmi/server/RemoteRef.java | 3 +-- .../share/classes/java/rmi/server/ServerRef.java | 3 +-- .../classes/sun/rmi/registry/RegistryImpl_Skel.java | 4 ++-- .../share/classes/sun/rmi/transport/DGCImpl_Skel.java | 4 ++-- .../classes/javax/sql/rowset/spi/SyncFactory.java | 3 +-- src/java.sql/share/classes/java/sql/Date.java | 3 +-- src/java.sql/share/classes/java/sql/Time.java | 3 +-- src/java.sql/share/classes/java/sql/Timestamp.java | 3 +-- .../xalan/internal/xsltc/dom/NodeSortRecord.java | 6 +++--- .../xalan/internal/xsltc/trax/SAX2StAXEventWriter.java | 4 ++-- .../xalan/internal/xsltc/trax/TemplatesImpl.java | 5 ++--- .../apache/xalan/internal/xsltc/trax/TrAXFilter.java | 5 ++--- .../xalan/internal/xsltc/trax/TransformerImpl.java | 5 ++--- .../sun/org/apache/xalan/internal/xsltc/trax/Util.java | 5 ++--- .../org/apache/xerces/internal/dom/DocumentImpl.java | 6 +++--- .../apache/xerces/internal/dom/NamedNodeMapImpl.java | 5 ++--- .../xerces/internal/impl/xs/traversers/XSDHandler.java | 6 ++---- .../apache/xml/internal/utils/StringComparable.java | 6 +++--- .../share/classes/javax/xml/catalog/CatalogReader.java | 3 +-- src/jdk.jartool/share/classes/sun/tools/jar/Main.java | 4 +--- .../share/classes/com/sun/tools/jdeps/Analyzer.java | 3 +-- .../classes/com/sun/tools/jdeps/Dependencies.java | 4 +--- .../jlink/internal/plugins/VersionPropsPlugin.java | 3 +-- .../jdk/jpackage/internal/BundlerParamInfo.java | 3 +-- .../jdk/jpackage/internal/StandardBundlerParam.java | 3 +-- .../sun/jndi/rmi/registry/ReferenceWrapper_Stub.java | 4 ++-- .../com/sun/jndi/rmi/registry/RegistryContext.java | 2 +- .../testlibrary/asm/org/objectweb/asm/ClassReader.java | 1 - .../testlibrary/asm/org/objectweb/asm/ClassWriter.java | 1 - .../asm/org/objectweb/asm/tree/MethodNode.java | 1 - 93 files changed, 121 insertions(+), 211 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index 61395f982b2..d8752bca142 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.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 @@ -198,7 +198,6 @@ class Bundle { String[] cldrBundles = getCLDRPath().split(","); // myMap contains resources for id. - @SuppressWarnings("unchecked") Map myMap = new HashMap<>(); int index; for (index = 0; index < cldrBundles.length; index++) { diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index d2d7e94fc98..6d5dde0d181 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.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 @@ -1079,7 +1079,6 @@ class LDMLParseHandler extends AbstractLDMLHandler { } @Override - @SuppressWarnings("fallthrough") public void endElement(String uri, String localName, String qName) throws SAXException { assert qName.equals(currentContainer.getqName()) : "current=" + currentContainer.getqName() + ", param=" + qName; switch (qName) { diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 15e687ebf06..9c9fbc837db 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -681,7 +681,6 @@ public class File if (isInvalid()) { throw new MalformedURLException("Invalid file path"); } - @SuppressWarnings("deprecation") var result = new URL("file", "", slashify(getAbsolutePath(), isDirectory())); return result; } diff --git a/src/java.base/share/classes/java/io/FileDescriptor.java b/src/java.base/share/classes/java/io/FileDescriptor.java index bdab57c0996..f6466f56eab 100644 --- a/src/java.base/share/classes/java/io/FileDescriptor.java +++ b/src/java.base/share/classes/java/io/FileDescriptor.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 @@ -340,7 +340,6 @@ public final class FileDescriptor { * * The caller closeable gets to call close0(). */ - @SuppressWarnings("try") synchronized void closeAll(Closeable releaser) throws IOException { if (!closed) { closed = true; diff --git a/src/java.base/share/classes/java/lang/Package.java b/src/java.base/share/classes/java/lang/Package.java index 82f40ce373b..14f5682ab0b 100644 --- a/src/java.base/share/classes/java/lang/Package.java +++ b/src/java.base/share/classes/java/lang/Package.java @@ -353,7 +353,6 @@ public final class Package extends NamedPackage implements java.lang.reflect.Ann */ @CallerSensitive @Deprecated(since="9") - @SuppressWarnings("deprecation") public static Package getPackage(String name) { ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); return l != null ? l.getPackage(name) : BootLoader.getDefinedPackage(name); diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java index 8d84c5f8096..0994071a79e 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.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 @@ -142,7 +142,7 @@ class LambdaFormEditor { return buf.toString(); } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public LambdaForm get() { if (cache instanceof LambdaForm lf) { return lf; diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java index 696772c39d5..35fd26331b1 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.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 @@ -711,7 +711,7 @@ final class MemberName implements Member, Cloneable { } @Override - @SuppressWarnings({"deprecation", "removal"}) + @SuppressWarnings("removal") public int hashCode() { // Avoid autoboxing getReferenceKind(), since this is used early and will force // early initialization of Byte$ByteCache diff --git a/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java b/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java index 69545478ec4..c344cd034c7 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.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 @@ -110,7 +110,7 @@ final class MethodTypeForm { return basicType; } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public MethodHandle cachedMethodHandle(int which) { Object entry = methodHandles[which]; if (entry == null) { @@ -136,7 +136,7 @@ final class MethodTypeForm { return mh; } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public LambdaForm cachedLambdaForm(int which) { Object entry = lambdaForms[which]; if (entry == null) { @@ -167,7 +167,6 @@ final class MethodTypeForm { * This MTF will stand for that type and all un-erased variations. * Eagerly compute some basic properties of the type, common to all variations. */ - @SuppressWarnings({"rawtypes", "unchecked"}) protected MethodTypeForm(MethodType erasedType) { this.erasedType = erasedType; diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index 30445307369..d072971307c 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.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 @@ -240,7 +240,7 @@ public final class Constructor extends Executable { * @since 1.5 */ @Override - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public TypeVariable>[] getTypeParameters() { if (getSignature() != null) { return (TypeVariable>[])getGenericInfo().getTypeParameters(); diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index f1d5ee63919..07616206075 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.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 @@ -231,7 +231,7 @@ public final class Method extends Executable { * @jls 8.4.4 Generic Methods */ @Override - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public TypeVariable[] getTypeParameters() { if (getGenericSignature() != null) return (TypeVariable[])getGenericInfo().getTypeParameters(); diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 3b34453bc3f..0d90cedd5c5 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.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 @@ -202,7 +202,6 @@ final class ProxyGenerator { * @param interfaces proxy interfaces * @param accessFlags access flags of the proxy class */ - @SuppressWarnings("removal") static byte[] generateProxyClass(ClassLoader loader, final String name, List> interfaces, diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java index 5543c8a73bc..3aae065715a 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDate.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 @@ -652,7 +652,6 @@ public interface ChronoLocalDate * @param localTime the local time to use, not null * @return the local date-time formed from this date and the specified time, not null */ - @SuppressWarnings("unchecked") default ChronoLocalDateTime atTime(LocalTime localTime) { return ChronoLocalDateTimeImpl.of(this, localTime); } diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java index 412d4845456..5fcde7b2aad 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java @@ -1,5 +1,5 @@ /* - * 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 @@ -269,7 +269,6 @@ final class ChronoLocalDateTimeImpl } //----------------------------------------------------------------------- - @SuppressWarnings("unchecked") @Override public ChronoLocalDateTimeImpl with(TemporalAdjuster adjuster) { if (adjuster instanceof ChronoLocalDate) { diff --git a/src/java.base/share/classes/java/util/Arrays.java b/src/java.base/share/classes/java/util/Arrays.java index 657b8123ec5..1bba844f791 100644 --- a/src/java.base/share/classes/java/util/Arrays.java +++ b/src/java.base/share/classes/java/util/Arrays.java @@ -1126,7 +1126,7 @@ public final class Arrays { * off is the offset to generate corresponding low, high in src * To be removed in a future release. */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("unchecked") private static void mergeSort(Object[] src, Object[] dest, int low, diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index ec08168e2a2..4dc7edeb852 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.java @@ -3363,7 +3363,6 @@ public final class Collections { @SuppressWarnings("serial") // Conditionally serializable final Collection c; /** @serial */ - @SuppressWarnings("serial") // Conditionally serializable final Class type; @SuppressWarnings("unchecked") @@ -3926,10 +3925,8 @@ public final class Collections { @SuppressWarnings("serial") // Conditionally serializable private final Map m; /** @serial */ - @SuppressWarnings("serial") // Conditionally serializable final Class keyType; /** @serial */ - @SuppressWarnings("serial") // Conditionally serializable final Class valueType; private void typeCheck(Object key, Object value) { diff --git a/src/java.base/share/classes/java/util/ComparableTimSort.java b/src/java.base/share/classes/java/util/ComparableTimSort.java index 7b908077224..ac2b1573152 100644 --- a/src/java.base/share/classes/java/util/ComparableTimSort.java +++ b/src/java.base/share/classes/java/util/ComparableTimSort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright 2009 Google Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -309,7 +309,7 @@ class ComparableTimSort { * @return the length of the run beginning at the specified position in * the specified array */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("unchecked") private static int countRunAndMakeAscending(Object[] a, int lo, int hi) { assert lo < hi; int runHi = lo + 1; @@ -648,7 +648,7 @@ class ComparableTimSort { * (must be aBase + aLen) * @param len2 length of second run to be merged (must be > 0) */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("unchecked") private void mergeLo(int base1, int len1, int base2, int len2) { assert len1 > 0 && len2 > 0 && base1 + len1 == base2; @@ -765,7 +765,7 @@ class ComparableTimSort { * (must be aBase + aLen) * @param len2 length of second run to be merged (must be > 0) */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("unchecked") private void mergeHi(int base1, int len1, int base2, int len2) { assert len1 > 0 && len2 > 0 && base1 + len1 == base2; @@ -895,7 +895,7 @@ class ComparableTimSort { else newSize = Math.min(newSize, a.length >>> 1); - @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + @SuppressWarnings("UnnecessaryLocalVariable") Object[] newArray = new Object[newSize]; tmp = newArray; tmpLen = newSize; diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 46c89984be8..3320b394e6c 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.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 @@ -365,7 +365,7 @@ public class HashMap extends AbstractMap * Returns k.compareTo(x) if x matches kc (k's screened comparable * class), else 0. */ - @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable + @SuppressWarnings("unchecked") // for cast to Comparable static int compareComparables(Class kc, Object k, Object x) { return (x == null || x.getClass() != kc ? 0 : ((Comparable)k).compareTo(x)); diff --git a/src/java.base/share/classes/java/util/LinkedHashSet.java b/src/java.base/share/classes/java/util/LinkedHashSet.java index bec2733dae3..1ec8214208d 100644 --- a/src/java.base/share/classes/java/util/LinkedHashSet.java +++ b/src/java.base/share/classes/java/util/LinkedHashSet.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 @@ -226,7 +226,6 @@ public class LinkedHashSet return new LinkedHashSet<>(HashMap.calculateHashMapCapacity(numElements)); } - @SuppressWarnings("unchecked") LinkedHashMap map() { return (LinkedHashMap) map; } diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index 86cf4267312..32430298363 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.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 @@ -501,7 +501,7 @@ public interface List extends SequencedCollection { * contract * @since 1.8 */ - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("unchecked") default void sort(Comparator c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index ea2fd4e1807..fbb41be5073 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.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 @@ -1658,7 +1658,6 @@ public interface Map { * @since 9 */ @SafeVarargs - @SuppressWarnings("varargs") static Map ofEntries(Entry... entries) { if (entries.length == 0) { // implicit null check of entries array @SuppressWarnings("unchecked") diff --git a/src/java.base/share/classes/java/util/PrimitiveIterator.java b/src/java.base/share/classes/java/util/PrimitiveIterator.java index b0e07ef6e5a..db6f1bcf483 100644 --- a/src/java.base/share/classes/java/util/PrimitiveIterator.java +++ b/src/java.base/share/classes/java/util/PrimitiveIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -84,7 +84,6 @@ public interface PrimitiveIterator extends Iterator { * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null */ - @SuppressWarnings("overloads") void forEachRemaining(T_CONS action); /** diff --git a/src/java.base/share/classes/java/util/PropertyResourceBundle.java b/src/java.base/share/classes/java/util/PropertyResourceBundle.java index aba65cbcd88..d8cc1fac198 100644 --- a/src/java.base/share/classes/java/util/PropertyResourceBundle.java +++ b/src/java.base/share/classes/java/util/PropertyResourceBundle.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 @@ -163,7 +163,6 @@ public class PropertyResourceBundle extends ResourceBundle { * {@code java.util.PropertyResourceBundle.encoding} is set to "UTF-8" * and {@code stream} contains an unmappable UTF-8 byte sequence. */ - @SuppressWarnings({"unchecked", "rawtypes"}) public PropertyResourceBundle (InputStream stream) throws IOException { this(new InputStreamReader(stream, "ISO-8859-1".equals(encoding) ? diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index 4206dda6a3a..fb88a38903a 100644 --- a/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/src/java.base/share/classes/java/util/ResourceBundle.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 @@ -3511,7 +3511,6 @@ public abstract class ResourceBundle { */ static ResourceBundle newResourceBundle(Class bundleClass) { try { - @SuppressWarnings("unchecked") Constructor ctor = bundleClass.getConstructor(); if (!Modifier.isPublic(ctor.getModifiers())) { diff --git a/src/java.base/share/classes/java/util/ReverseOrderDequeView.java b/src/java.base/share/classes/java/util/ReverseOrderDequeView.java index 695db6a74dc..35e34c4d80b 100644 --- a/src/java.base/share/classes/java/util/ReverseOrderDequeView.java +++ b/src/java.base/share/classes/java/util/ReverseOrderDequeView.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 @@ -161,7 +161,6 @@ class ReverseOrderDequeView implements Deque { return ArraysSupport.reverse(base.toArray()); } - @SuppressWarnings("unchecked") public T[] toArray(T[] a) { return ArraysSupport.toArrayReversed(base, a); } diff --git a/src/java.base/share/classes/java/util/ReverseOrderListView.java b/src/java.base/share/classes/java/util/ReverseOrderListView.java index 42b57e2d8b9..f48b41920c9 100644 --- a/src/java.base/share/classes/java/util/ReverseOrderListView.java +++ b/src/java.base/share/classes/java/util/ReverseOrderListView.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 @@ -286,7 +286,6 @@ class ReverseOrderListView implements List { return ArraysSupport.reverse(base.toArray()); } - @SuppressWarnings("unchecked") public T[] toArray(T[] a) { return ArraysSupport.toArrayReversed(base, a); } diff --git a/src/java.base/share/classes/java/util/ReverseOrderSortedMapView.java b/src/java.base/share/classes/java/util/ReverseOrderSortedMapView.java index 404950e8fd5..74703f3a866 100644 --- a/src/java.base/share/classes/java/util/ReverseOrderSortedMapView.java +++ b/src/java.base/share/classes/java/util/ReverseOrderSortedMapView.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 @@ -314,7 +314,6 @@ class ReverseOrderSortedMapView extends AbstractMap implements Sorte final K head; // head key, or negative infinity if null final K tail; // tail key, or positive infinity if null - @SuppressWarnings("unchecked") Submap(K head, K tail) { this.head = head; this.tail = tail; diff --git a/src/java.base/share/classes/java/util/ReverseOrderSortedSetView.java b/src/java.base/share/classes/java/util/ReverseOrderSortedSetView.java index 3719852e2a5..70511c8ae86 100644 --- a/src/java.base/share/classes/java/util/ReverseOrderSortedSetView.java +++ b/src/java.base/share/classes/java/util/ReverseOrderSortedSetView.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 @@ -170,7 +170,6 @@ class ReverseOrderSortedSetView implements SortedSet { return ArraysSupport.reverse(base.toArray()); } - @SuppressWarnings("unchecked") public T[] toArray(T[] a) { return ArraysSupport.toArrayReversed(base, a); } diff --git a/src/java.base/share/classes/java/util/ServiceLoader.java b/src/java.base/share/classes/java/util/ServiceLoader.java index c634d6321c0..5137adc1c08 100644 --- a/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/src/java.base/share/classes/java/util/ServiceLoader.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 @@ -726,7 +726,7 @@ public final class ServiceLoader @Override public boolean equals(Object ob) { - return ob instanceof @SuppressWarnings("unchecked")ProviderImpl that + return ob instanceof ProviderImpl that && this.service == that.service && this.type == that.type; } diff --git a/src/java.base/share/classes/java/util/Spliterator.java b/src/java.base/share/classes/java/util/Spliterator.java index 517d71c191b..6873bca6568 100644 --- a/src/java.base/share/classes/java/util/Spliterator.java +++ b/src/java.base/share/classes/java/util/Spliterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -628,7 +628,6 @@ public interface Spliterator { * upon entry to this method, else {@code true}. * @throws NullPointerException if the specified action is null */ - @SuppressWarnings("overloads") boolean tryAdvance(T_CONS action); /** @@ -649,7 +648,6 @@ public interface Spliterator { * @param action The action * @throws NullPointerException if the specified action is null */ - @SuppressWarnings("overloads") default void forEachRemaining(T_CONS action) { do { } while (tryAdvance(action)); } diff --git a/src/java.base/share/classes/java/util/TreeMap.java b/src/java.base/share/classes/java/util/TreeMap.java index ab565f371a9..f8eea8c8d8f 100644 --- a/src/java.base/share/classes/java/util/TreeMap.java +++ b/src/java.base/share/classes/java/util/TreeMap.java @@ -2982,7 +2982,7 @@ public class TreeMap return t.keySpliterator(); } if (m instanceof DescendingSubMap) { - @SuppressWarnings("unchecked") DescendingSubMap dm = + DescendingSubMap dm = (DescendingSubMap) m; TreeMap tm = dm.m; if (dm == tm.descendingMap) { @@ -2991,7 +2991,7 @@ public class TreeMap return t.descendingKeySpliterator(); } } - @SuppressWarnings("unchecked") NavigableSubMap sm = + NavigableSubMap sm = (NavigableSubMap) m; return sm.keySpliterator(); } diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java index b0818d3da6e..8734980cf80 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -744,7 +744,7 @@ public class ConcurrentHashMap extends AbstractMap * Returns k.compareTo(x) if x matches kc (k's screened comparable * class), else 0. */ - @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable + @SuppressWarnings("unchecked") // for cast to Comparable static int compareComparables(Class kc, Object k, Object x) { return (x == null || x.getClass() != kc ? 0 : ((Comparable)k).compareTo(x)); diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index f5069c61d45..2d3bdb429e9 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -1727,7 +1727,6 @@ public class CopyOnWriteArrayList } @Override - @SuppressWarnings("unchecked") public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); while (hasNext()) { diff --git a/src/java.base/share/classes/java/util/concurrent/Executors.java b/src/java.base/share/classes/java/util/concurrent/Executors.java index 49cf497c20b..ba7c2e1efee 100644 --- a/src/java.base/share/classes/java/util/concurrent/Executors.java +++ b/src/java.base/share/classes/java/util/concurrent/Executors.java @@ -576,10 +576,8 @@ public final class Executors { private static final class PrivilegedCallableUsingCurrentClassLoader implements Callable { final Callable task; - @SuppressWarnings("removal") final ClassLoader ccl; - @SuppressWarnings("removal") PrivilegedCallableUsingCurrentClassLoader(Callable task) { this.task = task; this.ccl = Thread.currentThread().getContextClassLoader(); @@ -637,7 +635,6 @@ public final class Executors { * Thread factory capturing the current class loader. */ private static class PrivilegedThreadFactory extends DefaultThreadFactory { - @SuppressWarnings("removal") final ClassLoader ccl; PrivilegedThreadFactory() { @@ -647,7 +644,6 @@ public final class Executors { public Thread newThread(final Runnable r) { return super.newThread(new Runnable() { - @SuppressWarnings("removal") public void run() { Thread.currentThread().setContextClassLoader(ccl); r.run(); diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 6062a0f6455..ec91e33975d 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -787,7 +787,6 @@ public abstract class ForkJoinTask implements Future, Serializable { invokeAll(tasks.toArray(new ForkJoinTask[0])); return tasks; } - @SuppressWarnings("unchecked") List> ts = (List>) tasks; Throwable ex = null; diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java index b22786a09f6..7c112eb8008 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -910,7 +910,6 @@ public class LinkedBlockingDeque * * @return an array containing all of the elements in this deque */ - @SuppressWarnings("unchecked") public Object[] toArray() { final ReentrantLock lock = this.lock; lock.lock(); diff --git a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java index a2fc3ac92bd..388241b115d 100644 --- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java +++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java @@ -1048,7 +1048,6 @@ public class SubmissionPublisher implements Publisher, * assignment coding style. Also, all methods and fields have * default visibility to simplify usage by callers. */ - @SuppressWarnings("serial") @jdk.internal.vm.annotation.Contended static final class BufferedSubscription implements Subscription, ForkJoinPool.ManagedBlocker { diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 654adb5376f..b7f03c1b0af 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.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 @@ -3369,7 +3369,6 @@ loop: for(int x=0, offset=0; x> @Override @SuppressWarnings("unchecked") final boolean copyIntoWithCancel(Sink wrappedSink, Spliterator spliterator) { - @SuppressWarnings({"rawtypes","unchecked"}) + @SuppressWarnings("rawtypes") AbstractPipeline p = AbstractPipeline.this; while (p.depth > 0) { p = p.previousStage; @@ -622,7 +622,6 @@ abstract class AbstractPipeline> } @Override - @SuppressWarnings("unchecked") final Node evaluate(Spliterator spliterator, boolean flatten, IntFunction generator) { @@ -790,7 +789,6 @@ abstract class AbstractPipeline> * @param spliterator the source {@code Spliterator} * @return a {@code Spliterator} describing the result of the evaluation */ - @SuppressWarnings("unchecked") Spliterator opEvaluateParallelLazy(PipelineHelper helper, Spliterator spliterator) { return opEvaluateParallel(helper, spliterator, Nodes.castingArray()).spliterator(); diff --git a/src/java.base/share/classes/java/util/stream/DoublePipeline.java b/src/java.base/share/classes/java/util/stream/DoublePipeline.java index 22b3bf67ef4..ea561d8507f 100644 --- a/src/java.base/share/classes/java/util/stream/DoublePipeline.java +++ b/src/java.base/share/classes/java/util/stream/DoublePipeline.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 @@ -324,7 +324,6 @@ abstract class DoublePipeline } @Override - @SuppressWarnings("unchecked") public void accept(double t) { mapper.accept(t, (DoubleConsumer) downstream); } diff --git a/src/java.base/share/classes/java/util/stream/IntPipeline.java b/src/java.base/share/classes/java/util/stream/IntPipeline.java index e78bc9fecc9..5c624e2fc42 100644 --- a/src/java.base/share/classes/java/util/stream/IntPipeline.java +++ b/src/java.base/share/classes/java/util/stream/IntPipeline.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 @@ -356,7 +356,6 @@ abstract class IntPipeline } @Override - @SuppressWarnings("unchecked") public void accept(int t) { mapper.accept(t, (IntConsumer) downstream); } diff --git a/src/java.base/share/classes/java/util/stream/LongPipeline.java b/src/java.base/share/classes/java/util/stream/LongPipeline.java index c8c296824ed..05d6d506bea 100644 --- a/src/java.base/share/classes/java/util/stream/LongPipeline.java +++ b/src/java.base/share/classes/java/util/stream/LongPipeline.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 @@ -339,7 +339,6 @@ abstract class LongPipeline } @Override - @SuppressWarnings("unchecked") public void accept(long t) { mapper.accept(t, (LongConsumer) downstream); } diff --git a/src/java.base/share/classes/java/util/stream/Node.java b/src/java.base/share/classes/java/util/stream/Node.java index 0f88850cfc5..d8308d778d9 100644 --- a/src/java.base/share/classes/java/util/stream/Node.java +++ b/src/java.base/share/classes/java/util/stream/Node.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, 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 @@ -245,7 +245,6 @@ interface Node { * @param action a consumer that is to be invoked with each * element in this {@code Node.OfPrimitive} */ - @SuppressWarnings("overloads") void forEach(T_CONS action); @Override diff --git a/src/java.base/share/classes/java/util/stream/Nodes.java b/src/java.base/share/classes/java/util/stream/Nodes.java index 77d70091717..d2627434f36 100644 --- a/src/java.base/share/classes/java/util/stream/Nodes.java +++ b/src/java.base/share/classes/java/util/stream/Nodes.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 @@ -643,7 +643,6 @@ final class Nodes { final T[] array; int curSize; - @SuppressWarnings("unchecked") ArrayNode(long size, IntFunction generator) { if (size >= MAX_ARRAY_SIZE) throw new IllegalArgumentException(BAD_SIZE); @@ -720,7 +719,6 @@ final class Nodes { } @Override - @SuppressWarnings("unchecked") public T[] asArray(IntFunction generator) { return c.toArray(generator.apply(c.size())); } diff --git a/src/java.base/share/classes/java/util/stream/ReferencePipeline.java b/src/java.base/share/classes/java/util/stream/ReferencePipeline.java index 3133b20b03d..3699990a326 100644 --- a/src/java.base/share/classes/java/util/stream/ReferencePipeline.java +++ b/src/java.base/share/classes/java/util/stream/ReferencePipeline.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 @@ -202,7 +202,6 @@ abstract class ReferencePipeline } @Override - @SuppressWarnings("unchecked") public final Stream map(Function mapper) { Objects.requireNonNull(mapper); return new StatelessOp<>(this, StreamShape.REFERENCE, @@ -509,7 +508,6 @@ abstract class ReferencePipeline } @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { mapper.accept(u, (IntConsumer)downstream); } @@ -533,7 +531,6 @@ abstract class ReferencePipeline } @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { mapper.accept(u, (LongConsumer) downstream); } @@ -558,7 +555,6 @@ abstract class ReferencePipeline } @Override - @SuppressWarnings("unchecked") public void accept(P_OUT u) { mapper.accept(u, (DoubleConsumer) downstream); } diff --git a/src/java.base/share/classes/java/util/stream/SpinedBuffer.java b/src/java.base/share/classes/java/util/stream/SpinedBuffer.java index 98bbc040a7b..cb9eb24d635 100644 --- a/src/java.base/share/classes/java/util/stream/SpinedBuffer.java +++ b/src/java.base/share/classes/java/util/stream/SpinedBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -583,7 +583,6 @@ class SpinedBuffer spineIndex = 0; } - @SuppressWarnings("overloads") public void forEach(T_CONS consumer) { // completed chunks, if any for (int j = 0; j < spineIndex; j++) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index 3ab5d24f09c..152569683ba 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.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 @@ -90,7 +90,6 @@ public final class ClassFileImpl implements ClassFile { null // _ -> null ); - @SuppressWarnings("unchecked") @Override public ClassFileImpl withOptions(Option... options) { var smo = stackMapsOption; 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 47908b99f44..609411f2e06 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 @@ -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 @@ -272,7 +272,6 @@ public final class CodeImpl } return; } - @SuppressWarnings("unchecked") int stackMapPos = ((BoundAttribute) a.get()).payloadStart; int bci = -1; //compensate for offsetDelta + 1 diff --git a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java index 07879353d90..c06c62488db 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, 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 @@ -49,7 +49,7 @@ import jdk.internal.jimage.decompressor.Decompressor; * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public class BasicImageReader implements AutoCloseable { - @SuppressWarnings("removal") + @SuppressWarnings({ "removal", "suppression" }) private static boolean isSystemProperty(String key, String value, String def) { // No lambdas during bootstrap return AccessController.doPrivileged( @@ -82,7 +82,7 @@ public class BasicImageReader implements AutoCloseable { private final ImageStringsReader stringsReader; private final Decompressor decompressor; - @SuppressWarnings({ "removal", "this-escape" }) + @SuppressWarnings({ "removal", "this-escape", "suppression" }) protected BasicImageReader(Path path, ByteOrder byteOrder) throws IOException { this.imagePath = Objects.requireNonNull(path); diff --git a/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java b/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java index 9ef02364195..b55080eb192 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java +++ b/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.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 @@ -33,7 +33,7 @@ import java.nio.ByteBuffer; * but also compiled and delivered as part of the jrtfs.jar to support access * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ -@SuppressWarnings("removal") +@SuppressWarnings({ "removal", "suppression"} ) class NativeImageBuffer { static { java.security.AccessController.doPrivileged( diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java index 7d4b0a18822..7846b740544 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.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 @@ -70,7 +70,6 @@ final class JrtFileStore extends FileStore { } @Override - @SuppressWarnings("unchecked") public V getFileStoreAttributeView(Class type) { Objects.requireNonNull(type, "type"); return (V) null; diff --git a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java index 4d3e0ed9d2c..c0d3eeab6bd 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.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 @@ -68,7 +68,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider { * Need RuntimePermission "accessSystemModules" to create or get jrt:/ */ private void checkPermission() { - @SuppressWarnings("removal") + @SuppressWarnings({ "removal", "suppression" }) SecurityManager sm = System.getSecurityManager(); if (sm != null) { RuntimePermission perm = new RuntimePermission("accessSystemModules"); @@ -123,7 +123,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider { ClassLoader cl = newJrtFsLoader(jrtfs); try { Class c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl); - @SuppressWarnings("deprecation") + @SuppressWarnings({ "deprecation", "suppression" }) Object tmp = c.newInstance(); return ((FileSystemProvider)tmp).newFileSystem(uri, newEnv); } catch (ClassNotFoundException | @@ -156,7 +156,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider { } } - @SuppressWarnings("removal") + @SuppressWarnings({ "removal", "suppression" }) private static URLClassLoader newJrtFsLoader(Path jrtfs) { final URL url; try { @@ -261,7 +261,6 @@ public final class JrtFileSystemProvider extends FileSystemProvider { } @Override - @SuppressWarnings("unchecked") public V getFileAttributeView(Path path, Class type, LinkOption... options) { return JrtFileAttributeView.get(toJrtPath(path), type, options); 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 e1770d9c55b..88cdf724e7d 100644 --- a/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java +++ b/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, 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 @@ -47,7 +47,7 @@ import jdk.internal.jimage.ImageReader.Node; * but also compiled and delivered as part of the jrtfs.jar to support access * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ -@SuppressWarnings("removal") +@SuppressWarnings({ "removal", "suppression"} ) abstract class SystemImage { abstract Node findNode(String path) throws IOException; diff --git a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java index a4c9e4baf63..01d8fedb0aa 100644 --- a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java +++ b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.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 @@ -263,7 +263,6 @@ public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, // The next event in the queue LogEvent next; - @SuppressWarnings("removal") private LogEvent(BootstrapLogger bootstrap, Level level, ResourceBundle bundle, String msg, Throwable thrown, Object[] params) { @@ -281,7 +280,6 @@ public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, this.bootstrap = bootstrap; } - @SuppressWarnings("removal") private LogEvent(BootstrapLogger bootstrap, Level level, Supplier msgSupplier, Throwable thrown, Object[] params) { @@ -299,7 +297,6 @@ public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, this.bootstrap = bootstrap; } - @SuppressWarnings("removal") private LogEvent(BootstrapLogger bootstrap, PlatformLogger.Level platformLevel, String sourceClass, String sourceMethod, @@ -319,7 +316,6 @@ public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, this.bootstrap = bootstrap; } - @SuppressWarnings("removal") private LogEvent(BootstrapLogger bootstrap, PlatformLogger.Level platformLevel, String sourceClass, String sourceMethod, @@ -860,7 +856,6 @@ public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, // The purpose of this class is to delay the initialization of // the detectedBackend field until it is actually read. // We do not want this field to get initialized if VM.isBooted() is false. - @SuppressWarnings("removal") private static final class DetectBackend { static final LoggingBackend detectedBackend = detectBackend(); diff --git a/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java b/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java index 8ff4742a59d..4e8f0070a7c 100644 --- a/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java +++ b/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.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 @@ -2086,7 +2086,6 @@ public abstract class Parser { * @exception Exception is parser specific exception form panic method. * @exception IOException */ - @SuppressWarnings("fallthrough") private void pent(char flag) throws Exception { char ch; int idx = mBuffIdx + 1; diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index c31fa4d441f..197da0d456c 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.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 @@ -459,7 +459,7 @@ public class VMSupport { * @param type of the object representing a decoded error * @return an immutable list of {@code A} objects */ - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public static List decodeAnnotations(byte[] encoded, AnnotationDecoder decoder) { try { ByteArrayInputStream bais = new ByteArrayInputStream(encoded); diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 3ba0758585e..8fbf76851cc 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.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 @@ -156,7 +156,6 @@ public final class LauncherHelper { * this code determine this value, using a suitable method or omit the * line entirely. */ - @SuppressWarnings("fallthrough") static void showSettings(boolean printToStderr, String optionFlag, long initialHeapSize, long maxHeapSize, long stackSize) { @@ -733,7 +732,6 @@ public final class LauncherHelper { * * @return the application's main class */ - @SuppressWarnings("fallthrough") public static Class checkAndLoadMain(boolean printToStderr, int mode, String what) { 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 602f798448c..5d8e6f467aa 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, 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 @@ -2069,7 +2069,6 @@ public class HttpURLConnection extends java.net.HttpURLConnection { * Gets the authentication for an HTTP proxy, and applies it to * the connection. */ - @SuppressWarnings("fallthrough") private AuthenticationInfo getHttpProxyAuthentication(AuthenticationHeader authhdr) throws IOException { diff --git a/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java b/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java index fb072ae402f..7978b83cbde 100644 --- a/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java +++ b/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, 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 @@ -338,7 +338,6 @@ public class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { * cachedBreakPositions so that we only have to do this work once * for each time we enter the range. */ - @SuppressWarnings("unchecked") private void divideUpDictionaryRange(int startPos, int endPos) { CharacterIterator text = getText(); diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java index 0695894f300..636d8f5fe2b 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapCtx.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 @@ -1227,7 +1227,6 @@ public final class LdapCtx extends ComponentDirContext // process the referrals sequentially while (true) { - @SuppressWarnings("unchecked") LdapReferralContext refCtx = (LdapReferralContext)e.getReferralContext(envprops, bindCtls); @@ -1886,7 +1885,6 @@ public final class LdapCtx extends ComponentDirContext // process the referrals sequentially while (true) { - @SuppressWarnings("unchecked") LdapReferralContext refCtx = (LdapReferralContext) e.getReferralContext(envprops, bindCtls); diff --git a/src/java.naming/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java b/src/java.naming/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java index 1a6d930460e..aa63bd1a738 100644 --- a/src/java.naming/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java +++ b/src/java.naming/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, 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 @@ -96,7 +96,6 @@ public class Continuation extends ResolveResult { * @param environment The environment used by the caller. It is used * when setting the "environment" of a CannotProceedException. */ - @SuppressWarnings("unchecked") // For Hashtable clone: environment.clone() public Continuation(Name top, Hashtable environment) { super(); starter = top; diff --git a/src/java.naming/share/classes/javax/naming/Name.java b/src/java.naming/share/classes/javax/naming/Name.java index 24865fb64e4..b4466a02f2f 100644 --- a/src/java.naming/share/classes/javax/naming/Name.java +++ b/src/java.naming/share/classes/javax/naming/Name.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 @@ -68,7 +68,6 @@ public interface Name * ineffectual. Do not use; no replacement. */ @Deprecated - @SuppressWarnings("serial") static final long serialVersionUID = -3617482732056931635L; /** diff --git a/src/java.naming/share/classes/javax/naming/directory/Attribute.java b/src/java.naming/share/classes/javax/naming/directory/Attribute.java index 4a0b51ba812..f1bd438457a 100644 --- a/src/java.naming/share/classes/javax/naming/directory/Attribute.java +++ b/src/java.naming/share/classes/javax/naming/directory/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, 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 @@ -340,6 +340,5 @@ public interface Attribute extends Cloneable, java.io.Serializable { * ineffectual. Do not use; no replacement. */ @Deprecated - @SuppressWarnings("serial") static final long serialVersionUID = 8707690322213556804L; } diff --git a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java index 4f75f434745..681abec46c3 100644 --- a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java +++ b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.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 @@ -58,7 +58,6 @@ class FileSystemPreferences extends AbstractPreferences { /** * Sync interval in seconds. */ - @SuppressWarnings("removal") private static final int SYNC_INTERVAL = Math.max(1, Integer.getInteger("java.util.prefs.syncInterval", 30)); diff --git a/src/java.rmi/share/classes/java/rmi/server/RemoteRef.java b/src/java.rmi/share/classes/java/rmi/server/RemoteRef.java index 57201cd8dc3..a32f56dabc1 100644 --- a/src/java.rmi/share/classes/java/rmi/server/RemoteRef.java +++ b/src/java.rmi/share/classes/java/rmi/server/RemoteRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -44,7 +44,6 @@ public interface RemoteRef extends java.io.Externalizable { * ineffectual. Do not use; no replacement. */ @Deprecated - @SuppressWarnings("serial") static final long serialVersionUID = 3632638527362204081L; /** diff --git a/src/java.rmi/share/classes/java/rmi/server/ServerRef.java b/src/java.rmi/share/classes/java/rmi/server/ServerRef.java index 1562f67fe7a..9ffb208640a 100644 --- a/src/java.rmi/share/classes/java/rmi/server/ServerRef.java +++ b/src/java.rmi/share/classes/java/rmi/server/ServerRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -44,7 +44,6 @@ public interface ServerRef extends RemoteRef { * ineffectual. Do not use; no replacement. */ @Deprecated - @SuppressWarnings("serial") static final long serialVersionUID = -4557750989390278438L; /** diff --git a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java index 22cfee5e0a7..95b94c57e1c 100644 --- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java +++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.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 @@ -36,7 +36,7 @@ import sun.rmi.transport.StreamRemoteCall; * Skeleton to dispatch RegistryImpl methods. * Originally generated by RMIC but frozen to match the stubs. */ -@SuppressWarnings({"deprecation", "serial"}) +@SuppressWarnings("deprecation") public final class RegistryImpl_Skel implements java.rmi.server.Skeleton { private static final java.rmi.server.Operation[] operations = { diff --git a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java index 1b413cffc19..20485dcd1e3 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl_Skel.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 @@ -31,7 +31,7 @@ import java.io.IOException; * Skeleton to dispatch DGC methods. * Originally generated by RMIC but frozen to match the stubs. */ -@SuppressWarnings({"deprecation", "serial"}) +@SuppressWarnings("deprecation") public final class DGCImpl_Skel implements java.rmi.server.Skeleton { private static final java.rmi.server.Operation[] operations = { diff --git a/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java b/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java index 9cc7a5b2da8..9bc730569cd 100644 --- a/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java +++ b/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.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 @@ -318,7 +318,6 @@ public class SyncFactory { private static String colon = ":"; private static String strFileSep = "/"; - @SuppressWarnings("removal") private static synchronized void initMapIfNecessary() throws SyncFactoryException { // Local implementation class names and keys from Properties diff --git a/src/java.sql/share/classes/java/sql/Date.java b/src/java.sql/share/classes/java/sql/Date.java index c1d4fed3023..56d138afdce 100644 --- a/src/java.sql/share/classes/java/sql/Date.java +++ b/src/java.sql/share/classes/java/sql/Date.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -286,7 +286,6 @@ public class Date extends java.util.Date { * @throws NullPointerException if {@code date} is null * @since 1.8 */ - @SuppressWarnings("deprecation") public static Date valueOf(LocalDate date) { return new Date(date.getYear() - 1900, date.getMonthValue() -1, date.getDayOfMonth()); diff --git a/src/java.sql/share/classes/java/sql/Time.java b/src/java.sql/share/classes/java/sql/Time.java index 32df3644354..802a7433162 100644 --- a/src/java.sql/share/classes/java/sql/Time.java +++ b/src/java.sql/share/classes/java/sql/Time.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -249,7 +249,6 @@ public class Time extends java.util.Date { * @throws NullPointerException if {@code time} is null * @since 1.8 */ - @SuppressWarnings("deprecation") public static Time valueOf(LocalTime time) { return new Time(time.getHour(), time.getMinute(), time.getSecond()); } diff --git a/src/java.sql/share/classes/java/sql/Timestamp.java b/src/java.sql/share/classes/java/sql/Timestamp.java index 8fb85f73c7e..a91ab7210c5 100644 --- a/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/src/java.sql/share/classes/java/sql/Timestamp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -493,7 +493,6 @@ public class Timestamp extends java.util.Date { * @throws NullPointerException if {@code dateTime} is null. * @since 1.8 */ - @SuppressWarnings("deprecation") public static Timestamp valueOf(LocalDateTime dateTime) { return new Timestamp(dateTime.getYear() - 1900, dateTime.getMonthValue() - 1, diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/NodeSortRecord.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/NodeSortRecord.java index 83071b62347..bd0b0355ee6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/NodeSortRecord.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/NodeSortRecord.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ import java.util.Locale; /** * Base class for sort records containing application specific sort keys * - * @LastModified: May 2019 + * @LastModified: Jan 2025 */ public abstract class NodeSortRecord { public static final int COMPARE_STRING = 0; @@ -127,7 +127,7 @@ public abstract class NodeSortRecord { * element. The value is extracted from the DOM if it is not already in * our sort key vector. */ - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("rawtypes") private final Comparable stringValue(int level) { // Get value from our array if possible if (_scanned <= level) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SAX2StAXEventWriter.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SAX2StAXEventWriter.java index fbe41a17028..a34f4fe3e8a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SAX2StAXEventWriter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SAX2StAXEventWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, 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 @@ -250,7 +250,7 @@ public class SAX2StAXEventWriter extends SAX2StAXBaseWriter { super.endCDATA(); } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") protected void createStartEvents(Attributes attributes, Collection[] events) { Map nsMap = null; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java index f167cf78d5a..24f10e69853 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -65,7 +65,7 @@ import jdk.xml.internal.JdkConstants; * @author G. Todd Millerj * @author Jochen Cordes * @author Santiago Pericas-Geertsen - * @LastModified: Nov 2024 + * @LastModified: Jan 2025 */ public final class TemplatesImpl implements Templates, Serializable { static final long serialVersionUID = 673094361519270707L; @@ -255,7 +255,6 @@ public final class TemplatesImpl implements Templates, Serializable { * if yes then we need to deserialize the URIResolver * Fix for bugzilla bug 22438 */ - @SuppressWarnings("unchecked") private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java index 95c8540ca28..2cecf112bd3 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -43,9 +43,8 @@ import org.xml.sax.helpers.XMLFilterImpl; * @author Santiago Pericas-Geertsen * @author G. Todd Miller * - * @LastModified: July 2023 + * @LastModified: Jan 2025 */ -@SuppressWarnings("deprecation") //org.xml.sax.helpers.XMLReaderFactory public class TrAXFilter extends XMLFilterImpl { private Templates _templates; private TransformerImpl _transformer; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java index 32eaec026bf..b48b9d2a657 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -100,7 +100,7 @@ import org.xml.sax.ext.LexicalHandler; * @author Morten Jorgensen * @author G. Todd Miller * @author Santiago Pericas-Geertsen - * @LastModified: Dec 2024 + * @LastModified: Jan 2025 */ public final class TransformerImpl extends Transformer implements DOMCache @@ -1355,7 +1355,6 @@ public final class TransformerImpl extends Transformer * Performs the access check without any interface changes * (e.g. Translet and DOMCache). */ - @SuppressWarnings("unchecked") //AbstractTranslet is the sole impl. AbstractTranslet t = (AbstractTranslet)translet; String systemId = SystemIDResolver.getAbsoluteURI(href, baseURI); String errMsg = null; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java index b4dd0ef6b97..fe685dcf5a6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/Util.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -50,9 +50,8 @@ import org.xml.sax.XMLReader; * * Added Catalog Support for URI resolution * - * @LastModified: Nov 2024 + * @LastModified: Jan 2025 */ -@SuppressWarnings("deprecation") //org.xml.sax.helpers.XMLReaderFactory public final class Util { private static final String property = "org.xml.sax.driver"; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java index 9b7938ca5b2..decd9943850 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -84,7 +84,7 @@ import org.w3c.dom.traversal.TreeWalker; * @author Andy Clark, IBM * @author Ralf Pfeiffer, IBM * @since PR-DOM-Level-1-19980818. - * @LastModified: Nov 2017 + * @LastModified: Jan 2025 */ public class DocumentImpl extends CoreDocumentImpl @@ -681,7 +681,7 @@ public class DocumentImpl * method was invoked by an EventListener; otherwise false. */ @Override - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") protected boolean dispatchEvent(NodeImpl node, Event event) { if (event == null) return false; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java index a2b3e3269a5..c95dfd2fd87 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -56,7 +56,7 @@ import org.w3c.dom.Node; * @xerces.internal * * @since PR-DOM-Level-1-19980818. - * @LastModified: June 2022 + * @LastModified: Jan 2025 */ public class NamedNodeMapImpl implements NamedNodeMap, Serializable { @@ -596,7 +596,6 @@ public class NamedNodeMapImpl } } - @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java index bd11ac73c60..9ebaf895c5c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -131,9 +131,8 @@ import org.xml.sax.XMLReader; * @author Neil Graham, IBM * @author Pavani Mukthipudi, Sun Microsystems * - * @LastModified: July 2023 + * @LastModified: Jan 2025 */ -@SuppressWarnings("deprecation") //org.xml.sax.helpers.XMLReaderFactory public class XSDHandler { /** Feature identifier: validation. */ @@ -2768,7 +2767,6 @@ public class XSDHandler { } } - @SuppressWarnings("unchecked") private void addNewImportedGrammars(SchemaGrammar srcGrammar, SchemaGrammar dstGrammar) { final ArrayList src = (ArrayList)srcGrammar.getImportedGrammars(); if (src != null) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/StringComparable.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/StringComparable.java index db6fe80824a..1b950591bac 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/StringComparable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/StringComparable.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,7 +29,7 @@ import java.util.Locale; /** * International friendly string comparison with case-order * @author Igor Hersht, igorh@ca.ibm.com - * @LastModified: Oct 2017 + * @LastModified: Jan 2025 */ public class StringComparable implements Comparable { @@ -52,7 +52,7 @@ public class StringComparable implements Comparable { m_mask = getMask(m_collator.getStrength()); } - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("rawtypes") public final static Comparable getComparator( final String text, final Locale locale, final Collator collator, final String caseOrder){ if((caseOrder == null) ||(caseOrder.length() == 0)){// no case-order specified diff --git a/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java b/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java index 1305beeceaa..0cee5cfa41d 100644 --- a/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java +++ b/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.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 @@ -84,7 +84,6 @@ class CatalogReader extends DefaultHandler implements EntityResolver, URIResolve * * @param catalog The Catalog object that represents a catalog */ - @SuppressWarnings("unchecked") public CatalogReader(Catalog catalog, SAXParser parser) { this.catalog = (CatalogImpl) catalog; this.parser = parser; diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index ae6893c021b..baedbf85205 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.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 @@ -243,7 +243,6 @@ public class Main { /** * Starts main program with the specified arguments. */ - @SuppressWarnings({"removal"}) public synchronized boolean run(String[] args) { ok = true; if (!parseArgs(args)) { @@ -1364,7 +1363,6 @@ public class Main { }); } - @SuppressWarnings("serial") Set newDirSet() { return new HashSet() { public boolean add(ZipEntry e) { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java index 22377715a1e..ea61d79a6c0 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.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 @@ -336,7 +336,6 @@ public class Analyzer { } @Override - @SuppressWarnings("unchecked") public boolean equals(Object o) { if (o instanceof Dep) { Dep d = (Dep) o; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java index c0ac835f4b6..90682c478c7 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, 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 @@ -56,7 +56,6 @@ public class Dependencies { /** * Thrown when a class file cannot be found. */ - @SuppressWarnings("this-escape") public static class ClassFileNotFoundException extends Exception { private static final long serialVersionUID = 3632265927794475048L; @@ -76,7 +75,6 @@ public class Dependencies { /** * Thrown when an exception is found processing a class file. */ - @SuppressWarnings("this-escape") public static class ClassFileError extends Error { private static final long serialVersionUID = 4111110813961313203L; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java index 86f68098453..a07661fd339 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.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 @@ -99,7 +99,6 @@ abstract class VersionPropsPlugin extends AbstractPlugin { private boolean redefined = false; - @SuppressWarnings("deprecation") private byte[] redefine(String path, byte[] classFile) { return ClassFile.of().transformClass(newClassReader(path, classFile), ClassTransform.transformingMethodBodies( diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index fa99073ff7f..48499dcf29c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.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 @@ -94,7 +94,6 @@ class BundlerParamInfo { return stringConverter; } - @SuppressWarnings("unchecked") final T fetchFrom(Map params) { return fetchFrom(params, true); } 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 0209eea584a..ec5b1aceaab 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.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 @@ -276,7 +276,6 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> s ); - @SuppressWarnings("unchecked") public static final StandardBundlerParam LICENSE_FILE = new StandardBundlerParam<>( Arguments.CLIOptions.LICENSE_FILE.getId(), diff --git a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/ReferenceWrapper_Stub.java b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/ReferenceWrapper_Stub.java index 211da640e20..6cac42e63f2 100644 --- a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/ReferenceWrapper_Stub.java +++ b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/ReferenceWrapper_Stub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, 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 @@ -30,7 +30,7 @@ package com.sun.jndi.rmi.registry; /** * ReferenceWrapper_Stub. */ -@SuppressWarnings({"deprecation", "rawtypes", "unchecked"}) +@SuppressWarnings({"deprecation", "rawtypes"}) public final class ReferenceWrapper_Stub extends java.rmi.server.RemoteStub implements com.sun.jndi.rmi.registry.RemoteReference, java.rmi.Remote { diff --git a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java index 2f77c383bd6..337f00fd7c7 100644 --- a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java +++ b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.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 diff --git a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassReader.java b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassReader.java index 643a6501470..7e499412dc2 100644 --- a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassReader.java +++ b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassReader.java @@ -205,7 +205,6 @@ public class ClassReader { * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. * @param classFileLength the length in bytes of the ClassFile to be read. */ - @SuppressWarnings("this-escape") public ClassReader( final byte[] classFileBuffer, final int classFileOffset, diff --git a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassWriter.java b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassWriter.java index ea28726914f..e3c0ad707a0 100644 --- a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassWriter.java +++ b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/ClassWriter.java @@ -292,7 +292,6 @@ public class ClassWriter extends ClassVisitor { * do not affect methods that are copied as is in the new class. This means that neither the * maximum stack size nor the stack frames will be computed for these methods. */ - @SuppressWarnings("this-escape") public ClassWriter(final ClassReader classReader, final int flags) { super(/* latest api = */ Opcodes.ASM9); this.flags = flags; diff --git a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/tree/MethodNode.java b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/tree/MethodNode.java index 4c265d44290..31da5e5c5ef 100644 --- a/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/tree/MethodNode.java +++ b/test/hotspot/jtreg/testlibrary/asm/org/objectweb/asm/tree/MethodNode.java @@ -275,7 +275,6 @@ public class MethodNode extends MethodVisitor { } @Override - @SuppressWarnings("serial") public AnnotationVisitor visitAnnotationDefault() { return new AnnotationNode( new ArrayList(0) { From 6012e8d2505af786bd4f17cf56b1e81a102485d4 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 5 Mar 2025 17:33:54 +0000 Subject: [PATCH 238/587] 8350808: Small typos in JShell method SnippetEvent.toString() Reviewed-by: jlahoda --- .../classes/jdk/jshell/SnippetEvent.java | 8 +-- .../jdk/jshell/SnippetEventToStringTest.java | 63 +++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 test/langtools/jdk/jshell/SnippetEventToStringTest.java diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java b/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java index f18fa429339..0c80b6d4388 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.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 @@ -148,9 +148,9 @@ public class SnippetEvent { ",previousStatus=" + previousStatus + ",status=" + status + ",isSignatureChange=" + isSignatureChange + - ",causeSnippet" + causeSnippet + - (value == null? "" : "value=" + value) + - (exception == null? "" : "exception=" + exception) + + ",causeSnippet=" + causeSnippet + + (value == null? "" : ",value=" + value) + + (exception == null? "" : ",exception=" + exception) + ")"; } } diff --git a/test/langtools/jdk/jshell/SnippetEventToStringTest.java b/test/langtools/jdk/jshell/SnippetEventToStringTest.java new file mode 100644 index 00000000000..7d2de387951 --- /dev/null +++ b/test/langtools/jdk/jshell/SnippetEventToStringTest.java @@ -0,0 +1,63 @@ +/* + * 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 8350808 + * @summary Check for proper formatting of SnippetEvent.toString() + * @run testng SnippetEventToStringTest + */ + +import java.util.Map; +import java.util.List; + +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; + +public class SnippetEventToStringTest { + + @DataProvider(name = "cases") + public String[][] sourceLevels() { + return new String[][] { + { "*", ",causeSnippet=null" }, + { "123", ",value=123" }, + { "throw new Exception(\"foo\");", ",exception=jdk.jshell.EvalException: foo" } + }; + } + + @Test(dataProvider = "cases") + private 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); + String string = result.get(0).toString(); + if (!string.contains(match)) + throw new AssertionError(String.format("\"%s\" not found in \"%s\"", match, string)); + } + } +} From c3b48196af40356a8251b42db13e02ed905c2139 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 5 Mar 2025 18:12:26 +0000 Subject: [PATCH 239/587] 8351074: Disallow null prefix and suffix in DecimalFormat Reviewed-by: naoto --- .../classes/java/text/DecimalFormat.java | 19 +++++-- .../text/Format/DecimalFormat/AffixTest.java | 50 +++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/text/Format/DecimalFormat/AffixTest.java diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index b23c5f360bf..ce2ecfb23a2 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.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 @@ -48,6 +48,7 @@ import java.text.spi.NumberFormatProvider; import java.util.ArrayList; import java.util.Currency; import java.util.Locale; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -2811,9 +2812,11 @@ public class DecimalFormat extends NumberFormat { * Set the positive prefix. *

Examples: +123, $123, sFr123 * - * @param newValue the new positive prefix + * @param newValue the new positive prefix. Non-null. + * @throws NullPointerException if {@code newValue} is {@code null} */ public void setPositivePrefix (String newValue) { + Objects.requireNonNull(newValue, "prefix must not be null"); positivePrefix = newValue; posPrefixPattern = null; positivePrefixFieldPositions = null; @@ -2853,9 +2856,11 @@ public class DecimalFormat extends NumberFormat { * Set the negative prefix. *

Examples: -123, ($123) (with negative suffix), sFr-123 * - * @param newValue the new negative prefix + * @param newValue the new negative prefix. Non-null. + * @throws NullPointerException if {@code newValue} is {@code null} */ public void setNegativePrefix (String newValue) { + Objects.requireNonNull(newValue, "prefix must not be null"); negativePrefix = newValue; negPrefixPattern = null; fastPathCheckNeeded = true; @@ -2894,9 +2899,11 @@ public class DecimalFormat extends NumberFormat { * Set the positive suffix. *

Example: 123% * - * @param newValue the new positive suffix + * @param newValue the new positive suffix. Non-null. + * @throws NullPointerException if {@code newValue} is {@code null} */ public void setPositiveSuffix (String newValue) { + Objects.requireNonNull(newValue, "suffix must not be null"); positiveSuffix = newValue; posSuffixPattern = null; fastPathCheckNeeded = true; @@ -2935,9 +2942,11 @@ public class DecimalFormat extends NumberFormat { * Set the negative suffix. *

Examples: 123% * - * @param newValue the new negative suffix + * @param newValue the new negative suffix. Non-null. + * @throws NullPointerException if {@code newValue} is {@code null} */ public void setNegativeSuffix (String newValue) { + Objects.requireNonNull(newValue, "suffix must not be null"); negativeSuffix = newValue; negSuffixPattern = null; fastPathCheckNeeded = true; diff --git a/test/jdk/java/text/Format/DecimalFormat/AffixTest.java b/test/jdk/java/text/Format/DecimalFormat/AffixTest.java new file mode 100644 index 00000000000..28b14e750a2 --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/AffixTest.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 + * @bug 8351074 + * @summary Test input value check for DecimalFormat affix setter methods + * @run junit AffixTest + */ + +import org.junit.jupiter.api.Test; + +import java.text.DecimalFormat; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class AffixTest { + + @Test + public void nullPrefixTest() { + assertThrows(NullPointerException.class, () -> new DecimalFormat().setPositivePrefix(null)); + assertThrows(NullPointerException.class, () -> new DecimalFormat().setNegativePrefix(null)); + } + + @Test + public void nullSuffixTest() { + assertThrows(NullPointerException.class, () -> new DecimalFormat().setPositiveSuffix(null)); + assertThrows(NullPointerException.class, () -> new DecimalFormat().setNegativeSuffix(null)); + } +} From 11a37c829c12d064874416a7b242596cf23972e5 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 5 Mar 2025 19:28:39 +0000 Subject: [PATCH 240/587] 8351165: Remove unused includes from vmStructs Reviewed-by: kbarrett --- .../share/classfile/compactHashtable.hpp | 3 +-- src/hotspot/share/classfile/stringTable.hpp | 1 - src/hotspot/share/classfile/symbolTable.hpp | 3 +-- .../share/classfile/systemDictionary.hpp | 1 - src/hotspot/share/memory/arena.hpp | 1 - src/hotspot/share/memory/resourceArea.hpp | 2 -- src/hotspot/share/runtime/sharedRuntime.hpp | 4 +-- src/hotspot/share/runtime/vmStructs.cpp | 27 ++----------------- .../serviceability/sa/ClhsdbPrintStatics.java | 4 +-- 9 files changed, 7 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 161f21eac99..2985f0f9a1a 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.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 @@ -241,7 +241,6 @@ template < bool (*EQUALS)(V value, K key, int len) > class CompactHashtable : public SimpleCompactHashtable { - friend class VMStructs; V decode(u4 offset) const { return DECODE(_base_address, offset); diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 0d58e09f208..15539009f66 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -40,7 +40,6 @@ class SerializeClosure; class StringTableConfig; class StringTable : AllStatic { - friend class VMStructs; friend class StringTableConfig; static volatile bool _has_work; diff --git a/src/hotspot/share/classfile/symbolTable.hpp b/src/hotspot/share/classfile/symbolTable.hpp index ee2cfe19d8e..cc861812dc3 100644 --- a/src/hotspot/share/classfile/symbolTable.hpp +++ b/src/hotspot/share/classfile/symbolTable.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 @@ -47,7 +47,6 @@ class constantPoolHandle; class SymbolClosure; class SymbolTable : public AllStatic { - friend class VMStructs; friend class Symbol; friend class ClassFileParser; friend class SymbolTableConfig; diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 7432166ba4e..1ba5d70af9e 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -79,7 +79,6 @@ class SystemDictionary : AllStatic { friend class AOTLinkedClassBulkLoader; friend class BootstrapInfo; friend class vmClasses; - friend class VMStructs; public: diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index dfa12209f40..01b1ae382db 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -129,7 +129,6 @@ private: protected: friend class HandleMark; friend class NoHandleMark; - friend class VMStructs; Chunk* _first; // First chunk Chunk* _chunk; // current chunk diff --git a/src/hotspot/share/memory/resourceArea.hpp b/src/hotspot/share/memory/resourceArea.hpp index 85ad6590d69..557a3c0a24e 100644 --- a/src/hotspot/share/memory/resourceArea.hpp +++ b/src/hotspot/share/memory/resourceArea.hpp @@ -43,8 +43,6 @@ //------------------------------ResourceArea----------------------------------- // A ResourceArea is an Arena that supports safe usage of ResourceMark. class ResourceArea: public Arena { - friend class VMStructs; - #ifdef ASSERT int _nesting; // current # of nested ResourceMarks void verify_has_resource_mark(); diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 854d4dcf1ad..94cbc460cad 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.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,8 +54,6 @@ enum class SharedStubId :int { #undef SHARED_STUB_ID_ENUM_DECLARE class SharedRuntime: AllStatic { - friend class VMStructs; - private: // Declare shared stub fields #define SHARED_STUB_FIELD_DECLARE(name, type) \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 53bdfe522d0..3daec6d8d06 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -23,18 +23,9 @@ */ #include "cds/filemap.hpp" -#include "ci/ciField.hpp" -#include "ci/ciInstance.hpp" -#include "ci/ciMethodData.hpp" -#include "ci/ciObjArrayKlass.hpp" -#include "ci/ciSymbol.hpp" #include "classfile/classLoaderDataGraph.hpp" -#include "classfile/dictionary.hpp" #include "classfile/javaClasses.hpp" #include "classfile/javaThreadStatus.hpp" -#include "classfile/stringTable.hpp" -#include "classfile/symbolTable.hpp" -#include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeBlob.hpp" @@ -103,10 +94,8 @@ #include "runtime/osThread.hpp" #include "runtime/perfMemory.hpp" #include "runtime/serviceThread.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" -#include "runtime/threadSMR.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vmStructs.hpp" #include "runtime/vm_version.hpp" @@ -411,7 +400,7 @@ volatile_static_field(PerfMemory, _initialized, int) \ \ /********************/ \ - /* SystemDictionary */ \ + /* VM Classes */ \ /********************/ \ \ static_field(vmClasses, VM_CLASS_AT(Object_klass), InstanceKlass*) \ @@ -635,7 +624,6 @@ nonstatic_field(JavaThread, _monitor_owner_id, int64_t) \ volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \ nonstatic_field(Thread, _osthread, OSThread*) \ - nonstatic_field(Thread, _resource_area, ResourceArea*) \ \ /************/ \ /* OSThread */ \ @@ -1009,17 +997,14 @@ declare_type(PerfData, CHeapObj) \ \ /********************/ \ - /* SystemDictionary */ \ + /* VM Classes */ \ /********************/ \ \ - declare_toplevel_type(SystemDictionary) \ declare_toplevel_type(vmClasses) \ declare_toplevel_type(vmSymbols) \ \ declare_toplevel_type(GrowableArrayBase) \ declare_toplevel_type(GrowableArray) \ - declare_toplevel_type(Arena) \ - declare_type(ResourceArea, Arena) \ \ /***********************************************************/ \ /* Thread hierarchy (needed for run-time type information) */ \ @@ -1090,8 +1075,6 @@ /* CodeBlob hierarchy (needed for run-time type information) */ \ /*************************************************************/ \ \ - declare_toplevel_type(SharedRuntime) \ - \ declare_toplevel_type(CodeBlob) \ declare_type(RuntimeBlob, CodeBlob) \ declare_type(BufferBlob, RuntimeBlob) \ @@ -1163,12 +1146,6 @@ declare_toplevel_type(BasicLock) \ declare_toplevel_type(BasicObjectLock) \ \ - /*********************/ \ - /* Adapter Blob Entries */ \ - /*********************/ \ - declare_toplevel_type(AdapterHandlerEntry) \ - declare_toplevel_type(AdapterHandlerEntry*) \ - \ /********************/ \ /* -XX flags */ \ /********************/ \ diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java index d53e5e47f26..abbcb552876 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.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 @@ -49,7 +49,7 @@ public class ClhsdbPrintStatics { System.out.println("Started LingeredApp with pid " + theApp.getPid()); List cmds = List.of( - "printstatics", "printstatics SystemDictionary", + "printstatics", "printstatics Threads", "printstatics Universe", "printstatics JvmtiExport"); From 107ee878d66f4006f102c1fd12af3bf156a25757 Mon Sep 17 00:00:00 2001 From: Nicole Xu Date: Thu, 6 Mar 2025 01:40:24 +0000 Subject: [PATCH 241/587] 8346954: [JMH] jdk.incubator.vector.MaskedLogicOpts fails due to IndexOutOfBoundsException Co-authored-by: Jatin Bhateja Reviewed-by: jbhateja, xgong --- .../jdk/incubator/vector/MaskedLogicOpts.java | 256 ++++++++---------- 1 file changed, 116 insertions(+), 140 deletions(-) diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java index 55a3c9d6b75..7fc1fbce2e4 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/MaskedLogicOpts.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 @@ -37,19 +37,9 @@ public class MaskedLogicOpts { @Param({"256","512","1024"}) private int ARRAYLEN; - boolean [] mask_arr = { - false, false, false, true, false, false, false, false, - false, false, false, true, false, false, false, false, - false, false, false, true, false, false, false, false, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - false, false, false, true, false, false, false, false, - false, false, false, true, false, false, false, false, - false, false, false, true, false, false, false, false - }; - int INVOC_COUNTER = 4096; + boolean [] mask_arr = new boolean[ARRAYLEN]; int [] i1 = new int[ARRAYLEN]; int [] i2 = new int[ARRAYLEN]; int [] i3 = new int[ARRAYLEN]; @@ -62,39 +52,23 @@ public class MaskedLogicOpts { long [] l4 = new long[ARRAYLEN]; long [] l5 = new long[ARRAYLEN]; - Vector iv1; - Vector iv2; - Vector iv3; - Vector iv4; - Vector iv5; - - Vector lv1; - Vector lv2; - Vector lv3; - Vector lv4; - Vector lv5; - - VectorMask imask; - VectorMask lmask; - - VectorSpecies ispecies; - VectorSpecies lspecies; - int int512_arr_idx; int int256_arr_idx; int int128_arr_idx; int long256_arr_idx; int long512_arr_idx; - private Random r = new Random(); + private Random r = new Random(1024); @Setup(Level.Trial) public void init() { - int512_arr_idx = 0; - int256_arr_idx = 0; - int128_arr_idx = 0; - long256_arr_idx = 0; - long512_arr_idx = 0; + int512_arr_idx = -16; + int256_arr_idx = -8; + int128_arr_idx = -4; + long256_arr_idx = -4; + long512_arr_idx = -8; + + mask_arr = new boolean[ARRAYLEN]; i1 = new int[ARRAYLEN]; i2 = new int[ARRAYLEN]; i3 = new int[ARRAYLEN]; @@ -108,6 +82,8 @@ public class MaskedLogicOpts { l5 = new long[ARRAYLEN]; for (int i=0; i SPECIES) { - imask = VectorMask.fromArray(SPECIES, mask_arr, 0); - iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); - iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); - iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); - iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); + public void maskedLogicKernel(VectorSpecies SPECIES, int index) { + VectorMask imask = VectorMask.fromArray(SPECIES, mask_arr, index); + IntVector iv2 = IntVector.fromArray(SPECIES, i2, index); + IntVector iv3 = IntVector.fromArray(SPECIES, i3, index); + IntVector iv4 = IntVector.fromArray(SPECIES, i4, index); + IntVector iv5 = IntVector.fromArray(SPECIES, i5, index); for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + for(int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { IntVector.fromArray(SPECIES, i1, j) .lanewise(VectorOperators.AND, iv2, imask) .lanewise(VectorOperators.OR, iv2, imask) @@ -157,65 +133,65 @@ public class MaskedLogicOpts { @Benchmark public void maskedLogicOperationsInt512() { - maskedLogicKernel(IntVector.SPECIES_512); + maskedLogicKernel(IntVector.SPECIES_512, int512_arr_idx); } @Benchmark public void maskedLogicOperationsInt256() { - maskedLogicKernel(IntVector.SPECIES_256); + maskedLogicKernel(IntVector.SPECIES_256, int256_arr_idx); } @Benchmark public void maskedLogicOperationsInt128() { - maskedLogicKernel(IntVector.SPECIES_128); + maskedLogicKernel(IntVector.SPECIES_128, int128_arr_idx); } @CompilerControl(CompilerControl.Mode.INLINE) - public void partiallyMaskedLogicOperationsIntKernel(VectorSpecies SPECIES) { - imask = VectorMask.fromArray(SPECIES, mask_arr, 0); - iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); - iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); - iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); - iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); - for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { - IntVector.fromArray(SPECIES, i1, j) - .lanewise(VectorOperators.AND, iv2, imask) - .lanewise(VectorOperators.OR, iv2, imask) - .lanewise(VectorOperators.AND, iv3) - .lanewise(VectorOperators.OR, iv3) - .lanewise(VectorOperators.OR, iv4, imask) - .lanewise(VectorOperators.AND, iv4, imask) - .lanewise(VectorOperators.XOR, iv5, imask) - .intoArray(i1, j); - } - } + public void partiallyMaskedLogicOperationsIntKernel(VectorSpecies SPECIES, int index) { + VectorMask imask = VectorMask.fromArray(SPECIES, mask_arr, index); + IntVector iv2 = IntVector.fromArray(SPECIES, i2, index); + IntVector iv3 = IntVector.fromArray(SPECIES, i3, index); + IntVector iv4 = IntVector.fromArray(SPECIES, i4, index); + IntVector iv5 = IntVector.fromArray(SPECIES, i5, index); + for (int i = 0; i < INVOC_COUNTER; i++) { + for (int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { + IntVector.fromArray(SPECIES, i1, j) + .lanewise(VectorOperators.AND, iv2, imask) + .lanewise(VectorOperators.OR, iv2, imask) + .lanewise(VectorOperators.AND, iv3) + .lanewise(VectorOperators.OR, iv3) + .lanewise(VectorOperators.OR, iv4, imask) + .lanewise(VectorOperators.AND, iv4, imask) + .lanewise(VectorOperators.XOR, iv5, imask) + .intoArray(i1, j); + } + } } @Benchmark public void partiallyMaskedLogicOperationsInt512() { - partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_512); + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_512, int512_arr_idx); } @Benchmark public void partiallyMaskedLogicOperationsInt256() { - partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_256); + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_256, int256_arr_idx); } @Benchmark public void partiallyMaskedLogicOperationsInt128() { - partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_128); + partiallyMaskedLogicOperationsIntKernel(IntVector.SPECIES_128, int128_arr_idx); } @CompilerControl(CompilerControl.Mode.INLINE) - public void bitwiseBlendOperationIntKernel(VectorSpecies SPECIES) { - imask = VectorMask.fromArray(SPECIES, mask_arr, 0); - iv2 = IntVector.fromArray(SPECIES, i2, int512_arr_idx); - iv3 = IntVector.fromArray(SPECIES, i3, int512_arr_idx); - iv4 = IntVector.fromArray(SPECIES, i4, int512_arr_idx); - iv5 = IntVector.fromArray(SPECIES, i5, int512_arr_idx); - for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { + public void bitwiseBlendOperationIntKernel(VectorSpecies SPECIES, int index) { + VectorMask imask = VectorMask.fromArray(SPECIES, mask_arr, index); + IntVector iv2 = IntVector.fromArray(SPECIES, i2, index); + IntVector iv3 = IntVector.fromArray(SPECIES, i3, index); + IntVector iv4 = IntVector.fromArray(SPECIES, i4, index); + IntVector iv5 = IntVector.fromArray(SPECIES, i5, index); + for (int i = 0; i < INVOC_COUNTER; i++) { + for (int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { IntVector.fromArray(SPECIES, i1, j) .lanewise(VectorOperators.BITWISE_BLEND, iv2, iv3, imask) .lanewise(VectorOperators.BITWISE_BLEND, iv3, iv4, imask) @@ -227,106 +203,106 @@ public class MaskedLogicOpts { @Benchmark public void bitwiseBlendOperationInt512() { - bitwiseBlendOperationIntKernel(IntVector.SPECIES_512); + bitwiseBlendOperationIntKernel(IntVector.SPECIES_512, int512_arr_idx); } @Benchmark public void bitwiseBlendOperationInt256() { - bitwiseBlendOperationIntKernel(IntVector.SPECIES_256); + bitwiseBlendOperationIntKernel(IntVector.SPECIES_256, int256_arr_idx); } @Benchmark public void bitwiseBlendOperationInt128() { - bitwiseBlendOperationIntKernel(IntVector.SPECIES_128); + bitwiseBlendOperationIntKernel(IntVector.SPECIES_128, int128_arr_idx); } @CompilerControl(CompilerControl.Mode.INLINE) - public void maskedLogicOperationsLongKernel(VectorSpecies SPECIES) { - lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); - lv2 = LongVector.fromArray(SPECIES, l2, long256_arr_idx); - lv3 = LongVector.fromArray(SPECIES, l3, long256_arr_idx); - lv4 = LongVector.fromArray(SPECIES, l4, long256_arr_idx); - lv5 = LongVector.fromArray(SPECIES, l5, long256_arr_idx); - for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { - LongVector.fromArray(SPECIES, l1, j) - .lanewise(VectorOperators.AND, lv2, lmask) - .lanewise(VectorOperators.OR, lv3, lmask) - .lanewise(VectorOperators.AND, lv3, lmask) - .lanewise(VectorOperators.OR, lv4, lmask) - .lanewise(VectorOperators.AND, lv4, lmask) - .lanewise(VectorOperators.XOR, lv5, lmask) - .intoArray(l1, j); - } - } + public void maskedLogicOperationsLongKernel(VectorSpecies SPECIES, int index) { + VectorMask lmask = VectorMask.fromArray(SPECIES, mask_arr, index); + LongVector lv2 = LongVector.fromArray(SPECIES, l2, index); + LongVector lv3 = LongVector.fromArray(SPECIES, l3, index); + LongVector lv4 = LongVector.fromArray(SPECIES, l4, index); + LongVector lv5 = LongVector.fromArray(SPECIES, l5, index); + for (int i = 0; i < INVOC_COUNTER; i++) { + for (int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.AND, lv2, lmask) + .lanewise(VectorOperators.OR, lv3, lmask) + .lanewise(VectorOperators.AND, lv3, lmask) + .lanewise(VectorOperators.OR, lv4, lmask) + .lanewise(VectorOperators.AND, lv4, lmask) + .lanewise(VectorOperators.XOR, lv5, lmask) + .intoArray(l1, j); + } + } } @Benchmark public void maskedLogicOperationsLong512() { - maskedLogicOperationsLongKernel(LongVector.SPECIES_512); + maskedLogicOperationsLongKernel(LongVector.SPECIES_512, long512_arr_idx); } @Benchmark public void maskedLogicOperationsLong256() { - maskedLogicOperationsLongKernel(LongVector.SPECIES_256); + maskedLogicOperationsLongKernel(LongVector.SPECIES_256, long256_arr_idx); } @CompilerControl(CompilerControl.Mode.INLINE) - public void partiallyMaskedLogicOperationsLongKernel(VectorSpecies SPECIES) { - lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); - lv2 = LongVector.fromArray(SPECIES, l2, long512_arr_idx); - lv3 = LongVector.fromArray(SPECIES, l3, long512_arr_idx); - lv4 = LongVector.fromArray(SPECIES, l4, long512_arr_idx); - lv5 = LongVector.fromArray(SPECIES, l5, long512_arr_idx); - for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { - LongVector.fromArray(SPECIES, l1, j) - .lanewise(VectorOperators.AND, lv2, lmask) - .lanewise(VectorOperators.OR, lv2, lmask) - .lanewise(VectorOperators.AND, lv3) - .lanewise(VectorOperators.OR, lv3) - .lanewise(VectorOperators.AND, lv4) - .lanewise(VectorOperators.OR, lv4, lmask) - .lanewise(VectorOperators.XOR, lv5, lmask) - .intoArray(l1, j); - } - } + public void partiallyMaskedLogicOperationsLongKernel(VectorSpecies SPECIES, int index) { + VectorMask lmask = VectorMask.fromArray(SPECIES, mask_arr, index); + LongVector lv2 = LongVector.fromArray(SPECIES, l2, index); + LongVector lv3 = LongVector.fromArray(SPECIES, l3, index); + LongVector lv4 = LongVector.fromArray(SPECIES, l4, index); + LongVector lv5 = LongVector.fromArray(SPECIES, l5, index); + for (int i = 0; i < INVOC_COUNTER; i++) { + for (int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.AND, lv2, lmask) + .lanewise(VectorOperators.OR, lv2, lmask) + .lanewise(VectorOperators.AND, lv3) + .lanewise(VectorOperators.OR, lv3) + .lanewise(VectorOperators.AND, lv4) + .lanewise(VectorOperators.OR, lv4, lmask) + .lanewise(VectorOperators.XOR, lv5, lmask) + .intoArray(l1, j); + } + } } @Benchmark public void partiallyMaskedLogicOperationsLong512() { - partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_512); + partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_512, long512_arr_idx); } @Benchmark public void partiallyMaskedLogicOperationsLong256() { - partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_256); + partiallyMaskedLogicOperationsLongKernel(LongVector.SPECIES_256, long256_arr_idx); } @CompilerControl(CompilerControl.Mode.INLINE) - public void bitwiseBlendOperationLongKernel(VectorSpecies SPECIES) { - lmask = VectorMask.fromArray(SPECIES, mask_arr, 0); - lv2 = LongVector.fromArray(SPECIES, l2, long512_arr_idx); - lv3 = LongVector.fromArray(SPECIES, l3, long512_arr_idx); - lv4 = LongVector.fromArray(SPECIES, l4, long512_arr_idx); - lv5 = LongVector.fromArray(SPECIES, l5, long512_arr_idx); - for(int i = 0; i < INVOC_COUNTER; i++) { - for(int j = 0 ; j < ARRAYLEN; j+= SPECIES.length()) { - LongVector.fromArray(SPECIES, l1, j) - .lanewise(VectorOperators.BITWISE_BLEND, lv2, lv3, lmask) - .lanewise(VectorOperators.BITWISE_BLEND, lv3, lv4, lmask) - .lanewise(VectorOperators.BITWISE_BLEND, lv4, lv5, lmask) - .intoArray(l1, j); + public void bitwiseBlendOperationLongKernel(VectorSpecies SPECIES, int index) { + VectorMask lmask = VectorMask.fromArray(SPECIES, mask_arr, index); + LongVector lv2 = LongVector.fromArray(SPECIES, l2, index); + LongVector lv3 = LongVector.fromArray(SPECIES, l3, index); + LongVector lv4 = LongVector.fromArray(SPECIES, l4, index); + LongVector lv5 = LongVector.fromArray(SPECIES, l5, index); + for (int i = 0; i < INVOC_COUNTER; i++) { + for (int j = 0 ; j < SPECIES.loopBound(ARRAYLEN); j+= SPECIES.length()) { + LongVector.fromArray(SPECIES, l1, j) + .lanewise(VectorOperators.BITWISE_BLEND, lv2, lv3, lmask) + .lanewise(VectorOperators.BITWISE_BLEND, lv3, lv4, lmask) + .lanewise(VectorOperators.BITWISE_BLEND, lv4, lv5, lmask) + .intoArray(l1, j); } } } @Benchmark public void bitwiseBlendOperationLong512() { - bitwiseBlendOperationLongKernel(LongVector.SPECIES_512); + bitwiseBlendOperationLongKernel(LongVector.SPECIES_512, long512_arr_idx); } @Benchmark public void bitwiseBlendOperationLong256() { - bitwiseBlendOperationLongKernel(LongVector.SPECIES_256); + bitwiseBlendOperationLongKernel(LongVector.SPECIES_256, long256_arr_idx); } } From 4bb3d81479c1bbe2c6fc7b5234d0f1b6897be117 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 6 Mar 2025 01:41:22 +0000 Subject: [PATCH 242/587] 8351138: Running subset of gtests gets error printing result information Reviewed-by: erikj --- make/RunTests.gmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 44d387080df..37193fb8171 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -543,8 +543,8 @@ define SetupRunGtestTestBody print arr[0]; \ found=1; \ } \ - if (!found) { print 0; } \ - }' \ + } \ + END { if (!found) print 0; }' \ $$($1_RESULT_FILE))) \ $$(eval $1_FAILED := $$(shell $$(AWK) '/\[ FAILED \] .* tests?, \ listed below/ { print $$$$4 }' $$($1_RESULT_FILE))) \ From 3626ac35b34650dc64938af63ea21f9f4e011fe4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 6 Mar 2025 06:22:18 +0000 Subject: [PATCH 243/587] 8204868: java/util/zip/ZipFile/TestCleaner.java still fails with "cleaner failed to clean zipfile." Reviewed-by: lancea --- .../java/util/zip/ZipFile/TestCleaner.java | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/test/jdk/java/util/zip/ZipFile/TestCleaner.java b/test/jdk/java/util/zip/ZipFile/TestCleaner.java index d24aa5045fd..103191c96dd 100644 --- a/test/jdk/java/util/zip/ZipFile/TestCleaner.java +++ b/test/jdk/java/util/zip/ZipFile/TestCleaner.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 @@ -23,16 +23,24 @@ /* @test * @bug 8185582 8197989 - * @modules java.base/java.util.zip:open java.base/jdk.internal.vm.annotation * @summary Check the resources of Inflater, Deflater and ZipFile are always * cleaned/released when the instance is not unreachable + * @modules java.base/java.util.zip:open java.base/jdk.internal.vm.annotation + * @library /test/lib + * @comment The test relies on the Cleaner to invoke the cleaning actions. So + * we use "othervm" to prevent any Cleaner delays that could be contributed by any + * other tests or code that might have executed on the agentvm prior to this test + * execution + * @run main/othervm TestCleaner */ import java.io.*; import java.lang.reflect.*; import java.util.*; +import java.util.concurrent.atomic.AtomicLong; import java.util.zip.*; import jdk.internal.vm.annotation.DontInline; +import jdk.test.lib.util.ForceGC; import static java.nio.charset.StandardCharsets.US_ASCII; public class TestCleaner { @@ -59,11 +67,11 @@ public class TestCleaner { Field zsRefDef = Deflater.class.getDeclaredField("zsRef"); Field zsRefInf = Inflater.class.getDeclaredField("zsRef"); if (!zsRefDef.trySetAccessible() || !zsRefInf.trySetAccessible()) { - throw new RuntimeException("'zsRef' is not accesible"); + throw new RuntimeException("'zsRef' is not accessible"); } if (addrOf(zsRefDef.get(new Deflater())) == -1 || addrOf(zsRefInf.get(new Inflater())) == -1) { - throw new RuntimeException("'addr' is not accesible"); + throw new RuntimeException("'addr' is not accessible"); } List list = new ArrayList<>(); byte[] buf1 = new byte[1024]; @@ -84,16 +92,17 @@ public class TestCleaner { } } - int n = 10; - long cnt = list.size(); - while (n-- > 0 && cnt != 0) { - Thread.sleep(100); - System.gc(); - cnt = list.stream().filter(o -> addrOf(o) != 0).count(); + final AtomicLong numNotYetCleaned = new AtomicLong(); + // trigger GC + final boolean resourcesCleaned = ForceGC.wait(() -> { + final long remaining = list.stream().filter(o -> addrOf(o) != 0).count(); + numNotYetCleaned.set(remaining); + return remaining == 0; + }); + if (!resourcesCleaned) { + throw new RuntimeException(numNotYetCleaned.get() + + " resources haven't yet been cleaned"); } - if (cnt != 0) - throw new RuntimeException("cleaner failed to clean : " + cnt); - } @DontInline @@ -139,17 +148,18 @@ public class TestCleaner { if (zsrc != null) { Field zfileField = zsrc.getClass().getDeclaredField("zfile"); if (!zfileField.trySetAccessible()) { - throw new RuntimeException("'ZipFile.Source.zfile' is not accesible"); + throw new RuntimeException("'ZipFile.Source.zfile' is not accessible"); } - //System.out.println("zffile: " + zfileField.get(zsrc)); - int n = 10; - while (n-- > 0 && zfileField.get(zsrc) != null) { - System.out.println("waiting gc ... " + n); - System.gc(); - Thread.sleep(100); - } - if (zfileField.get(zsrc) != null) { - throw new RuntimeException("cleaner failed to clean zipfile."); + final boolean resourceCleaned = ForceGC.wait(() -> { + try { + return zfileField.get(zsrc) == null; + } catch (IllegalAccessException e) { + // shouldn't happen + throw new RuntimeException(e); + } + }); + if (!resourceCleaned) { + throw new RuntimeException("cleaner failed to clean zipfile " + zip); } } } From e82031ec1a8ae2478f83d009594d512a13fdb77e Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 6 Mar 2025 06:48:42 +0000 Subject: [PATCH 244/587] 8350756: C2 SuperWord Multiversioning: remove useless slow loop when the fast loop disappears Reviewed-by: kvn, chagedorn --- src/hotspot/share/opto/loopnode.cpp | 62 +++++++++ src/hotspot/share/opto/loopnode.hpp | 4 + src/hotspot/share/opto/loopopts.cpp | 5 +- src/hotspot/share/opto/opaquenode.cpp | 20 +++ src/hotspot/share/opto/opaquenode.hpp | 17 ++- .../compiler/lib/ir_framework/IRNode.java | 5 + ...TestMultiversionRemoveUselessSlowLoop.java | 124 ++++++++++++++++++ 7 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMultiversionRemoveUselessSlowLoop.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 8be412412ea..1ccc132fd38 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -41,6 +41,7 @@ #include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/opaquenode.hpp" +#include "opto/opcodes.hpp" #include "opto/predicates.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" @@ -2731,6 +2732,20 @@ Node* CountedLoopNode::match_incr_with_optional_truncation(Node* expr, Node** tr return nullptr; } +IfNode* CountedLoopNode::find_multiversion_if_from_multiversion_fast_main_loop() { + assert(is_main_loop() && is_multiversion_fast_loop(), "must be multiversion fast main loop"); + CountedLoopEndNode* pre_end = find_pre_loop_end(); + if (pre_end == nullptr) { return nullptr; } + Node* pre_entry = pre_end->loopnode()->in(LoopNode::EntryControl); + const Predicates predicates(pre_entry); + IfTrueNode* before_predicates = predicates.entry()->isa_IfTrue(); + if (before_predicates != nullptr && + before_predicates->in(0)->in(1)->is_OpaqueMultiversioning()) { + return before_predicates->in(0)->as_If(); + } + return nullptr; +} + LoopNode* CountedLoopNode::skip_strip_mined(int expect_skeleton) { if (is_strip_mined() && in(EntryControl) != nullptr && in(EntryControl)->is_OuterStripMinedLoop()) { verify_strip_mined(expect_skeleton); @@ -4536,6 +4551,49 @@ void PhaseIdealLoop::eliminate_useless_zero_trip_guard() { } } +void PhaseIdealLoop::eliminate_useless_multiversion_if() { + if (_multiversion_opaque_nodes.size() == 0) { + return; + } + + ResourceMark rm; + Unique_Node_List useful_multiversioning_opaque_nodes; + + // The OpaqueMultiversioning is only used from the fast main loop in AutoVectorization, to add + // speculative runtime-checks to the multiversion_if. Thus, a OpaqueMultiversioning is only + // useful if it can be found from a fast main loop. If it can not be found from a fast main loop, + // then we cannot ever use that multiversion_if to add more speculative runtime-checks, and hence + // it is useless. If it is still in delayed mode, i.e. has not yet had any runtime-checks added, + // then we can let it constant fold towards the fast loop. + for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { + IdealLoopTree* lpt = iter.current(); + if (lpt->_child == nullptr && lpt->is_counted()) { + CountedLoopNode* head = lpt->_head->as_CountedLoop(); + if (head->is_main_loop() && head->is_multiversion_fast_loop()) { + // There are fast_loop pre/main/post loops, but the finding traversal starts at the main + // loop, and traverses via the fast pre loop to the multiversion_if. + IfNode* multiversion_if = head->find_multiversion_if_from_multiversion_fast_main_loop(); + if (multiversion_if != nullptr) { + useful_multiversioning_opaque_nodes.push(multiversion_if->in(1)->as_OpaqueMultiversioning()); + } + } + } + } + + for (uint i = 0; i < _multiversion_opaque_nodes.size(); i++) { + OpaqueMultiversioningNode* opaque = _multiversion_opaque_nodes.at(i)->as_OpaqueMultiversioning(); + if (!useful_multiversioning_opaque_nodes.member(opaque)) { + if (opaque->is_delayed_slow_loop()) { + // We cannot hack the node directly, otherwise the slow_loop will complain that it cannot + // find the multiversioning opaque node. Instead, we mark the opaque node as useless, and + // it can be constant folded during IGVN. + opaque->mark_useless(); + _igvn._worklist.push(opaque); + } + } + } +} + //------------------------process_expensive_nodes----------------------------- // Expensive nodes have their control input set to prevent the GVN // from commoning them and as a result forcing the resulting node to @@ -4805,6 +4863,7 @@ void PhaseIdealLoop::build_and_optimize() { } eliminate_useless_zero_trip_guard(); + eliminate_useless_multiversion_if(); if (stop_early) { assert(do_expensive_nodes, "why are we here?"); @@ -6596,6 +6655,9 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { _zero_trip_guard_opaque_nodes.push(n); } + if (!_verify_only && n->Opcode() == Op_OpaqueMultiversioning) { + _multiversion_opaque_nodes.push(n); + } } #ifdef ASSERT diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index a9c5d697c6b..dd310e769d6 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -290,6 +290,8 @@ public: bool has_atomic_post_loop () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; } void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; } + IfNode* find_multiversion_if_from_multiversion_fast_main_loop(); + int main_idx() const { return _main_idx; } @@ -932,6 +934,7 @@ private: // clear out dead code after build_loop_late Node_List _deadlist; Node_List _zero_trip_guard_opaque_nodes; + Node_List _multiversion_opaque_nodes; // Support for faster execution of get_late_ctrl()/dom_lca() // when a node has many uses and dominator depth is deep. @@ -1453,6 +1456,7 @@ public: void eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates); void eliminate_useless_zero_trip_guard(); + void eliminate_useless_multiversion_if(); public: // Change the control input of expensive nodes to allow commoning by diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 2d564c3c8cf..125399ea11a 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -791,7 +791,10 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { // Ignore Template Assertion Predicates with OpaqueTemplateAssertionPredicate nodes. return nullptr; } - assert(bol->Opcode() == Op_Bool, "Unexpected node"); + if (!bol->is_Bool()) { + assert(false, "Expected Bool, but got %s", NodeClassNames[bol->Opcode()]); + return nullptr; + } int cmp_op = bol->in(1)->Opcode(); if (cmp_op == Op_SubTypeCheck) { // SubTypeCheck expansion expects an IfNode return nullptr; diff --git a/src/hotspot/share/opto/opaquenode.cpp b/src/hotspot/share/opto/opaquenode.cpp index 672ea13e507..949bdfbc839 100644 --- a/src/hotspot/share/opto/opaquenode.cpp +++ b/src/hotspot/share/opto/opaquenode.cpp @@ -82,6 +82,26 @@ IfNode* OpaqueZeroTripGuardNode::if_node() const { return iff->as_If(); } +Node* OpaqueMultiversioningNode::Identity(PhaseGVN* phase) { + // Constant fold the multiversion_if. Since the slow_loop is still delayed, + // i.e. we have not yet added any possibly failing condition, we can just + // take the true branch in all cases. + if (_useless) { + assert(_is_delayed_slow_loop, "the slow_loop should still be delayed"); + return in(1); + } + return Opaque1Node::Identity(phase); +} + +#ifndef PRODUCT +void OpaqueMultiversioningNode::dump_spec(outputStream *st) const { + Opaque1Node::dump_spec(st); + if (_useless) { + st->print(" #useless"); + } +} +#endif + const Type* OpaqueNotNullNode::Value(PhaseGVN* phase) const { return phase->type(in(1)); } diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 0e8a53efd34..80d5ae6cd3e 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -101,17 +101,30 @@ public: class OpaqueMultiversioningNode : public Opaque1Node { private: bool _is_delayed_slow_loop; + bool _useless; public: OpaqueMultiversioningNode(Compile* C, Node* n) : - Opaque1Node(C, n), _is_delayed_slow_loop(true) + Opaque1Node(C, n), _is_delayed_slow_loop(true), _useless(false) { init_class_id(Class_OpaqueMultiversioning); } virtual int Opcode() const; virtual const Type* bottom_type() const { return TypeInt::BOOL; } bool is_delayed_slow_loop() const { return _is_delayed_slow_loop; } - void notify_slow_loop_that_it_can_resume_optimizations() { _is_delayed_slow_loop = false; } + + void notify_slow_loop_that_it_can_resume_optimizations() { + assert(!_useless, "must still be useful"); + _is_delayed_slow_loop = false; + } + + void mark_useless() { + assert(_is_delayed_slow_loop, "must still be delayed"); + _useless = true; + } + + virtual Node* Identity(PhaseGVN* phase); + NOT_PRODUCT(virtual void dump_spec(outputStream* st) const;) }; // This node is used in the context of intrinsics. We sometimes implicitly know that an object is non-null even though diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 6e373207d9c..20a0af1f111 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -329,6 +329,11 @@ public class IRNode { superWordNodes(ADD_REDUCTION_VL, "AddReductionVL"); } + public static final String OPAQUE_MULTIVERSIONING = PREFIX + "OPAQUE_MULTIVERSIONING" + POSTFIX; + static { + beforeMatchingNameRegex(OPAQUE_MULTIVERSIONING, "OpaqueMultiversioning"); + } + public static final String ADD_P_OF = COMPOSITE_PREFIX + "ADD_P_OF" + POSTFIX; static { String regex = START + "addP_" + IS_REPLACED + MID + ".*" + END; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMultiversionRemoveUselessSlowLoop.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMultiversionRemoveUselessSlowLoop.java new file mode 100644 index 00000000000..7d2f56c66f3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMultiversionRemoveUselessSlowLoop.java @@ -0,0 +1,124 @@ +/* + * 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.*; + +/* + * @test + * @bug 8350756 + * @summary Test case where the multiversion fast_loop disappears, and we should + * constant fold the multiversion_if, to remove the slow_loop. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMultiversionRemoveUselessSlowLoop + */ + +public class TestMultiversionRemoveUselessSlowLoop { + + public static void main(String[] args) { + TestFramework framework = new TestFramework(TestMultiversionRemoveUselessSlowLoop.class); + // No traps means we cannot use the predicates version for SuperWord / AutoVectorization, + // and instead use multiversioning directly. + framework.addFlags("-XX:-TieredCompilation", "-XX:PerMethodTrapLimit=0"); + framework.setDefaultWarmup(0); // simulates Xcomp + framework.start(); + } + + public static final int SIZE = 20; + public static final int[] a = new int[SIZE]; + public static final int[] b = new int[SIZE]; + public static final int SIZE2 = 10_000; + public static final int[] a2 = new int[SIZE2]; + public static final int[] b2 = new int[SIZE2]; + + @Test + @IR(counts = {"pre .* multiversion_fast", "= 2", // regular pre-main-post for both loops + "main .* multiversion_fast", "= 2", + "post .* multiversion_fast", "= 2", + "multiversion_delayed_slow", "= 2", // both have the delayed slow_loop + "multiversion", "= 8", // nothing unexpected + IRNode.OPAQUE_MULTIVERSIONING, "= 2"}, // Both multiversion_if are still here + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PHASEIDEALLOOP1) + @IR(counts = {"pre .* multiversion_fast", "= 2", + "main .* multiversion_fast", "= 1", // The first main loop is fully unrolled + "post .* multiversion_fast", "= 3", // the second loop is vectorized, and has a vectorized post loop + "multiversion_delayed_slow", "= 1", // As a consequence of the first main loop being removed, we constant fold the multiversion_if + "multiversion", "= 7", // nothing unexpected + IRNode.OPAQUE_MULTIVERSIONING, "= 1"}, // The multiversion_if of the first loop was constant folded, because the main loop disappeared. + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PHASEIDEALLOOP_ITERATIONS) + @IR(counts = {"pre .* multiversion_fast.*", ">= 1", // In some cases, the pre loop of the first loop also disappears because it only has a single iteration + "pre .* multiversion_fast.*", "<= 2", // but not in other cases the pre loop of the first loop remains. + "main .* multiversion_fast", "= 1", + "post .* multiversion_fast", "= 3", + "multiversion_delayed_slow", "= 0", // The second loop's multiversion_if was also not used, so it is constant folded after loop opts. + "multiversion", ">= 5", // nothing unexpected + "multiversion", "<= 6", // nothing unexpected + IRNode.OPAQUE_MULTIVERSIONING, "= 0"}, // After loop-opts, we also constant fold the multiversion_if of the second loop, as it is unused. + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + phase = CompilePhase.PRINT_IDEAL) + public static void testIR() { + // This loop is short, and the multiversion_fast main loop eventuall is fully unrolled. + for (int i = 0; i < SIZE; i++) { + a[i] = b[i]; + } + // We take this second loop with a larger limit so that loop opts keeps going once the loop + // above is fully optimized. It also gives us a reference where the main loop of the + // multiverion fast_loop does not disappear. + for (int i = 0; i < SIZE2; i++) { + a2[i] = b2[i]; + } + } + + static long instanceCount; + static int iFld; + static int iFld1; + + // The inner loop is Multiversioned, then PreMainPost and Unroll. + // Eventually, both the fast and slow loops (pre main and post) disappear, + // and leave us with a simple if-diamond using the multiversion_if. + // + // Verification code in PhaseIdealLoop::conditional_move finds this diamond + // and expects a Bool but gets an OpaqueMultiversioning instead. + // + // If we let the multiversion_if constant fold soon after the main fast loop + // disappears, then this issue does not occur any more. + @Test + public static void testCrash() { + boolean b2 = true; + for (int i = 0; i < 1000; i++) { + for (int i21 = 82; i21 > 9; --i21) { + if (b2) + break; + iFld1 = iFld; + b2 = true; + } + instanceCount = iFld1; + } + } +} From 5c552a9d64c8116161cb9ef4c777e75a2602a75b Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 6 Mar 2025 07:00:44 +0000 Subject: [PATCH 245/587] 8349358: [JMH] Cannot access class jdk.internal.vm.ContinuationScope Reviewed-by: alanb --- .../bench/loom/obsolete/FreezeAndThaw.java | 149 ----------- .../openjdk/bench/loom/obsolete/OneShot.java | 252 ------------------ .../bench/loom/obsolete/Oscillation.java | 104 -------- 3 files changed, 505 deletions(-) delete mode 100644 test/micro/org/openjdk/bench/loom/obsolete/FreezeAndThaw.java delete mode 100644 test/micro/org/openjdk/bench/loom/obsolete/OneShot.java delete mode 100644 test/micro/org/openjdk/bench/loom/obsolete/Oscillation.java diff --git a/test/micro/org/openjdk/bench/loom/obsolete/FreezeAndThaw.java b/test/micro/org/openjdk/bench/loom/obsolete/FreezeAndThaw.java deleted file mode 100644 index dd011f2033a..00000000000 --- a/test/micro/org/openjdk/bench/loom/obsolete/FreezeAndThaw.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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.loom.obsolete; - -import jdk.internal.vm.Continuation; -import jdk.internal.vm.ContinuationScope; - -import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.*; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(1) -public class FreezeAndThaw { - static final ContinuationScope SCOPE = new ContinuationScope() { }; - - static class Arg { - volatile int field; - } - - /** - * A recursive task that optionally yields when the stack gets to a specific - * depth. If continued after yielding, it runs to completion. - */ - static class Yielder implements Runnable { - private final int paramCount; - private final int maxDepth; - private final boolean yieldAtLimit; - - private Yielder(int paramCount, int maxDepth, boolean yieldAtLimit) { - if (paramCount < 1 || paramCount > 3) - throw new IllegalArgumentException(); - this.paramCount = paramCount; - this.maxDepth = maxDepth; - this.yieldAtLimit = yieldAtLimit; - } - - @Override - public void run() { - switch (paramCount) { - case 1: run1(maxDepth); break; - case 2: run2(maxDepth, new Arg()); break; - case 3: run3(maxDepth, new Arg(), new Arg()); break; - default: throw new Error("should not happen"); - } - } - - private void run1(int depth) { - if (depth > 0) { - run1(depth - 1); - } if (depth == 0) { - if (yieldAtLimit) Continuation.yield(SCOPE); - } - } - - private void run2(int depth, Arg arg2) { - if (depth > 0) { - run2(depth - 1, arg2); - } if (depth == 0) { - if (yieldAtLimit) Continuation.yield(SCOPE); - } else { - // never executed - arg2.field = 0; - } - } - - private void run3(int depth, Arg arg2, Arg arg3) { - if (depth > 0) { - run3(depth - 1, arg2, arg3); - } if (depth == 0) { - if (yieldAtLimit) { - Continuation.yield(SCOPE); - } - } else { - // never executed - arg2.field = 0; - arg3.field = 0; - } - } - - static Continuation continuation(int paramCount, int maxDepth, - boolean yieldAtLimit) { - Runnable task = new Yielder(paramCount, maxDepth, yieldAtLimit); - return new Continuation(SCOPE, task); - } - } - - @Param({"1", "2", "3"}) - public int paramCount; - - @Param({"5", "10", "20", "100"}) - public int stackDepth; - - Continuation cont; - Continuation cont0; - - @Setup(Level.Invocation) - public void setup() { - // System.out.println("pc = " + paramCount + " sd = " + stackDepth); - cont = Yielder.continuation(paramCount, stackDepth, true); - cont0 = Yielder.continuation(paramCount, stackDepth, false); - } - - /** - * Creates and runs a continuation that yields at a given stack depth. - */ - @Benchmark - public void baseline() { - // Continuation cont0 = Yielder.continuation(paramCount, stackDepth, false); - cont0.run(); - assert cont0.isDone(); - } - - /** - * Creates and runs a continuation that yields at a given stack depth. - */ - @Benchmark - public void yieldAndContinue() { - // Continuation cont = Yielder.continuation(paramCount, stackDepth, true); - cont.run(); - assert !cont.isDone(); - cont.run(); - assert cont.isDone(); - } -} diff --git a/test/micro/org/openjdk/bench/loom/obsolete/OneShot.java b/test/micro/org/openjdk/bench/loom/obsolete/OneShot.java deleted file mode 100644 index bd96153315b..00000000000 --- a/test/micro/org/openjdk/bench/loom/obsolete/OneShot.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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.loom.obsolete; - -import jdk.internal.vm.Continuation; -import jdk.internal.vm.ContinuationScope; - -import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.*; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(1) -public class OneShot { - static final ContinuationScope SCOPE = new ContinuationScope() { }; - - static class Arg { - volatile int field; - } - - /** - * A recursive task that optionally yields when the stack gets to a specific - * depth. If continued after yielding, it runs to completion. - */ - static class Yielder implements Runnable { - private final int paramCount; - private final int maxDepth; - private final boolean yieldAtLimit; - - private Yielder(int paramCount, int maxDepth, boolean yieldAtLimit) { - if (paramCount < 1 || paramCount > 3) - throw new IllegalArgumentException(); - this.paramCount = paramCount; - this.maxDepth = maxDepth; - this.yieldAtLimit = yieldAtLimit; - } - - @Override - public void run() { - switch (paramCount) { - case 1: run1(maxDepth); break; - case 2: run2(maxDepth, new Arg()); break; - case 3: run3(maxDepth, new Arg(), new Arg()); break; - default: throw new Error("should not happen"); - } - } - - private void run1(int depth) { - if (depth > 0) { - run1(depth - 1); - } if (depth == 0) { - if (yieldAtLimit) Continuation.yield(SCOPE); - } - } - - private void run2(int depth, Arg arg2) { - if (depth > 0) { - run2(depth - 1, arg2); - } if (depth == 0) { - if (yieldAtLimit) Continuation.yield(SCOPE); - } else { - // never executed - arg2.field = 0; - } - } - - private void run3(int depth, Arg arg2, Arg arg3) { - if (depth > 0) { - run3(depth - 1, arg2, arg3); - } if (depth == 0) { - if (yieldAtLimit) Continuation.yield(SCOPE); - } else { - // never executed - arg2.field = 0; - arg3.field = 0; - } - } - - static Continuation continuation(int paramCount, int maxDepth, - boolean yieldAtLimit) { - Runnable task = new Yielder(paramCount, maxDepth, yieldAtLimit); - return new Continuation(SCOPE, task); - } - } - - /** - * A recursive task that optionally yields before and/or after each call. - */ - static class Stepper implements Runnable { - private final int paramCount; - private final int maxDepth; - private final boolean yieldBefore; - private final boolean yieldAfter; - - private Stepper(int paramCount, - int maxDepth, - boolean yieldBefore, - boolean yieldAfter) { - this.paramCount = paramCount; - this.maxDepth = maxDepth; - this.yieldBefore = yieldBefore; - this.yieldAfter = yieldAfter; - } - - public void run() { - switch (paramCount) { - case 1: run1(maxDepth); break; - case 2: run2(maxDepth, new Arg()); break; - case 3: run3(maxDepth, new Arg(), new Arg()); break; - default: throw new Error("should not happen"); - } - } - - private void run1(int depth) { - if (depth > 0) { - if (yieldBefore) Continuation.yield(SCOPE); - run1(depth - 1); - if (yieldAfter) Continuation.yield(SCOPE); - } - } - - private void run2(int depth, Arg arg2) { - if (depth > 0) { - if (yieldBefore) Continuation.yield(SCOPE); - run2(depth - 1, arg2); - if (yieldAfter) Continuation.yield(SCOPE); - } else if (depth < 0) { - // never executed - arg2.field = 0; - } - } - - private void run3(int depth, Arg arg2, Arg arg3) { - if (depth > 0) { - if (yieldBefore) Continuation.yield(SCOPE); - run3(depth - 1, arg2, arg3); - if (yieldAfter) Continuation.yield(SCOPE); - } else if (depth < 0) { - // never executed - arg2.field = 0; - arg3.field = 0; - } - } - - static Continuation continuation(int paramCount, int maxDepth, - boolean yieldBefore, boolean yieldAfter) { - Runnable task = new Stepper(paramCount, maxDepth, yieldBefore, yieldAfter); - return new Continuation(SCOPE, task); - } - } - - @Param({"1", "2", "3"}) - public int paramCount; - - @Param({"5", "10", "20", "100"}) - public int stackDepth; - - /** - * Creates and run continuation that does not yield. - */ - @Benchmark - public void noYield() { - Continuation cont = Yielder.continuation(paramCount, stackDepth, false); - cont.run(); - if (!cont.isDone()) - throw new RuntimeException("continuation not done???"); - } - - /** - * Creates and runs a continuation that yields at a given stack depth. - */ - @Benchmark - public void yield() { - Continuation cont = Yielder.continuation(paramCount, stackDepth, true); - cont.run(); - if (cont.isDone()) - throw new RuntimeException("continuation done???"); - } - - /** - * Creates and runs a continuation that yields at a given stack depth, it is - * then continued to run to completion. - */ - @Benchmark - public void yieldThenContinue() { - Continuation cont = Yielder.continuation(paramCount, stackDepth, true); - cont.run(); - cont.run(); // continue - if (!cont.isDone()) - throw new RuntimeException("continuation not done???"); - } - - /** - * Creates and runs a continuation to the given stack depth, yielding before - * each call. - */ - @Benchmark - public void yieldBeforeEachCall() { - Continuation cont = Stepper.continuation(paramCount, stackDepth, true, false); - while (!cont.isDone()) { - cont.run(); - } - } - - /** - * Creates and runs a continuation to the given stack depth, yielding after - * each call. - */ - @Benchmark - public void yieldAfterEachCall() { - Continuation cont = Stepper.continuation(paramCount, stackDepth, false, true); - while (!cont.isDone()) { - cont.run(); - } - } - - /** - * Creates and runs a continuation to the given stack depth, yielding before - * and after each call. - */ - @Benchmark - public void yieldBeforeAndAfterEachCall() { - Continuation cont = Stepper.continuation(paramCount, stackDepth, true, true); - while (!cont.isDone()) { - cont.run(); - } - } -} diff --git a/test/micro/org/openjdk/bench/loom/obsolete/Oscillation.java b/test/micro/org/openjdk/bench/loom/obsolete/Oscillation.java deleted file mode 100644 index 0117508bd8d..00000000000 --- a/test/micro/org/openjdk/bench/loom/obsolete/Oscillation.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2018, 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 - * 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.loom.obsolete; - -import jdk.internal.vm.Continuation; -import jdk.internal.vm.ContinuationScope; - -import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.*; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Benchmark) -@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@Fork(1) -public class Oscillation { - static final ContinuationScope SCOPE = new ContinuationScope() { }; - - /** - * A task that oscillates between a minimum and maximum stack depth, yielding - * at the maximum stack until continued. - */ - static class Wave implements Runnable { - private final int min; - private final int max; - - private enum Mode { GROW, SHRINK } - private Mode mode; - - Wave(int min, int max) { - if (min < 0) - throw new IllegalArgumentException("negative min"); - if (max <= min) - throw new IllegalArgumentException("max must be greater than min"); - this.min = min; - this.max = max; - this.mode = Mode.GROW; - } - - private void run(int depth) { - if (depth == max) { - Continuation.yield(SCOPE); - mode = Mode.SHRINK; - } else if (depth == min) { - while (true) { - mode = Mode.GROW; - run(depth + 1); - } - } else if (mode == Mode.GROW) { - run(depth + 1); - } - } - - @Override - public void run() { - run(0); - } - } - - @Param({"2", "3", "4"}) - public int minDepth; - - @Param({"5", "6", "7", "8"}) - public int maxDepth; - - @Param({"10", "100", "1000"}) - public int repeat; - - /** - * Creates and runs a continuation that oscillates between a minimum and - * maximum stack depth, yielding at the maximum stack until continued. - * - * Useful to measure freeze and thaw, also to compare full stack vs. lazy copy. - */ - @Benchmark - public void oscillate() { - Continuation cont = new Continuation(SCOPE, new Wave(minDepth, maxDepth)); - for (int i=0; i Date: Thu, 6 Mar 2025 07:42:16 +0000 Subject: [PATCH 246/587] 8323158: HotSpot Style Guide should specify more include ordering Reviewed-by: kbarrett, stuefe, dholmes, kvn --- doc/hotspot-style.html | 28 ++++++++++++++++++---------- doc/hotspot-style.md | 29 +++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 9f26fc66362..72e5ce66e19 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -207,23 +207,31 @@ the simple "getter".

  • All source files must have a globally unique basename. The build system depends on this uniqueness.

  • +
  • Keep the include lines within a section alphabetically sorted.

  • +
  • Put conditional inclusions (`#if ...`) at the end of the section of HotSpot +include lines. This also applies to macro-expanded includes of platform +dependent files.

  • +
  • Put system includes in a section after the HotSpot include lines with a blank +line separating the two sections.

  • Do not put non-trivial function implementations in .hpp files. If -the implementation depends on other .hpp files, put it in a .cpp or a -.inline.hpp file.

  • +the implementation depends on other .hpp files, put it in a .cpp or +a .inline.hpp file.

  • .inline.hpp files should only be included in .cpp or .inline.hpp files.

  • -
  • All .inline.hpp files should include their corresponding .hpp -file as the first include line. Declarations needed by other files -should be put in the .hpp file, and not in the .inline.hpp file. This -rule exists to resolve problems with circular dependencies between -.inline.hpp files.

  • +
  • All .inline.hpp files should include their corresponding .hpp file as +the first include line with a blank line separating it from the rest of the +include lines. Declarations needed by other files should be put in the .hpp +file, and not in the .inline.hpp file. This rule exists to resolve problems +with circular dependencies between .inline.hpp files.

  • +
  • Do not include a .hpp file if the corresponding .inline.hpp file is included.

  • +
  • Use include guards for .hpp and .inline.hpp files. The name of the defined +guard should be derived from the full search path of the file relative to the +hotspot source directory. The guard should be all upper case with all paths +separators and periods replaced by underscores.

  • Some build configurations use precompiled headers to speed up the build times. The precompiled headers are included in the precompiled.hpp file. Note that precompiled.hpp is just a build time optimization, so don't rely on it to resolve include problems.

  • -
  • Keep the include lines alphabetically sorted.

  • -
  • Put conditional inclusions (#if ...) at the end of -the include list.

JTReg Tests